--- a/.hgignore Thu Jul 19 13:17:35 2007 +0200
+++ b/.hgignore Fri Sep 28 11:59:46 2007 +0100
@@ -1,9 +1,10 @@
-.*.orig$
-.*\.o$
-.*~$
-build-dir
-build
-.*\.sconsign
-doc/html.*
-doc/latex.*
-.lock-wscript
+\.rej$
+\.orig$
+\.o$
+~$
+^build-dir
+^build
+^doc/html
+^doc/latex
+^\.lock-wscript
+^\.waf
--- a/.hgtags Thu Jul 19 13:17:35 2007 +0200
+++ b/.hgtags Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,8 @@
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
--- a/AUTHORS Thu Jul 19 13:17:35 2007 +0200
+++ b/AUTHORS Fri Sep 28 11:59:46 2007 +0100
@@ -3,4 +3,5 @@
Craig Dowell (craigdo@ee.washington.edu)
Tom Henderson (tomhend@u.washington.edu)
Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
+Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
George F. Riley (riley@ece.gatech.edu)
--- a/README Thu Jul 19 13:17:35 2007 +0200
+++ b/README Fri Sep 28 11:59:46 2007 +0100
@@ -71,17 +71,13 @@
To build the set of default libraries and the example
programs included in this package, you need to use the
-tool 'scons'. Detailed information on how to install
-and use scons is included in the file doc/build.txt
+tool 'waf'. Detailed information on how to install
+and 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 "scons" the the directory which contains
+type the command "./waf" the the directory which contains
this README file. The files built will be copied in the
-build-dir/dbg-shared/bin and build-dir/dbg-shared/lib
-directories. build-dir/dbg-shared/bin will contain
-one binary for each of the sample code in the 'samples'
-directory and one binary for each of the detailed examples
-found in the 'examples' directory.
+build/debug or build/optimized.
The current codebase is expected to build and run on the
following set of platforms:
@@ -106,12 +102,7 @@
should be easy to run the sample programs with the
following command:
-./build-dir/dbg-shared/bin/simple-p2p
-
-or:
-
-cd build-dir/dbg-shared/bin
-./simple-p2p
+./waf --run simple-p2p
That program should generate a simple-p2p.tr text
trace file and a set of simple-p2p-xx-xx.pcap binary
@@ -152,7 +143,7 @@
file in http://code.nsnam.org/docs
- the doxygen documentation is generated from the doc/doxygen.conf
- configuration file. The command "scons doc" will generate it
+ configuration file. The command "./waf --doxygen" will generate it
as doc/html/index.html if you have installed the doxygen tools
(see http://www.doxygen.org)
--- a/RELEASE_NOTES Thu Jul 19 13:17:35 2007 +0200
+++ b/RELEASE_NOTES Fri Sep 28 11:59:46 2007 +0100
@@ -3,6 +3,32 @@
This file contains ns-3 release notes (most recent releases first).
+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
+ - Generalized, polymorphic Address class
+ - Add CSMA NetDevice model (from Emmanuelle Laprise)
+ - Modularize IPv4 routing support (from Gustavo Carneiro)
+ - Add mobility framework and basic mobility models
+ - Global unicast centralized routing
+
+Release 3.0.4 (2007/07/15)
+========================
+
+ - Enable waf as the default build system.
+ - Per-packet metadata: a system to track which headers and trailers
+ are added to a packet
+ - Simplifications to point-to-point devices and channel
+
Release 3.0.3 (2007/06/15)
========================
--- a/SConstruct Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,542 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import os.path
-import build
-
-version_file = open ('VERSION', 'r')
-version = version_file.readline ()
-version_file.close ()
-version = version.strip ()
-
-ns3 = build.Ns3()
-ns3.build_dir = 'build-dir'
-ns3.version = version
-ns3.name = 'ns3'
-ns3.distname = 'ns'
-ns3.doxygen_config = os.path.join('doc', 'doxygen.conf')
-ns3.add_extra_dist(os.path.join('doc', 'main.txt'))
-ns3.add_extra_dist ('doc/architecture.pdf')
-ns3.add_extra_dist ('doc/contributing.txt')
-ns3.add_extra_dist ('doc/build.txt')
-ns3.add_extra_dist ('doc/codingstd.txt')
-ns3.add_extra_dist ('doc/mercurial.txt')
-ns3.add_extra_dist ('README')
-ns3.add_extra_dist ('RELEASE_NOTES')
-ns3.add_extra_dist ('AUTHORS')
-ns3.add_extra_dist ('VERSION')
-
-ns3.add_extra_dist('doc/build-waf.txt')
-ns3.add_extra_dist('ns3/_placeholder_')
-for wscript in [
- "src/core/wscript",
- "src/node/wscript",
- "src/devices/p2p/wscript",
- "src/common/wscript",
- "src/applications/wscript",
- "src/simulator/wscript",
- "src/internet-node/wscript",
- "src/wscript",
- "utils/wscript",
- "samples/wscript",
- "examples/wscript",
- "wscript",
- ]:
- ns3.add_extra_dist(wscript)
-ns3.add_extra_dist('waf')
-ns3.add_extra_dist('waf.bat')
-
-
-
-#
-# The Core module
-#
-core = build.Ns3Module('core', 'src/core')
-ns3.add(core)
-core.add_sources([
- 'callback-test.cc',
- 'debug.cc',
- 'assert.cc',
- 'ptr.cc',
- 'object.cc',
- 'test.cc',
- 'random-variable.cc',
- 'rng-stream.cc',
- 'uid-manager.cc',
- 'default-value.cc',
- 'random-variable-default-value.cc',
- 'command-line.cc',
- 'type-name.cc',
- 'component-manager.cc',
- ])
-env = Environment()
-if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin':
- core.add_external_dep('pthread')
- core.add_sources([
- 'unix-system-wall-clock-ms.cc',
- ])
-elif env['PLATFORM'] == 'win32':
- core.add_sources([
- 'win32-system-wall-clock-ms.cc',
- ])
-core.add_headers ([
- 'uid-manager.h',
- 'singleton.h',
-])
-core.add_inst_headers([
- 'system-wall-clock-ms.h',
- 'empty.h',
- 'callback.h',
- 'ptr.h',
- 'object.h',
- 'debug.h',
- 'assert.h',
- 'fatal-error.h',
- 'test.h',
- 'random-variable.h',
- 'rng-stream.h',
- 'default-value.h',
- 'random-variable-default-value.h',
- 'command-line.h',
- 'type-name.h',
- 'component-manager.h',
- ])
-
-def config_core (env, config):
- retval = []
- # XXX This check is primitive but it should be
- # good enough for now.
- if config.CheckCHeader ('stdlib.h') == 1:
- retval.append ('#define HAVE_STDLIB_H 1')
- retval.append ('#define HAVE_GETENV 1')
- else:
- retval.append ('#undef HAVE_STDLIB_H')
- retval.append ('#undef HAVE_GETENV')
- return retval
-core.add_config (config_core)
-
-#
-# The Simu module
-#
-simu = build.Ns3Module('simulator', 'src/simulator')
-ns3.add(simu)
-simu.add_dep('core')
-simu.add_external_dep('m')
-simu.add_sources([
- 'high-precision.cc',
- 'time.cc',
- 'event-id.cc',
- 'scheduler.cc',
- 'scheduler-factory.cc',
- 'scheduler-list.cc',
- 'scheduler-heap.cc',
- 'scheduler-map.cc',
- 'event-impl.cc',
- 'simulator.cc',
- 'time-default-value.cc',
- ])
-simu.add_headers([
- 'scheduler-heap.h',
- 'scheduler-map.h',
- 'scheduler-list.h'
- ])
-simu.add_inst_headers([
- 'high-precision.h',
- 'nstime.h',
- 'event-id.h',
- 'event-impl.h',
- 'simulator.h',
- 'scheduler.h',
- 'scheduler-factory.h',
- 'simulation-singleton.h',
- 'time-default-value.h',
- ])
-high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
-if high_precision_as_double == 'y':
- simu.add_inst_header ('high-precision-double.h')
- simu.add_source ('high-precision-double.cc')
-else:
- simu.add_inst_headers ([
- 'high-precision-128.h',
- 'cairo-wideint-private.h'
- ])
- simu.add_sources ([
- 'high-precision-128.cc',
- 'cairo-wideint.c',
- ])
-
-def config_simulator (env, config):
- retval = []
- high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
- if high_precision_as_double == 'y':
- retval.append ('#define USE_HIGH_PRECISION_DOUBLE 1')
- else:
- retval.append ('#undef USE_HIGH_PRECISION_DOUBLE')
- if config.CheckCHeader ('stdint.h') == 1:
- retval.append ('#define HAVE_STDINT_H 1')
- elif config.CheckCHeader ('inttypes.h') == 1:
- retval.append ('#define HAVE_INTTYPES_H 1')
- elif config.CheckCHeader ('sys/inttypes.h') == 1:
- retval.append ('#define HAVE_SYS_INT_TYPES_H 1')
- return retval
-simu.add_config (config_simulator)
-
-
-#
-# The Common module
-#
-common = build.Ns3Module('common', 'src/common')
-common.add_deps(['core', 'simulator'])
-ns3.add(common)
-common.add_sources([
- 'buffer.cc',
- 'chunk.cc',
- 'header.cc',
- 'trailer.cc',
- 'packet.cc',
- 'tags.cc',
- 'pcap-writer.cc',
- 'variable-tracer-test.cc',
- 'trace-context.cc',
- 'trace-resolver.cc',
- 'callback-trace-source.cc',
- 'empty-trace-resolver.cc',
- 'composite-trace-resolver.cc',
- 'trace-root.cc',
- 'data-rate.cc',
- ])
-common.add_headers ([
- ])
-common.add_inst_headers([
- 'buffer.h',
- 'chunk.h',
- 'header.h',
- 'trailer.h',
- 'tags.h',
- 'packet.h',
- 'uv-trace-source.h',
- 'sv-trace-source.h',
- 'fv-trace-source.h',
- 'pcap-writer.h',
- 'callback-trace-source.h',
- 'trace-context.h',
- 'trace-resolver.h',
- 'empty-trace-resolver.h',
- 'composite-trace-resolver.h',
- 'array-trace-resolver.h',
- 'trace-root.h',
- 'terminal-trace-resolver.h',
- 'data-rate.h',
- ])
-
-mobility = build.Ns3Module ('mobility', 'src/mobility');
-ns3.add (mobility);
-mobility.add_deps (['core', 'simulator', 'node'])
-mobility.add_sources ([
- 'position.cc',
- 'speed.cc',
- 'random-position.cc',
- 'rectangle-default-value.cc',
- 'rectangle.cc',
- 'mobility-model.cc',
- 'mobility-model-notifier.cc',
- 'static-speed-helper.cc',
- 'static-mobility-model.cc',
- 'static-speed-mobility-model.cc',
- 'hierarchical-mobility-model.cc',
- 'random-direction-2d-mobility-model.cc',
- 'random-waypoint-mobility-model.cc',
- 'random-walk-2d-mobility-model.cc',
- 'grid-topology.cc',
- 'random-topology.cc',
- 'ns2-mobility-file-topology.cc',
- ])
-mobility.add_inst_headers ([
- 'position.h',
- 'speed.h',
- 'random-position.h',
- 'rectangle-default-value.h',
- 'rectangle.h',
- 'mobility-model.h',
- 'mobility-model-notifier.h',
- 'static-speed-helper.h',
- 'static-mobility-model.h',
- 'static-speed-mobility-model.h',
- 'hierarchical-mobility-model.h',
- 'random-direction-2d-mobility-model.h',
- 'random-waypoint-mobility-model.h',
- 'random-walk-2d-mobility-model.h',
- 'grid-topology.h',
- 'random-topology.h',
- 'ns2-mobility-file-topology.h',
- ])
-mobility.add_headers ([
- 'mobility.h'
- ])
-
-node = build.Ns3Module ('node', 'src/node')
-ns3.add (node)
-node.add_deps (['core', 'common', 'simulator'])
-node.add_sources ([
- 'node.cc',
- 'ipv4-address.cc',
- 'net-device.cc',
- 'mac-address.cc',
- 'llc-snap-header.cc',
- 'ipv4-route.cc',
- 'queue.cc',
- 'drop-tail-queue.cc',
- 'channel.cc',
- 'node-list.cc',
- 'socket.cc',
- 'socket-factory.cc',
- 'udp.cc',
- 'ipv4.cc',
- 'application.cc',
- ])
-node.add_inst_headers ([
- 'node.h',
- 'ipv4-address.h',
- 'net-device.h',
- 'mac-address.h',
- 'ipv4-route.h',
- 'queue.h',
- 'drop-tail-queue.h',
- 'llc-snap-header.h',
- 'channel.h',
- 'node-list.h',
- 'socket.h',
- 'socket-factory.h',
- 'udp.h',
- 'ipv4.h',
- 'application.h',
- ])
-
-applications = build.Ns3Module ('applications', 'src/applications')
-ns3.add (applications)
-applications.add_deps (['node'])
-applications.add_sources ([
- 'onoff-application.cc',
-])
-applications.add_inst_headers ([
- 'onoff-application.h',
-])
-
-inode = build.Ns3Module ('internet-node', 'src/internet-node')
-ns3.add (inode)
-inode.add_deps (['node'])
-inode.add_sources ([
- 'internet-node.cc',
- 'l3-demux.cc',
- 'l3-protocol.cc',
- 'ipv4-l4-demux.cc',
- 'ipv4-l4-protocol.cc',
- 'ipv4-header.cc',
- 'udp-header.cc',
- 'ipv4-checksum.cc',
- 'ipv4-interface.cc',
- 'ipv4-l3-protocol.cc',
- 'ipv4-end-point.cc',
- 'udp-l4-protocol.cc',
- 'arp-header.cc',
- 'arp-cache.cc',
- 'arp-ipv4-interface.cc',
- 'arp-l3-protocol.cc',
- 'ipv4-loopback-interface.cc',
- 'header-utils.cc',
- 'udp-socket.cc',
- 'ipv4-end-point-demux.cc',
- 'arp-private.cc',
- 'ipv4-impl.cc',
- 'ipv4-private.cc',
- 'ascii-trace.cc',
- 'pcap-trace.cc',
- 'udp-impl.cc',
-])
-inode.add_headers ([
- 'ipv4-header.h',
- 'udp-header.h',
- 'ipv4-checksum.h',
- 'arp-header.h',
- 'arp-cache.h',
- 'arp-l3-protocol.h',
- 'ipv4-loopback-interface.h',
- 'l3-demux.h',
- 'header-utils.h',
- 'arp-ipv4-interface.h',
- 'udp-socket.h',
- 'udp-l4-protocol.h',
- 'arp-private.h',
- 'ipv4-impl.h',
- 'ipv4-private.h',
- 'ipv4-l3-protocol.h',
- 'l3-protocol.h',
- 'ipv4-l4-protocol.h',
- 'ipv4-l4-demux.h',
- 'ipv4-end-point-demux.h',
- 'ipv4-end-point.h',
- 'ipv4-header.h',
- 'udp-header.h',
- 'ipv4-interface.h',
- 'sgi-hashmap.h',
- 'udp-impl.h',
-])
-inode.add_inst_headers ([
- 'internet-node.h',
- 'ascii-trace.h',
- 'pcap-trace.h',
-])
-
-
-
-p2p = build.Ns3Module ('p2p', 'src/devices/p2p')
-ns3.add (p2p)
-p2p.add_deps (['node'])
-p2p.add_sources ([
- 'p2p-net-device.cc',
- 'p2p-channel.cc',
- 'p2p-topology.cc',
- ])
-p2p.add_inst_headers ([
- 'p2p-net-device.h',
- 'p2p-channel.h',
- 'p2p-topology.h',
- ])
-
-
-# utils
-mobgen = build.Ns3Module ('mobility-generator', 'utils')
-ns3.add (mobgen)
-mobgen.set_executable ()
-mobgen.add_deps (['simulator', 'node', 'mobility'])
-mobgen.add_source ('mobility-generator.cc')
-
-run_tests = build.Ns3Module('run-tests', 'utils')
-ns3.add(run_tests)
-run_tests.set_executable()
-run_tests.add_deps(['core', 'simulator', 'common'])
-run_tests.add_source('run-tests.cc')
-
-bench_object = build.Ns3Module('bench-object', 'utils')
-ns3.add(bench_object)
-bench_object.set_executable()
-bench_object.add_deps(['core'])
-bench_object.add_source('bench-object.cc')
-
-bench_packets = build.Ns3Module('bench-packets', 'utils')
-#ns3.add(bench_packets)
-bench_packets.set_executable()
-bench_packets.add_dep('core')
-bench_packets.add_source('bench-packets.cc')
-
-bench_simu = build.Ns3Module('bench-simulator', 'utils')
-ns3.add(bench_simu)
-bench_simu.set_executable()
-bench_simu.add_dep('simulator')
-bench_simu.add_source('bench-simulator.cc')
-
-replay_simu = build.Ns3Module('replay-simulation', 'utils')
-ns3.add(replay_simu)
-replay_simu.set_executable()
-replay_simu.add_dep('simulator')
-replay_simu.add_source('replay-simulation.cc')
-
-
-# samples
-sample_debug = build.Ns3Module('sample-debug', 'samples')
-sample_debug.set_executable()
-ns3.add(sample_debug)
-sample_debug.add_dep('core')
-sample_debug.add_source('main-debug.cc')
-sample_debug.add_source('main-debug-other.cc')
-
-sample_callback = build.Ns3Module('sample-callback', 'samples')
-sample_callback.set_executable()
-ns3.add(sample_callback)
-sample_callback.add_dep('core')
-sample_callback.add_source('main-callback.cc')
-
-sample_random_walk = build.Ns3Module('sample-random-walk', 'samples')
-sample_random_walk.set_executable()
-ns3.add(sample_random_walk)
-sample_random_walk.add_deps(['core', 'mobility'])
-sample_random_walk.add_source('main-random-walk.cc')
-
-sample_grid_topology = build.Ns3Module('sample-grid-topology', 'samples')
-sample_grid_topology.set_executable()
-ns3.add(sample_grid_topology)
-sample_grid_topology.add_deps(['core', 'internet-node', 'mobility'])
-sample_grid_topology.add_source('main-grid-topology.cc')
-
-sample_ptr = build.Ns3Module('sample-ptr', 'samples')
-sample_ptr.set_executable()
-ns3.add(sample_ptr)
-sample_ptr.add_dep('core')
-sample_ptr.add_source('main-ptr.cc')
-
-sample_trace = build.Ns3Module('sample-trace', 'samples')
-#ns3.add(sample_trace)
-sample_trace.add_dep('common')
-sample_trace.set_executable()
-sample_trace.add_source('main-trace.cc')
-
-sample_query_interface = build.Ns3Module('sample-query-interface', 'samples')
-ns3.add(sample_query_interface)
-sample_query_interface.add_dep('common')
-sample_query_interface.set_executable()
-sample_query_interface.add_source('main-query-interface.cc')
-
-sample_simu = build.Ns3Module('sample-simulator', 'samples')
-ns3.add(sample_simu)
-sample_simu.set_executable()
-sample_simu.add_dep('simulator')
-sample_simu.add_source('main-simulator.cc')
-
-sample_packet = build.Ns3Module('sample-packet', 'samples')
-ns3.add(sample_packet)
-sample_packet.set_executable()
-sample_packet.add_dep('common')
-sample_packet.add_source('main-packet.cc')
-
-sample_test = build.Ns3Module('sample-test', 'samples')
-sample_test.set_executable()
-ns3.add(sample_test)
-sample_test.add_dep('core')
-sample_test.add_source('main-test.cc')
-
-sample_simple = build.Ns3Module('sample-simple', 'samples')
-sample_simple.set_executable()
-ns3.add(sample_simple)
-sample_simple.add_deps(['core', 'simulator', 'node', 'internet-node'])
-sample_simple.add_source('main-simple.cc')
-
-sample_sp2p = build.Ns3Module('sample-simple-p2p', 'samples')
-sample_sp2p.set_executable()
-#n3.add(sample_sp2p)
-sample_sp2p.add_deps(['core', 'simulator', 'node', 'internet-node', 'p2p'])
-sample_sp2p.add_source('main-simple-p2p.cc')
-
-sample_default_value = build.Ns3Module('sample-default-value', 'samples')
-sample_default_value.set_executable()
-ns3.add(sample_default_value)
-sample_default_value.add_deps(['core', 'simulator', 'node', 'p2p'])
-sample_default_value.add_source('main-default-value.cc')
-
-sample_object = build.Ns3Module('sample-object', 'samples')
-sample_object.set_executable()
-ns3.add(sample_object)
-sample_object.add_deps(['core'])
-sample_object.add_source('main-object.cc')
-
-sample_component_manager = build.Ns3Module('sample-component-manager', 'samples')
-sample_component_manager.set_executable()
-ns3.add(sample_component_manager)
-sample_component_manager.add_deps(['core'])
-sample_component_manager.add_source('main-component-manager.cc')
-
-# examples
-example_simple_p2p = build.Ns3Module('simple-p2p', 'examples')
-example_simple_p2p.set_executable()
-ns3.add(example_simple_p2p)
-example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications'])
-example_simple_p2p.add_source('simple-p2p.cc')
-
-ns3.generate_dependencies()
--- a/VERSION Thu Jul 19 13:17:35 2007 +0200
+++ b/VERSION Fri Sep 28 11:59:46 2007 +0100
@@ -1,1 +1,1 @@
-3.0.3
+3.0.6
--- a/build.py Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,561 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-# Copyright (c) 2006 INRIA
-# All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation;
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
-
-
-
-import os
-import os.path
-import shutil
-from SCons.Environment import Environment
-from SCons.Builder import Builder
-from SCons.Action import Action
-import SCons
-
-# hack stolen from wengo
-# to get an ARGUMENTS defined correctly
-try:
- ARGUMENTS = SCons.Script.ARGUMENTS
- COMMAND_LINE_TARGETS = SCons.Script.COMMAND_LINE_TARGETS
-except AttributeError:
- from SCons.Script.SConscript import Arguments
- from SCons.Script.SConscript import CommandLineTargets
- ARGUMENTS = Arguments
- COMMAND_LINE_TARGETS = CommandLineTargets
-
-class Ns3Module:
- def __init__(self, name, dir):
- self.sources = []
- self.inst_headers = []
- self.headers = []
- self.extra_dist = []
- self.deps = []
- self.external_deps = []
- self.config = []
- self.name = name
- self.dir = dir
- self.executable = False
- self.library = True
- self.ldflags = []
- self.header_inst_dir = ''
- def set_library(self):
- self.library = True
- self.executable = False
- def set_executable(self):
- self.library = False
- self.executable = True
- def add_config(self, config_fn):
- self.config.append(config_fn)
- def add_extra_dist(self, dist):
- self.extra_dist.append(dist)
- def add_external_dep(self, dep):
- self.external_deps.append(dep)
- def add_dep(self, dep):
- self.deps.append(dep)
- def add_deps(self, deps):
- self.deps.extend(deps)
- def add_source(self, source):
- self.sources.append(source)
- def add_sources(self, sources):
- self.sources.extend(sources)
- def add_header(self, header):
- self.headers.append(header)
- def add_headers(self, headers):
- self.headers.extend(headers)
- def add_inst_header(self, header):
- self.inst_headers.append(header)
- def add_inst_headers(self, headers):
- self.inst_headers.extend(headers)
- def add_ldflags (self, ldflags):
- self.ldflags.extend (ldflags)
- def add_ldflag (self, ldflag):
- self.add_ldflags ([ldflag])
- def set_header_inst_dir (self, inst_dir):
- self.header_inst_dir = inst_dir
-
-
-def MyCopyAction(target, source, env):
- try:
- if len(target) == len(source):
- for i in range(len(target)):
- shutil.copy(source[i].path, target[i].path)
- return 0
- else:
- return 'invalid target/source match'
- except:
- print
- return 'exception'
-def MyCopyActionPrint(target, source, env):
- if len(target) == len(source):
- output = ''
- for i in range(len(target)):
- output = output + 'copy \'' + source[i].path + '\' to \'' + target[i].path + '\''
- if i < len(target) - 1:
- output = output + '\n'
- return output
- else:
- return 'error in copy'
-def GcxxEmitter(target, source, env):
- if os.path.exists(source[0].path):
- return [target, source]
- else:
- return [[], []]
-def MyRmTree(target, source, env):
- shutil.rmtree(env['RM_DIR'])
- return 0
-def MyRmTreePrint(target, source, env):
- return ''
-def print_cmd_line(s, target, src, env):
- print 'Building ' + (' and '.join([str(x) for x in target])) + '...'
-
-class Ns3BuildVariant:
- def __init__(self):
- self.static = False
- self.gcxx_deps = False
- self.gcxx_root = ''
- self.build_root = ''
- self.env = None
-
-class Ns3:
- def __init__(self):
- self.__modules = []
- self.extra_dist = []
- self.build_dir = 'build'
- self.version = '0.0.1'
- self.name = 'noname'
- self.distname = 'noname'
- self.doxygen_config = ''
- def add(self, module):
- self.__modules.append(module)
- def add_extra_dist(self, dist):
- self.extra_dist.append(dist)
- def __get_module(self, name):
- for module in self.__modules:
- if module.name == name:
- return module
- return None
- def get_mod_output(self, module, variant):
- if module.executable:
- suffix = variant.env.subst(variant.env['PROGSUFFIX'])
- filename = os.path.join(variant.build_root, 'bin',
- module.name + suffix)
- else:
- if variant.static:
- prefix = variant.env['LIBPREFIX']
- suffix = variant.env['LIBSUFFIX']
- else:
- prefix = variant.env['SHLIBPREFIX']
- suffix = variant.env['SHLIBSUFFIX']
- prefix = variant.env.subst(prefix)
- suffix = variant.env.subst(suffix)
- filename = os.path.join(variant.build_root, 'lib',
- prefix + module.name + suffix)
- return filename
- def get_obj_builders(self, variant, module):
- env = variant.env.Copy ()
- objects = []
- hash = {}
- self.get_internal_deps (module, hash)
- for dep in hash.values ():
- if dep.header_inst_dir != '':
- inc_dir = os.path.join(variant.build_root, 'include',
- self.name, dep.header_inst_dir)
- env.Append (CPPPATH = [inc_dir])
-
- if len(module.config) > 0:
- src_config_file = os.path.join(self.build_dir, 'config', module.name + '-config.h')
- tgt_config_file = os.path.join(variant.build_root, 'include',
- self.name, module.name + '-config.h')
-
- for source in module.sources:
- obj_file = os.path.splitext(source)[0] + '.o'
- tgt = os.path.join(variant.build_root, module.dir, obj_file)
- src = os.path.join(module.dir, source)
- if variant.static:
- obj_builder = env.StaticObject(target = tgt, source = src)
- else:
- obj_builder = env.SharedObject(target = tgt, source = src)
- if len(module.config) > 0:
- config_file = env.MyCopyBuilder(target = [tgt_config_file],
- source = [src_config_file])
- env.Depends(obj_builder, config_file)
- if variant.gcxx_deps:
- gcno_tgt = os.path.join(variant.build_root, module.dir,
- os.path.splitext(source)[0] + '.gcno')
- gcda_tgt = os.path.join(variant.build_root, module.dir,
- os.path.splitext(source)[0] + '.gcda')
- gcda_src = os.path.join(variant.gcxx_root, module.dir,
- os.path.splitext(source)[0] + '.gcda')
- gcno_src = os.path.join(variant.gcxx_root, module.dir,
- os.path.splitext(source)[0] + '.gcno')
- gcno_builder = env.CopyGcxxBuilder(target = gcno_tgt, source = gcno_src)
- gcda_builder = env.CopyGcxxBuilder(target = gcda_tgt, source = gcda_src)
- env.Depends(obj_builder, gcda_builder)
- env.Depends(obj_builder, gcno_builder)
- objects.append(obj_builder)
- return objects
- def get_internal_deps(self, module, hash):
- for dep_name in module.deps:
- dep = self.__get_module(dep_name)
- hash[dep_name] = dep
- self.get_internal_deps(dep, hash)
- def get_external_deps(self, module):
- hash = {}
- self.get_internal_deps(module, hash)
- ext_hash = {}
- for mod in hash.values():
- for ext_dep in mod.external_deps:
- ext_hash[ext_dep] = 1
- return ext_hash.keys()
- def get_sorted_deps(self, module):
- h = {}
- self.get_internal_deps(module, h)
- modules = []
- for dep in h.keys():
- deps_copy = []
- mod = h[dep]
- deps_copy.extend(mod.deps)
- modules.append([mod, deps_copy])
- sorted = []
- while len(modules) > 0:
- to_remove = []
- for item in modules:
- if len(item[1]) == 0:
- to_remove.append(item[0].name)
- for item in to_remove:
- for i in modules:
- if item in i[1]:
- i[1].remove(item)
- new_modules = []
- for mod in modules:
- found = False
- for i in to_remove:
- if i == mod[0].name:
- found = True
- break
- if not found:
- new_modules.append(mod)
- modules = new_modules
- sorted.extend(to_remove)
- sorted.reverse()
- # append external deps
- ext_deps = self.get_external_deps(module)
- for dep in ext_deps:
- sorted.append(dep)
- return sorted
-
- def gen_mod_dep(self, variant):
- build_root = variant.build_root
- cpp_path = os.path.join(variant.build_root, 'include')
- env = variant.env
- env.Append(CPPPATH = [cpp_path])
- header_dir = os.path.join(build_root, 'include', self.name)
- lib_path = os.path.join(build_root, 'lib')
- env.Append (LIBPATH = [lib_path])
- module_builders = []
- for module in self.__modules:
- my_env = env.Copy ();
- objects = self.get_obj_builders(variant, module)
- libs = self.get_sorted_deps(module)
- my_env.Append (LIBS = libs)
- my_env.Append (LINKFLAGS = module.ldflags)
-
- filename = self.get_mod_output(module, variant)
- if module.executable:
- module_builder = my_env.Program(target=filename, source=objects)
- else:
- if variant.static:
- module_builder = my_env.StaticLibrary(target=filename, source=objects)
- else:
- module_builder = my_env.SharedLibrary(target=filename, source=objects)
-
- for dep_name in module.deps:
- dep = self.__get_module(dep_name)
- my_env.Depends(module_builder, self.get_mod_output(dep, variant))
-
- for header in module.inst_headers:
- if module.header_inst_dir != '':
- tgt = os.path.join(header_dir, module.header_inst_dir, header)
- else:
- tgt = os.path.join(header_dir, header)
- src = os.path.join(module.dir, header)
- #builder = env.Install(target = tgt, source = src)
- header_builder = my_env.MyCopyBuilder(target=tgt, source=src)
- my_env.Depends(module_builder, header_builder)
-
- module_builders.append(module_builder)
- return module_builders
- def gen_mod_config(self, env):
- config_dir = os.path.join(self.build_dir, 'config')
- for module in self.__modules:
- if len(module.config) > 0:
- config_file = os.path.join(config_dir, module.name + '-config.h')
- config_file_guard = module.name + '_CONFIG_H'
- config_file_guard.upper()
- if not os.path.isfile(config_file):
- if not os.path.isdir(config_dir):
- os.makedirs(config_dir)
- outfile = open(config_file, 'w')
- outfile.write('#ifndef ' + config_file_guard + '\n')
- outfile.write('#define ' + config_file_guard + '\n')
- config = env.Configure()
- for fn in module.config:
- output = fn(env, config)
- for o in output:
- outfile.write(o)
- outfile.write('\n')
- outfile.write('#endif /*' + config_file_guard + '*/\n')
- config.Finish()
- def generate_dependencies(self):
- inheritenv = (ARGUMENTS.get('inheritenv', 'n') in 'yY1')
- if inheritenv:
- env = Environment(ENV=os.environ)
- else:
- env = Environment()
- self.gen_mod_config(env)
- cc = env['CC']
- cxx = env.subst(env['CXX'])
- if cc == '':
- print "Missing C compiler."
- env.Exit (1);
- if cxx == '':
- print "Missing C++ compiler."
- env.Exit (1);
- common_flags = ARGUMENTS.get('cflags', '').split(' ')
- cxxflags = ARGUMENTS.get('cxxflags', '').split(' ')
- ldflags = ARGUMENTS.get('ldflags', '').split(' ')
- if cc == 'cl' and cxx == 'cl':
- env = Environment(tools=['mingw'])
- cc = env['CC']
- cxx = env.subst(env['CXX'])
- if cc == 'gcc' and cxx == 'g++':
- common_flags.extend(['-g3', '-Wall', '-Werror'])
- debug_flags = []
- opti_flags = ['-O3']
- elif cc == 'cl' and cxx == 'cl':
- env = Environment(ENV=os.environ)
- debug_flags = ['-W1', '-GX', '-EHsc', '-D_DEBUG', '/MDd']
- opti_flags = ['-O2', '-EHsc', '-DNDEBUG', '/MD']
- cc = ARGUMENTS.get ('cc', '')
- cxx = ARGUMENTS.get ('cxx', '')
- if cc != '':
- env.Replace (CC = cc)
- if cxx != '':
- env.Replace (CXX = cxx)
- env.Append(CCFLAGS = common_flags,
- CPPDEFINES = ['RUN_SELF_TESTS'],
- TARFLAGS = '-c -z',
- CPPFLAGS = cxxflags,
- LINKFLAGS = ldflags)
- if env['PLATFORM'] == 'posix':
- env.Append(LINKFLAGS = ' -z origin')
- env.Append(RPATH=env.Literal(os.path.join('\\$$ORIGIN', os.pardir, 'lib')))
- verbose = ARGUMENTS.get('verbose', 'n')
- if verbose == 'n':
- env['PRINT_CMD_LINE_FUNC'] = print_cmd_line
- header_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint))
- env.Append(BUILDERS = {'MyCopyBuilder':header_builder})
- gcxx_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint),
- emitter = GcxxEmitter)
- env.Append(BUILDERS = {'CopyGcxxBuilder':gcxx_builder})
- variant = Ns3BuildVariant()
- builders = []
-
-
- gcov_env = env.Copy()
- gcov_env.Append(CFLAGS = ['-fprofile-arcs', '-ftest-coverage'],
- CXXFLAGS = ['-fprofile-arcs', '-ftest-coverage'],
- LINKFLAGS = ['-fprofile-arcs'])
- # code coverage analysis
- variant.static = False
- variant.env = gcov_env
- variant.build_root = os.path.join(self.build_dir, 'gcov')
- builders = self.gen_mod_dep(variant)
- for builder in builders:
- gcov_env.Alias('gcov', builder)
- gcov_env.Alias('lcov-report')
- if 'lcov-report' in COMMAND_LINE_TARGETS:
- lcov_report_dir = os.path.join(self.build_dir, 'lcov-report')
- create_dir_command = "rm -rf " + lcov_report_dir
- create_dir_command += " && mkdir " + lcov_report_dir + ";"
- gcov_env.Execute(create_dir_command)
- info_file = os.path.join(lcov_report_dir, self.name + '.info')
- lcov_command = "utils/lcov/lcov -c -d . -o " + info_file
- lcov_command += " --source-dirs=" + os.getcwd()
- lcov_command += ":" + os.path.join(os.getcwd(),
- variant.build_root,
- 'include')
- gcov_env.Execute(lcov_command)
- genhtml_command = "utils/lcov/genhtml -o " + lcov_report_dir
- genhtml_command += " " + info_file
- gcov_env.Execute(genhtml_command)
-
-
-
- opt_env = env.Copy()
- opt_env.Append(CFLAGS=opti_flags,
- CXXFLAGS=opti_flags,
- CPPDEFINES=['NDEBUG'])
- # optimized static support
- variant.static = True
- variant.env = opt_env
- variant.build_root = os.path.join(self.build_dir, 'opt-static')
- builders = self.gen_mod_dep(variant)
- for builder in builders:
- opt_env.Alias('opt-static', builder)
-
-
- opt_env = env.Copy()
- opt_env.Append(CFLAGS = opti_flags,
- CXXFLAGS = opti_flags,
- CPPDEFINES = ['NDEBUG'])
- # optimized shared support
- variant.static = False
- variant.env = opt_env
- variant.build_root = os.path.join(self.build_dir, 'opt-shared')
- builders = self.gen_mod_dep(variant)
- for builder in builders:
- opt_env.Alias('opt-shared', builder)
-
-
- arc_env = env.Copy()
- arc_env.Append(CFLAGS=opti_flags,
- CXXFLAGS=opti_flags,
- CPPDEFINES=['NDEBUG'])
- arc_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-generate'],
- CXXFLAGS=['-frandom-seed=0', '-fprofile-generate'],
- LINKFLAGS=['-frandom-seed=0', '-fprofile-generate'])
- # arc profiling
- variant.static = False
- variant.env = arc_env
- variant.build_root = os.path.join(self.build_dir, 'opt-arc')
- builders = self.gen_mod_dep(variant)
- for builder in builders:
- arc_env.Alias('opt-arc', builder)
-
-
- arcrebuild_env = env.Copy()
- arcrebuild_env.Append(CFLAGS=opti_flags,
- CXXFLAGS=opti_flags,
- CPPDEFINES=['NDEBUG'])
- arcrebuild_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-use'],
- CXXFLAGS=['-frandom-seed=0', '-fprofile-use'],
- LINKFLAGS=['-frandom-seed=0', '-fprofile-use'])
- # arc rebuild
- variant.static = False
- variant.env = arcrebuild_env
- variant.gcxx_deps = True
- variant.gcxx_root = os.path.join(self.build_dir, 'opt-arc')
- variant.build_root = os.path.join(self.build_dir, 'opt-arc-rebuild')
- builders = self.gen_mod_dep(variant)
- for builder in builders:
- arcrebuild_env.Alias('opt-arc-rebuild', builder)
- variant.gcxx_deps = False
-
-
-
-
- dbg_env = env.Copy()
- dbg_env.Append(CFLAGS = debug_flags,
- CXXFLAGS = debug_flags,
- CPPDEFINES = ['NS3_DEBUG_ENABLE',
- 'NS3_ASSERT_ENABLE'])
- # debug static support
- variant.static = True
- variant.env = dbg_env
- variant.build_root = os.path.join(self.build_dir, 'dbg-static')
- builders = self.gen_mod_dep(variant)
- for builder in builders:
- dbg_env.Alias('dbg-static', builder)
-
- dbg_env = env.Copy()
- dbg_env.Append(CFLAGS=debug_flags,
- CXXFLAGS=debug_flags,
- CPPDEFINES = ['NS3_DEBUG_ENABLE',
- 'NS3_ASSERT_ENABLE'])
- # debug shared support
- variant.static = False
- variant.env = dbg_env
- variant.build_root = os.path.join(self.build_dir, 'dbg-shared')
- builders = self.gen_mod_dep(variant)
- for builder in builders:
- dbg_env.Alias('dbg-shared', builder)
-
- env.Alias('dbg', 'dbg-shared')
- env.Alias('opt', 'opt-shared')
- env.Default('dbg')
- env.Alias('all', ['dbg-shared', 'dbg-static', 'opt-shared', 'opt-static'])
-
-
- # dist support
- dist_env = env.Copy()
- if dist_env['PLATFORM'] == 'posix' or dist_env['PLATFORM'] == 'darwin':
- dist_list = []
- for module in self.__modules:
- for f in module.sources:
- dist_list.append(os.path.join(module.dir, f))
- for f in module.headers:
- dist_list.append(os.path.join(module.dir, f))
- for f in module.inst_headers:
- dist_list.append(os.path.join(module.dir, f))
- for f in module.extra_dist:
- dist_list.append(os.path.join(module.dir, f))
- for f in self.extra_dist:
- dist_list.append(f)
- dist_list.append (self.doxygen_config)
- dist_list.append('SConstruct')
- dist_list.append('build.py')
-
- targets = []
- basename = self.distname + '-' + self.version
- for src in dist_list:
- tgt = os.path.join(basename, src)
- targets.append(dist_env.MyCopyBuilder(target=tgt, source=src))
- tar = basename + '.tar.gz'
- zip = basename + '.zip'
- tmp_tar = os.path.join(self.build_dir, tar)
- tmp_zip = os.path.join(self.build_dir, zip)
- dist_tgt = [tar, zip]
- dist_src = [tmp_tar, tmp_zip]
- dist_env.Tar(tmp_tar, targets)
- dist_env.Zip(tmp_zip, targets)
- dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
- dist_env.Alias('dist', dist_builder)
- dist_env.Append(RM_DIR=basename)
- dist_env.AddPostAction(dist_builder, dist_env.Action(MyRmTree,
- strfunction=MyRmTreePrint))
- dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
- dist_env.Alias('fastdist', dist_tgt)
-
- # distcheck
- distcheck_list = []
- for src in dist_list:
- tgt = os.path.join(self.build_dir, basename, src)
- distcheck_list.append(tgt)
- untar = env.Command(distcheck_list, tar,
- ['cd ' + self.build_dir + ' && tar -zxf ../' + tar])
- scons_dir = os.path.join(self.build_dir, basename)
- distcheck_builder = env.Command('x', distcheck_list,
- ['cd ' + scons_dir + ' && scons'])
- env.AlwaysBuild(distcheck_builder)
- env.Alias('distcheck', distcheck_builder)
- if self.doxygen_config != '':
- doxy = env.Command('doc/html/*', self.doxygen_config,
- ['doxygen ' + self.doxygen_config])
- env.AlwaysBuild(doxy)
- env.Alias('doc', doxy)
--- a/doc/build-waf.txt Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-The main ns-3 build system is SCons. Read the file build.txt
-for SCons instructions.
-
-Waf is an alternative build system, similar to SCons. ns-3 now is
-able to build with Waf, in parallel to SCons.
-
-(http://www.freehackers.org/~tnagy/waf.html)
-
-Note: the Waf build scripts are experimental at this stage.
-Gustavo Carneiro (gjcarneiro@gmail.com) is the maintainer.
-
-=== Building with Waf ===
-
-To build ns-3 with waf type the commands:
- 1. ./waf configure [options]
- 2. ./waf
-
-[ Note: if ./waf does not exist, see the section "Note for developers" below ]
-
-To see valid configure options, type ./waf --help. The most important
-option is -d <debug level>. Valid debug levels (which are listed in
-./waf --help) are: ultradebug, debug, release, and optimized.
-
-The resulting binaries are placed in build/<debuglevel>/srcpath.
-
-Other waf usages include:
-
- 1. ./waf check
- Runs the unit tests
-
- 2. ./waf --doxygen
- Run doxygen to generate documentation
-
- 3. ./waf --lcov-report
- Run code coverage analysis (assuming the project was configured
-with --enable-gcov)
-
- 4. ./waf --run "program [args]"
- Run a ns3 program, given its target name, with the given
- arguments. This takes care of automatically modifying the the
- path for finding the ns3 dynamic libraries in the environment
- before running the program. Note: the "program [args]" string is
- parsed using POSIX shell rules.
-
- 5. ./waf --shell
- Starts a nested system shell with modified environment to run ns3 programs.
-
-
-=== Extending ns-3 ===
-
-To add new modules:
- 1. Create the module directory under src (or src/devices, or whatever);
- 2. Add the source files to it;
- 3. Add a 'wscript' describing it;
- 4. Add the module subdirectory name to the all_modules list in src/wscript.
-
-A module's wscript file is basically a regular Waf script. A ns-3
-module is created as a cpp/shlib object, like this:
-
-def build(bld):
- obj = bld.create_obj('cpp', 'shlib')
-
- ## set module name; by convention it starts with ns3-
- obj.name = 'ns3-mymodule'
- obj.target = obj.name
-
- ## list dependencies to other modules
- obj.uselib_local = ['ns3-core']
-
- ## list source files (private or public header files excluded)
- obj.source = [
- 'mymodule.cc',
- ]
-
- ## list module public header files
- headers = bld.create_obj('ns3header')
- headers.source = [
- 'mymodule-header.h',
- ]
-
-
-=== Note for developers ===
-
-The ns-3 code repository does not contain the waf script. Instead,
-developers should check it out from a subversion repository:
-
- svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
-
-[ note: 'tags/ns3' is a tag that represents the last svn version
-tested to work correctly with ns3, although 'trunk' will likely work
- as well ]
-
-Then it can be installed system-wide with 'sudo ./waf-light install'.
-When preparing a distribution, the resulting 'waf' script, which is
-self contained (no external files needed), can be easily included in
-the tarball so that users downloading ns-3 can easily build it without
-having Waf installed (although Python >= 2.3 is still needed).
-
-The command 'waf dist' can be used to create a distribution tarball.
-It includes all files in the source directory, except some particular
-extensions that are blacklisted, such as back files (ending in ~).
-
--- a/doc/build.txt Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/build.txt Fri Sep 28 11:59:46 2007 +0100
@@ -1,186 +1,115 @@
-If you want to build ns3, you need to install scons (see
-http://www.scons.org). scons takes care of building
-the whole source tree using your system compiler. scons
-0.91.1 and 0.91.96 have been tested and are known to
-work on linux FC5, Mac os X and MinGW.
+The Waf build system is used to build ns-3. Waf is a Python-based
+build system (http://www.freehackers.org/~tnagy/waf.html)
+
+=== Installing Waf ===
-To start a build, you can just type 'scons' which
-will generate a debug shared build by default, located
-in the directory 'build-dir/dbg-shared/bin' and
-'build-dir/dbg-shared/lib'.
+If this file is part of a development release tarball, the top-level
+ns-3 directory should contain a current waf script.
+
+However, the ns-3 Mercurial code repository does not contain the waf
+script. Instead, developers should check it out from a subversion
+repository:
-All builds are built with debugging symbols. Debugging
-builds enable asserts while optimized builds disable them.
-On platforms which support it, rpath is used which means that
-the executable binaries generated link explicitely against
-the right libraries. This saves you the pain of having to
-setup environment variables to point to the right libraries.
+ svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
+
+[ note: 'tags/ns3' is a tag that represents the last svn version
+tested to work correctly with ns3, although 'trunk' will likely work
+ as well ]
-(Note: An alternative build system (Waf) is being
-evaluated in the development branch of ns-3-dev on our server
-only (i.e., not in the release tarballs)-- see doc/build-waf.txt)
+Then it can be installed system-wide with 'sudo waf-light install'.
+When preparing a distribution, the resulting 'waf' script, which is
+self contained (no external files needed), can be easily included in
+the tarball so that users downloading ns-3 can easily build it without
+having Waf installed (although Python >= 2.3 is still needed).
-1) Options
-----------
+=== Building with Waf ===
-- verbose: if you have installed scons 0.91.96 or higher,
- the default build output is terse. To get a more verbose
- output, you need to set the 'verbose' variable to 'y'.
-Example: scons verbose=y
-- cflags: flags for the C compiler.
-Example: scons cflags="-O3 -ffast-math"
-- cxxflags: flags for the C++ compiler.
-Example: scons cxxflags="-O3 -ffast-math"
-- ldflags: flags for the linker:
-Example: scons ldflags="-L/foo -L/bar"
-- cc: the C compiler to use:
-Example: scons cc=gcc-4.0
-- cxx: the C++ compiler to use:
-Example: scons cxx=g++-4.0
-- high-precision-as-double: set to 'y' to make sure that the
- high-precision arithmetics performed by the Time class on
- behalf of the user will use doubles. By default, the code
- uses 128 integers.
-Example: scons high-precision-as-double=y
-- inheritenv: set to 'y' if you want to make your compiler
- execute within the same environment (env vars) as your own
- shell. This is typically used to make colorgcc work.
-Example: scons inheritenv=y
+To build ns-3 with waf type the commands:
+ 1. waf configure [options]
+ 2. waf
-2) Targets
-----------
-
-- doc: build the doxygen documentation.
-Example: scons doc
+To see valid configure options, type waf --help. The most important
+option is -d <debug level>. Valid debug levels (which are listed in
+waf --help) are: ultradebug, debug, release, and optimized. It is
+also possible to change the flags used for compilation with (e.g.):
+CXXFLAGS="-O3" waf configure.
-- dbg-shared: a debug build using shared libraries.
- The files are built in 'build-dir/dbg-shared/'.
-Example: scons dbg-shared
-
-- dbg-static: a debug build using static libraries
- The files are built in 'build-dir/dbg-static/'.
-Example: scons dbg-static
+[ Note: Unlike some other build tools, to change the build target,
+the option must be supplied during the configure stage rather than
+the build stage (i.e., "waf -d optimized" will not work; instead, do
+"waf -d optimized configure; waf" ]
-- opt-shared: an optimized build using shared libraries.
- The files are built in 'build-dir/opt-shared/'.
-Example: scons opt-shared
+The resulting binaries are placed in build/<debuglevel>/srcpath.
-- opt-static: an optimized build using static libraries.
- The files are built in 'build-dir/opt-static/'.
-Example: scons opt-static
+Other waf usages include:
-- dbg: an alias for dbg-shared
-Example: scons dbg
-
-- opt: an alias for opt-shared
-Example: scons opt
+ 1. waf check
+ Runs the unit tests
-- all: alias for dbg-shared, dbg-static, opt-shared
- and opt-static
-Example: scons all
+ 2. waf --doxygen
+ Run doxygen to generate documentation
-- gcov: code coverage analysis. Build a debugging version of
- the code for code coverage analysis in 'build-dir/gcov'. Once
- the code has been built, you can run various applications to
- exercise the code paths. To generate an html report from
- the gcov data, use the lcov-report target
-
-- lcov-report: generate html report of gcov data. The output
- is stored in 'build-dir/lcov-report/'.
+ 3. waf --lcov-report
+ Run code coverage analysis (assuming the project was configured
+with --enable-gcov)
-- dist: generate a release tarball and zipfile from the
- source tree. The tarball and zipfile name are generated
- according to the version number stored in the SConstruct
- file.
-Example in SConstruct:
-ns3 = Ns3 ()
-ns3.name = 'foo'
-ns3.version = '0.0.10'
-Example command: scons dist
-Example output files:
-foo-0.0.10.tar.gz
-foo-0.0.10.zip
+ 4. waf --run "program [args]"
+ Run a ns3 program, given its target name, with the given
+ arguments. This takes care of automatically modifying the the
+ path for finding the ns3 dynamic libraries in the environment
+ before running the program. Note: the "program [args]" string is
+ parsed using POSIX shell rules.
-- distcheck: generate a release tarball and zipfile and
- attempt to run the 'all' target for the release tarball.
-Example: scons distcheck
+ 4.1 waf --run programname --command-template "... %s ..."
-3) How the build system works
------------------------------
+ Same as --run, but uses a command template with %s replaced by the
+ actual program (whose name is given by --run). This can be use to
+ run ns-3 programs with helper tools. For example, to run unit
+ tests with valgrind, use the command:
-The current build system defines what are called "ns3 modules": each module
-is a set of source files, normal header files and installable header
-files. Each module also depends on a set of other modules. We build
-modules automatically in the correct order. That is, we always start
-from the module which does not depend on any other module (core) and
-proceed with the other modules and make sure that when a module is
-built, all the modules it depends upon have already been built.
+ waf --run run-tests --command-template "valgrind %s"
+
+ 5. waf --shell
+ Starts a nested system shell with modified environment to run ns3 programs.
+
+ 6. waf distclean
+ Cleans out the entire build/ directory
-To build a module, we:
-1) generate the .o files
-2) link the .o files together
-3) install the installable headers in the common directory
-top_build_dir/include/ns3.
+ 7. waf dist
+ The command 'waf dist' can be used to create a distribution tarball.
+ It includes all files in the source directory, except some particular
+ extensions that are blacklisted, such as back files (ending in ~).
-This means that if you want to use a header from your own module, you
-should just include it: #include "foo.h" but if you want to include a
-header from another module, you need to include it with #include
-"ns3/bar.h". This allows you to make sure that our "public" ns3 headers
-do not conflict with existing system-level headers. For instance,
-if you were to define a header called queue.h, you would include
-ns3/queue.h rather than queue.h, when including from a separate module,
-since many systems provide a queue.h system include file.
-4) How to add files to a module ?
----------------------------------
+=== Extending ns-3 ===
-In the main SConstruct file, you can add source code
-to the add_sources method. For example, to add a foo.cc
-file to the core module, we coud do this:
-core.add_sources ('foo.cc')
-Of course, if this file implements public API, its
-header should be installable:
-core.add_inst_headers ('foo.h')
+To add new modules:
+ 1. Create the module directory under src (or src/devices, or whatever);
+ 2. Add the source files to it;
+ 3. Add a 'wscript' describing it;
+ 4. Add the module subdirectory name to the all_modules list in src/wscript.
-5) How to create a new module ?
--------------------------------
+A module's wscript file is basically a regular Waf script. A ns-3
+module is created as a cpp/shlib object, like this:
+
+def build(bld):
+ obj = bld.create_obj('cpp', 'shlib')
-# create a new module. First arg is the name of
-# the new module. Second arg is the directory in
-# which all source files for this module reside.
-my_module = build.Ns3Module ('my', 'src/my_dir')
-# add it to build system
-ns3.add (my_module)
-# specify module dependencies. Here, depends
-# on the 'ipv4' and 'core' modules
-my_module.add_deps (['core', 'ipv4'])
-# add source code to build located in
-# src/my_dir
-my_module.add_sources ([
- 'my_a.cc',
- 'my_b.cc',
- 'my_c.cc'
-])
-my_module.add_sources ([
- 'my_d.cc'
-])
-# add headers which are not public
-my_module.add_headers ([
- 'my_a.h',
- 'my_c.h'
-])
-# add headers which are public
-my_module.add_inst_headers ([
- 'my_b.h'
-])
-my_module.add_inst_headers ([
- 'my_d.h'
-])
-# if you need to link against an external library,
-# you must add 'external' dependencies. Here, the
-# pthread library
-my_module.add_external_dep ('pthread')
-# by default, a module is conceptually a library. If you
-# want to generate an executable from a module you need to:
-my_module.set_executable ()
+ ## set module name; by convention it starts with ns3-
+ obj.name = 'ns3-mymodule'
+ obj.target = obj.name
+
+ ## list dependencies to other modules
+ obj.uselib_local = ['ns3-core']
+ ## list source files (private or public header files excluded)
+ obj.source = [
+ 'mymodule.cc',
+ ]
+
+ ## list module public header files
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'mymodule-header.h',
+ ]
+
--- a/doc/doxygen.conf Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/doxygen.conf Fri Sep 28 11:59:46 2007 +0100
@@ -450,7 +450,7 @@
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = src doc/main.txt
+INPUT = src doc/main.txt doc/trace-source-list.h doc/tracing.h
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -514,7 +514,7 @@
# directories that contain image that are included in the documentation (see
# the \image command).
-IMAGE_PATH =
+IMAGE_PATH = doc
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@@ -999,7 +999,7 @@
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
-PREDEFINED = RUN_SELF_TESTS NS3_DEBUG_ENABLE
+PREDEFINED = RUN_SELF_TESTS NS3_DEBUG_ENABLE NS3_ASSERT_ENABLE
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
--- a/doc/main.txt Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/main.txt Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,7 @@
* - \ref config
* - a base class for objects which need to support reference counting
* and QueryInterface: ns3::Object and ns3::InterfaceId
+ * - a set of low-level trace facilities integrated in the ns3::Object system: \ref tracing
* - a ns3::ComponentManager which can be used to manage the creation
* of any object which derives from ns3::Object through an ns3::ClassId
* - a smart-pointer class ns3::Ptr designed to work together with ns3::Object
@@ -33,11 +34,10 @@
* ns3::Scheduler and ns3::SchedulerFactory
* - a simulator class used to create, schedule and cancel events: ns3::Simulator
*
- * The "common" module contains:
+ * The "core" module contains:
* - a packet class to create and manipulate simulation packets: ns3::Packet, ns3::Header,
* and ns3::Trailer. This packet class also supports per-packet ns3::Tag which are
* globs of data which can be attached to any packet.
- * - a set of low-level trace facilities: \ref lowleveltracing
*
* The "node" module contains:
* - a ns3::Node base class which should be subclassed by any new type of
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/namespace-2.dia Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1658 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+ <dia:diagramdata>
+ <dia:attribute name="background">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="pagebreak">
+ <dia:color val="#000099"/>
+ </dia:attribute>
+ <dia:attribute name="paper">
+ <dia:composite type="paper">
+ <dia:attribute name="name">
+ <dia:string>#A4#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="tmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="bmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="lmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="rmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="is_portrait">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="scaling">
+ <dia:real val="1.0929253101348877"/>
+ </dia:attribute>
+ <dia:attribute name="fitto">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="fitwidth">
+ <dia:int val="2"/>
+ </dia:attribute>
+ <dia:attribute name="fitheight">
+ <dia:int val="2"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="grid">
+ <dia:composite type="grid">
+ <dia:attribute name="width_x">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="width_y">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_x">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_y">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:composite type="color"/>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#d8e5e5"/>
+ </dia:attribute>
+ <dia:attribute name="guides">
+ <dia:composite type="guides">
+ <dia:attribute name="hguides"/>
+ <dia:attribute name="vguides"/>
+ </dia:composite>
+ </dia:attribute>
+ </dia:diagramdata>
+ <dia:layer name="Background" visible="true">
+ <dia:object type="Flowchart - Box" version="0" id="O0">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-1,-27"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-1.05,-27.05;6.05,-24.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-1,-27"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/devices/[0-n]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-0.65,-25.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O1">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-8,-39"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-8.05,-39.05;-0.95,-36.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-8,-39"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#NodeList#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-4.5,-37.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O2">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-1,-29"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-1.05,-29.05;6.05,-26.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-1,-29"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Node#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="2.5,-27.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O3">
+ <dia:attribute name="obj_pos">
+ <dia:point val="3,-16"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.95,-16.05;7.05,-13.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="3,-16"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/queue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="3.35,-14.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O4">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-8,-37"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-8.05,-37.05;-0.95,-34.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-8,-37"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/nodes/[0-n]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-7.65,-35.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O5">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-8,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-8.05,-31.05;-3.95,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-8,-31"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/udp#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-7.65,-29.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O6">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-16,-25"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-16.05,-25.05;-13.95,-22.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-16,-25"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/rx#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-15.65,-23.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O7">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-17,-19"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-17.05,-19.05;-9.95,-16.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-17,-19"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/netdevice#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-16.65,-17.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O8">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-4.5,-35"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-4.55754,-35.0575;3,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="-4.5,-35"/>
+ <dia:point val="-4,-32"/>
+ <dia:point val="2.5,-31"/>
+ <dia:point val="2.5,-29"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O4" connection="13"/>
+ <dia:connection handle="3" to="O2" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O9">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-4.5,-35"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-8.00142,-35.0606;-4.43937,-32.8685"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="-4.5,-35"/>
+ <dia:point val="-5,-33"/>
+ <dia:point val="-7,-36"/>
+ <dia:point val="-7.5,-33"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O4" connection="13"/>
+ <dia:connection handle="3" to="O18" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O10">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-11,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-11.05,-31.05;-7.95,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-11,-31"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="3"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/ipv4#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-10.65,-29.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O11">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-14,-25"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-14.05,-25.05;-6.95,-22.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-14,-25"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/interfaces/[0-n]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-13.65,-23.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O12">
+ <dia:attribute name="obj_pos">
+ <dia:point val="7,-16"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="6.95,-16.05;11.05,-13.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="7,-16"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/rx#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="7.35,-14.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O13">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-8,-16"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-8.05,-16.05;-3.95,-13.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-8,-16"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/queue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-7.65,-14.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O14">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-4,-16"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-4.05,-16.05;2.05,-13.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-4,-16"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="6"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/rx#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-3.65,-14.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O15">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-7,-9"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-7.05,-9.05;-1.95,-6.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-7,-9"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/enqueue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-6.65,-7.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O16">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-7,-7"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-7.05,-7.05;-1.95,-4.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-7,-7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/dequeue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-6.65,-5.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O17">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-7,-5"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-7.05,-5.05;-1.95,-2.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-7,-5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/drop#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-6.65,-3.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O18">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-11,-33"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-11.05,-33.05;-3.95,-30.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-11,-33"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#InternetNode#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-7.5,-31.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O19">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-8,-18"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-8.05,-18.05;2.05,-15.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-8,-18"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="10"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2.0000000000000018"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#PointToPointNetDevice#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-3,-16.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O20">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-7,-11"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-7.05,-11.05;-1.95,-8.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-7,-11"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Queue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-4.5,-9.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O21">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-16,-27"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-16.05,-27.05;-6.95,-24.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-16,-27"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="9"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Ipv4L3Protocol#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-11.5,-25.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O22">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-17,-21"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-17.05,-21.05;-9.95,-18.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-17,-21"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Ipv4Interface#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-13.5,-19.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O23">
+ <dia:attribute name="obj_pos">
+ <dia:point val="3,-18"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.95,-18.05;11.05,-15.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="3,-18"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="8.0000000000000071"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#CsmaNetDevice#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="7,-16.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O24">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-9.5,-29"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-12,-29.0606;-9.38388,-26.95"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="-9.5,-29"/>
+ <dia:point val="-9,-27"/>
+ <dia:point val="-11.5,-29"/>
+ <dia:point val="-11.5,-27"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O10" connection="13"/>
+ <dia:connection handle="3" to="O21" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O25">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-10.5,-23"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-13.9972,-23.0606;-10.4066,-20.8302"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="-10.5,-23"/>
+ <dia:point val="-10,-21"/>
+ <dia:point val="-14,-23"/>
+ <dia:point val="-13.5,-21"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O11" connection="13"/>
+ <dia:connection handle="3" to="O22" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O26">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-6,-14"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-6.05,-14.05;-4.0028,-10.8302"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="-6,-14"/>
+ <dia:point val="-6,-11"/>
+ <dia:point val="-5,-13"/>
+ <dia:point val="-4.5,-11"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O13" connection="13"/>
+ <dia:connection handle="3" to="O20" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O27">
+ <dia:attribute name="obj_pos">
+ <dia:point val="5,-14"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="4.95,-14.05;7,-10.95"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="5,-14"/>
+ <dia:point val="5,-12"/>
+ <dia:point val="6.5,-13"/>
+ <dia:point val="6.5,-11"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O3" connection="13"/>
+ <dia:connection handle="3" to="O33" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O28">
+ <dia:attribute name="obj_pos">
+ <dia:point val="2.5,-25"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-3.5,-25.05;2.55,-17.95"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="2.5,-25"/>
+ <dia:point val="2.5,-23"/>
+ <dia:point val="-3,-20"/>
+ <dia:point val="-3,-18"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O0" connection="13"/>
+ <dia:connection handle="3" to="O19" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O29">
+ <dia:attribute name="obj_pos">
+ <dia:point val="2.5,-25"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.45,-25.05;7.5,-17.95"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="2.5,-25"/>
+ <dia:point val="2.5,-23"/>
+ <dia:point val="7,-20"/>
+ <dia:point val="7,-18"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O0" connection="13"/>
+ <dia:connection handle="3" to="O23" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O30">
+ <dia:attribute name="obj_pos">
+ <dia:point val="4,-9"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.95,-9.05;9.05,-6.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="4,-9"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/enqueue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="4.35,-7.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O31">
+ <dia:attribute name="obj_pos">
+ <dia:point val="4,-7"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.95,-7.05;9.05,-4.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="4,-7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/dequeue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="4.35,-5.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O32">
+ <dia:attribute name="obj_pos">
+ <dia:point val="4,-5"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.95,-5.05;9.05,-2.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="4,-5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#/drop#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="4.35,-3.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O33">
+ <dia:attribute name="obj_pos">
+ <dia:point val="4,-11"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.95,-11.05;9.05,-8.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="4,-11"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#e6c7c7"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="corner_radius">
+ <dia:real val="0.40000000000000002"/>
+ </dia:attribute>
+ <dia:attribute name="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Queue#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="1.1000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="6.5,-9.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="1"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O34">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-10,-18"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-10.0693,-20.6883;-5.0028,-17.8302"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="-10,-18"/>
+ <dia:point val="-8,-21"/>
+ <dia:point val="-6.5,-22"/>
+ <dia:point val="-5.5,-18"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O7" connection="8"/>
+ <dia:connection handle="3" to="O19" connection="1"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O35">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-10,-18"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-10.0702,-22.2491;5.4972,-17.8302"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="-10,-18"/>
+ <dia:point val="-1,-25"/>
+ <dia:point val="4,-22"/>
+ <dia:point val="5,-18"/>
+ </dia:attribute>
+ <dia:attribute name="corner_types">
+ <dia:enum val="0"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O7" connection="8"/>
+ <dia:connection handle="3" to="O23" connection="1"/>
+ </dia:connections>
+ </dia:object>
+ </dia:layer>
+</dia:diagram>
Binary file doc/namespace-2.png has changed
--- a/doc/release_steps.txt Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/release_steps.txt Fri Sep 28 11:59:46 2007 +0100
@@ -5,11 +5,16 @@
- revise and check in RELEASE_NOTES
- update and check in VERSION to the latest release number
2. make a new "architecture.pdf" document and place it in the doc/ directory
-3. scons dist
-4. test tarball on release platforms (run-tests and simple-p2p)
+3. cd ns-3-dev; ./waf configure; ./waf dist
+4. test tarball on release platforms (waf check and maybe some other scripts)
5. tag ns-3-dev with "release ns-3.0.X"
-6. clone the ns-3-dev and place it on the repository
-7. upload "ns-3.0.x.tar.gz" to the releases/ directory on the server
+ - hg tag "release ns-3.0.x"
+ - hg push
+6. clone the tagged ns-3-dev and place it on the repository
+ - ssh code.nsnam.org; sudo; su code;
+ - cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x
+ - cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately
+7. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server
8. update web page
- add link to news.html
- update download.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/trace-source-list.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,204 @@
+///
+/// \ingroup TraceSourceList
+/// \brief send ipv4 packet to outgoing interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet sent.
+/// \param arg3 index of output ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/ipv4/tx.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback0 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive ipv4 packet from incoming interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+/// \param arg3 index of input ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/ipv4/rx.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback1 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop ipv4 packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/ipv4/drop.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback2 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief store packet in queue
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet queued.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/enqueue.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::NodeNetDeviceIndex
+/// - ns3::QueueTraceType
+void TraceSinkCallback3 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief remove packet from queue
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dequeued.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/dequeue.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::NodeNetDeviceIndex
+/// - ns3::QueueTraceType
+void TraceSinkCallback4 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop packet from queue
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/drop.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::NodeNetDeviceIndex
+/// - ns3::QueueTraceType
+void TraceSinkCallback5 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive MAC packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/rx.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::NodeNetDeviceIndex
+/// - ns3::PointToPointTraceType
+void TraceSinkCallback6 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive MAC packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/rx.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::NodeNetDeviceIndex
+/// - ns3::CsmaTraceType
+void TraceSinkCallback7 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop MAC packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/drop.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::NodeNetDeviceIndex
+/// - ns3::CsmaTraceType
+void TraceSinkCallback8 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief The value of the speed vector changed
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 the mobility model whose course changed.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$MobilityModelNotifier/course-change.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+void TraceSinkCallback9 (const TraceContext & arg1, Ptr<const MobilityModel> arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief send ipv4 packet to outgoing interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet sent.
+/// \param arg3 index of output ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/tx.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback10 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive ipv4 packet from incoming interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+/// \param arg3 index of input ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/rx.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback11 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop ipv4 packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/drop.
+///
+/// The following classes can be extracted from \p arg1 with
+/// ns3::TraceContext::GetElement:
+/// - ns3::NodeListIndex
+/// - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback12 (const TraceContext & arg1, const Packet & arg2);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tracing.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,576 @@
+/**
+ * \defgroup TraceSourceList List of trace sources
+ */
+
+/**
+ * \defgroup tracing Tracing
+ *
+ * The flexibility of the ns-3 tracing system comes at the cost of quite
+ * a bit of complexity so, before trying to use the low-level aspects
+ * of the tracing API, it is important to focus on some basic definitions:
+ *
+ * - A trace source is an object instance which can report trace events
+ * to a set of listening trace sinks.
+ *
+ * - A trace sink is a user-provided callback (a function) which can
+ * be connected to a set of trace sources to receive the events generated
+ * by each trace source.
+ *
+ * - A trace resolver is an object which allows users to establish
+ * connections between a set of trace sources and a set of trace sinks.
+ *
+ * \section TraceSource Generating Trace Events
+ *
+ * So, what does it look like in practice ? First, let's look at trace
+ * sources. We have two types of trace sources: numeric, and, normal
+ * trace sources. Numeric trace sources behave as normal c++ integers
+ * or c++ floating point numbers except that they report as trace events
+ * each change of their value. For example:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * void DoSomething (void)
+ * {
+ * // use the "int" trace source just
+ * // like any other "int" variable.
+ * m_cwnd *= 2;
+ * m_cwnd += 4;
+ * if (m_cwnd > 100)
+ * {
+ * // do something.
+ * }
+ * }
+ * private:
+ * // declare an instance of a "int" trace source
+ * SVTraceSource<int> m_cwnd;
+ * };
+ * \endcode
+ * Normal trace sources, on the other hand, allow you to trace the
+ * call of arbitrary functions and methods, as shown below. They are
+ * typically used to track "rx", "tx", or "drop" events but could
+ * also be used to track route change events, or position change
+ * events:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * void DoSomething (Packet packet)
+ * {
+ * // report this event on packet
+ * m_doSomething (packet);
+ * // do something
+ * }
+ * private:
+ * // report every "something" function call.
+ * CallbackTraceSource<Packet> m_doSomething;
+ * };
+ * \endcode
+ * Every type of trace source derives from the ns3::TraceSource base class.
+ * As of today, the set of concrete subclasses is relatively short:
+ * ns3::CallbackTraceSource, ns3::SvTraceSource, ns3::UvTraceSource, and,
+ * ns3::FvTraceSource.
+ *
+ * \section TraceSink Receiving Trace Events
+ *
+ * To receive these trace events, a user should specify a set of trace sinks.
+ * For example, to receive the "int" and the "something" events shown in the
+ * examples above, a user would declare the following functions:
+ * \code
+ * // oldValue and newValue contain the previous and new values of
+ * // the connected SVTraceSource<int> trace source.
+ * void
+ * CwndTraceSink (const TraceContext &context, int64_t oldValue, int64_t newValue)
+ * {
+ * // for example, print the new value:
+ * std::cout << "cwnd=" << newValue << std::endl;
+ * }
+ * void
+ * DoSomethingTraceSink (const TraceContext &context, Packet packet)
+ * {
+ * // for example, print the arguments
+ * std::cout << "packet " << packet << std::endl;
+ * }
+ * \endcode
+ * Each of these sink function takes, as a first argument, a reference to a
+ * const TraceContext object. This context object contains information which
+ * describes the instance of the connected trace source: that information is
+ * setup during the connection process and does not change afterwards
+ * The type and the number of the other arguments to each trace sink depends
+ * on the type of the connected trace source: it conveys per-event information
+ * from the trace source to the trace sink. For example, UVTraceSource and
+ * SVTraceSource trace sources require two extra arguments. The former requires
+ * two unsigned 64 bit integers while the latter requires two signed 64 bit
+ * integers. More generally, users can consult the \ref TraceSourceList
+ * to figure out the arguments which a trace sink is required to receive
+ * for each trace source: a signature of the user trace sink must match
+ * _exactly_ the signature documented in the \ref TraceSourceList.
+ *
+ *
+ * \section TraceSourceSimpleExport A simple way to connect Trace Sources with Trace Sinks
+ *
+ * The crux of the complexity of the ns-3 tracing system comes from its
+ * flexible system used to connect trace sources to trace sinks but what is really
+ * nice about it is that it is not necessary to use it to setup simple traces.
+ *
+ * The simplest way to export a set of trace sources to a user, for example,
+ * during the early prototyping phases of a system, is to add a set of public methods
+ * to give to your users access to the trace source object instances you use to generate
+ * trace events:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * void DoSomething (Packet packet)
+ * {
+ * // report this event on packet
+ * m_doSomething (packet);
+ * // do something
+ * }
+ * CallbackTraceSource<Packet> *PeekSomethingTraceSource (void) const
+ * {
+ * return &m_doSomething
+ * }
+ * private:
+ * // report every "something" function call.
+ * CallbackTraceSource<Packet> m_doSomething;
+ * };
+ * \endcode
+ * If your users hold a pointer to an instance of MyModel, and if they want to connect
+ * a MySomethingSink, they can simply do the following which invokes the
+ * TraceSource::AddCallback method and creates a Callback object from the user's
+ * sink with the MakeCallback function.
+ * \code
+ * void
+ * MySomethingSink (const TraceContext &context, Packet packet)
+ * {
+ * // do whatever you want.
+ * }
+ * MyModel *model = ...;
+ * CallbackTraceSource<Packet> *source = model->PeekSomethingTraceSource ();
+ * source->AddCallback (MakeCallback (&MySomethingSink));
+ * \endcode
+ *
+ * The full power of the tracing system comes however from its ns3::NodeList::Connect
+ * method which is described in the following sections.
+ *
+ * \section TraceConnection Connecting Trace Sources to Trace Sinks
+ *
+ * If a trace source is integrated in the ns-3 trace connection facility, a user
+ * should call the ns3::NodeList::Connect method to establish a connection between
+ * a trace sink and a set of matching trace sources. The second argument to that
+ * method is a callback to the user's trace sink.
+ * That callback is easy to construct: call ns3::MakeCallback and you are done. The
+ * first argument is a string whose format is similar to a unix path and which is
+ * used to uniquely identify the set of trace sources you want to connect to.
+ * The set of acceptable path strings is also documented in the \ref TraceSourceList.
+ *
+ * So, what does this look like from the perspective of a user ? If we wanted to
+ * connect to a trace source defined somewhere deep into the a set of NetDevice objects
+ * located in some nodes of the system, we could write the following:
+ * \code
+ * void
+ * DoSomethingTraceSink (const TraceContext &context, Packet packet)
+ * {
+ * // for example, print the arguments
+ * std::cout << "packet: " << packet << std::endl;
+ * }
+ * // connect the above sink to a matching trace source
+ * NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback &DoSomethingTraceSink);
+ * \endcode
+ *
+ * The connection path string "/nodes/* /devices/* /rx" matches the "rx" trace source
+ * located in every netdevice located in every node. The syntax of that path string
+ * is loosely based on regular expressions so, a user could conceivably connect
+ * to the trace sources present in only one node identified by node index:
+ * "/nodex/3/devices/* /rx".
+ *
+ * The matching algorithm used here is very useful since it allows you to connect
+ * at once a large set of trace sources to a single sink but it introduces another
+ * problem: it becomes impossible when you receive an event in your trace sink to
+ * know from _which_ trace source the event is coming from. In our example, the
+ * trace source might be coming from the NetDevice number 2 of Node 10 or Netdevice
+ * number 0 of Node 5. In both cases, you might need to know which of these NetDevice
+ * is generating this event, if only to generate some ascii trace dump. Another
+ * similar use-case is that you might have connected the same trace sink to
+ * multiple types of events which have the same signature: it is quite common
+ * to receive all tx, rx, and drop events in the same trace sink and that would be
+ * quite trivial to achieve with a string such as: "/nodes/* /devices/* /*"
+ *
+ * The source of a trace event can be retrieved from a trace sink using
+ * different means: the simplest
+ * way to get this information is to use the builtin printing facility of
+ * the TraceContext object:
+ * \code
+ * void
+ * DoSomethingTraceSink (const TraceContext &context, Packet packet)
+ * {
+ * // for example, print the arguments
+ * std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
+ * }
+ * \endcode
+ * The above code is going to generate output which looks like the following:
+ * \code
+ * context="nodeid=2 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
+ * context="nodeid=1 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
+ * ...
+ * \endcode
+ *
+ * Another more advanced way to get information out of a TraceContext is to call its
+ * ns3::TraceContext::GetElement method. This method takes as its first and only
+ * argument an instance of the object we want to read and the list of available
+ * object instances we can read from a TraceContext is documented, once again,
+ * in the \ref TraceSourceList. For example, we could write the following to
+ * generate adhoc trace output:
+ * \code
+ * void DeviceRxSink (const TraceContext &context, const Packet &packet)
+ * {
+ * NodeListIndex nodeIndex;
+ * NodeNetDeviceIndex deviceIndex;
+ * context.GetElement (nodeIndex);
+ * context.GetElement (deviceIndex);
+ * std::cout << "node-index=" << nodeIndex.Get ();
+ * std::cout << ", device-index=" << deviceIndex.Get ();
+ * std::cout << ", packet: " << packet;
+ * std::cout << std::endl;
+ * }
+ * \endcode
+ *
+ * \section ExportingTraceSources Exporting new Trace Sources
+ *
+ * Using existing trace sources to connect them to a set of adhoc trace sinks
+ * is not really complicated but, setting up new trace sources which can hook
+ * in this automatic connection system is a bit more complicated.
+ *
+ * So far, we know that a model author can generate trace events really easily:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * void DoSomething (Packet packet)
+ * {
+ * // report this event on packet with value
+ * m_doSomething (packet);
+ * // do something
+ * }
+ * private:
+ * // report every "something" function call.
+ * CallbackTraceSource<Packet> m_doSomething;
+ * };
+ * \endcode
+ *
+ * To make these new trace sources available to the rest of the connection system,
+ * the first step is to make sure that your model object derives from the ns3::Object
+ * base class either directly (as shown below) or indirectly through another base class:
+ * \code
+ * class MyModel : public Object {...};
+ * // or:
+ * class SomeOtherObject : public Object {...};
+ * class MyModel : public SomeOtherObject {...};
+ * \endcode
+ *
+ * This is pretty trivial and lays the ground for the second step: overriding the
+ * ns3::Object::GetTraceResolver method:
+ * \code
+ * class MyModel : public MyParent
+ * {
+ * public:
+ * // declare overriden method
+ * virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+ * private:
+ * // the new trace source to export.
+ * CallbackTraceSource<Packet> m_rxSource;
+ * };
+ * \endcode
+ *
+ * To implement this method, you could attempt to implement a new subclass of
+ * the ns3::TraceResolver base class and return an instance from this method but
+ * this would be very hard. Instead, you should use the helper class
+ * ns3::CompositeTraceResolver to register your trace sources and chain up to
+ * your parent:
+ * \code
+ * Ptr<TraceResolver>
+ * MyModel::GetTraceResolver (void) const
+ * {
+ * // create an empty trace resolver
+ * Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ * // register m_rxSource
+ * resolver->AddSource ("rx", // the name of the trace source in the path string
+ * TraceDoc ("some help text to explain the purpose of this trace source",
+ * "Packet", // the type of the first argument to the trace source
+ * "the purpose of the first argument",
+ * "type-of-second-argument", "purpose-of-second-argument"),
+ * m_rxSource // the trace source itself is registered
+ * );
+ * // make sure we include the trace sources implemented in the parent.
+ * resolver->SetParentResolver (MyParent::GetTraceResolver ());
+ * return resolver;
+ * }
+ * \endcode
+ *
+ * Once you have written that code, you must make sure that this new method GetTraceResolver
+ * is going to be called at some point by the tracing system. If your model is located somewhere
+ * deep in MAC or PHY layer, that is, it is part of a NetDevice implementation, all you
+ * have to do is to make sure that your model is registered as a "composite" of your NetDevice
+ * subclass:
+ * \code
+ * class MyNetDevice : public NetDevice
+ * {
+ * public:
+ * Ptr<TraceResolver> GetTraceResolver (void) const;
+ * private:
+ * Ptr<MyModel> m_model;
+ * };
+ *
+ * Ptr<TraceResolver>
+ * MyNetDevice::GetTraceResolver (void) const
+ * {
+ * Ptr<CompositeTraceResolver> resolver = ...;
+ * // register other trace source
+ * ...
+ * // register now your model as a "composite"
+ * resolver->AddComposite ("my-model", m_model);
+ * // chain up to parent.
+ * resolver->SetParentResolver (NetDevice::GetTraceResolver ());
+ * return resolver;
+ * }
+ * \endcode
+ *
+ * The code above will make your "rx" trace source appear under the
+ * /nodes/xx/devices/xx/my-model/rx namespace path.
+ *
+ * If you have implemented a new layer 3 or 4 protocol object, the process to
+ * export your trace sources is quite similar. You need to subclass from
+ * ns3::Object, override the ns3::Object::GetTraceResolver method, make
+ * sure you chain up to your parent's GetTraceResolver method, and, finally,
+ * make sure that someone calls your new GetTraceResolver method. How to accomplish
+ * the latter should be documented in the node's API documentation which describes
+ * how to implement a new layer 3 or 4 protocol object.
+ *
+ * \section AdvancedTraceContext Creating new Trace Context Elements
+ *
+ * The last important feature which model developers need to understand
+ * is how to provide extra context information to trace sinks. For example,
+ * if your model exports both rx and tx trace sources which share the same
+ * signature, it is quite natural for a user to connect to a single trace sink
+ * to both of them with a trace path string such as "/nodes/* /devices/* /(rx|tx)".
+ * In this case, it becomes necessary to be able, from the trace sink function,
+ * to tell which event triggered the call to the trace sink: a rx or a tx event.
+ *
+ * That example is detailed below with a TX, a RX, and a DROP source:
+ * \code
+ * class MyModel
+ * {
+ * private:
+ * CallbackTraceSource<Packet> m_rxSource;
+ * CallbackTraceSource<Packet> m_txSource;
+ * CallbackTraceSource<Packet> m_dropSource;
+ * };
+ * \endcode
+ * When a single sink is connected to all 3 sources here, one might want
+ * to write code like the following:
+ * \code
+ * void DeviceRxSink (const TraceContext &context, const Packet &packet)
+ * {
+ * switch (type) {
+ * case RX:
+ * std::cout << "rx" << std::endl;
+ * break;
+ * case TX:
+ * std::cout << "tx" << std::endl;
+ * break;
+ * case DROP:
+ * std::cout << "drop" << std::endl;
+ * break;
+ * }
+ * \endcode
+ *
+ * \subsection AdvancedTraceContextSimpleSolution The simple solution
+ *
+ * The simplest way to do achieve the result shown above is to include
+ * in the trace source an extra explicit argument which describes the source event:
+ * - define a small enum with 3 values
+ * - change the signature of m_rxSource, m_txSource, and m_dropSource to include
+ * the enum
+ * - pass the enum value in each event
+ *
+ * The resulting code is shown below:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ * // define the trace type enum.
+ * enum TraceType {
+ * RX,
+ * TX,
+ * DROP
+ * };
+ * private:
+ * // generate events
+ * void NotifyRxPacket (Packet p) {
+ * m_rxSource (p, MyModel::RX);
+ * }
+ * void NotifyTxPacket (Packet p) {
+ * m_rxSource (p, MyModel::TX);
+ * }
+ * void NotifyDropPacket (Packet p) {
+ * m_rxSource (p, MyModel::DROP);
+ * }
+ * CallbackTraceSource<Packet,enum TraceType> m_rxSource;
+ * CallbackTraceSource<Packet,enum TraceType> m_txSource;
+ * CallbackTraceSource<Packet,enum TraceType> m_dropSource;
+ * };
+ * \endcode
+ * These 3 new sources can be connected easily to a new trace sink:
+ * \code
+ * void ASimpleTraceSink (const TraceContext &context, const Packet &packet, enum MyModel::TraceType type)
+ * {
+ * // here, read the "type" argument
+ * }
+ * \endcode
+ *
+ * This solution works but it makes it impossible to connect a single trace sink to a set
+ * of trace sources which represent "rx" events in different NetDevice objects since
+ * each of them will define a different enum type with different values: since the
+ * trace sink signature must match exactly the trace source signature, it is impossible
+ * to connect at the same time to all "rx" events of different NetDevice.
+ *
+ * \subsection AdvancedTraceContextFancySolution The more complex and generic solution
+ *
+ * There is, hopefully, a way to get the best of both worlds, that is, to allow a
+ * user to connect to a lot of trace source events of the same kind but coming from different
+ * implementations and to allow the user to differentiate between these different
+ * implementations.
+ *
+ * Rather than define an adhoc enum type with a list of trace sources, you can also
+ * define a new ns3::TraceContextElement for your source sources. For example, if you
+ * define a new MyModelTraceType class which contains the type of trace, your users can
+ * then write trace sink code which looks like this:
+ * \code
+ * void AFancyTraceSink (const TraceContext &context, const Packet &packet)
+ * {
+ * MyModelTraceType type;
+ * if (context.GetElement (type))
+ * {
+ * switch (type.Get ())
+ * {
+ * case MyModelTraceType::RX:
+ * std::cout << "rx" << std::endl;
+ * break;
+ * case MyModelTraceType::TX:
+ * std::cout << "tx" << std::endl;
+ * break;
+ * case MyModelTraceType::DROP:
+ * std::cout << "drop" << std::endl;
+ * break;
+ * }
+ * }
+ * }
+ * \endcode
+ *
+ * Of course, since the type of trace is stored in the TraceContext, your users can
+ * also take the shortcut which uses the printing functionality of the TraceContext:
+ * \code
+ * void ALessFancyTraceSink (const TraceContext &context, const Packet &packet)
+ * {
+ * std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
+ * }
+ * \endcode
+ * which will generate something like the following when the trace source comes
+ * from MyModel:
+ * \code
+ * context="my-model-rx" packet: ...
+ * \endcode
+ *
+ * The first step to achieve this is to define and implement a new
+ * subclass of the ns3::TraceContextElement base class. The exact list of
+ * public methods which must be implemented is described in the API
+ * documentation of the ns3::TraceContextElement class.
+ * \code
+ * class MyModelTraceType : public TraceContextElement
+ * {
+ * public:
+ * enum Type {
+ * RX,
+ * TX,
+ * DROP
+ * };
+ * // called from MyModel::GetTraceResolver
+ * MyModelTraceType (enum Type type);
+ * // called from trace sink
+ * enum Type Get (void) const;
+ * // needed by the tracing subsystem
+ * static uint16_t GetUid (void);
+ * // needed by the tracing subsystem to
+ * // print the content of a TraceContext
+ * void Print (std::ostream &os) const;
+ * // needed by the tracing subsystem to
+ * // generate the doxygen documentation.
+ * std::string GetTypeName (void) const;
+ * private:
+ * enum Type m_type;
+ * };
+ * \endcode
+ * The implementation does not require much thinking:
+ * \code
+ * MyModelTraceType::MyModelTraceType (enum Type type)
+ * : m_type (type)
+ * {}
+ * enum Type
+ * MyModelTraceType::Get (void) const
+ * {
+ * return m_type;
+ * }
+ * uint16_t
+ * MyModelTraceType::GetUid (void)
+ * {
+ * // use protected TraceContextElement::AllocateUid method
+ * // the input string is used to uniquely identify this new subclass
+ * static uint16_t uid = AllocateUid<MyModelTraceType> ("ns3::MyModelTraceType");
+ * return uid;
+ * }
+ * void
+ * MyModelTraceType::Print (std::ostream &os) const
+ * (
+ * // this method is invoked by the print function of a TraceContext
+ * // if it contains an instance of this TraceContextElement.
+ * switch (m_type) {
+ * case RX: os << "rx"; break;
+ * // ...
+ * }
+ * )
+ * std::string
+ * MyModelTraceType::GetTypeName (void) const
+ * {
+ * // This method should return a fully-qualified c++ typename
+ * // This method is used only for documentation purposes to
+ * // generate the content of the Trace Source List.
+ * return "ns3::MyModelTraceType";
+ * }
+ * \endcode
+ *
+ * Once this subclass is implemented, the work is almost completed: you
+ * just need to pass an instance of that class as the last argument of
+ * the ns3::CompositeTraceResolver::AddSource method as shown below:
+ * \code
+ * Ptr<TraceResolver>
+ * MyModel::GetTraceResolver (void) const
+ * {
+ * // create an empty trace resolver
+ * Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ * // register m_rxSource
+ * resolver->AddSource ("rx", // the name of the trace source in the path string
+ * TraceDoc ("some help text to explain the purpose of this trace source",
+ * "Packet", // the type of the first argument to the trace source
+ * "the purpose of the first argument",
+ * "type-of-second-argument", "purpose-of-second-argument"),
+ * m_rxSource, // the trace source itself is registered
+ * // the TraceContextElement associated to this trace source.
+ * MyModelTraceType (MyModelTraceType::RX)
+ * );
+ * // make sure we include the trace sources implemented in the parent.
+ * resolver->SetParentResolver (MyParent::GetTraceResolver ());
+ * return resolver;
+ * }
+ * \endcode
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-broadcast.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,204 @@
+/* -*- 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
+ */
+
+//
+// Example of the sending of a datagram to a broadcast address
+//
+// Network topology
+// ==============
+// | |
+// n0 n1 n2
+// | |
+// ==========
+//
+// n0 originates UDP broadcast to 255.255.255.255/discard port, which
+// is replicated and received on both n1 and n2
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/log.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/mac48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/onoff-application.h"
+#include "ns3/packet-sink.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaBroadcastExample");
+
+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 ("CsmaBroadcastExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ // Enable the below logging command to see the packets being received
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+#endif
+
+ // Set up some default values for the simulation. Use the Bind()
+ // technique to tell the system what subclass of Queue to use,
+ // and what the queue limit is
+
+ // The below Bind command tells the queue factory which class to
+ // instantiate, when the queue factory is invoked in the topology code
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+
+ // Allow the user to override any of the defaults and the above
+ // Bind()s at run-time, via command-line arguments
+ CommandLine::Parse (argc, argv);
+
+ // Here, we will explicitly create four nodes. In more sophisticated
+ // topologies, we could configure a node factory.
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+
+ // We create the channels first without any IP addressing information
+ NS_LOG_INFO ("Create channels.");
+ Ptr<CsmaChannel> channel0 =
+ CsmaTopology::CreateCsmaChannel(
+ DataRate(5000000), MilliSeconds(2));
+
+ // We create the channels first without any IP addressing information
+ Ptr<CsmaChannel> channel1 =
+ CsmaTopology::CreateCsmaChannel(
+ DataRate(5000000), MilliSeconds(2));
+
+ NS_LOG_INFO ("Build Topology.");
+ uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel0,
+ Mac48Address("10:54:23:54:0:50"));
+ uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel1,
+ Mac48Address("10:54:23:54:0:51"));
+ uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, channel0,
+ Mac48Address("10:54:23:54:23:51"));
+ uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channel1,
+ Mac48Address("10:54:23:54:23:52"));
+
+ // Later, we add IP addresses.
+ NS_LOG_INFO ("Assign IP Addresses.");
+ CsmaIpv4Topology::AddIpv4Address (
+ n0, n0ifIndex0, Ipv4Address("10.1.0.1"), Ipv4Mask("255.255.0.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n1, n1ifIndex, Ipv4Address("10.1.0.2"), Ipv4Mask("255.255.0.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n0, n0ifIndex1, Ipv4Address("192.168.1.1"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n2, n2ifIndex, Ipv4Address("192.168.1.2"), Ipv4Mask("255.255.255.0"));
+
+ // RFC 863 discard port ("9") indicates packet should be thrown away
+ // by the system. We allow this silent discard to be overridden
+ // by the PacketSink application.
+ uint16_t port = 9;
+
+ // Create the OnOff application to send UDP datagrams of size
+ // 512 bytes (default) at a rate of 500 Kb/s (default) from n0
+ NS_LOG_INFO ("Create Applications.");
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("255.255.255.255", port),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.0));
+ ooff->Stop (Seconds(10.0));
+
+ // Create an optional packet sink to receive these packets
+ Ptr<PacketSink> sink = Create<PacketSink> (
+ n1,
+ InetSocketAddress (Ipv4Address::GetAny (), port),
+ "Udp");
+ // Start the sink
+ sink->Start (Seconds (1.0));
+ sink->Stop (Seconds (10.0));
+
+ // Create an optional packet sink to receive these packets
+ sink = Create<PacketSink> (
+ n2,
+ InetSocketAddress (Ipv4Address::GetAny (), port),
+ "Udp");
+ // Start the sink
+ sink->Start (Seconds (1.0));
+ sink->Stop (Seconds (10.0));
+
+ NS_LOG_INFO ("Configure Tracing.");
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the csma-broadcast.tr file
+ AsciiTrace asciitrace ("csma-broadcast.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+
+ // Also configure some tcpdump traces; each interface will be traced
+ // The output files will be named
+ // simple-point-to-point.pcap-<nodeId>-<interfaceId>
+ // and can be read by the "tcpdump -r" command (use "-tt" option to
+ // display timestamps correctly)
+ PcapTrace pcaptrace ("csma-broadcast.pcap");
+ pcaptrace.TraceAllIp ();
+
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-multicast.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,333 @@
+/* -*- 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
+//
+// Lan1
+// ===========
+// | | |
+// n0 n1 n2 n3 n4
+// | | |
+// ===========
+// Lan0
+//
+// - Multicast source is at node n0;
+// - Multicast forwarded by node n2 onto LAN1;
+// - Nodes n0, n1, n2, n3, and n4 receive the multicast frame.
+// - Node n4 listens for the data (actual listener not yet implementted)
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/mac48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/onoff-application.h"
+#include "ns3/packet-sink.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaMulticastExample");
+
+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 ("CsmaMulticastExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+#endif
+//
+// Set up default values for the simulation. Use the DefaultValue::Bind()
+// technique to tell the system what subclass of Queue to use. The Bind
+// command command tells the queue factory which class to instantiate when the
+// queue factory is invoked in the topology code
+//
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+//
+// Allow the user to override any of the defaults and the above Bind() at
+// run-time, via command-line arguments
+//
+ CommandLine::Parse (argc, argv);
+//
+// Explicitly create the nodes required by the topology (shown above).
+//
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+ Ptr<Node> n4 = Create<InternetNode> ();
+
+ NS_LOG_INFO ("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+ Ptr<CsmaChannel> lan0 =
+ CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
+
+ Ptr<CsmaChannel> lan1 =
+ CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
+
+ NS_LOG_INFO ("Build Topology.");
+//
+// 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. Interpret nd2Lan0 as the net device we created for node two to
+// connect to Lan0.
+//
+ uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan0,
+ Mac48Address("08:00:2e:00:00:00"));
+ uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan0,
+ Mac48Address("08:00:2e:00:00:01"));
+ uint32_t nd2Lan0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan0,
+ Mac48Address("08:00:2e:00:00:02"));
+
+ uint32_t nd2Lan1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1,
+ Mac48Address("08:00:2e:00:00:03"));
+ uint32_t nd3 __attribute__ ((unused)) =
+ CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1,
+ Mac48Address("08:00:2e:00:00:04"));
+ uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan1,
+ Mac48Address("08:00:2e:00:00:05"));
+
+ NS_LOG_INFO ("nd0 = " << nd0);
+ NS_LOG_INFO ("nd1 = " << nd1);
+ NS_LOG_INFO ("nd2Lan0 = " << nd2Lan0);
+ NS_LOG_INFO ("nd2Lan1 = " << nd2Lan1);
+ NS_LOG_INFO ("nd3 = " << nd3);
+ NS_LOG_INFO ("nd4 = " << nd3);
+//
+// We've got the "hardware" in place. Now we need to add IP addresses.
+//
+ NS_LOG_INFO ("Assign IP Addresses.");
+ 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"));
+
+//
+// We'll need these addresses later
+//
+ Ipv4Address n2Lan0Addr ("10.1.1.3");
+ Ipv4Address n2Lan1Addr ("10.1.2.1");
+
+ CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan0, n2Lan0Addr,
+ Ipv4Mask ("255.255.255.0"));
+//
+// Assign IP addresses to the net devices and associated interfaces on Lan1
+//
+ CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan1, n2Lan1Addr,
+ Ipv4Mask ("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (n3, nd1, Ipv4Address ("10.1.2.2"),
+ Ipv4Mask ("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (n4, nd4, Ipv4Address ("10.1.2.3"),
+ Ipv4Mask ("255.255.255.0"));
+
+ NS_LOG_INFO ("Configure multicasting.");
+//
+// Now we can configure multicasting. As described above, the multicast
+// source is at node zero, which we assigned the IP address of 10.1.1.1
+// earlier. We need to define a multicast group to send packets to. This
+// can be any multicast address from 224.0.0.0 through 239.255.255.255
+// (avoiding the reserved routing protocol addresses). We just pick a
+// convenient number (225.0.0.0) and or in some bits to let us verify that
+// correct Ethernet multicast addresses are constructed down in the system.
+//
+ Ipv4Address multicastSource ("10.1.1.1");
+ Ipv4Address multicastGroup ("225.1.2.4");
+//
+// We are going to manually configure multicast routing. This means telling
+// node two that it should expect multicast data coming from IP address
+// 10.1.1.1 originally. It should expect these data coming in over its IP
+// interface connected to Lan0. When node two receives these packets, they
+// should be forwarded out the interface that connects it to Lan1.
+//
+// We're going to need the interface indices on node two corresponding to
+// these interfaces, which we call ifIndexLan0 and ifIndexLan1. The most
+// general way to get these interfaces is to look them up by IP address.
+// Looking back to the topology creation calls above, we saved the addresses
+// assigned to the interface connecting node two to Lan0 and Lan1. Now is
+// a fine time to find the interface indices on node two.
+//
+ Ptr<Ipv4> ipv4;
+ ipv4 = n2->QueryInterface<Ipv4> (Ipv4::iid);
+
+ uint32_t ifIndexLan0 = ipv4->FindInterfaceForAddr (n2Lan0Addr);
+ uint32_t ifIndexLan1 = ipv4->FindInterfaceForAddr (n2Lan1Addr);
+//
+// Now, we need to do is to call the AddMulticastRoute () method on node
+// two's Ipv4 interface and tell it that whenever it receives a packet on
+// the interface from Lan0, with the packet from the multicast source,
+// destined for the multicast group, it should forward these packets down
+// the interface connecting it to Lan1. (Note: the vector of output
+// interfaces is in case there are multiple net devices on a node -- not
+// true in this case).
+//
+ std::vector<uint32_t> outputInterfaces (1);
+ outputInterfaces[0] = ifIndexLan1;
+
+ ipv4->AddMulticastRoute (multicastSource, multicastGroup, ifIndexLan0,
+ outputInterfaces);
+//
+// We need to specify how the source node handles multicasting. There are a
+// number of ways we can deal with this, we just need to pick one. The first
+// method is to add an explicit route out of the source node, just as we did
+// for the forwarding node. Use this method when you want to send packets out
+// multiple interfaces or send packets out different interfaces based on the
+// differing multicast groups. Since the source is local, there will be no
+// input interface over which packets are received, so use
+// Ipv4RoutingProtocol::IF_INDEX_ANY as a wildcard.
+//
+// A second way is to specify a multicast route using wildcards. If you
+// want to send multicasts out differing sets of interfaces based on the
+// multicast group, you can use AddMulticastRoute () but specify the origin
+// as a wildcard. If you want all multicasts to go out a single set of
+// interfaces, you can make both the origin and group a wildcard.
+//
+// If you have a simple system, where the source has a single interface, this
+// can be done via the SetDefaultMulticastRoute () method on the Ipv4
+// interface. This tells the system to send all multicasts out a single
+// specified network interface index.
+//
+// A last way is to specify a (or use an existing) default unicast route. The
+// multicast routing code uses the unicast default route as a multicast "route
+// of last resort." this method for is also on Ipv4 and is called
+// SetDefaultRoute ().
+//
+// Since this is a simple multicast example, we use the
+// SetDefaultMulticastRoute () approach. We are going to first need the
+// Ipv4 interface for node 0 which is the multicast source. We use this
+// interface to find the output interface index, and tell node zero to send
+// its multicast traffic out that interface.
+//
+ ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t ifIndexSrc = ipv4->FindInterfaceForAddr (multicastSource);
+ ipv4->SetDefaultMulticastRoute (ifIndexSrc);
+//
+// As described above, node four will be the only node listening for the
+// multicast data. To enable forwarding bits up the protocol stack, we need
+// to tell the stack to join the multicast group.
+//
+ ipv4 = n4->QueryInterface<Ipv4> (Ipv4::iid);
+ ipv4->JoinMulticastGroup (multicastSource, multicastGroup);
+//
+// Create an OnOff application to send UDP datagrams from node zero to the
+// multicast group (node four will be listening).
+//
+ NS_LOG_INFO ("Create Applications.");
+
+ uint16_t port = 9; // Discard port (RFC 863)
+
+ // Configure a multicast packet generator that generates a packet
+ // every few seconds
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress (multicastGroup, port),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0),
+ DataRate ("255b/s"),
+ 128);
+//
+// Tell the application when to start and stop.
+//
+ ooff->Start(Seconds(1.));
+ ooff->Stop (Seconds(10.));
+
+ // Create an optional packet sink to receive these packets
+ // If you enable logging on this (above) it will print a log statement
+ // for every packet received
+ Ptr<PacketSink> sink = Create<PacketSink> (
+ n4,
+ InetSocketAddress (Ipv4Address::GetAny (), port),
+ "Udp");
+ // Start the sink
+ sink->Start (Seconds (1.0));
+ sink->Stop (Seconds (10.0));
+
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "csma-multicast.tr"
+//
+ NS_LOG_INFO ("Configure Tracing.");
+ AsciiTrace asciitrace ("csma-multicast.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+// csma-multicast.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
+ PcapTrace pcaptrace ("csma-multicast.pcap");
+ pcaptrace.TraceAllIp ();
+//
+// Now, do the actual simulation.
+//
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-one-subnet.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,215 @@
+/* -*- 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
+//
+// - CBR/UDP flows from n0 to n1 and from n3 to n0
+// - DropTail queues
+// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/mac48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/onoff-application.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaOneSubnetExample");
+
+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 ("CsmaOneSubnetExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+//
+// Set up default values for the simulation. Use the DefaultValue::Bind()
+// technique to tell the system what subclass of Queue to use. The Bind
+// command command tells the queue factory which class to instantiate when the
+// queue factory is invoked in the topology code
+//
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+//
+// Allow the user to override any of the defaults and the above Bind() at
+// run-time, via command-line arguments
+//
+ CommandLine::Parse (argc, argv);
+//
+// Explicitly create the nodes required by the topology (shown above).
+//
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ NS_LOG_INFO ("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+ Ptr<CsmaChannel> lan = CsmaTopology::CreateCsmaChannel(
+ DataRate(5000000), MilliSeconds(2));
+
+ NS_LOG_INFO ("Build Topology.");
+//
+// 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.
+//
+ 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"));
+//
+// We've got the "hardware" in place. Now we need to add IP addresses.
+//
+ NS_LOG_INFO ("Assign IP Addresses.");
+//
+// XXX BUGBUG
+// Need a better way to get the interface index. The point-to-point topology
+// as implemented can't return the index since it creates interfaces on both
+// sides (i.e., it does AddIpv4Addresses, not AddIpv4Address). We need a
+// method on Ipv4 to find the interface index corresponding to a given ipv4
+// address.
+//
+// Assign IP addresses to the net devices and associated interfaces
+// on the lan. The AddIpv4Address method returns an Ipv4 interface index
+// which we do not need here.
+//
+ 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"));
+//
+// 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)
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("10.1.1.2", port),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0));
+//
+// Tell the application when to start and stop.
+//
+ ooff->Start(Seconds(1.0));
+ ooff->Stop (Seconds(10.0));
+//
+// Create a similar flow from n3 to n0, starting at time 1.1 seconds
+//
+ ooff = Create<OnOffApplication> (
+ n3,
+ InetSocketAddress ("10.1.1.1", port),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0));
+
+ ooff->Start(Seconds(1.1));
+ ooff->Stop (Seconds(10.0));
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "csma-one-subnet.tr"
+//
+ NS_LOG_INFO ("Configure Tracing.");
+ AsciiTrace asciitrace ("csma-one-subnet.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+// csma-one-subnet.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
+ PcapTrace pcaptrace ("csma-one-subnet.pcap");
+ pcaptrace.TraceAllIp ();
+//
+// Now, do the actual simulation.
+//
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-packet-socket.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,169 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+// n0 n1 n2 n3
+// | | | |
+// =====================
+//
+// - CBR/UDP flows from n0 to n1, and from n3 to n0
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+// (i.e., DataRate of 448,000 bps)
+// - DropTail queues
+// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/log.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/mac48-address.h"
+#include "ns3/packet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/onoff-application.h"
+#include "ns3/queue.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample");
+
+static Ptr<CsmaNetDevice>
+CreateCsmaDevice (Ptr<Node> node, Ptr<CsmaChannel> channel)
+{
+ Ptr<CsmaNetDevice> device = Create<CsmaNetDevice> (node);
+ device->Attach (channel);
+ Ptr<Queue> queue = Queue::CreateDefault ();
+ device->AddQueue (queue);
+ return device;
+}
+
+int
+main (int argc, char *argv[])
+{
+#if 0
+ LogComponentEnable ("CsmaPacketSocketExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+
+ CommandLine::Parse (argc, argv);
+
+ // Here, we will explicitly create four nodes. In more sophisticated
+ // topologies, we could configure a node factory.
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<Node> ();
+ Ptr<Node> n1 = Create<Node> ();
+ Ptr<Node> n2 = Create<Node> ();
+ Ptr<Node> n3 = Create<Node> ();
+
+ // create the shared medium used by all csma devices.
+ NS_LOG_INFO ("Create channels.");
+ Ptr<CsmaChannel> channel = Create<CsmaChannel> (DataRate(5000000), MilliSeconds(2));
+
+ // use a helper function to connect our nodes to the shared channel.
+ NS_LOG_INFO ("Build Topology.");
+ Ptr<NetDevice> n0If = CreateCsmaDevice (n0, channel);
+ Ptr<NetDevice> n1If = CreateCsmaDevice (n1, channel);
+ Ptr<NetDevice> n2If = CreateCsmaDevice (n2, channel);
+ Ptr<NetDevice> n3If = CreateCsmaDevice (n3, channel);
+
+ // create the address which identifies n1 from n0
+ PacketSocketAddress n0ToN1;
+ n0ToN1.SetSingleDevice (n0If->GetIfIndex ()); // set outgoing interface for outgoing packets
+ n0ToN1.SetPhysicalAddress (n1If->GetAddress ()); // set destination address for outgoing packets
+ n0ToN1.SetProtocol (2); // set arbitrary protocol for outgoing packets
+
+ // create the address which identifies n0 from n3
+ PacketSocketAddress n3ToN0;
+ n3ToN0.SetSingleDevice (n3If->GetIfIndex ());
+ n3ToN0.SetPhysicalAddress (n0If->GetAddress ());
+ n3ToN0.SetProtocol (3);
+
+ // Create the OnOff application to send raw datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ // from n0 to n1
+ NS_LOG_INFO ("Create Applications.");
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ n0ToN1,
+ "Packet",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.0));
+ ooff->Stop (Seconds(10.0));
+
+ // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+ ooff = Create<OnOffApplication> (
+ n3,
+ n3ToN0,
+ "Packet",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.1));
+ ooff->Stop (Seconds(10.0));
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the csma-packet-socket.tr file
+ NS_LOG_INFO ("Configure Tracing.");
+ AsciiTrace asciitrace ("csma-packet-socket.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mixed-global-routing.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,224 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+// This script exercises global routing code in a mixed point-to-point
+// and csma/cd environment
+//
+// Network topology
+//
+// n0
+// \ p-p
+// \ (shared csma/cd)
+// n2 -------------------------n3
+// / | |
+// / p-p n4 n5 ---------- n6
+// n1 p-p
+//
+// - CBR/UDP flows from n0 to n6
+// - Tracing of queues and packet receptions to file "mixed-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/log.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/mac48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("MixedGlobalRoutingExample");
+
+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 ("MixedGlobalRoutingExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+ // Set up some default values for the simulation. Use the Bind ()
+ // technique to tell the system what subclass of Queue to use,
+ // and what the queue limit is
+
+ // The below DefaultValue::Bind command tells the queue factory which
+ // class to instantiate, when the queue factory is invoked in the
+ // topology code
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+
+ DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+ DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+ //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
+
+ // Allow the user to override any of the defaults and the above
+ // Bind ()s at run-time, via command-line arguments
+ CommandLine::Parse (argc, argv);
+
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+ Ptr<Node> n4 = Create<InternetNode> ();
+ Ptr<Node> n5 = Create<InternetNode> ();
+ Ptr<Node> n6 = Create<InternetNode> ();
+
+ // We create the channels first without any IP addressing information
+ NS_LOG_INFO ("Create channels.");
+ Ptr<PointToPointChannel> channel0 =
+ PointToPointTopology::AddPointToPointLink (
+ n0, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel1 =
+ PointToPointTopology::AddPointToPointLink (
+ n1, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel2 =
+ PointToPointTopology::AddPointToPointLink (
+ n5, n6, DataRate (1500000), MilliSeconds (10));
+
+ // We create the channels first without any IP addressing information
+ Ptr<CsmaChannel> channelc0 =
+ CsmaTopology::CreateCsmaChannel(
+ DataRate(5000000), MilliSeconds(2));
+
+ NS_LOG_INFO ("Build Topology.");
+ uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channelc0,
+ Mac48Address("10:54:23:54:23:50"));
+ uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, channelc0,
+ Mac48Address("10:54:23:54:23:51"));
+ uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, channelc0,
+ Mac48Address("10:54:23:54:23:52"));
+ uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, channelc0,
+ Mac48Address("10:54:23:54:23:53"));
+
+ // Later, we add IP addresses.
+ NS_LOG_INFO ("Assign IP Addresses.");
+ PointToPointTopology::AddIpv4Addresses (
+ channel0, n0, Ipv4Address ("10.1.1.1"),
+ n2, Ipv4Address ("10.1.1.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel1, n1, Ipv4Address ("10.1.2.1"),
+ n2, Ipv4Address ("10.1.2.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel2, n5, Ipv4Address ("10.1.3.1"),
+ n6, Ipv4Address ("10.1.3.2"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n2, n2ifIndex, Ipv4Address("10.250.1.1"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n3, n3ifIndex, Ipv4Address("10.250.1.2"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n4, n4ifIndex, Ipv4Address("10.250.1.3"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n5, n5ifIndex, Ipv4Address("10.250.1.4"), Ipv4Mask("255.255.255.0"));
+
+ // Create router nodes, initialize routing database and set up the routing
+ // tables in the nodes.
+ GlobalRouteManager::PopulateRoutingTables ();
+
+ // Create the OnOff application to send UDP datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ NS_LOG_INFO ("Create Applications.");
+ uint16_t port = 9; // Discard port (RFC 863)
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("10.1.3.2", port),
+ "Udp",
+ ConstantVariable (1),
+ ConstantVariable (0),
+ DataRate("300bps"),
+ 50);
+ // Start the application
+ ooff->Start (Seconds (1.0));
+ ooff->Stop (Seconds (10.0));
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the simple-global-routing.tr file
+ NS_LOG_INFO ("Configure Tracing.");
+ AsciiTrace asciitrace ("mixed-global-routing.tr");
+ asciitrace.TraceAllQueues ();
+ asciitrace.TraceAllNetDeviceRx ();
+
+ // Also configure some tcpdump traces; each interface will be traced
+ // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+ // and can be read by the "tcpdump -r" command (use "-tt" option to
+ // display timestamps correctly)
+ PcapTrace pcaptrace ("mixed-global-routing.pcap");
+ pcaptrace.TraceAllIp ();
+
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/simple-global-routing.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,226 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ns-2 simple.tcl script (ported from ns-2)
+ * Originally authored by Steve McCanne, 12/19/1996
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+// n0
+// \ 5 Mb/s, 2ms
+// \ 1.5Mb/s, 10ms
+// n2 -------------------------n3
+// /
+// / 5 Mb/s, 2ms
+// n1
+//
+// - all links are point-to-point links with indicated one-way BW/delay
+// - CBR/UDP flows from n0 to n3, and from n3 to n1
+// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+// (i.e., DataRate of 448,000 bps)
+// - DropTail queues
+// - Tracing of queues and packet receptions to file "simple-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/log.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/packet-sink.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SimpleGlobalRoutingExample");
+
+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 ("SimpleGlobalRoutingExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+ // Set up some default values for the simulation. Use the
+ // DefaultValue::Bind () technique to tell the system what subclass of
+ // Queue to use, and what the queue limit is
+
+ // The below Bind command tells the queue factory which class to
+ // instantiate, when the queue factory is invoked in the topology code
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+
+ DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+ DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+ //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
+
+ // Allow the user to override any of the defaults and the above
+ // DefaultValue::Bind ()s at run-time, via command-line arguments
+ CommandLine::Parse (argc, argv);
+
+ // Here, we will explicitly create four nodes. In more sophisticated
+ // topologies, we could configure a node factory.
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ // We create the channels first without any IP addressing information
+ NS_LOG_INFO ("Create channels.");
+ Ptr<PointToPointChannel> channel0 =
+ PointToPointTopology::AddPointToPointLink (
+ n0, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel1 =
+ PointToPointTopology::AddPointToPointLink (
+ n1, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel2 =
+ PointToPointTopology::AddPointToPointLink (
+ n2, n3, DataRate (1500000), MilliSeconds (10));
+
+ // Later, we add IP addresses.
+ NS_LOG_INFO ("Assign IP Addresses.");
+ PointToPointTopology::AddIpv4Addresses (
+ channel0, n0, Ipv4Address ("10.1.1.1"),
+ n2, Ipv4Address ("10.1.1.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel1, n1, Ipv4Address ("10.1.2.1"),
+ n2, Ipv4Address ("10.1.2.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel2, n2, Ipv4Address ("10.1.3.1"),
+ n3, Ipv4Address ("10.1.3.2"));
+
+ // Create router nodes, initialize routing database and set up the routing
+ // tables in the nodes.
+ GlobalRouteManager::PopulateRoutingTables ();
+
+ // Create the OnOff application to send UDP datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ NS_LOG_INFO ("Create Applications.");
+ uint16_t port = 9; // Discard port (RFC 863)
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("10.1.3.2", port),
+ "Udp",
+ ConstantVariable (1),
+ ConstantVariable (0));
+ // Start the application
+ ooff->Start (Seconds (1.0));
+ ooff->Stop (Seconds (10.0));
+
+ // Create a packet sink to receive these packets
+ // The last argument "true" disables output from the Receive callback
+ Ptr<PacketSink> sink = Create<PacketSink> (
+ n3,
+ InetSocketAddress (Ipv4Address::GetAny (), port),
+ "Udp");
+ // Start the sink
+ sink->Start (Seconds (1.0));
+ sink->Stop (Seconds (10.0));
+
+ // Create a similar flow from n3 to n1, starting at time 1.1 seconds
+ ooff = Create<OnOffApplication> (
+ n3,
+ InetSocketAddress ("10.1.2.1", port),
+ "Udp",
+ ConstantVariable (1),
+ ConstantVariable (0));
+ // Start the application
+ ooff->Start (Seconds (1.1));
+ ooff->Stop (Seconds (10.0));
+
+ // Create a packet sink to receive these packets
+ sink = Create<PacketSink> (
+ n1,
+ InetSocketAddress (Ipv4Address::GetAny (), port),
+ "Udp");
+ // Start the sink
+ sink->Start (Seconds (1.1));
+ sink->Stop (Seconds (10.0));
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the simple-global-routing.tr file
+ NS_LOG_INFO ("Configure Tracing.");
+ AsciiTrace asciitrace ("simple-global-routing.tr");
+ asciitrace.TraceAllQueues ();
+ asciitrace.TraceAllNetDeviceRx ();
+
+ // Also configure some tcpdump traces; each interface will be traced
+ // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+ // and can be read by the "tcpdump -r" command (use "-tt" option to
+ // display timestamps correctly)
+ PcapTrace pcaptrace ("simple-global-routing.pcap");
+ pcaptrace.TraceAllIp ();
+
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+
+ return 0;
+}
--- a/examples/simple-p2p.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +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
- *
- * ns-2 simple.tcl script (ported from ns-2)
- * Originally authored by Steve McCanne, 12/19/1996
- */
-
-// Port of ns-2/tcl/ex/simple.tcl to ns-3
-//
-// Network topology
-//
-// n0
-// \ 5 Mb/s, 2ms
-// \ 1.5Mb/s, 10ms
-// n2 -------------------------n3
-// /
-// / 5 Mb/s, 2ms
-// n1
-//
-// - all links are p2p links with indicated one-way BW/delay
-// - CBR/UDP flows from n0 to n3, and from n3 to n1
-// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
-// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
-// (i.e., DataRate of 448,000 bps)
-// - DropTail queues
-// - Tracing of queues and packet receptions to file "simple-p2p.tr"
-
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
-#include "ns3/command-line.h"
-#include "ns3/default-value.h"
-#include "ns3/ptr.h"
-#include "ns3/random-variable.h"
-
-#include "ns3/simulator.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-
-#include "ns3/ascii-trace.h"
-#include "ns3/pcap-trace.h"
-#include "ns3/internet-node.h"
-#include "ns3/p2p-channel.h"
-#include "ns3/p2p-net-device.h"
-#include "ns3/mac-address.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/socket.h"
-#include "ns3/ipv4-route.h"
-#include "ns3/p2p-topology.h"
-#include "ns3/onoff-application.h"
-
-using namespace ns3;
-
-int main (int argc, char *argv[])
-{
-
- // Users may find it convenient to turn on explicit debugging
- // for selected modules; the below lines suggest how to do this
-#if 0
- DebugComponentEnable("Object");
- DebugComponentEnable("Queue");
- DebugComponentEnable("DropTailQueue");
- DebugComponentEnable("Channel");
- DebugComponentEnable("PointToPointChannel");
- DebugComponentEnable("PointToPointNetDevice");
-#endif
-
- // Set up some default values for the simulation. Use the Bind()
- // technique to tell the system what subclass of Queue to use,
- // and what the queue limit is
-
- // The below Bind command tells the queue factory which class to
- // instantiate, when the queue factory is invoked in the topology code
- Bind ("Queue", "DropTailQueue");
-
- Bind ("OnOffApplicationPacketSize", "210");
- Bind ("OnOffApplicationDataRate", "448kb/s");
-
- //Bind ("DropTailQueue::m_maxPackets", 30);
-
- // Allow the user to override any of the defaults and the above
- // Bind()s at run-time, via command-line arguments
- CommandLine::Parse (argc, argv);
-
- // Here, we will explicitly create four nodes. In more sophisticated
- // topologies, we could configure a node factory.
- Ptr<Node> n0 = Create<InternetNode> ();
- Ptr<Node> n1 = Create<InternetNode> ();
- Ptr<Node> n2 = Create<InternetNode> ();
- Ptr<Node> n3 = Create<InternetNode> ();
-
- // We create the channels first without any IP addressing information
- Ptr<PointToPointChannel> channel0 =
- PointToPointTopology::AddPointToPointLink (
- n0, n2, DataRate(5000000), MilliSeconds(2));
-
- Ptr<PointToPointChannel> channel1 =
- PointToPointTopology::AddPointToPointLink (
- n1, n2, DataRate(5000000), MilliSeconds(2));
-
- Ptr<PointToPointChannel> channel2 =
- PointToPointTopology::AddPointToPointLink (
- n2, n3, DataRate(1500000), MilliSeconds(10));
-
- // Later, we add IP addresses.
- PointToPointTopology::AddIpv4Addresses (
- channel0, n0, Ipv4Address("10.1.1.1"),
- n2, Ipv4Address("10.1.1.2"));
-
- PointToPointTopology::AddIpv4Addresses (
- channel1, n1, Ipv4Address("10.1.2.1"),
- n2, Ipv4Address("10.1.2.2"));
-
- PointToPointTopology::AddIpv4Addresses (
- channel2, n2, Ipv4Address("10.1.3.1"),
- n3, Ipv4Address("10.1.3.2"));
-
- // Finally, we add static routes. These three steps (Channel and
- // NetDevice creation, IP Address assignment, and routing) are
- // separated because there may be a need to postpone IP Address
- // assignment (emulation) or modify to use dynamic routing
- PointToPointTopology::AddIpv4Routes(n0, n2, channel0);
- PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
- PointToPointTopology::AddIpv4Routes(n2, n3, channel2);
-
-
- // Create the OnOff application to send UDP datagrams of size
- // 210 bytes at a rate of 448 Kb/s
- Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
- n0,
- Ipv4Address("10.1.3.2"),
- 80,
- "Udp",
- ConstantVariable(1),
- ConstantVariable(0));
- // Start the application
- ooff->Start(Seconds(1.0));
- ooff->Stop (Seconds(10.0));
-
- // Create a similar flow from n3 to n1, starting at time 1.1 seconds
- ooff = Create<OnOffApplication> (
- n3,
- Ipv4Address("10.1.2.1"),
- 80,
- "Udp",
- ConstantVariable(1),
- ConstantVariable(0));
- // Start the application
- ooff->Start(Seconds(1.1));
- ooff->Stop (Seconds(10.0));
-
- // Here, finish off packet routing configuration
- // This will likely set by some global StaticRouting object in the future
- Ptr<Ipv4> ipv4;
- ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
- ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
- ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
- ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
-
- // Configure tracing of all enqueue, dequeue, and NetDevice receive events
- // Trace output will be sent to the simple-p2p.tr file
- AsciiTrace asciitrace ("simple-p2p.tr");
- asciitrace.TraceAllQueues ();
- asciitrace.TraceAllNetDeviceRx ();
-
- // Also configure some tcpdump traces; each interface will be traced
- // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
- // and can be read by the "tcpdump -r" command (use "-tt" option to
- // display timestamps correctly)
- PcapTrace pcaptrace ("simple-p2p.pcap");
- pcaptrace.TraceAllIp ();
-
- Simulator::Run ();
-
- Simulator::Destroy ();
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/simple-point-to-point.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,233 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ns-2 simple.tcl script (ported from ns-2)
+ * Originally authored by Steve McCanne, 12/19/1996
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+// n0
+// \ 5 Mb/s, 2ms
+// \ 1.5Mb/s, 10ms
+// n2 -------------------------n3
+// /
+// / 5 Mb/s, 2ms
+// n1
+//
+// - all links are point-to-point links with indicated one-way BW/delay
+// - CBR/UDP flows from n0 to n3, and from n3 to n1
+// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+// (i.e., DataRate of 448,000 bps)
+// - DropTail queues
+// - Tracing of queues and packet receptions to file
+// "simple-point-to-point.tr"
+
+#include "ns3/log.h"
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/packet-sink.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SimplePointToPointExample");
+
+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 ("SimplePointToPointExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+
+ // Set up some default values for the simulation. Use the Bind()
+ // technique to tell the system what subclass of Queue to use,
+ // and what the queue limit is
+
+ // The below Bind command tells the queue factory which class to
+ // instantiate, when the queue factory is invoked in the topology code
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+
+ DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+ DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+ //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
+
+ // Allow the user to override any of the defaults and the above
+ // Bind()s at run-time, via command-line arguments
+ CommandLine::Parse (argc, argv);
+
+ // Here, we will explicitly create four nodes. In more sophisticated
+ // topologies, we could configure a node factory.
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ // We create the channels first without any IP addressing information
+ NS_LOG_INFO ("Create channels.");
+ Ptr<PointToPointChannel> channel0 =
+ PointToPointTopology::AddPointToPointLink (
+ n0, n2, DataRate(5000000), MilliSeconds(2));
+
+ Ptr<PointToPointChannel> channel1 =
+ PointToPointTopology::AddPointToPointLink (
+ n1, n2, DataRate(5000000), MilliSeconds(2));
+
+ Ptr<PointToPointChannel> channel2 =
+ PointToPointTopology::AddPointToPointLink (
+ n2, n3, DataRate(1500000), MilliSeconds(10));
+
+ // Later, we add IP addresses.
+ NS_LOG_INFO ("Assign IP Addresses.");
+ PointToPointTopology::AddIpv4Addresses (
+ channel0, n0, Ipv4Address("10.1.1.1"),
+ n2, Ipv4Address("10.1.1.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel1, n1, Ipv4Address("10.1.2.1"),
+ n2, Ipv4Address("10.1.2.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel2, n2, Ipv4Address("10.1.3.1"),
+ n3, Ipv4Address("10.1.3.2"));
+
+ // Finally, we add static routes. These three steps (Channel and
+ // NetDevice creation, IP Address assignment, and routing) are
+ // separated because there may be a need to postpone IP Address
+ // assignment (emulation) or modify to use dynamic routing
+ NS_LOG_INFO ("Add Static Routes.");
+ PointToPointTopology::AddIpv4Routes(n0, n2, channel0);
+ PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
+ PointToPointTopology::AddIpv4Routes(n2, n3, channel2);
+
+ // Create the OnOff application to send UDP datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ NS_LOG_INFO ("Create Applications.");
+ uint16_t port = 9; // Discard port (RFC 863)
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("10.1.3.2", port),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.0));
+ ooff->Stop (Seconds(10.0));
+
+ // Create an optional packet sink to receive these packets
+ Ptr<PacketSink> sink = Create<PacketSink> (
+ n3,
+ InetSocketAddress (Ipv4Address::GetAny (), port),
+ "Udp");
+ // Start the sink
+ sink->Start (Seconds (1.0));
+ sink->Stop (Seconds (10.0));
+
+ // Create a similar flow from n3 to n1, starting at time 1.1 seconds
+ ooff = Create<OnOffApplication> (
+ n3,
+ InetSocketAddress ("10.1.2.1", port),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.1));
+ ooff->Stop (Seconds(10.0));
+
+ // Create a packet sink to receive these packets
+ sink = Create<PacketSink> (
+ n1,
+ InetSocketAddress (Ipv4Address::GetAny (), port),
+ "Udp");
+ // Start the sink
+ sink->Start (Seconds (1.1));
+ sink->Stop (Seconds (10.0));
+
+ // Here, finish off packet routing configuration
+ // This will likely set by some global StaticRouting object in the future
+ NS_LOG_INFO ("Set Default Routes.");
+ Ptr<Ipv4> ipv4;
+ ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
+ ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
+ ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
+ ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the simple-point-to-point.tr file
+ NS_LOG_INFO ("Configure Tracing.");
+ AsciiTrace asciitrace ("simple-point-to-point.tr");
+ asciitrace.TraceAllQueues ();
+ asciitrace.TraceAllNetDeviceRx ();
+
+ // Also configure some tcpdump traces; each interface will be traced
+ // The output files will be named
+ // simple-point-to-point.pcap-<nodeId>-<interfaceId>
+ // and can be read by the "tcpdump -r" command (use "-tt" option to
+ // display timestamps correctly)
+ PcapTrace pcaptrace ("simple-point-to-point.pcap");
+ pcaptrace.TraceAllIp ();
+
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/udp-echo.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,213 @@
+/* -*- 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 "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/mac48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/udp-echo-client.h"
+#include "ns3/udp-echo-server.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoExample");
+
+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 ("UdpEchoExample", LOG_LEVEL_INFO);
+
+ LogComponentEnable("Object", LOG_LEVEL_ALL);
+ LogComponentEnable("Queue", LOG_LEVEL_ALL);
+ LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+ LogComponentEnable("Channel", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+ LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("Socket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+ LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+ LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+ LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+//
+// Set up default values for the simulation. Use the DefaultValue::Bind()
+// technique to tell the system what subclass of Queue to use. The Bind
+// command command tells the queue factory which class to instantiate when the
+// queue factory is invoked in the topology code
+//
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+//
+// Allow the user to override any of the defaults and the above Bind() at
+// run-time, via command-line arguments
+//
+ CommandLine::Parse (argc, argv);
+//
+// Explicitly create the nodes required by the topology (shown above).
+//
+ NS_LOG_INFO ("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ NS_LOG_INFO ("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+ Ptr<CsmaChannel> lan = CsmaTopology::CreateCsmaChannel(
+ DataRate(5000000), MilliSeconds(2));
+
+ NS_LOG_INFO ("Build Topology.");
+//
+// 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.
+//
+ 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"));
+//
+// We've got the "hardware" in place. Now we need to add IP addresses.
+//
+ NS_LOG_INFO ("Assign IP Addresses.");
+//
+// XXX BUGBUG
+// Need a better way to get the interface index. The point-to-point topology
+// as implemented can't return the index since it creates interfaces on both
+// sides (i.e., it does AddIpv4Addresses, not AddIpv4Address). We need a
+// method on Ipv4 to find the interface index corresponding to a given ipv4
+// address.
+//
+// Assign IP addresses to the net devices and associated interfaces
+// on the lan. The AddIpv4Address method returns an Ipv4 interface index
+// which we do not need here.
+//
+ 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"));
+
+ NS_LOG_INFO ("Create Applications.");
+//
+// Create a UdpEchoServer application on node one.
+//
+ uint16_t port = 9; // well-known echo port number
+
+ Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
+//
+// Create a UdpEchoClient application to send UDP datagrams from node zero to
+// node one.
+//
+ uint32_t packetSize = 1024;
+ uint32_t maxPacketCount = 1;
+ Time interPacketInterval = Seconds (1.);
+
+ Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port,
+ maxPacketCount, interPacketInterval, packetSize);
+//
+// Tell the applications when to start and stop.
+//
+ server->Start(Seconds(1.));
+ client->Start(Seconds(2.));
+
+ server->Stop (Seconds(10.));
+ client->Stop (Seconds(10.));
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "udp-echo.tr"
+//
+ NS_LOG_INFO ("Configure Tracing.");
+ AsciiTrace asciitrace ("udp-echo.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+// udp-echo.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
+ PcapTrace pcaptrace ("udp-echo.pcap");
+ pcaptrace.TraceAllIp ();
+//
+// Now, do the actual simulation.
+//
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- a/examples/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/examples/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -1,13 +1,35 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
def build(bld):
- def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
- obj = bld.create_obj('cpp', 'program')
- obj.target = name
- obj.uselib_local = ["ns3-%s" % dep for dep in deps]
- obj.source = source
- return obj
- obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', deps=['p2p', 'internet-node'])
+ obj = bld.create_ns3_program('simple-global-routing',
+ ['point-to-point', 'internet-node', 'global-routing'])
+ obj.source = 'simple-global-routing.cc'
+
+ obj = bld.create_ns3_program('simple-point-to-point',
+ ['point-to-point', 'internet-node'])
+ obj.source = 'simple-point-to-point.cc'
+
+ obj = bld.create_ns3_program('csma-one-subnet',
+ ['csma', 'internet-node'])
+ obj.source = 'csma-one-subnet.cc'
+
+ obj = bld.create_ns3_program('udp-echo',
+ ['csma', 'internet-node'])
+ obj.source = 'udp-echo.cc'
+ obj = bld.create_ns3_program('csma-broadcast',
+ ['csma', 'internet-node'])
+ obj.source = 'csma-broadcast.cc'
+
+ obj = bld.create_ns3_program('csma-packet-socket',
+ ['csma', 'internet-node'])
+ obj.source = 'csma-packet-socket.cc'
+
+ obj = bld.create_ns3_program('csma-multicast',
+ ['csma', 'internet-node'])
+ obj.source = 'csma-multicast.cc'
+
+ obj = bld.create_ns3_program( 'mixed-global-routing',
+ ['point-to-point', 'internet-node', 'global-routing' , 'csma-cd'])
+ obj.source = 'mixed-global-routing.cc'
--- a/samples/main-channel.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-channel.cc Fri Sep 28 11:59:46 2007 +0100
@@ -18,7 +18,7 @@
*/
#include <string>
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "ns3/assert.h"
#include "ns3/packet.h"
#include "ns3/drop-tail.h"
@@ -27,6 +27,8 @@
using namespace ns3;
+NS_LOG_COMPONENT_DEFINE ("ChannelSample");
+
// ===========================================================================
// Cook up a simplistic Internet Node
// ===========================================================================
@@ -48,19 +50,19 @@
FakeInternetNode::FakeInternetNode ()
{
- NS_DEBUG_UNCOND("FakeInternetNode::FakeInternetNode ()");
+ NS_LOG_FUNCTION;
}
FakeInternetNode::~FakeInternetNode ()
{
- NS_DEBUG_UNCOND("FakeInternetNode::~FakeInternetNode ()");
+ NS_LOG_FUNCTION;
}
void
FakeInternetNode::Doit (void)
{
- NS_DEBUG_UNCOND("FakeInternetNode::Doit ()");
- NS_DEBUG_UNCOND("FakeInternetNode::Doit (): **** Send outbound packet");
+ NS_LOG_FUNCTION;
+ NS_LOG_INFO ("**** Send outbound packet");
Packet p;
m_dtqOutbound.Enqueue(p);
@@ -70,9 +72,9 @@
bool
FakeInternetNode::UpperDoSendUp (Packet &p)
{
- NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (" << &p << ")");
-
- NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (): **** Receive inbound packet");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
+ NS_LOG_INFO ("**** Receive inbound packet");
m_dtqInbound.Enqueue(p);
return m_dtqInbound.Dequeue(p);
}
@@ -80,7 +82,8 @@
bool
FakeInternetNode::UpperDoPull (Packet &p)
{
- NS_DEBUG_UNCOND("FakeInternetNode::DoPull (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
return m_dtqOutbound.Dequeue(p);
}
@@ -107,29 +110,29 @@
FakePhysicalLayer::FakePhysicalLayer ()
{
- NS_DEBUG_UNCOND("FakePhysicalLayer::FakePhysicalLayer ()");
+ NS_LOG_FUNCTION;
}
FakePhysicalLayer::~FakePhysicalLayer ()
{
- NS_DEBUG_UNCOND("FakePhysicalLayer::~FakePhysicalLayer ()");
+ NS_LOG_FUNCTION;
}
bool
FakePhysicalLayer::LowerDoNotify (LayerConnectorUpper *upper)
{
- NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify ()");
+ NS_LOG_FUNCTION;
Packet p;
- NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Starting pull");
+ NS_LOG_LOGIC ("Starting pull");
NS_ASSERT(m_upperPartner);
m_upperPartner->UpperPull(p);
m_dtqOutbound.Enqueue(p);
- NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Got bits, Notify lower");
+ NS_LOG_LOGIC ("Got bits, Notify lower");
NS_ASSERT(m_lowerPartner);
return m_lowerPartner->LowerNotify(this);
@@ -138,7 +141,8 @@
bool
FakePhysicalLayer::UpperDoSendUp (Packet &p)
{
- NS_DEBUG_UNCOND("FakePhysicalLayer::UpperDoSendUp (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
NS_ASSERT(m_upperPartner);
return m_upperPartner->UpperSendUp(p);
@@ -147,7 +151,8 @@
bool
FakePhysicalLayer::UpperDoPull (Packet &p)
{
- NS_DEBUG_UNCOND("FakePhysicalLayer::DoPull (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
return m_dtqOutbound.Dequeue(p);
}
@@ -164,24 +169,17 @@
FakeChannel::FakeChannel ()
{
- NS_DEBUG_UNCOND("FakeChannel::FakeChannel ()");
+ NS_LOG_FUNCTION;
}
FakeChannel::~FakeChannel ()
{
- NS_DEBUG_UNCOND("FakeChannel::~FakeChannel ()");
+ NS_LOG_FUNCTION;
}
int main (int argc, char *argv[])
{
- NS_DEBUG_UNCOND("Channel Hackorama");
-
-#if 0
- DebugComponentEnable("Queue");
- DebugComponentEnable("DropTailQueue");
- DebugComponentEnable("LayerConnector");
- DebugComponentEnable("Channel");
-#endif
+ NS_LOG_INFO ("Channel Hackorama");
FakeInternetNode node1, node2, node3, node4;
FakePhysicalLayer phys1, phys2, phys3, phys4;
--- a/samples/main-default-value.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-default-value.cc Fri Sep 28 11:59:46 2007 +0100
@@ -3,7 +3,7 @@
#include <string>
#include "ns3/default-value.h"
#include "ns3/command-line.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
using namespace ns3;
@@ -14,8 +14,8 @@
// value of the default parameter. Then as other code require the values of
// the defaults, they query them with GetValue() to get the present value.
static BooleanDefaultValue defaultTestBool1 ("testBool1", "helpBool", true);
-static IntegerDefaultValue<int> defaultTestInt1 ("testInt1", "helpInt1", 33);
-static IntegerDefaultValue<uint32_t> defaultTestInt2 ("testInt2", "helpInt2", 47);
+static NumericDefaultValue<int> defaultTestInt1 ("testInt1", "helpInt1", 33);
+static NumericDefaultValue<uint32_t> defaultTestInt2 ("testInt2", "helpInt2", 47);
//
// This test class demonstrates the declaration of variables that
@@ -73,12 +73,12 @@
// global variable and value (string) to overwrite the default.
// Here, the default value of 33 for testInt1 is overwritten with 57
//
- Bind("testInt1", "57");
+ DefaultValue::Bind("testInt1", "57");
TestClass* testclass = new TestClass ();
- NS_DEBUG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
- NS_DEBUG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")");
- NS_DEBUG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")");
+ NS_LOG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
+ NS_LOG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")");
+ NS_LOG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")");
delete testclass;
return 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-header.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,124 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#include "ns3/packet.h"
+#include "ns3/header.h"
+#include <iostream>
+
+using namespace ns3;
+
+/* A sample Header implementation
+ */
+class MyHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
+
+ MyHeader ();
+ virtual ~MyHeader ();
+
+ void SetData (uint16_t data);
+ uint16_t GetData (void) const;
+
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
+ uint32_t GetSerializedSize (void) const;
+private:
+ uint16_t m_data;
+};
+
+MyHeader::MyHeader ()
+{
+ // we must provide a public default constructor,
+ // implicit or explicit, but never private.
+}
+MyHeader::~MyHeader ()
+{}
+
+uint32_t
+MyHeader::GetUid (void)
+{
+ // This string is used by the internals of the packet
+ // code to keep track of the packet metadata.
+ // You need to make sure that this string is absolutely
+ // unique. The code will detect any duplicate string.
+ static uint32_t uid = AllocateUid<MyHeader> ("MyHeader.test.nsnam.org");
+ return uid;
+}
+
+std::string
+MyHeader::GetName (void) const
+{
+ // This string is used to identify the type of
+ // my header by the packet printing routines.
+ return "MYHEADER";
+}
+void
+MyHeader::Print (std::ostream &os) const
+{
+ // This method is invoked by the packet printing
+ // routines to print the content of my header.
+ os << "data=" << m_data << std::endl;
+}
+uint32_t
+MyHeader::GetSerializedSize (void) const
+{
+ // we reserve 2 bytes for our header.
+ return 2;
+}
+void
+MyHeader::Serialize (Buffer::Iterator start) const
+{
+ // we can serialize two bytes at the start of the buffer.
+ // we write them in network byte order.
+ start.WriteHtonU16 (m_data);
+}
+uint32_t
+MyHeader::Deserialize (Buffer::Iterator start)
+{
+ // we can deserialize two bytes from the start of the buffer.
+ // we read them in network byte order and store them
+ // in host byte order.
+ m_data = start.ReadNtohU16 ();
+
+ // we return the number of bytes effectively read.
+ return 2;
+}
+
+void
+MyHeader::SetData (uint16_t data)
+{
+ m_data = data;
+}
+uint16_t
+MyHeader::GetData (void) const
+{
+ return m_data;
+}
+
+
+
+int main (int argc, char *argv[])
+{
+ // instantiate a header.
+ MyHeader sourceHeader;
+ sourceHeader.SetData (2);
+
+ // instantiate a packet
+ Packet p;
+ // and store my header into the packet.
+ p.AddHeader (sourceHeader);
+
+ // print the content of my packet on the standard output.
+ p.Print (std::cout);
+
+ // you can now remove the header from the packet:
+ MyHeader destinationHeader;
+ p.RemoveHeader (destinationHeader);
+
+ // and check that the destination and source
+ // headers contain the same values.
+ NS_ASSERT (sourceHeader.GetData () == destinationHeader.GetData ());
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-printer.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,184 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "ns3/packet.h"
+#include "ns3/header.h"
+#include "ns3/packet-printer.h"
+#include "ns3/ipv4-header.h"
+#include "ns3/udp-header.h"
+
+using namespace ns3;
+
+// This sample file shows how to use the Packet metadata facility
+//
+// Packets are stored as ``packed'' data structures, to facilitate
+// fragmentation and network emulation. However, when debugging a program,
+// or for certain tracing applications, it may be convenient to dump out
+// the contents of a packet header in a human-friendly form.
+//
+// To do this, a few things are needed:
+// i) enable the metadata facility (disabled by default, because it causes
+// a small performance hit
+// ii) decide on whether you want to use a default or customized (you
+// provide your own) routine to dump a particular header
+//
+// This sample steps through two routines; one to use the default
+// printing of IPv4 and UDP headers, and one to show a non-default case.
+// There is a lot of emphasis in this sample of how this facility
+// interacts with packet fragmentation.
+
+void DefaultPrint (void)
+{
+ // We create a packet with 1000 bytes of zero payload
+ // and add 3 headers to this packet.
+ Packet p (1000);
+ Ipv4Header ipv4;
+ UdpHeader udp;
+ ipv4.SetSource (Ipv4Address ("192.168.0.1"));
+ ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
+ udp.SetSource (1025);
+ udp.SetDestination (80);
+ udp.SetPayloadSize (1000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
+
+ std::cout << "full packet size=" << p.GetSize () << std::endl;
+ // Here, invoke the default Print routine, directed to std out
+ p.Print (std::cout);
+ std::cout << std::endl;
+
+
+ // Now, we fragment our packet in 3 consecutive pieces.
+ Packet p1 = p.CreateFragment (0, 2);
+ Packet p2 = p.CreateFragment (2, 1000);
+ Packet p3 = p.CreateFragment (1002, 26);
+
+ std::cout << "fragment1" << std::endl;
+ p1.Print (std::cout);
+ std::cout << std::endl;
+ std::cout << "fragment2" << std::endl;
+ p2.Print (std::cout);
+ std::cout << std::endl;
+ std::cout << "fragment3" << std::endl;
+ p3.Print (std::cout);
+ std::cout << std::endl;
+
+ // And, finally, we re-aggregate the 3 consecutive pieces.
+ Packet aggregate = p1;
+ aggregate.AddAtEnd (p2);
+ aggregate.AddAtEnd (p3);
+ std::cout << "aggregated" << std::endl;
+ aggregate.Print (std::cout);
+ std::cout << std::endl;
+}
+
+void
+DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
+ struct PacketPrinter::FragmentInformation info)
+{
+ os << "PAYLOAD (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
+}
+void
+DoPrintIpv4Header (std::ostream &os, uint32_t packetUid, uint32_t size, const Ipv4Header *ipv4)
+{
+ os << "IPV4 " << ipv4->GetSource () << " > " << ipv4->GetDestination ();
+}
+void
+DoPrintIpv4HeaderFragment (std::ostream &os, uint32_t packetUid, uint32_t size,
+ std::string &name, struct PacketPrinter::FragmentInformation info)
+{
+ os << "IPV4 fragment";
+}
+
+// This function walks through a non-default case. A few features of
+// the API (defined in common/packet-printer.h) are shown.
+//
+void NonDefaultPrint (void)
+{
+ // create an adhoc packet printer.
+ PacketPrinter printer;
+ // print from first header to last trailer
+ printer.PrintForward ();
+ // set a string separator automatically inserted
+ // between each call to a printing function.
+ printer.SetSeparator (" - ");
+ // set the payload print function
+ printer.SetPayloadPrinter (MakeCallback (&DoPrintPayload));
+ // set the print function for the header type Ipv4Header.
+ printer.SetHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
+ MakeCallback (&DoPrintIpv4HeaderFragment));
+
+
+ // We create a packet with 1000 bytes of zero payload
+ Packet p (1000);
+ Ipv4Header ipv4;
+ UdpHeader udp;
+ ipv4.SetSource (Ipv4Address ("192.168.0.1"));
+ ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
+ udp.SetSource (1025);
+ udp.SetDestination (80);
+ udp.SetPayloadSize (1000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
+
+ std::cout << "full packet size=" << p.GetSize () << std::endl;
+ p.Print (std::cout, printer);
+ std::cout << std::endl;
+
+
+ // fragment our packet in 3 pieces
+ Packet p1 = p.CreateFragment (0, 2);
+ Packet p2 = p.CreateFragment (2, 1000);
+ Packet p3 = p.CreateFragment (1002, 26);
+ std::cout << "fragment1" << std::endl;
+ p1.Print (std::cout, printer);
+ std::cout << std::endl;
+ std::cout << "fragment2" << std::endl;
+ p2.Print (std::cout, printer);
+ std::cout << std::endl;
+ std::cout << "fragment3" << std::endl;
+ p3.Print (std::cout, printer);
+ std::cout << std::endl;
+
+ // aggregate all 3 fragments of the original packet
+ // to reconstruct a copy of the original packet.
+ Packet aggregate = p1;
+ aggregate.AddAtEnd (p2);
+ aggregate.AddAtEnd (p3);
+ std::cout << "aggregated" << std::endl;
+ aggregate.Print (std::cout, printer);
+ std::cout << std::endl;
+}
+
+
+
+int main (int argc, char *argv[])
+{
+ Packet::EnableMetadata ();
+
+ std::cout << "DefaultPrint()" << std::endl;
+ DefaultPrint ();
+
+ std::cout << std::endl << "NonDefaultPrint()" << std::endl;
+ NonDefaultPrint ();
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-tag.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "ns3/tag.h"
+#include "ns3/packet.h"
+#include <iostream>
+
+using namespace ns3;
+
+// define this class in a public header
+class MyTag : public Tag
+{
+public:
+ // we have to define a public constructor
+ MyTag ();
+ // we have to define a public copy constructor
+ MyTag (const MyTag &other);
+ // we have to define a public destructor
+ ~MyTag ();
+ // we have to define a public static GetUid method
+ static uint32_t GetUid (void);
+ // we have to define a public Print method
+ void Print (std::ostream &os) const;
+ // we have to define a public GetSerializedSize method
+ uint32_t GetSerializedSize (void) const;
+ // we have to define a public Serialize method
+ void Serialize (Buffer::Iterator i) const;
+ // we have to define a public Deserialize method
+ uint32_t Deserialize (Buffer::Iterator i);
+
+ // these are our accessors to our tag structure
+ void SetSimpleValue (uint8_t value);
+ uint8_t GetSimpleValue (void) const;
+private:
+ uint8_t m_simpleValue;
+};
+
+MyTag::MyTag ()
+{}
+MyTag::MyTag (const MyTag &other)
+ : m_simpleValue (other.m_simpleValue)
+{}
+MyTag::~MyTag ()
+{}
+uint32_t
+MyTag::GetUid (void)
+{
+ // we input a unique string to AllocateUid
+ // to avoid name collisions.
+ static uint32_t uid = AllocateUid<MyTag> ("MyTag.tests.nsnam.org");
+ return uid;
+}
+void
+MyTag::Print (std::ostream &os) const
+{
+ // print the content of this tag for Packet::PrintTags
+ os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec;
+}
+uint32_t
+MyTag::GetSerializedSize (void) const
+{
+ // we do not want to deal with parallel simulations
+ // so we return 0.
+ return 0;
+}
+void
+MyTag::Serialize (Buffer::Iterator i) const
+{
+ // we will never be invoked because we are not doing
+ // parallel simulations so, we assert.
+ NS_ASSERT (false);
+}
+uint32_t
+MyTag::Deserialize (Buffer::Iterator i)
+{
+ // we will never be invoked because we are not doing
+ // parallel simulations so, we assert.
+ NS_ASSERT (false);
+ // theoretically, return the number of bytes read
+ return 0;
+}
+
+
+void
+MyTag::SetSimpleValue (uint8_t value)
+{
+ m_simpleValue = value;
+}
+uint8_t
+MyTag::GetSimpleValue (void) const
+{
+ return m_simpleValue;
+}
+
+
+int main (int argc, char *argv[])
+{
+ // create a tag.
+ MyTag tag;
+ tag.SetSimpleValue (0x56);
+
+ // store the tag in a packet.
+ Packet p;
+ p.AddTag (tag);
+
+ // create a copy of the packet
+ Packet aCopy = p;
+
+ // read the tag from the packet copy
+ MyTag tagCopy;
+ p.PeekTag (tagCopy);
+
+ // the copy and the original are the same !
+ NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
+
+ aCopy.PrintTags (std::cout);
+ std::cout << std::endl;
+
+ return 0;
+}
--- a/samples/main-packet.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-#include "ns3/packet.h"
-#include "ns3/header.h"
-#include <iostream>
-
-using namespace ns3;
-
-/* A sample Header implementation
- */
-class MyHeader : public Header {
-public:
- MyHeader ();
- virtual ~MyHeader ();
-
- void SetData (uint16_t data);
- uint16_t GetData (void) const;
-private:
- virtual void PrintTo (std::ostream &os) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
- virtual uint32_t GetSerializedSize (void) const;
-
- uint16_t m_data;
-};
-
-MyHeader::MyHeader ()
-{}
-MyHeader::~MyHeader ()
-{}
-void
-MyHeader::PrintTo (std::ostream &os) const
-{
- os << "MyHeader data=" << m_data << std::endl;
-}
-uint32_t
-MyHeader::GetSerializedSize (void) const
-{
- return 2;
-}
-void
-MyHeader::SerializeTo (Buffer::Iterator start) const
-{
- // serialize in head of buffer
- start.WriteHtonU16 (m_data);
-}
-uint32_t
-MyHeader::DeserializeFrom (Buffer::Iterator start)
-{
- // deserialize from head of buffer
- m_data = start.ReadNtohU16 ();
- return GetSerializedSize ();
-}
-
-void
-MyHeader::SetData (uint16_t data)
-{
- m_data = data;
-}
-uint16_t
-MyHeader::GetData (void) const
-{
- return m_data;
-}
-
-/* A sample Tag implementation
- */
-struct MyTag {
- uint16_t m_streamId;
-};
-
-static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
-
-
-static void
-Receive (Packet p)
-{
- MyHeader my;
- p.RemoveHeader (my);
- std::cout << "received data=" << my.GetData () << std::endl;
- struct MyTag myTag;
- p.PeekTag (myTag);
-}
-
-
-int main (int argc, char *argv[])
-{
- Packet p;
- MyHeader my;
- my.SetData (2);
- std::cout << "send data=2" << std::endl;
- p.AddHeader (my);
- struct MyTag myTag;
- myTag.m_streamId = 5;
- p.AddTag (myTag);
- Receive (p);
- return 0;
-}
--- a/samples/main-query-interface.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-query-interface.cc Fri Sep 28 11:59:46 2007 +0100
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "ns3/object.h"
#include "ns3/component-manager.h"
@@ -79,10 +79,11 @@
void
AnInterface::methodA (void)
{
+ NS_LOG_FUNCTION;
// pre-dispatch asserts
- NS_DEBUG_UNCOND("AnInterface pre-condition::methodA");
+ NS_LOG_LOGIC ("pre-condition");
domethodA ();
- NS_DEBUG_UNCOND("AnInterface post-condition::methodA\n");
+ NS_LOG_LOGIC ("post-condition");
// post-dispatch asserts
}
@@ -114,12 +115,13 @@
void
AnImplementation::methodImpl (void)
{
- NS_DEBUG_UNCOND("AnImplementation::methodImpl\n");
+ NS_LOG_FUNCTION;
}
AnImplementation::AnImplementation (void)
{
+ NS_LOG_FUNCTION;
// enable our interface
SetInterfaceId (AnImplementation::iid);
}
@@ -127,7 +129,7 @@
void
AnImplementation::domethodA ()
{
- NS_DEBUG_UNCOND("AnImplementation::domethodA");
+ NS_LOG_FUNCTION;
}
//
@@ -201,7 +203,7 @@
void
ANewImplementation::methodImpl (void)
{
- NS_DEBUG_UNCOND("ANewImplementation::methodImpl\n");
+ NS_LOG_FUNCTION;
}
const InterfaceId ANewImplementation::iid =
@@ -238,7 +240,7 @@
void
AnExtendedImplementation::methodExtendedImpl (void)
{
- NS_DEBUG_UNCOND("AnExtendedImplementation::methodExtendedImpl\n");
+ NS_LOG_FUNCTION;
}
const InterfaceId AnExtendedImplementation::iid =
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-random-topology.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,53 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include <vector>
+
+#include "ns3/ptr.h"
+#include "ns3/mobility-model.h"
+#include "ns3/mobility-model-notifier.h"
+#include "ns3/static-mobility-model.h"
+#include "ns3/random-topology.h"
+#include "ns3/default-value.h"
+#include "ns3/command-line.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+
+using namespace ns3;
+
+static void
+CourseChange (const TraceContext &context, Ptr<const MobilityModel> position)
+{
+ Position pos = position->Get ();
+ std::cout << Simulator::Now () << ", pos=" << position << ", x=" << pos.x << ", y=" << pos.y
+ << ", z=" << pos.z << std::endl;
+}
+
+int main (int argc, char *argv[])
+{
+ DefaultValue::Bind ("RandomDiscPositionX", "100");
+ DefaultValue::Bind ("RandomDiscPositionY", "50");
+ DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
+
+ DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition");
+ DefaultValue::Bind ("RandomTopologyMobilityType", "StaticMobilityModel");
+
+ CommandLine::Parse (argc, argv);
+
+ RandomTopology topology;
+
+ std::vector<Ptr<Object> > objects;
+ for (uint32_t i = 0; i < 10000; i++)
+ {
+ Ptr<MobilityModelNotifier> notifier = Create<MobilityModelNotifier> ();
+ notifier->TraceConnect ("/course-change", MakeCallback (&CourseChange));
+ objects.push_back (notifier);
+ }
+
+ topology.Layout (objects.begin (), objects.end ());
+
+ Simulator::StopAt (Seconds (100.0));
+
+ Simulator::Run ();
+
+ return 0;
+}
--- a/samples/main-simple.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-simple.cc Fri Sep 28 11:59:46 2007 +0100
@@ -4,7 +4,9 @@
#include "ns3/simulator.h"
#include "ns3/socket-factory.h"
#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
#include "ns3/nstime.h"
+#include "ns3/packet.h"
using namespace ns3;
@@ -12,7 +14,7 @@
GenerateTraffic (Ptr<Socket> socket, uint32_t size)
{
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl;
- socket->Send (0, size);
+ socket->Send (Packet (size));
if (size > 0)
{
Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50);
@@ -24,15 +26,15 @@
}
static void
-SocketPrinter (Ptr<Socket> socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort)
+SocketPrinter (Ptr<Socket> socket, const Packet &packet, const Address &from)
{
- std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl;
+ std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet.GetSize () << std::endl;
}
static void
PrintTraffic (Ptr<Socket> socket)
{
- socket->RecvDummy (MakeCallback (&SocketPrinter));
+ socket->SetRecvCallback (MakeCallback (&SocketPrinter));
}
void
@@ -44,10 +46,12 @@
Ptr<SocketFactory> socketFactory = a->QueryInterface<SocketFactory> (iid);
Ptr<Socket> sink = socketFactory->CreateSocket ();
- sink->Bind (80);
+ InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
+ sink->Bind (local);
Ptr<Socket> source = socketFactory->CreateSocket ();
- source->Connect (Ipv4Address::GetLoopback (), 80);
+ InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80);
+ source->Connect (remote);
GenerateTraffic (source, 500);
PrintTraffic (sink);
--- a/samples/main-tw.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-tw.cc Fri Sep 28 11:59:46 2007 +0100
@@ -18,14 +18,14 @@
*/
#include <string>
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "ns3/trace-writer.h"
using namespace ns3;
int main (int argc, char *argv[])
{
- NS_DEBUG_UNCOND("TraceWriter Test")
+ NS_LOG_UNCOND("TraceWriter Test")
TraceWriter writer1;
writer1.Open("trace-writer-test.txt");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- a/samples/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -1,24 +1,43 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
def build(bld):
- def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
- obj = bld.create_obj('cpp', 'program')
- obj.target = name
- obj.uselib_local = ["ns3-%s" % dep for dep in deps]
- obj.source = source
- return obj
-
- obj = create_ns_prog('main-debug', ['main-debug.cc', 'main-debug-other.cc'])
- obj = create_ns_prog('main-callback', 'main-callback.cc')
- obj = create_ns_prog('main-ptr', 'main-ptr.cc')
- #obj = create_ns_prog('main-trace', 'main-trace.cc')
- obj = create_ns_prog('main-simulator', 'main-simulator.cc')
- obj = create_ns_prog('main-packet', 'main-packet.cc')
- obj = create_ns_prog('main-test', 'main-test.cc')
- obj = create_ns_prog('main-simple', 'main-simple.cc',
- deps=['node', 'internet-node', 'applications'])
- #obj = create_ns_prog('main-simple-p2p', 'main-simple-p2p.cc', deps=['node', 'p2p'])
- obj = create_ns_prog('main-default-value', 'main-default-value.cc',
- deps=['core', 'simulator', 'node', 'p2p'])
+ obj = bld.create_ns3_program('main-debug')
+ obj.source = ['main-debug.cc', 'main-debug-other.cc']
+
+ obj = bld.create_ns3_program('main-callback')
+ obj.source = 'main-callback.cc'
+
+ obj = bld.create_ns3_program('main-ptr')
+ obj.source = 'main-ptr.cc'
+
+ obj = bld.create_ns3_program('main-simulator')
+ obj.source = 'main-simulator.cc'
+
+ obj = bld.create_ns3_program('main-packet-header', ['common', 'simulator'])
+ obj.source = 'main-packet-header.cc'
+
+ obj = bld.create_ns3_program('main-packet-tag', ['common', 'simulator'])
+ obj.source = 'main-packet-tag.cc'
+ obj = bld.create_ns3_program('main-packet-printer', ['common', 'simulator', 'internet-node'])
+ obj.source = 'main-packet-printer.cc'
+
+ obj = bld.create_ns3_program('main-test')
+ obj.source = 'main-test.cc'
+
+ obj = bld.create_ns3_program('main-simple',
+ ['node', 'internet-node', 'onoff'])
+ obj.source = 'main-simple.cc'
+
+ obj = bld.create_ns3_program('main-default-value',
+ ['core', 'simulator', 'node', 'point-to-point'])
+ obj.source = 'main-default-value.cc'
+
+ obj = bld.create_ns3_program('main-grid-topology',
+ ['core', 'simulator', 'mobility', 'internet-node'])
+ obj.source = 'main-grid-topology.cc'
+
+ obj = bld.create_ns3_program('main-random-topology',
+ ['core', 'simulator', 'mobility'])
+ obj.source = 'main-random-topology.cc'
+
--- a/src/applications/onoff-application.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +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<riley@ece.gatech.edu>
-//
-
-// ns3 - On/Off Data Source Application class
-// George F. Riley, Georgia Tech, Spring 2007
-// Adapted from ApplicationOnOff in GTNetS.
-
-#include "ns3/ipv4-address.h"
-#include "ns3/node.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-#include "ns3/random-variable.h"
-#include "ns3/socket.h"
-#include "ns3/simulator.h"
-#include "ns3/socket-factory.h"
-#include "ns3/default-value.h"
-#include "onoff-application.h"
-
-using namespace std;
-
-namespace ns3 {
-
-// Defaults for rate/size
-static DataRateDefaultValue g_defaultRate ("OnOffApplicationDataRate",
- "The data rate in on state for OnOffApplication",
- DataRate ("500kb/s"));
-static IntegerDefaultValue<uint32_t> g_defaultSize ("OnOffApplicationPacketSize",
- "The size of packets sent in on state for OnOffApplication",
- 512, 1);
-// Constructors
-
-OnOffApplication::OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
- std::string iid,
- const RandomVariable& ontime,
- const RandomVariable& offtime)
- : Application(n),
- m_cbrRate (g_defaultRate.GetValue ())
-{
- Construct (n, rip, rport, iid,
- ontime, offtime,
- g_defaultSize.GetValue ());
-}
-
-OnOffApplication::OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
- std::string iid,
- const RandomVariable& ontime,
- const RandomVariable& offtime,
- DataRate rate,
- uint32_t size)
- : Application(n),
- m_cbrRate (rate)
-{
- Construct (n, rip, rport, iid,
- ontime, offtime, size);
-}
-
-void
-OnOffApplication::Construct (Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
- std::string iid,
- const RandomVariable& onTime,
- const RandomVariable& offTime,
- uint32_t size)
-{
- m_socket = 0;
- m_peerIp = rip;
- m_peerPort = rport;
- m_connected = false;
- m_onTime = onTime.Copy ();
- m_offTime = offTime.Copy ();
- m_pktSize = size;
- m_residualBits = 0;
- m_lastStartTime = Seconds (0);
- m_maxBytes = 0xffffffff;
- m_totBytes = 0;
- m_iid = iid;
-}
-
-
-OnOffApplication::~OnOffApplication()
-{}
-
-void
-OnOffApplication::SetMaxBytes(uint32_t maxBytes)
-{
- m_maxBytes = maxBytes;
-}
-
-void
-OnOffApplication::SetDefaultRate (const DataRate &rate)
-{
- g_defaultRate.SetValue (rate);
-}
-void
-OnOffApplication::SetDefaultSize (uint32_t size)
-{
- g_defaultSize.SetValue (size);
-}
-
-void
-OnOffApplication::DoDispose (void)
-{
- m_socket = 0;
- delete m_onTime;
- delete m_offTime;
-
- m_onTime = 0;
- m_offTime = 0;
-
- // chain up
- Application::DoDispose ();
-}
-
-
-// Application Methods
-void OnOffApplication::StartApplication() // Called at time specified by Start
-{
- // Create the socket if not already
- if (!m_socket)
- {
- InterfaceId iid = InterfaceId::LookupByName (m_iid);
- Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
- m_socket = socketFactory->CreateSocket ();
- m_socket->Bind ();
- m_socket->Connect (m_peerIp, m_peerPort);
- }
- // Insure no pending event
- StopApplication();
- // 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;
- ScheduleStartEvent();
-}
-
-void OnOffApplication::StopApplication() // Called at time specified by Stop
-{
- if (m_sendEvent.IsRunning ())
- { // Cancel the pending send packet event
- // Calculate residual bits since last packet sent
- Time delta(Simulator::Now() - m_lastStartTime);
- m_residualBits += (uint32_t)(m_cbrRate.GetBitRate() * delta.GetSeconds());
- }
- Simulator::Cancel(m_sendEvent);
- Simulator::Cancel(m_startStopEvent);
-}
-
-// Event handlers
-void OnOffApplication::StartSending()
-{
- ScheduleNextTx(); // Schedule the send packet event
-}
-
-void OnOffApplication::StopSending()
-{
- Simulator::Cancel(m_sendEvent);
-}
-
-// Private helpers
-void OnOffApplication::ScheduleNextTx()
-{
- if (m_totBytes < m_maxBytes)
- {
- uint32_t bits = m_pktSize * 8 - m_residualBits;
- Time nextTime(Seconds (bits /
- static_cast<double>(m_cbrRate.GetBitRate()))); // Time till next packet
- m_sendEvent = Simulator::Schedule(nextTime, &OnOffApplication::SendPacket, this);
- }
- else
- { // All done, cancel any pending events
- StopApplication();
- }
-}
-
-void OnOffApplication::ScheduleStartEvent()
-{ // Schedules the event to start sending data (switch to the "On" state)
- Time offInterval = Seconds(m_offTime->GetValue());
- m_startStopEvent = Simulator::Schedule(offInterval, &OnOffApplication::StartSending, this);
-}
-
-void OnOffApplication::ScheduleStopEvent()
-{ // Schedules the event to stop sending data (switch to "Off" state)
- Time onInterval = Seconds(m_onTime->GetValue());
- Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
-}
-
-
-void OnOffApplication::SendPacket()
-{
- NS_ASSERT (m_sendEvent.IsExpired ());
- m_socket->Send(0, m_pktSize);
- m_totBytes += m_pktSize;
- m_lastStartTime = Simulator::Now();
- m_residualBits = 0;
- ScheduleNextTx();
-}
-
-void OnOffApplication::ConnectionSucceeded(Ptr<Socket>)
-{
- m_connected = true;
- ScheduleStartEvent();
-}
-
-void OnOffApplication::ConnectionFailed(Ptr<Socket>)
-{
- cout << "OnOffApplication, Connection Failed" << endl;
-}
-
-} // Namespace ns3
--- a/src/applications/onoff-application.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +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<riley@ece.gatech.edu>
-//
-
-// ns3 - On/Off Data Source Application class
-// George F. Riley, Georgia Tech, Spring 2007
-// Adapted from ApplicationOnOff in GTNetS.
-
-#ifndef __onoff_application_h__
-#define __onoff_application_h__
-
-#include "ns3/application.h"
-#include "ns3/event-id.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Ipv4Address;
-class RandomVariable;
-class Socket;
-class DataRate;
-
-/**
- * \brief Generate traffic to a single destination according to an
- * OnOff pattern.
- *
- * This traffic 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".
- */
-class OnOffApplication : public Application
-{
-public:
- /**
- * \param n node associated to this application
- * \param rip remote ip address
- * \param rport remove port number
- * \param iid
- * \param ontime on time random variable
- * \param offtime off time random variable
- */
- OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
- std::string iid,
- const RandomVariable& ontime,
- const RandomVariable& offtime);
-
- /**
- * \param n node associated to this application
- * \param rip remote ip address
- * \param rport remove port number
- * \param iid
- * \param ontime on time random variable
- * \param offtime off time random variable
- * \param rate data rate when on
- * \param size size of packets when sending data.
- */
- OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
- std::string iid,
- const RandomVariable& ontime,
- const RandomVariable& offtime,
- DataRate rate,
- uint32_t size);
-
- virtual ~OnOffApplication();
-
- void SetMaxBytes(uint32_t maxBytes);
-
- /**
- * \param r the data rate
- *
- * Set the data rate to use for every OnOffApplication for which
- * the user does not specify an explicit data rate.
- */
- static void SetDefaultRate(const DataRate & r);
-
- /**
- * \param size the packet size
- *
- * Set the packet size to use for every OnOffApplication for
- * which the user does not specify an explicit packet size.
- */
- static void SetDefaultSize (uint32_t size);
-
-protected:
- virtual void DoDispose (void);
-private:
- // inherited from Application base class.
- virtual void StartApplication (void); // Called at time specified by Start
- virtual void StopApplication (void); // Called at time specified by Stop
-
- void Construct (Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
- std::string iid,
- const RandomVariable& ontime,
- const RandomVariable& offtime,
- uint32_t size);
-
-
- // Event handlers
- void StartSending();
- void StopSending();
- void SendPacket();
-
- Ptr<Socket> m_socket; // Associated socket
- Ipv4Address m_peerIp; // Peer IP address
- uint16_t m_peerPort; // Peer port
- bool m_connected; // True if connected
- RandomVariable* m_onTime; // rng for On Time
- RandomVariable* m_offTime; // rng for Off Time
- DataRate m_cbrRate; // Rate that data is generated
- uint32_t m_pktSize; // Size of packets
- uint32_t m_residualBits; // Number of generated, but not sent, bits
- Time m_lastStartTime;// Time last packet sent
- uint32_t m_maxBytes; // Limit total number of bytes sent
- uint32_t m_totBytes; // Total bytes sent so far
- EventId m_startStopEvent; // Event id for next start or stop event
- EventId m_sendEvent; // Eventid of pending "send packet" event
- bool m_sending; // True if currently in sending state
- std::string m_iid;
-
-private:
- void ScheduleNextTx();
- void ScheduleStartEvent();
- void ScheduleStopEvent();
- void ConnectionSucceeded(Ptr<Socket>);
- void ConnectionFailed(Ptr<Socket>);
- void Ignore(Ptr<Socket>);
-};
-
-} // namespace ns3
-
-#endif
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/onoff-application.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+
+// ns3 - On/Off Data Source Application class
+// George F. Riley, Georgia Tech, Spring 2007
+// Adapted from ApplicationOnOff in GTNetS.
+
+#include "ns3/log.h"
+#include "ns3/address.h"
+#include "ns3/node.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/random-variable.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/default-value.h"
+#include "ns3/packet.h"
+#include "onoff-application.h"
+
+NS_LOG_COMPONENT_DEFINE ("OnOffApplication");
+
+using namespace std;
+
+namespace ns3 {
+
+// Defaults for rate/size
+static DataRateDefaultValue g_defaultRate ("OnOffApplicationDataRate",
+ "The data rate in on state for OnOffApplication",
+ DataRate ("500kb/s"));
+static NumericDefaultValue<uint32_t> g_defaultSize ("OnOffApplicationPacketSize",
+ "The size of packets sent in on state for OnOffApplication",
+ 512, 1);
+// Constructors
+
+OnOffApplication::OnOffApplication(Ptr<Node> n,
+ const Address &remote,
+ std::string iid,
+ const RandomVariable& ontime,
+ const RandomVariable& offtime)
+ : Application(n),
+ m_cbrRate (g_defaultRate.GetValue ())
+{
+ Construct (n, remote, iid,
+ ontime, offtime,
+ g_defaultSize.GetValue ());
+}
+
+OnOffApplication::OnOffApplication(Ptr<Node> n,
+ const Address &remote,
+ std::string iid,
+ const RandomVariable& ontime,
+ const RandomVariable& offtime,
+ DataRate rate,
+ uint32_t size)
+ : Application(n),
+ m_cbrRate (rate)
+{
+ NS_LOG_FUNCTION;
+ Construct (n, remote, iid, ontime, offtime, size);
+}
+
+void
+OnOffApplication::Construct (Ptr<Node> n,
+ const Address &remote,
+ std::string iid,
+ const RandomVariable& onTime,
+ const RandomVariable& offTime,
+ uint32_t size)
+{
+ NS_LOG_FUNCTION;
+
+ m_socket = 0;
+ m_peer = remote;
+ m_connected = false;
+ m_onTime = onTime.Copy ();
+ m_offTime = offTime.Copy ();
+ m_pktSize = size;
+ m_residualBits = 0;
+ m_lastStartTime = Seconds (0);
+ m_maxBytes = 0xffffffff;
+ m_totBytes = 0;
+ m_iid = iid;
+}
+
+OnOffApplication::~OnOffApplication()
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+OnOffApplication::SetMaxBytes(uint32_t maxBytes)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << maxBytes << ")");
+ m_maxBytes = maxBytes;
+}
+
+void
+OnOffApplication::SetDefaultRate (const DataRate &rate)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &rate << ")");
+ g_defaultRate.SetValue (rate);
+}
+
+void
+OnOffApplication::SetDefaultSize (uint32_t size)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << size << ")");
+ g_defaultSize.SetValue (size);
+}
+
+void
+OnOffApplication::DoDispose (void)
+{
+ NS_LOG_FUNCTION;
+
+ m_socket = 0;
+ delete m_onTime;
+ delete m_offTime;
+
+ m_onTime = 0;
+ m_offTime = 0;
+
+ // chain up
+ Application::DoDispose ();
+}
+
+// Application Methods
+void OnOffApplication::StartApplication() // Called at time specified by Start
+{
+ NS_LOG_FUNCTION;
+
+ // Create the socket if not already
+ if (!m_socket)
+ {
+ InterfaceId iid = InterfaceId::LookupByName (m_iid);
+ Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
+ m_socket = socketFactory->CreateSocket ();
+ m_socket->Bind ();
+ m_socket->Connect (m_peer);
+ }
+ // Insure no pending event
+ StopApplication();
+ // 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;
+ ScheduleStartEvent();
+}
+
+void OnOffApplication::StopApplication() // Called at time specified by Stop
+{
+ NS_LOG_FUNCTION;
+
+ if (m_sendEvent.IsRunning ())
+ { // Cancel the pending send packet event
+ // Calculate residual bits since last packet sent
+ Time delta(Simulator::Now() - m_lastStartTime);
+ m_residualBits += (uint32_t)(m_cbrRate.GetBitRate() * delta.GetSeconds());
+ }
+ Simulator::Cancel(m_sendEvent);
+ Simulator::Cancel(m_startStopEvent);
+}
+
+// Event handlers
+void OnOffApplication::StartSending()
+{
+ NS_LOG_FUNCTION;
+
+ ScheduleNextTx(); // Schedule the send packet event
+}
+
+void OnOffApplication::StopSending()
+{
+ NS_LOG_FUNCTION;
+
+ Simulator::Cancel(m_sendEvent);
+}
+
+// Private helpers
+void OnOffApplication::ScheduleNextTx()
+{
+ NS_LOG_FUNCTION;
+
+ if (m_totBytes < m_maxBytes)
+ {
+ uint32_t bits = m_pktSize * 8 - m_residualBits;
+ NS_LOG_LOGIC ("bits = " << bits);
+ Time nextTime(Seconds (bits /
+ static_cast<double>(m_cbrRate.GetBitRate()))); // Time till next packet
+ NS_LOG_LOGIC ("nextTime = " << nextTime);
+ m_sendEvent = Simulator::Schedule(nextTime,
+ &OnOffApplication::SendPacket, this);
+ }
+ else
+ { // All done, cancel any pending events
+ StopApplication();
+ }
+}
+
+void OnOffApplication::ScheduleStartEvent()
+{ // Schedules the event to start sending data (switch to the "On" state)
+ NS_LOG_FUNCTION;
+
+ Time offInterval = Seconds(m_offTime->GetValue());
+ NS_LOG_LOGIC ("start at " << offInterval);
+ m_startStopEvent = Simulator::Schedule(offInterval, &OnOffApplication::StartSending, this);
+}
+
+void OnOffApplication::ScheduleStopEvent()
+{ // Schedules the event to stop sending data (switch to "Off" state)
+ NS_LOG_FUNCTION;
+
+ Time onInterval = Seconds(m_onTime->GetValue());
+ Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
+}
+
+
+void OnOffApplication::SendPacket()
+{
+ NS_LOG_FUNCTION;
+
+ NS_ASSERT (m_sendEvent.IsExpired ());
+ m_socket->Send(Packet (m_pktSize));
+ m_totBytes += m_pktSize;
+ m_lastStartTime = Simulator::Now();
+ m_residualBits = 0;
+ ScheduleNextTx();
+}
+
+void OnOffApplication::ConnectionSucceeded(Ptr<Socket>)
+{
+ NS_LOG_FUNCTION;
+
+ m_connected = true;
+ ScheduleStartEvent();
+}
+
+void OnOffApplication::ConnectionFailed(Ptr<Socket>)
+{
+ NS_LOG_FUNCTION;
+ cout << "OnOffApplication, Connection Failed" << endl;
+}
+
+} // Namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/onoff-application.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+
+// ns3 - On/Off Data Source Application class
+// George F. Riley, Georgia Tech, Spring 2007
+// Adapted from ApplicationOnOff in GTNetS.
+
+#ifndef __onoff_application_h__
+#define __onoff_application_h__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class Address;
+class RandomVariable;
+class Socket;
+
+/**
+ * \brief Generate traffic to a single destination according to an
+ * OnOff pattern.
+ *
+ * This traffic 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".
+ */
+class OnOffApplication : public Application
+{
+public:
+ /**
+ * \param n node associated to this application
+ * \param remote remote ip address
+ * \param iid
+ * \param ontime on time random variable
+ * \param offtime off time random variable
+ */
+ OnOffApplication(Ptr<Node> n,
+ const Address &remote,
+ std::string iid,
+ const RandomVariable& ontime,
+ const RandomVariable& offtime);
+
+ /**
+ * \param n node associated to this application
+ * \param remote remote ip address
+ * \param iid
+ * \param ontime on time random variable
+ * \param offtime off time random variable
+ * \param rate data rate when on
+ * \param size size of packets when sending data.
+ */
+ OnOffApplication(Ptr<Node> n,
+ const Address &remote,
+ std::string iid,
+ const RandomVariable& ontime,
+ const RandomVariable& offtime,
+ DataRate rate,
+ uint32_t size);
+
+ virtual ~OnOffApplication();
+
+ void SetMaxBytes(uint32_t maxBytes);
+
+ /**
+ * \param r the data rate
+ *
+ * Set the data rate to use for every OnOffApplication for which
+ * the user does not specify an explicit data rate.
+ */
+ static void SetDefaultRate(const DataRate & r);
+
+ /**
+ * \param size the packet size
+ *
+ * Set the packet size to use for every OnOffApplication for
+ * which the user does not specify an explicit packet size.
+ */
+ static void SetDefaultSize (uint32_t size);
+
+protected:
+ virtual void DoDispose (void);
+private:
+ // inherited from Application base class.
+ virtual void StartApplication (void); // Called at time specified by Start
+ virtual void StopApplication (void); // Called at time specified by Stop
+
+ void Construct (Ptr<Node> n,
+ const Address &remote,
+ std::string iid,
+ const RandomVariable& ontime,
+ const RandomVariable& offtime,
+ uint32_t size);
+
+
+ // Event handlers
+ void StartSending();
+ void StopSending();
+ void SendPacket();
+
+ Ptr<Socket> m_socket; // Associated socket
+ Address m_peer; // Peer address
+ bool m_connected; // True if connected
+ RandomVariable* m_onTime; // rng for On Time
+ RandomVariable* m_offTime; // rng for Off Time
+ DataRate m_cbrRate; // Rate that data is generated
+ uint32_t m_pktSize; // Size of packets
+ uint32_t m_residualBits; // Number of generated, but not sent, bits
+ Time m_lastStartTime;// Time last packet sent
+ uint32_t m_maxBytes; // Limit total number of bytes sent
+ uint32_t m_totBytes; // Total bytes sent so far
+ EventId m_startStopEvent; // Event id for next start or stop event
+ EventId m_sendEvent; // Eventid of pending "send packet" event
+ bool m_sending; // True if currently in sending state
+ std::string m_iid;
+
+private:
+ void ScheduleNextTx();
+ void ScheduleStartEvent();
+ void ScheduleStopEvent();
+ void ConnectionSucceeded(Ptr<Socket>);
+ void ConnectionFailed(Ptr<Socket>);
+ void Ignore(Ptr<Socket>);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,12 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ module = bld.create_ns3_module('onoff', ['core'])
+ module.source = [
+ 'onoff-application.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'onoff-application.h',
+ ]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/packet-sink.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,109 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Author: Tom Henderson (tomhend@u.washington.edu)
+ */
+#include "ns3/address.h"
+#include "ns3/log.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/node.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/packet.h"
+#include "packet-sink.h"
+
+using namespace std;
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("PacketSinkApplication");
+
+// Constructors
+
+PacketSink::PacketSink (Ptr<Node> n,
+ const Address &local,
+ std::string iid)
+ : Application(n)
+{
+ Construct (n, local, iid);
+}
+
+void
+PacketSink::Construct (Ptr<Node> n,
+ const Address &local,
+ std::string iid)
+{
+ m_socket = 0;
+ m_local = local;
+ m_iid = iid;
+}
+
+PacketSink::~PacketSink()
+{}
+
+void
+PacketSink::DoDispose (void)
+{
+ m_socket = 0;
+
+ // chain up
+ Application::DoDispose ();
+}
+
+
+// Application Methods
+void PacketSink::StartApplication() // Called at time specified by Start
+{
+ // Create the socket if not already
+ if (!m_socket)
+ {
+ InterfaceId iid = InterfaceId::LookupByName (m_iid);
+ Ptr<SocketFactory> socketFactory =
+ GetNode ()->QueryInterface<SocketFactory> (iid);
+ m_socket = socketFactory->CreateSocket ();
+ m_socket->Bind (m_local);
+ }
+ m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+ const Address &>) MakeCallback(&PacketSink::Receive, this));
+}
+
+void PacketSink::StopApplication() // Called at time specified by Stop
+{
+ if (!m_socket)
+ {
+ m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+ const Address &>) NULL);
+
+ }
+}
+
+// This LOG output inspired by the application on Joseph Kopena's wiki
+void PacketSink::Receive(Ptr<Socket> socket, const Packet &packet,
+ const Address &from)
+{
+ if (InetSocketAddress::IsMatchingType (from))
+ {
+ InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+ NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " <<
+ address.GetIpv4() << " [" << address << "]---'" <<
+ packet.PeekData() << "'");
+ // TODO: Add a tracing source here
+ }
+}
+
+} // Namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/packet-sink.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Author: Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#ifndef __packet_sink_h__
+#define __packet_sink_h__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Address;
+class Socket;
+class Packet;
+
+/**
+ * \brief Receive and consume traffic generated to an IP address and port
+ *
+ * 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.
+ *
+ * The constructor specifies the Address (IP address and port) and the
+ * transport protocol to use. A virtual Receive () method is installed
+ * as a callback on the receiving socket. By default, when logging is
+ * enabled, it prints out the size of packets and their address, but
+ * we intend to also add a tracing source to Receive() at a later date.
+ */
+class PacketSink : public Application
+{
+public:
+ /**
+ * \param n node associated to this application
+ * \param local local address to bind to
+ * \param iid string to identify transport protocol of interest
+ */
+ PacketSink (Ptr<Node> n,
+ const Address &local,
+ std::string iid);
+
+ virtual ~PacketSink ();
+
+protected:
+ virtual void DoDispose (void);
+private:
+ // inherited from Application base class.
+ virtual void StartApplication (void); // Called at time specified by Start
+ virtual void StopApplication (void); // Called at time specified by Stop
+
+ void Construct (Ptr<Node> n,
+ const Address &local,
+ std::string iid);
+
+ virtual void Receive (Ptr<Socket> socket, const Packet& packet, const Address& from);
+
+ Ptr<Socket> m_socket; // Associated socket
+ Address m_local; // Local address to bind to
+ std::string m_iid; // Protocol name (e.g., "Udp")
+
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,12 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ module = bld.create_ns3_module('packet-sink', ['node'])
+ module.source = [
+ 'packet-sink.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'packet-sink.h',
+ ]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-client.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,168 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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/log.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/nstime.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/packet.h"
+#include "udp-echo-client.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoClientApplication");
+
+UdpEchoClient::UdpEchoClient (
+ Ptr<Node> n,
+ Ipv4Address serverAddress,
+ uint16_t serverPort,
+ uint32_t count,
+ Time interval,
+ uint32_t size)
+:
+ Application(n)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << n << ", " << serverAddress <<
+ ", " << serverPort << ", " << count << ", " << interval <<
+ ", " << size << ")");
+
+ Construct (n, serverAddress, serverPort, count, interval, size);
+}
+
+UdpEchoClient::~UdpEchoClient()
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+UdpEchoClient::Construct (
+ Ptr<Node> n,
+ Ipv4Address serverAddress,
+ uint16_t serverPort,
+ uint32_t count,
+ Time interval,
+ uint32_t size)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << n << ", " << serverAddress <<
+ ", " << serverPort << ", " << count << ", " << interval <<
+ ", " << size << ")");
+
+ m_node = n;
+ m_serverAddress = serverAddress;
+ m_serverPort = serverPort;
+ m_count = count;
+ m_interval = interval;
+ m_size = size;
+
+ m_sent = 0;
+ m_socket = 0;
+ m_peer = InetSocketAddress (serverAddress, serverPort);
+ m_sendEvent = EventId ();
+}
+
+void
+UdpEchoClient::DoDispose (void)
+{
+ NS_LOG_FUNCTION;
+ Application::DoDispose ();
+}
+
+void
+UdpEchoClient::StartApplication (void)
+{
+ NS_LOG_FUNCTION;
+
+ if (!m_socket)
+ {
+ InterfaceId iid = InterfaceId::LookupByName ("Udp");
+ Ptr<SocketFactory> socketFactory =
+ GetNode ()->QueryInterface<SocketFactory> (iid);
+ m_socket = socketFactory->CreateSocket ();
+ m_socket->Bind ();
+ m_socket->Connect (m_peer);
+ }
+
+ m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+ const Address &>) MakeCallback(&UdpEchoClient::Receive, this));
+
+ ScheduleTransmit (Seconds(0.));
+}
+
+void
+UdpEchoClient::StopApplication ()
+{
+ NS_LOG_FUNCTION;
+
+ if (!m_socket)
+ {
+ m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+ const Address &>) NULL);
+ }
+
+ Simulator::Cancel(m_sendEvent);
+}
+
+void
+UdpEchoClient::ScheduleTransmit (Time dt)
+{
+ NS_LOG_FUNCTION;
+ m_sendEvent = Simulator::Schedule(dt, &UdpEchoClient::Send, this);
+}
+
+void
+UdpEchoClient::Send (void)
+{
+ NS_LOG_FUNCTION;
+
+ NS_ASSERT (m_sendEvent.IsExpired ());
+
+ Packet p (m_size);
+ m_socket->Send (p);
+ ++m_sent;
+
+ NS_LOG_INFO ("Sent " << m_size << " bytes to " << m_serverAddress);
+
+ if (m_sent < m_count)
+ {
+ ScheduleTransmit (m_interval);
+ }
+}
+
+void
+UdpEchoClient::Receive(
+ Ptr<Socket> socket,
+ const Packet &packet,
+ const Address &from)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << socket << ", " << packet << ", " << from << ")");
+
+ if (InetSocketAddress::IsMatchingType (from))
+ {
+ InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+ NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " <<
+ address.GetIpv4());
+ }
+}
+
+
+} // Namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-client.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ */
+
+#ifndef __UDP_ECHO_CLIENT_H__
+#define __UDP_ECHO_CLIENT_H__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Address;
+class Socket;
+class Packet;
+
+class UdpEchoClient : public Application
+{
+public:
+ UdpEchoClient (Ptr<Node> n, Ipv4Address serverAddr, uint16_t serverPort,
+ uint32_t count, Time interval, uint32_t size);
+
+ virtual ~UdpEchoClient ();
+
+protected:
+ virtual void DoDispose (void);
+
+private:
+ void Construct (Ptr<Node> n, Ipv4Address serverAddr, uint16_t serverPort,
+ uint32_t count, Time interval, uint32_t size);
+
+ virtual void StartApplication (void);
+ virtual void StopApplication (void);
+
+ void ScheduleTransmit (Time dt);
+ void Send (void);
+
+ void Receive(Ptr<Socket> socket, const Packet &packet, const Address &from);
+
+ Ptr<Node> m_node;
+ Ipv4Address m_serverAddress;
+ uint16_t m_serverPort;
+ uint32_t m_count;
+ Time m_interval;
+ uint32_t m_size;
+
+ uint32_t m_sent;
+ Ptr<Socket> m_socket;
+ Address m_peer;
+ EventId m_sendEvent;
+
+};
+
+} // namespace ns3
+
+#endif // __UDP_ECHO_CLIENT_H__
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-server.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,123 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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/log.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/nstime.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/packet.h"
+
+#include "udp-echo-server.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoServerApplication");
+
+UdpEchoServer::UdpEchoServer (
+ Ptr<Node> n,
+ uint16_t port)
+:
+ Application(n)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << n << ", " << port << ")");
+
+ Construct (n, port);
+}
+
+UdpEchoServer::~UdpEchoServer()
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+UdpEchoServer::Construct (
+ Ptr<Node> n,
+ uint16_t port)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << n << ", " << port << ")");
+
+ m_node = n;
+ m_port = port;
+
+ m_socket = 0;
+ m_local = InetSocketAddress (Ipv4Address::GetAny (), port);
+}
+
+void
+UdpEchoServer::DoDispose (void)
+{
+ NS_LOG_FUNCTION;
+ Application::DoDispose ();
+}
+
+void
+UdpEchoServer::StartApplication (void)
+{
+ NS_LOG_FUNCTION;
+
+ if (!m_socket)
+ {
+ InterfaceId iid = InterfaceId::LookupByName ("Udp");
+ Ptr<SocketFactory> socketFactory =
+ GetNode ()->QueryInterface<SocketFactory> (iid);
+ m_socket = socketFactory->CreateSocket ();
+ m_socket->Bind (m_local);
+ }
+
+ m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+ const Address &>) MakeCallback(&UdpEchoServer::Receive, this));
+}
+
+void
+UdpEchoServer::StopApplication ()
+{
+ NS_LOG_FUNCTION;
+
+ if (!m_socket)
+ {
+ m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+ const Address &>) NULL);
+ }
+}
+
+void
+UdpEchoServer::Receive(
+ Ptr<Socket> socket,
+ const Packet &packet,
+ const Address &from)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << socket << ", " << packet << ", " << from << ")");
+
+ if (InetSocketAddress::IsMatchingType (from))
+ {
+ InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+ NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " <<
+ address.GetIpv4());
+
+ NS_LOG_LOGIC ("Echoing packet");
+ socket->SendTo (from, packet);
+ }
+}
+
+} // Namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-server.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,59 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ */
+
+#ifndef __UDP_ECHO_SERVER_H__
+#define __UDP_ECHO_SERVER_H__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Address;
+class Socket;
+class Packet;
+
+class UdpEchoServer : public Application
+{
+public:
+ UdpEchoServer (Ptr<Node> n, uint16_t clientPort);
+ virtual ~UdpEchoServer ();
+
+protected:
+ virtual void DoDispose (void);
+
+private:
+ void Construct (Ptr<Node> n, uint16_t clientPort);
+
+ virtual void StartApplication (void);
+ virtual void StopApplication (void);
+
+ void Receive(Ptr<Socket> socket, const Packet &packet, const Address &from);
+
+ Ptr<Node> m_node;
+ uint16_t m_port;
+
+ Ptr<Socket> m_socket;
+ Address m_local;
+};
+
+} // namespace ns3
+
+#endif // __UDP_ECHO_SERVER_H__
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,14 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ module = bld.create_ns3_module('udp-echo', ['internet-node'])
+ module.source = [
+ 'udp-echo-client.cc',
+ 'udp-echo-server.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'udp-echo-client.h',
+ 'udp-echo-server.h',
+ ]
+
--- a/src/applications/wscript Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-
-def configure(conf):
- conf.env.append_value('NS3_MODULES', 'ns3-applications')
-
-
-def build(bld):
- obj = bld.create_obj('cpp', 'shlib')
- obj.name = 'ns3-applications'
- obj.target = obj.name
- obj.uselib_local = ['ns3-node']
- obj.source = [
- 'onoff-application.cc',
- ]
-
- headers = bld.create_obj('ns3header')
- headers.source = [
- 'onoff-application.h',
- ]
--- a/src/common/array-trace-resolver.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef ARRAY_TRACE_RESOLVER_H
-#define ARRAY_TRACE_RESOLVER_H
-
-#include <stdint.h>
-#include <string>
-#include "ns3/callback.h"
-#include "trace-resolver.h"
-
-namespace ns3 {
-
-/**
- * \brief a helper class to offer trace resolution for an array of objects.
- * \ingroup lowleveltracing
- */
-template <typename T>
-class ArrayTraceResolver : public TraceResolver
-{
-public:
- /**
- * \brief array index trace context
- *
- * During namespace parsing, ns3::ArrayTraceResolver will
- * embed an instance of this class in the TraceContext
- * associated to every child object of the object stored
- * at the index.
- *
- * The reason why this class exists is to ensure that we
- * need to ensure that we can store a unique type as context
- * into the TraceContext associated to this trace resolver.
- */
- class Index
- {
- public:
- Index ();
- Index (uint32_t index);
- /**
- * The Index is automatically convertible to the
- * uin32_t type such that it really behaves like a uint32_t
- * array index for the user.
- *
- * \returns the index itself
- */
- operator uint32_t ();
- private:
- uint32_t m_index;
- };
- /**
- * \param context trace context associated to this trace resolver
- * \param getSize callback which returns dynamically the size of underlying array
- * \param get callback which returns any element in the underlying array
- *
- * Construct a trace resolver which can match any input integer
- * against an element in an array. The array is accessed using a
- * pair of callbacks. It is the responsability of the user to
- * provide two such callbacks whose job is to adapt the array
- * API to the resolver needs. Each element of the array is expected
- * to provide a method named CreateTraceResolver which takes as
- * only argument a reference to a const TraceContext and returns
- * a pointer to a TraceResolver. i.e. the signature is:
- * TraceResolver * (*) (TraceContext const &)
- */
- ArrayTraceResolver (TraceContext const &context,
- Callback<uint32_t> getSize,
- Callback<T *, uint32_t> get);
-private:
- virtual TraceResolverList DoLookup (std::string id) const;
- Callback<uint32_t> m_getSize;
- Callback<T *, uint32_t> m_get;
-};
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename T>
-ArrayTraceResolver<T>::Index::Index ()
- : m_index ()
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::Index (uint32_t index)
- : m_index (index)
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::operator uint32_t ()
-{
- return m_index;
-}
-
-template <typename T>
-ArrayTraceResolver<T>::ArrayTraceResolver (TraceContext const &context,
- Callback<uint32_t> getSize,
- Callback<T *, uint32_t> get)
- : TraceResolver (context),
- m_getSize (getSize),
- m_get (get)
-{}
-template <typename T>
-TraceResolver::TraceResolverList
-ArrayTraceResolver<T>::DoLookup (std::string id) const
-{
- TraceResolverList list;
- if (id == "*")
- {
- for (uint32_t i = 0; i < m_getSize (); i++)
- {
- TraceContext context = GetContext ();
- typename ArrayTraceResolver<T>::Index index = typename ArrayTraceResolver<T>::Index (i);
- context.Add (index);
- list.push_back (m_get (i)->CreateTraceResolver (context));
- }
- }
- return list;
-}
-
-
-}//namespace ns3
-
-#endif /* ARRAY_TRACE_RESOLVER_H */
--- a/src/common/buffer.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/buffer.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2005,2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2005,2006,2007 INRIA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,376 +19,534 @@
*/
#include "buffer.h"
#include "ns3/assert.h"
-
+#include "ns3/log.h"
#include <iostream>
-//#define TRACE(x) std::cout << x << std::endl;
-#define TRACE(x)
+
+NS_LOG_COMPONENT_DEFINE ("Buffer");
+
+#define LOG_INTERNAL_STATE(y) \
+NS_LOG_LOGIC (y << "start="<<m_start<<", end="<<m_end<<", zero start="<<m_zeroAreaStart<< \
+ ", zero end="<<m_zeroAreaEnd<<", count="<<m_data->m_count<<", size="<<m_data->m_size<< \
+ ", dirty start="<<m_data->m_dirtyStart<<", dirty end="<<m_data->m_dirtyEnd)
+
+#ifdef BUFFER_HEURISTICS
+#define HEURISTICS(x) x
+#else
+#define HEURISTICS(x)
+#endif
+
+//#define PRINT_STATS 1
namespace ns3 {
-Buffer::BufferDataList Buffer::m_freeList;
-uint32_t Buffer::m_maxTotalAddStart = 0;
-uint32_t Buffer::m_maxTotalAddEnd = 0;
+/**
+ * This data structure is variable-sized through its last member whose size
+ * is determined at allocation time and stored in the m_size field.
+ *
+ * The so-called "dirty area" describes the area in the buffer which
+ * has been reserved and used by a user. Multiple Buffer instances
+ * may reference the same BufferData object instance and may
+ * reference different parts of the underlying byte buffer. The
+ * "dirty area" is union of all the areas referenced by the Buffer
+ * instances which reference the same BufferData instance.
+ * New user data can be safely written only outside of the "dirty
+ * area" if the reference count is higher than 1 (that is, if
+ * more than one Buffer instance references the same BufferData).
+ */
+struct BufferData {
+ /* The reference count of an instance of this data structure.
+ * Each buffer which references an instance holds a count.
+ */
+ uint32_t m_count;
+ /* the size of the m_data field below.
+ */
+ uint32_t m_size;
+ /* offset from the start of the m_data field below to the
+ * start of the area in which user bytes were written.
+ */
+ uint32_t m_dirtyStart;
+ /* offset from the start of the m_data field below to the
+ * end of the area in which user bytes were written.
+ */
+ uint32_t m_dirtyEnd;
+ /* The real data buffer holds _at least_ one byte.
+ * Its real size is stored in the m_size field.
+ */
+ uint8_t m_data[1];
+};
+class BufferDataList : public std::vector<struct BufferData*>
+{
+public:
+ ~BufferDataList ();
+};
+
+static struct BufferData *BufferAllocate (uint32_t reqSize);
-struct Buffer::BufferData *
-Buffer::Allocate (uint32_t reqSize, uint32_t reqStart)
+static void BufferDeallocate (struct BufferData *data);
+
+
+} // namespace ns3
+
+namespace ns3 {
+
+#ifdef BUFFER_HEURISTICS
+static uint32_t g_recommendedStart = 0;
+static uint64_t g_nAddNoRealloc = 0;
+static uint64_t g_nAddRealloc = 0;
+static BufferDataList g_freeList;
+static uint32_t g_maxSize = 0;
+static uint64_t g_nAllocs = 0;
+static uint64_t g_nCreates = 0;
+#endif /* BUFFER_HEURISTICS */
+
+BufferDataList::~BufferDataList ()
+{
+#ifdef PRINT_STATS
+#ifdef BUFFER_HEURISTICS
+ double efficiency;
+ efficiency = g_nAllocs;
+ efficiency /= g_nCreates;
+ std::cout <<"buffer free list efficiency="<<efficiency<<" (lower is better)" << std::endl;
+ std::cout <<"buffer free list max size="<<g_maxSize<<std::endl;
+ std::cout <<"buffer free list recommended start="<<g_recommendedStart<<std::endl;
+ double addEfficiency;
+ addEfficiency = g_nAddRealloc;
+ addEfficiency /= g_nAddNoRealloc;
+ std::cout <<"buffer add efficiency=" << addEfficiency << " (lower is better)"<<std::endl;
+ //std::cout <<"n add reallocs="<< g_nAddRealloc << std::endl;
+ //std::cout <<"n add no reallocs="<< g_nAddNoRealloc << std::endl;
+#endif /* BUFFER_HEURISTICS */
+#endif /* PRINT_STATS */
+ for (BufferDataList::iterator i = begin ();
+ i != end (); i++)
+ {
+ BufferDeallocate (*i);
+ }
+}
+
+struct BufferData *
+BufferAllocate (uint32_t reqSize)
{
if (reqSize == 0)
{
reqSize = 1;
}
NS_ASSERT (reqSize >= 1);
- uint32_t size = reqSize - 1 + sizeof (struct Buffer::BufferData);
+ uint32_t size = reqSize - 1 + sizeof (struct BufferData);
uint8_t *b = new uint8_t [size];
- struct BufferData *data = reinterpret_cast<struct Buffer::BufferData*>(b);
+ struct BufferData *data = reinterpret_cast<struct BufferData*>(b);
data->m_size = reqSize;
- data->m_initialStart = reqStart;
- data->m_dirtyStart = reqStart;
- data->m_dirtySize = 0;
data->m_count = 1;
return data;
}
void
-Buffer::Deallocate (struct Buffer::BufferData *data)
+BufferDeallocate (struct BufferData *data)
{
+ NS_ASSERT (data->m_count == 0);
uint8_t *buf = reinterpret_cast<uint8_t *> (data);
delete [] buf;
}
-#ifdef USE_FREE_LIST
+#ifdef BUFFER_HEURISTICS
void
-Buffer::Recycle (struct Buffer::BufferData *data)
+Buffer::Recycle (struct BufferData *data)
{
NS_ASSERT (data->m_count == 0);
- /* get rid of it if it is too small for later reuse. */
- if (data->m_size < (Buffer::m_maxTotalAddStart + Buffer::m_maxTotalAddEnd))
- {
- Buffer::Deallocate (data);
- return;
- }
+ g_maxSize = std::max (g_maxSize, data->m_size);
/* feed into free list */
- if (Buffer::m_freeList.size () > 1000)
+ if (data->m_size < g_maxSize ||
+ g_freeList.size () > 1000)
{
- Buffer::Deallocate (data);
- }
- else
+ BufferDeallocate (data);
+ }
+ else
{
- Buffer::m_freeList.push_back (data);
+ g_freeList.push_back (data);
}
}
-Buffer::BufferData *
-Buffer::Create (void)
+BufferData *
+Buffer::Create (uint32_t dataSize)
{
/* try to find a buffer correctly sized. */
- while (!Buffer::m_freeList.empty ())
+ g_nCreates++;
+ while (!g_freeList.empty ())
{
- struct Buffer::BufferData *data = Buffer::m_freeList.back ();
- Buffer::m_freeList.pop_back ();
- if (data->m_size >= (m_maxTotalAddStart + m_maxTotalAddEnd))
+ struct BufferData *data = g_freeList.back ();
+ g_freeList.pop_back ();
+ if (data->m_size >= dataSize)
{
- data->m_initialStart = m_maxTotalAddStart;
- data->m_dirtyStart = m_maxTotalAddStart;
- data->m_dirtySize = 0;
data->m_count = 1;
return data;
}
- Buffer::Deallocate (data);
+ BufferDeallocate (data);
}
- struct Buffer::BufferData *data = Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
- m_maxTotalAddStart);
+ g_nAllocs++;
+ struct BufferData *data = BufferAllocate (dataSize);
NS_ASSERT (data->m_count == 1);
return data;
}
#else
void
-Buffer::Recycle (struct Buffer::BufferData *data)
+Buffer::Recycle (struct BufferData *data)
{
- Buffer::Deallocate (data);
+ NS_ASSERT (data->m_count == 0);
+ BufferDeallocate (data);
}
-Buffer::BufferData *
-Buffer::Create (void)
+BufferData *
+Buffer::Create (uint32_t size)
{
- return Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
- m_maxTotalAddStart);
+ return BufferAllocate (size);
}
#endif
-}; // namespace ns3
+Buffer::Buffer ()
+{
+ Initialize (0);
+}
+Buffer::Buffer (uint32_t dataSize)
+{
+ Initialize (dataSize);
+}
-#include "ns3/assert.h"
+bool
+Buffer::CheckInternalState (void) const
+{
+ bool offsetsOk =
+ m_start <= m_zeroAreaStart &&
+ m_zeroAreaStart <= m_zeroAreaEnd &&
+ m_zeroAreaEnd <= m_end;
+ bool dirtyOk =
+ m_start >= m_data->m_dirtyStart &&
+ m_end <= m_data->m_dirtyEnd;
+ bool internalSizeOk = m_end - (m_zeroAreaEnd - m_zeroAreaStart) <= m_data->m_size &&
+ m_start <= m_data->m_size &&
+ m_zeroAreaStart <= m_data->m_size;
-namespace ns3 {
+ NS_ASSERT (offsetsOk);
+ NS_ASSERT (dirtyOk);
+ NS_ASSERT (internalSizeOk);
+ return m_data->m_count > 0 && offsetsOk && dirtyOk &&
+ internalSizeOk;
+}
-void
-Buffer::AddAtStart (uint32_t start)
+void
+Buffer::Initialize (uint32_t zeroSize)
{
- NS_ASSERT (m_start <= m_data->m_initialStart);
- bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
- if (m_start >= start && !isDirty)
- {
- /* enough space in the buffer and not dirty. */
- m_start -= start;
- m_size += start;
- }
- else if (m_size + start <= m_data->m_size && !isDirty)
+ m_data = Buffer::Create (0);
+#ifdef BUFFER_HEURISTICS
+ m_start = std::min (m_data->m_size, g_recommendedStart);
+ m_maxZeroAreaStart = m_start;
+#else
+ m_start = 0;
+#endif /* BUFFER_HEURISTICS */
+ m_zeroAreaStart = m_start;
+ m_zeroAreaEnd = m_zeroAreaStart + zeroSize;
+ m_end = m_zeroAreaEnd;
+ m_data->m_dirtyStart = m_start;
+ m_data->m_dirtyEnd = m_end;
+ NS_ASSERT (CheckInternalState ());
+}
+
+Buffer::Buffer (Buffer const&o)
+ : m_data (o.m_data),
+#ifdef BUFFER_HEURISTICS
+ m_maxZeroAreaStart (o.m_zeroAreaStart),
+#endif
+ m_zeroAreaStart (o.m_zeroAreaStart),
+ m_zeroAreaEnd (o.m_zeroAreaEnd),
+ m_start (o.m_start),
+ m_end (o.m_end)
+{
+ m_data->m_count++;
+ NS_ASSERT (CheckInternalState ());
+}
+
+Buffer &
+Buffer::operator = (Buffer const&o)
+{
+ NS_ASSERT (CheckInternalState ());
+ if (m_data != o.m_data)
{
- /* enough space but need to move data around to fit new data */
- memmove (m_data->m_data + start, GetStart (), m_size);
- NS_ASSERT (start > m_start);
- m_data->m_initialStart += start - m_start;
- m_start = 0;
- m_size += start;
- }
- else if (m_start < start)
- {
- /* not enough space in buffer */
- uint32_t newSize = m_size + start;
- struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
- memcpy (newData->m_data + start, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart + start;
- m_data->m_count--;
- if (m_data->m_count == 0)
- {
- Buffer::Deallocate (m_data);
- }
- m_data = newData;
- m_start = 0;
- m_size = newSize;
- }
- else
- {
- /* enough space in the buffer but it is dirty ! */
- NS_ASSERT (isDirty);
- struct Buffer::BufferData *newData = Buffer::Create ();
- memcpy (newData->m_data + m_start, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart;
+ // not assignment to self.
m_data->m_count--;
if (m_data->m_count == 0)
{
Recycle (m_data);
}
- m_data = newData;
+ m_data = o.m_data;
+ m_data->m_count++;
+ }
+ HEURISTICS (
+ g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart);
+ m_maxZeroAreaStart = o.m_maxZeroAreaStart;
+ );
+ m_zeroAreaStart = o.m_zeroAreaStart;
+ m_zeroAreaEnd = o.m_zeroAreaEnd;
+ m_start = o.m_start;
+ m_end = o.m_end;
+ NS_ASSERT (CheckInternalState ());
+ return *this;
+}
+
+Buffer::~Buffer ()
+{
+ HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart));
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ Recycle (m_data);
+ }
+}
+
+uint32_t
+Buffer::GetSize (void) const
+{
+ NS_ASSERT (CheckInternalState ());
+ return m_end - m_start;
+}
+
+Buffer::Iterator
+Buffer::Begin (void) const
+{
+ NS_ASSERT (CheckInternalState ());
+ return Buffer::Iterator (this);
+}
+Buffer::Iterator
+Buffer::End (void) const
+{
+ NS_ASSERT (CheckInternalState ());
+ return Buffer::Iterator (this, false);
+}
+
+uint32_t
+Buffer::GetInternalSize (void) const
+{
+ return m_zeroAreaStart - m_start + m_end - m_zeroAreaEnd;
+}
+uint32_t
+Buffer::GetInternalEnd (void) const
+{
+ return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
+}
+
+void
+Buffer::AddAtStart (uint32_t start)
+{
+ NS_ASSERT (CheckInternalState ());
+ bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
+ if (m_start >= start && !isDirty)
+ {
+ /* enough space in the buffer and not dirty.
+ * To add: |..|
+ * Before: |*****---------***|
+ * After: |***..---------***|
+ */
+ NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
m_start -= start;
- m_size += start;
+ HEURISTICS (g_nAddNoRealloc++);
}
+#if 0
+ // the following is an optimization
+ else if (m_start >= start)
+ {
+ struct BufferData *newData = Buffer::Create (m_data->m_size);
+ memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ Buffer::Recycle (m_data);
+ }
+ m_data = newData;
+
+ m_start -= start;
+ HEURISTICS (g_nAddRealloc++);
+ }
+ else
+ {
+ NS_ASSERT (m_start < start);
+#else
+ else
+ {
+#endif
+ uint32_t newSize = GetInternalSize () + start;
+ struct BufferData *newData = Buffer::Create (newSize);
+ memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ());
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ Buffer::Recycle (m_data);
+ }
+ m_data = newData;
+
+ int32_t delta = start - m_start;
+ m_start = 0;
+ m_zeroAreaStart += delta;
+ m_zeroAreaEnd += delta;
+ m_end += delta;
+
+ HEURISTICS (g_nAddRealloc++);
+ }
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
// update dirty area
m_data->m_dirtyStart = m_start;
- m_data->m_dirtySize = m_size;
- // update m_maxTotalAddStart
- uint32_t addedAtStart;
- if (m_data->m_initialStart > m_start)
- {
- addedAtStart = m_data->m_initialStart - m_start;
- }
- else
- {
- addedAtStart = 0;
- }
- if (addedAtStart > m_maxTotalAddStart)
- {
- m_maxTotalAddStart = addedAtStart;
- }
- TRACE ("start add="<<start<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ m_data->m_dirtyEnd = m_end;
+ LOG_INTERNAL_STATE ("add start=" << start << ", ");
+ NS_ASSERT (CheckInternalState ());
}
void
Buffer::AddAtEnd (uint32_t end)
{
- NS_ASSERT (m_start <= m_data->m_initialStart);
- bool isDirty = m_data->m_count > 1 &&
- m_start + m_size < m_data->m_dirtyStart + m_data->m_dirtySize;
- if (m_start + m_size + end <= m_data->m_size && !isDirty)
- {
- /* enough space in buffer and not dirty */
- m_size += end;
- }
- else if (m_size + end <= m_data->m_size && !isDirty)
+ NS_ASSERT (CheckInternalState ());
+ bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
+ if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
{
- /* enough space but need to move data around to fit the extra data */
- uint32_t newStart = m_data->m_size - (m_size + end);
- memmove (m_data->m_data + newStart, GetStart (), m_size);
- NS_ASSERT (newStart < m_start);
- m_data->m_initialStart -= m_start - newStart;
- m_start = newStart;
- m_size += end;
+ /* enough space in buffer and not dirty
+ * Add: |...|
+ * Before: |**----*****|
+ * After: |**----...**|
+ */
+ NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
+ m_end += end;
+
+ HEURISTICS (g_nAddNoRealloc++);
}
- else if (m_start + m_size + end > m_data->m_size)
+#if 0
+ // this is an optimization
+ else if (GetInternalEnd () + end > m_data->m_size)
{
- /* not enough space in buffer */
- uint32_t newSize = m_size + end;
- struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
- memcpy (newData->m_data, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart;
+ struct BufferData *newData = Buffer::Create (newSize);
+ memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
m_data->m_count--;
if (m_data->m_count == 0)
{
- Buffer::Deallocate (m_data);
+ Buffer::Recycle (m_data);
}
m_data = newData;
- m_size = newSize;
- m_start = 0;
- }
- else
+
+ m_end += end;
+ HEURISTICS (g_nAddRealloc++);
+ }
+#endif
+ else
{
- /* enough space in the buffer but it is dirty ! */
- NS_ASSERT (isDirty);
- struct Buffer::BufferData *newData = Buffer::Create ();
- memcpy (newData->m_data + m_start, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart;
+ uint32_t newSize = GetInternalSize () + end;
+ struct BufferData *newData = Buffer::Create (newSize);
+ memcpy (newData->m_data, m_data->m_data + m_start, GetInternalSize ());
m_data->m_count--;
if (m_data->m_count == 0)
{
- Recycle (m_data);
+ Buffer::Recycle (m_data);
}
m_data = newData;
- m_size += end;
+
+
+ m_zeroAreaStart -= m_start;
+ m_zeroAreaEnd -= m_start;
+ m_end -= m_start;
+ m_start = 0;
+
+ m_end += end;
+
+ HEURISTICS (g_nAddRealloc++);
}
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
// update dirty area
m_data->m_dirtyStart = m_start;
- m_data->m_dirtySize = m_size;
- // update m_maxTotalAddEnd
- uint32_t endLoc = m_start + m_size;
- uint32_t addedAtEnd;
- if (m_data->m_initialStart < endLoc)
- {
- addedAtEnd = endLoc - m_data->m_initialStart;
- }
- else
- {
- addedAtEnd = 0;
- }
- if (addedAtEnd > m_maxTotalAddEnd)
- {
- m_maxTotalAddEnd = addedAtEnd;
- }
- TRACE ("end add="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ m_data->m_dirtyEnd = m_end;
+ LOG_INTERNAL_STATE ("add end=" << end << ", ");
+ NS_ASSERT (CheckInternalState ());
}
void
Buffer::RemoveAtStart (uint32_t start)
{
- if (m_zeroAreaSize == 0)
+ NS_ASSERT (CheckInternalState ());
+ uint32_t newStart = m_start + start;
+ if (newStart <= m_zeroAreaStart)
+ {
+ /* only remove start of buffer
+ */
+ m_start = newStart;
+ }
+ else if (newStart <= m_zeroAreaEnd)
{
- if (m_size <= start)
- {
- m_start += m_size;
- m_size = 0;
- }
- else
- {
- m_start += start;
- m_size -= start;
- }
+ /* remove start of buffer _and_ start of zero area
+ */
+ uint32_t delta = newStart - m_zeroAreaStart;
+ m_start = m_zeroAreaStart;
+ m_zeroAreaEnd -= delta;
+ m_end -= delta;
}
+ else if (newStart <= m_end)
+ {
+ /* remove start of buffer, complete zero area, and part
+ * of end of buffer
+ */
+ NS_ASSERT (m_end >= start);
+ uint32_t zeroSize = m_zeroAreaEnd - m_zeroAreaStart;
+ m_start = newStart - zeroSize;
+ m_end -= zeroSize;
+ m_zeroAreaStart = m_start;
+ m_zeroAreaEnd = m_start;
+ }
else
{
- NS_ASSERT (m_data->m_initialStart >= m_start);
- uint32_t zeroStart = m_data->m_initialStart - m_start;
- uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
- uint32_t dataEnd = m_size + m_zeroAreaSize;
- if (start <= zeroStart)
- {
- /* only remove start of buffer */
- m_start += start;
- m_size -= start;
- }
- else if (start <= zeroEnd)
- {
- /* remove start of buffer _and_ start of zero area */
- m_start += zeroStart;
- uint32_t zeroDelta = start - zeroStart;
- m_zeroAreaSize -= zeroDelta;
- NS_ASSERT (zeroDelta <= start);
- m_size -= zeroStart;
- }
- else if (start <= dataEnd)
- {
- /* remove start of buffer, complete zero area, and part
- * of end of buffer */
- m_start += start - m_zeroAreaSize;
- m_size -= start - m_zeroAreaSize;
- m_zeroAreaSize = 0;
- }
- else
- {
- /* remove all buffer */
- m_start += m_size;
- m_size = 0;
- m_zeroAreaSize = 0;
- }
+ /* remove all buffer */
+ m_end -= m_zeroAreaEnd - m_zeroAreaStart;
+ m_start = m_end;
+ m_zeroAreaEnd = m_end;
+ m_zeroAreaStart = m_end;
}
- TRACE ("start remove="<<start<<", start="<<m_start<<", size="<<m_size<<
- ", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
+ LOG_INTERNAL_STATE ("rem start=" << start << ", ");
+ NS_ASSERT (CheckInternalState ());
}
void
Buffer::RemoveAtEnd (uint32_t end)
{
- if (m_zeroAreaSize == 0)
+ NS_ASSERT (CheckInternalState ());
+ uint32_t newEnd = m_end - std::min (end, m_end - m_start);
+ if (newEnd > m_zeroAreaEnd)
{
- if (m_size <= end)
- {
- m_size = 0;
- }
- else
- {
- m_size -= end;
- }
- }
- else
+ /* remove part of end of buffer */
+ m_end = newEnd;
+ }
+ else if (newEnd > m_zeroAreaStart)
+ {
+ /* remove end of buffer, part of zero area */
+ m_end = newEnd;
+ m_zeroAreaEnd = newEnd;
+ }
+ else if (newEnd > m_start)
{
- NS_ASSERT (m_data->m_initialStart >= m_start);
- uint32_t zeroStart = m_data->m_initialStart - m_start;
- uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
- uint32_t dataEnd = m_size + m_zeroAreaSize;
- NS_ASSERT (zeroStart <= m_size);
- NS_ASSERT (zeroEnd <= m_size + m_zeroAreaSize);
- if (dataEnd <= end)
- {
- /* remove all buffer */
- m_zeroAreaSize = 0;
- m_start += m_size;
- m_size = 0;
- }
- else if (dataEnd - zeroStart <= end)
- {
- /* remove end of buffer, zero area, part of start of buffer */
- NS_ASSERT (end >= m_zeroAreaSize);
- m_size -= end - m_zeroAreaSize;
- m_zeroAreaSize = 0;
- }
- else if (dataEnd - zeroEnd <= end)
- {
- /* remove end of buffer, part of zero area */
- uint32_t zeroDelta = end - (dataEnd - zeroEnd);
- m_zeroAreaSize -= zeroDelta;
- m_size -= end - zeroDelta;
- }
- else
- {
- /* remove part of end of buffer */
- m_size -= end;
- }
+ /* remove end of buffer, zero area, part of start of buffer */
+ m_end = newEnd;
+ m_zeroAreaEnd = newEnd;
+ m_zeroAreaStart = newEnd;
}
- TRACE ("end remove="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ else
+ {
+ /* remove all buffer */
+ m_end = m_start;
+ m_zeroAreaEnd = m_start;
+ m_zeroAreaStart = m_start;
+ }
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
+ LOG_INTERNAL_STATE ("rem end=" << end << ", ");
+ NS_ASSERT (CheckInternalState ());
}
Buffer
Buffer::CreateFragment (uint32_t start, uint32_t length) const
{
- uint32_t zeroStart = m_data->m_initialStart - m_start;
- uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
- if (m_zeroAreaSize != 0 &&
+ NS_ASSERT (CheckInternalState ());
+ uint32_t zeroStart = m_zeroAreaStart - m_start;
+ uint32_t zeroEnd = zeroStart + m_zeroAreaEnd;
+ if (m_zeroAreaEnd != 0 &&
start + length > zeroStart &&
start <= zeroEnd)
{
@@ -398,50 +555,442 @@
Buffer tmp = *this;
tmp.RemoveAtStart (start);
tmp.RemoveAtEnd (GetSize () - (start + length));
+ NS_ASSERT (CheckInternalState ());
return tmp;
}
+Buffer
+Buffer::CreateFullCopy (void) const
+{
+ NS_ASSERT (CheckInternalState ());
+ if (m_zeroAreaEnd != 0)
+ {
+ Buffer tmp;
+ tmp.AddAtStart (m_zeroAreaEnd - m_zeroAreaStart);
+ tmp.Begin ().WriteU8 (0, m_zeroAreaEnd - m_zeroAreaStart);
+ uint32_t dataStart = m_zeroAreaStart - m_start;
+ tmp.AddAtStart (dataStart);
+ tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
+ uint32_t dataEnd = m_end - m_zeroAreaEnd;
+ tmp.AddAtEnd (dataEnd);
+ Buffer::Iterator i = tmp.End ();
+ i.Prev (dataEnd);
+ i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
+ return tmp;
+ }
+ NS_ASSERT (CheckInternalState ());
+ return *this;
+}
+
void
Buffer::TransformIntoRealBuffer (void) const
{
- if (m_zeroAreaSize != 0)
- {
- NS_ASSERT (m_data->m_initialStart >= m_start);
- NS_ASSERT (m_size >= (m_data->m_initialStart - m_start));
- Buffer tmp;
- tmp.AddAtStart (m_zeroAreaSize);
- tmp.Begin ().WriteU8 (0, m_zeroAreaSize);
- uint32_t dataStart = m_data->m_initialStart - m_start;
- tmp.AddAtStart (dataStart);
- tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
- uint32_t dataEnd = m_size - (m_data->m_initialStart - m_start);
- tmp.AddAtEnd (dataEnd);
- Buffer::Iterator i = tmp.End ();
- i.Prev (dataEnd);
- i.Write (m_data->m_data+m_data->m_initialStart,dataEnd);
- *const_cast<Buffer *> (this) = tmp;
- }
+ NS_ASSERT (CheckInternalState ());
+ Buffer tmp = CreateFullCopy ();
+ *const_cast<Buffer *> (this) = tmp;
+ NS_ASSERT (CheckInternalState ());
}
uint8_t const*
Buffer::PeekData (void) const
{
+ NS_ASSERT (CheckInternalState ());
TransformIntoRealBuffer ();
+ NS_ASSERT (CheckInternalState ());
return m_data->m_data + m_start;
}
+/******************************************************
+ * The buffer iterator below.
+ ******************************************************/
+
+
+Buffer::Iterator::Iterator ()
+ : m_zeroStart (0),
+ m_zeroEnd (0),
+ m_dataStart (0),
+ m_dataEnd (0),
+ m_current (0),
+ m_data (0)
+{}
+Buffer::Iterator::Iterator (Buffer const*buffer)
+{
+ Construct (buffer);
+ m_current = m_dataStart;
+}
+Buffer::Iterator::Iterator (Buffer const*buffer, bool dummy)
+{
+ Construct (buffer);
+ m_current = m_dataEnd;
+}
+
+void
+Buffer::Iterator::Construct (const Buffer *buffer)
+{
+ m_zeroStart = buffer->m_zeroAreaStart;
+ m_zeroEnd = buffer->m_zeroAreaEnd;
+ m_dataStart = buffer->m_start;
+ m_dataEnd = buffer->m_end;
+ m_data = buffer->m_data->m_data;
+}
+
+void
+Buffer::Iterator::Next (void)
+{
+ NS_ASSERT (m_current + 1 <= m_dataEnd);
+ m_current++;
+}
+void
+Buffer::Iterator::Prev (void)
+{
+ NS_ASSERT (m_current >= 1);
+ m_current--;
+}
+void
+Buffer::Iterator::Next (uint32_t delta)
+{
+ NS_ASSERT (m_current + delta <= m_dataEnd);
+ m_current += delta;
+}
+void
+Buffer::Iterator::Prev (uint32_t delta)
+{
+ NS_ASSERT (m_current >= delta);
+ m_current -= delta;
+}
+uint32_t
+Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
+{
+ NS_ASSERT (m_data == o.m_data);
+ int32_t diff = m_current - o.m_current;
+ if (diff < 0)
+ {
+ return -diff;
+ }
+ else
+ {
+ return diff;
+ }
+}
+
+bool
+Buffer::Iterator::IsEnd (void) const
+{
+ return m_current == m_dataEnd;
+}
+bool
+Buffer::Iterator::IsStart (void) const
+{
+ return m_current == m_dataStart;
+}
+
+bool
+Buffer::Iterator::CheckNoZero (uint32_t start, uint32_t end) const
+{
+ bool ok = true;
+ for (uint32_t i = start; i < end; i++)
+ {
+ if (!Check (i))
+ {
+ ok = false;
+ }
+ }
+ return ok;
+}
+bool
+Buffer::Iterator::Check (uint32_t i) const
+{
+ return i >= m_dataStart &&
+ !(i >= m_zeroStart && i < m_zeroEnd) &&
+ i <= m_dataEnd;
+}
+void
+Buffer::Iterator::Write (Iterator start, Iterator end)
+{
+ NS_ASSERT (start.m_data == end.m_data);
+ NS_ASSERT (start.m_current <= end.m_current);
+ NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
+ NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
+ NS_ASSERT (m_data != start.m_data);
+ uint32_t size = end.m_current - start.m_current;
+ Iterator cur = start;
+ for (uint32_t i = 0; i < size; i++)
+ {
+ uint8_t data = cur.ReadU8 ();
+ WriteU8 (data);
+ }
+}
-}; // namespace ns3
+void
+Buffer::Iterator::WriteU16 (uint16_t data)
+{
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+}
+void
+Buffer::Iterator::WriteU32 (uint32_t data)
+{
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+}
+void
+Buffer::Iterator::WriteU64 (uint64_t data)
+{
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+}
+void
+Buffer::Iterator::WriteHtonU16 (uint16_t data)
+{
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 0) & 0xff);
+}
+void
+Buffer::Iterator::WriteHtonU32 (uint32_t data)
+{
+ WriteU8 ((data >> 24) & 0xff);
+ WriteU8 ((data >> 16) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 0) & 0xff);
+}
+void
+Buffer::Iterator::WriteHtonU64 (uint64_t data)
+{
+ WriteU8 ((data >> 56) & 0xff);
+ WriteU8 ((data >> 48) & 0xff);
+ WriteU8 ((data >> 40) & 0xff);
+ WriteU8 ((data >> 32) & 0xff);
+ WriteU8 ((data >> 24) & 0xff);
+ WriteU8 ((data >> 16) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 0) & 0xff);
+}
+void
+Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
+{
+ for (uint32_t i = 0; i < size; i++)
+ {
+ WriteU8 (buffer[i]);
+ }
+}
+
+uint16_t
+Buffer::Iterator::ReadU16 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint16_t data = byte1;
+ data <<= 8;
+ data |= byte0;
+
+ return data;
+}
+uint32_t
+Buffer::Iterator::ReadU32 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint8_t byte2 = ReadU8 ();
+ uint8_t byte3 = ReadU8 ();
+ uint32_t data = byte3;
+ data <<= 8;
+ data |= byte2;
+ data <<= 8;
+ data |= byte1;
+ data <<= 8;
+ data |= byte0;
+ return data;
+}
+uint64_t
+Buffer::Iterator::ReadU64 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint8_t byte2 = ReadU8 ();
+ uint8_t byte3 = ReadU8 ();
+ uint8_t byte4 = ReadU8 ();
+ uint8_t byte5 = ReadU8 ();
+ uint8_t byte6 = ReadU8 ();
+ uint8_t byte7 = ReadU8 ();
+ uint32_t data = byte7;
+ data <<= 8;
+ data |= byte6;
+ data <<= 8;
+ data |= byte5;
+ data <<= 8;
+ data |= byte4;
+ data <<= 8;
+ data |= byte3;
+ data <<= 8;
+ data |= byte2;
+ data <<= 8;
+ data |= byte1;
+ data <<= 8;
+ data |= byte0;
+
+ return data;
+}
+uint16_t
+Buffer::Iterator::ReadNtohU16 (void)
+{
+ uint16_t retval = 0;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ return retval;
+}
+uint32_t
+Buffer::Iterator::ReadNtohU32 (void)
+{
+ uint32_t retval = 0;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ return retval;
+}
+uint64_t
+Buffer::Iterator::ReadNtohU64 (void)
+{
+ uint64_t retval = 0;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ return retval;
+}
+void
+Buffer::Iterator::Read (uint8_t *buffer, uint32_t size)
+{
+ for (uint32_t i = 0; i < size; i++)
+ {
+ buffer[i] = ReadU8 ();
+ }
+}
+
+#ifndef BUFFER_USE_INLINE
+
+void
+Buffer::Iterator::WriteU8 (uint8_t data)
+{
+ if (m_current < m_dataStart)
+ {
+ // XXX trying to write outside of data area
+ NS_ASSERT (false);
+ }
+ else if (m_current < m_zeroStart)
+ {
+ m_data[m_current] = data;
+ m_current++;
+ }
+ else if (m_current < m_zeroEnd)
+ {
+ // XXX trying to write in zero area
+ NS_ASSERT (false);
+ }
+ else if (m_current < m_dataEnd)
+ {
+ m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
+ m_current++;
+ }
+ else
+ {
+ // XXX trying to write outside of data area
+ NS_ASSERT (false);
+ }
+}
+
+void
+Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
+{
+ for (uint32_t i = 0; i < len; i++)
+ {
+ WriteU8 (data);
+ }
+}
+
+uint8_t
+Buffer::Iterator::ReadU8 (void)
+{
+ if (m_current < m_dataStart)
+ {
+ // XXX trying to read from outside of data area
+ NS_ASSERT (false);
+ }
+ else if (m_current < m_zeroStart)
+ {
+ uint8_t data = m_data[m_current];
+ m_current++;
+ return data;
+ }
+ else if (m_current < m_zeroEnd)
+ {
+ m_current++;
+ return 0;
+ }
+ else if (m_current < m_dataEnd)
+ {
+ uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
+ m_current++;
+ return data;
+ }
+ else
+ {
+ // XXX trying to read from outside of data area
+ NS_ASSERT (false);
+ }
+ // to quiet compiler.
+ return 0;
+}
+
+#endif /* BUFFER_USE_INLINE */
+
+} // namespace ns3
#ifdef RUN_SELF_TESTS
#include "ns3/test.h"
+#include "ns3/random-variable.h"
#include <iomanip>
+
namespace ns3 {
class BufferTest: public Test {
@@ -501,14 +1050,14 @@
uint8_t bytes[] = {__VA_ARGS__}; \
if (!EnsureWrittenBytes (buffer, n , bytes)) \
{ \
- ok = false; \
+ result = false; \
} \
}
bool
BufferTest::RunTests (void)
{
- bool ok = true;
+ bool result = true;
Buffer buffer;
Buffer::Iterator i;
buffer.AddAtStart (6);
@@ -555,7 +1104,7 @@
i.Prev (2);
if (i.ReadNtohU16 () != 0xff00)
{
- ok = false;
+ result = false;
}
i.Prev (2);
i.WriteU16 (saved);
@@ -645,7 +1194,7 @@
buffer.RemoveAtEnd (8);
if (buffer.GetSize () != 0)
{
- ok = false;
+ result = false;
}
buffer = Buffer (6);
@@ -663,14 +1212,51 @@
i.Prev (4);
i.WriteU8 (1, 4);
- return ok;
+ buffer = Buffer (1);
+ buffer.AddAtEnd (100);
+ i = buffer.End ();
+ i.Prev (100);
+ i.WriteU8 (1, 100);
+
+#if 0
+ buffer = Buffer (10);
+ ENSURE_WRITTEN_BYTES (buffer, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ buffer.Begin ().WriteU8 (1);
+ ENSURE_WRITTEN_BYTES (buffer, 10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+#endif
+
+ // Bug #54
+ {
+ const uint32_t actualSize = 72602;
+ const uint32_t chunkSize = 67624;
+ UniformVariable bytesRng (0, 256);
+
+ Buffer inputBuffer;
+ Buffer outputBuffer;
+
+ inputBuffer.AddAtEnd (actualSize);
+ {
+ Buffer::Iterator iter = inputBuffer.Begin ();
+ for (uint32_t i = 0; i < actualSize; i++)
+ iter.WriteU8 (static_cast<uint8_t> (bytesRng.GetValue ()));
+ }
+
+ outputBuffer.AddAtEnd (chunkSize);
+ Buffer::Iterator iter = outputBuffer.End ();
+ iter.Prev (chunkSize);
+ iter.Write (inputBuffer.PeekData (), chunkSize);
+
+ NS_TEST_ASSERT (memcmp (inputBuffer.PeekData (), outputBuffer.PeekData (), chunkSize) == 0);
+ }
+
+ return result;
}
static BufferTest gBufferTest;
-}; // namespace ns3
+} // namespace ns3
#endif /* RUN_SELF_TESTS */
--- a/src/common/buffer.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/buffer.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2005,2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2005,2006,2007 INRIA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +23,16 @@
#include <stdint.h>
#include <vector>
+#define BUFFER_HEURISTICS 1
+#define BUFFER_USE_INLINE 1
+
+
+#ifdef BUFFER_USE_INLINE
+#define BUFFER_INLINE inline
+#else
+#define BUFFER_INLINE
+#endif
+
namespace ns3 {
/**
@@ -36,6 +45,51 @@
* by creating new Buffers of the maximum size ever used.
* The correct maximum size is learned at runtime during use by
* recording the maximum size of each packet.
+ *
+ * \internal
+ * The implementation of the Buffer class uses a COW (Copy On Write)
+ * technique to ensure that the underlying data buffer which holds
+ * the data bytes is shared among a lot of Buffer instances despite
+ * data being added or removed from them.
+ *
+ * When multiple Buffer instances hold a reference to the same
+ * underlying BufferData object, they must be able to detect when
+ * the operation they want to perform should trigger a copy of the
+ * BufferData. If the BufferData::m_count field is one, it means that
+ * there exist only one instance of Buffer which references the
+ * BufferData instance so, it is safe to modify it. It is also
+ * safe to modify the content of a BufferData if the modification
+ * falls outside of the "dirty area" defined by the BufferData.
+ * In every other case, the BufferData must be copied before
+ * being modified.
+ *
+ * To understand the way the Buffer::Add and Buffer::Remove methods
+ * work, you first need to understand the "virtual offsets" used to
+ * keep track of the content of buffers. Each Buffer instance
+ * contains real data bytes in its BufferData instance but it also
+ * contains "virtual zero data" which typically is used to represent
+ * application-level payload. No memory is allocated to store the
+ * zero bytes of application-level payload unless the user fragments
+ * a Buffer: this application-level payload is kept track of with
+ * a pair of integers which describe where in the buffer content
+ * the "virtual zero area" starts and ends.
+ *
+ * ***: unused bytes
+ * xxx: bytes "added" at the front of the zero area
+ * ...: bytes "added" at the back of the zero area
+ * 000: virtual zero bytes
+ *
+ * Real byte buffer: |********xxxxxxxxxxxx.........*****|
+ * |--------^ m_start
+ * |-------------------^ m_zeroAreaStart
+ * |-----------------------------^ m_end - (m_zeroAreaEnd - m_zeroAreaStart)
+ * virtual byte buffer: |xxxxxxxxxxxx0000000000000.........|
+ * |--------^ m_start
+ * |--------------------^ m_zeroAreaStart
+ * |---------------------------------^ m_zeroAreaEnd
+ * |------------------------------------------^ m_end
+ *
+ * A simple state invariant is that m_start <= m_zeroStart <= m_zeroEnd <= m_end
*/
class Buffer {
public:
@@ -44,23 +98,23 @@
*/
class Iterator {
public:
- inline Iterator ();
+ Iterator ();
/**
* go forward by one byte
*/
- inline void Next (void);
+ void Next (void);
/**
* go backward by one byte
*/
- inline void Prev (void);
+ void Prev (void);
/**
* \param delta number of bytes to go forward
*/
- inline void Next (uint32_t delta);
+ void Next (uint32_t delta);
/**
* \param delta number of bytes to go backward
*/
- inline void Prev (uint32_t delta);
+ void Prev (uint32_t delta);
/**
* \param o the second iterator
* \return number of bytes included between the two iterators
@@ -69,18 +123,18 @@
* to the same underlying buffer. Debug builds ensure
* this with an assert.
*/
- inline int32_t GetDistanceFrom (Iterator const &o) const;
+ uint32_t GetDistanceFrom (Iterator const &o) const;
/**
* \return true if this iterator points to the end of the byte array.
* false otherwise.
*/
- inline bool IsEnd (void) const;
+ bool IsEnd (void) const;
/**
* \return true if this iterator points to the start of the byte array.
* false otherwise.
*/
- inline bool IsStart (void) const;
+ bool IsStart (void) const;
/**
* \param data data to write in buffer
@@ -88,7 +142,7 @@
* Write the data in buffer and avance the iterator position
* by one byte.
*/
- inline void WriteU8 (uint8_t data);
+ BUFFER_INLINE void WriteU8 (uint8_t data);
/**
* \param data data to write in buffer
* \param len number of times data must be written in buffer
@@ -96,7 +150,7 @@
* Write the data in buffer len times and avance the iterator position
* by len byte.
*/
- inline void WriteU8 (uint8_t data, uint32_t len);
+ BUFFER_INLINE void WriteU8 (uint8_t data, uint32_t len);
/**
* \param data data to write in buffer
*
@@ -106,7 +160,7 @@
* return exactly what we wrote with writeU16 if the program
* is run on the same machine.
*/
- inline void WriteU16 (uint16_t data);
+ void WriteU16 (uint16_t data);
/**
* \param data data to write in buffer
*
@@ -116,7 +170,7 @@
* return exactly what we wrote with writeU32 if the program
* is run on the same machine.
*/
- inline void WriteU32 (uint32_t data);
+ void WriteU32 (uint32_t data);
/**
* \param data data to write in buffer
*
@@ -126,7 +180,7 @@
* return exactly what we wrote with writeU64 if the program
* is run on the same machine.
*/
- inline void WriteU64 (uint64_t data);
+ void WriteU64 (uint64_t data);
/**
* \param data data to write in buffer
*
@@ -134,7 +188,7 @@
* by two bytes. The data is written in network order and the
* input data is expected to be in host order.
*/
- inline void WriteHtonU16 (uint16_t data);
+ void WriteHtonU16 (uint16_t data);
/**
* \param data data to write in buffer
*
@@ -142,7 +196,7 @@
* by four bytes. The data is written in network order and the
* input data is expected to be in host order.
*/
- inline void WriteHtonU32 (uint32_t data);
+ void WriteHtonU32 (uint32_t data);
/**
* \param data data to write in buffer
*
@@ -150,7 +204,7 @@
* by eight bytes. The data is written in network order and the
* input data is expected to be in host order.
*/
- inline void WriteHtonU64 (uint64_t data);
+ void WriteHtonU64 (uint64_t data);
/**
* \param buffer a byte buffer to copy in the internal buffer.
* \param size number of bytes to copy.
@@ -158,7 +212,7 @@
* Write the data in buffer and avance the iterator position
* by size bytes.
*/
- inline void Write (uint8_t const*buffer, uint16_t size);
+ void Write (uint8_t const*buffer, uint32_t size);
/**
* \param start the start of the data to copy
* \param end the end of the data to copy
@@ -170,7 +224,7 @@
* we do to avoid overlapping copies. This is enforced
* in debug builds by asserts.
*/
- inline void Write (Iterator start, Iterator end);
+ void Write (Iterator start, Iterator end);
/**
* \return the byte read in the buffer.
@@ -178,7 +232,7 @@
* Read data and advance the Iterator by the number of bytes
* read.
*/
- inline uint8_t ReadU8 (void);
+ BUFFER_INLINE uint8_t ReadU8 (void);
/**
* \return the two bytes read in the buffer.
*
@@ -186,7 +240,7 @@
* read.
* The data is read in the format written by writeU16.
*/
- inline uint16_t ReadU16 (void);
+ uint16_t ReadU16 (void);
/**
* \return the four bytes read in the buffer.
*
@@ -194,7 +248,7 @@
* read.
* The data is read in the format written by writeU32.
*/
- inline uint32_t ReadU32 (void);
+ uint32_t ReadU32 (void);
/**
* \return the eight bytes read in the buffer.
*
@@ -202,7 +256,7 @@
* read.
* The data is read in the format written by writeU64.
*/
- inline uint64_t ReadU64 (void);
+ uint64_t ReadU64 (void);
/**
* \return the two bytes read in the buffer.
*
@@ -210,7 +264,7 @@
* read.
* The data is read in network format and return in host format.
*/
- inline uint16_t ReadNtohU16 (void);
+ uint16_t ReadNtohU16 (void);
/**
* \return the four bytes read in the buffer.
*
@@ -218,7 +272,7 @@
* read.
* The data is read in network format and return in host format.
*/
- inline uint32_t ReadNtohU32 (void);
+ uint32_t ReadNtohU32 (void);
/**
* \return the eight bytes read in the buffer.
*
@@ -226,7 +280,7 @@
* read.
* The data is read in network format and return in host format.
*/
- inline uint64_t ReadNtohU64 (void);
+ uint64_t ReadNtohU64 (void);
/**
* \param buffer buffer to copy data into
* \param size number of bytes to copy
@@ -235,22 +289,45 @@
* input buffer and avance the Iterator by the number of
* bytes read.
*/
- inline void Read (uint8_t *buffer, uint16_t size);
+ void Read (uint8_t *buffer, uint32_t size);
private:
friend class Buffer;
- inline Iterator (Buffer const*buffer, uint32_t m_current);
- inline uint32_t GetIndex (uint32_t n);
+ Iterator (Buffer const*buffer);
+ Iterator (Buffer const*buffer, bool);
+ void Construct (const Buffer *buffer);
+ bool CheckNoZero (uint32_t start, uint32_t end) const;
+ bool Check (uint32_t i) const;
+
+ /* offset in virtual bytes from the start of the data buffer to the
+ * start of the "virtual zero area".
+ */
uint32_t m_zeroStart;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * end of the "virtual zero area".
+ */
uint32_t m_zeroEnd;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * start of the data which can be read by this iterator
+ */
+ uint32_t m_dataStart;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * end of the data which can be read by this iterator
+ */
uint32_t m_dataEnd;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * current position represented by this iterator.
+ */
uint32_t m_current;
+ /* a pointer to the underlying byte buffer. All offsets are relative
+ * to this pointer.
+ */
uint8_t *m_data;
};
/**
* \return the number of bytes stored in this buffer.
*/
- inline uint32_t GetSize (void) const;
+ uint32_t GetSize (void) const;
/**
* \return a pointer to the start of the internal
@@ -313,393 +390,135 @@
* \return an Iterator which points to the
* start of this Buffer.
*/
- inline Buffer::Iterator Begin (void) const;
+ Buffer::Iterator Begin (void) const;
/**
* \return an Iterator which points to the
* end of this Buffer.
*/
- inline Buffer::Iterator End (void) const;
+ Buffer::Iterator End (void) const;
+
+ Buffer CreateFullCopy (void) const;
- inline Buffer (Buffer const &o);
- inline Buffer &operator = (Buffer const &o);
- inline Buffer ();
- inline Buffer (uint32_t dataSize);
- inline ~Buffer ();
+ Buffer (Buffer const &o);
+ Buffer &operator = (Buffer const &o);
+ Buffer ();
+ Buffer (uint32_t dataSize);
+ ~Buffer ();
private:
- struct BufferData {
- uint32_t m_count;
- uint32_t m_size;
- uint32_t m_initialStart;
- uint32_t m_dirtyStart;
- uint32_t m_dirtySize;
- uint8_t m_data[1];
- };
- typedef std::vector<struct Buffer::BufferData*> BufferDataList;
- inline uint8_t *GetStart (void) const;
void TransformIntoRealBuffer (void) const;
- static void Recycle (struct Buffer::BufferData *data);
- static struct Buffer::BufferData *Create (void);
- static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start);
- static void Deallocate (struct Buffer::BufferData *data);
+ bool CheckInternalState (void) const;
+ void Initialize (uint32_t zeroSize);
+ uint32_t GetInternalSize (void) const;
+ uint32_t GetInternalEnd (void) const;
+ static void Recycle (struct BufferData *data);
+ static struct BufferData *Create (uint32_t size);
- static BufferDataList m_freeList;
- static uint32_t m_maxTotalAddStart;
- static uint32_t m_maxTotalAddEnd;
-
+ /* This structure is described in the buffer.cc file.
+ */
struct BufferData *m_data;
- uint32_t m_zeroAreaSize;
+#ifdef BUFFER_HEURISTICS
+ /* keep track of the maximum value of m_zeroAreaStart across
+ * the lifetime of a Buffer instance. This variable is used
+ * purely as a source of information for the heuristics which
+ * decide on the position of the zero area in new buffers.
+ * It is read from the Buffer destructor to update the global
+ * heuristic data and these global heuristic data are used from
+ * the Buffer constructor to choose an initial value for
+ * m_zeroAreaStart.
+ * It is possible to disable all these heuristics by undefining the
+ * BUFFER_HEURISTICS macro at the top of buffer.h
+ */
+ uint32_t m_maxZeroAreaStart;
+#endif /* BUFFER_HEURISTICS */
+ /* offset to the start of the virtual zero area from the start
+ * of m_data->m_data
+ */
+ uint32_t m_zeroAreaStart;
+ /* offset to the end of the virtual zero area from the start
+ * of m_data->m_data
+ */
+ uint32_t m_zeroAreaEnd;
+ /* offset to the start of the data referenced by this Buffer
+ * instance from the start of m_data->m_data
+ */
uint32_t m_start;
- uint32_t m_size;
+ /* offset to the end of the data referenced by this Buffer
+ * instance from the start of m_data->m_data
+ */
+ uint32_t m_end;
};
-}; // namespace ns3
-
+} // namespace ns3
-/**************************************************
- Start of implementation of methods which
- need to be inline for performance reasons.
- *************************************************/
+#ifdef BUFFER_USE_INLINE
#include "ns3/assert.h"
namespace ns3 {
-Buffer::Buffer ()
- : m_data (Buffer::Create ()),
- m_zeroAreaSize (0),
- m_start (m_maxTotalAddStart),
- m_size (0)
-{
- if (m_start > m_data->m_size)
- {
- m_start = 0;
- }
- NS_ASSERT (m_start <= m_data->m_size);
-}
-
-Buffer::Buffer (uint32_t dataSize)
- : m_data (Buffer::Create ()),
- m_zeroAreaSize (dataSize),
- m_start (m_maxTotalAddStart),
- m_size (0)
-{
- if (m_start > m_data->m_size)
- {
- m_start = 0;
- }
- NS_ASSERT (m_start <= m_data->m_size);
-}
-
-
-Buffer::Buffer (Buffer const&o)
- : m_data (o.m_data),
- m_zeroAreaSize (o.m_zeroAreaSize),
- m_start (o.m_start),
- m_size (o.m_size)
-{
- m_data->m_count++;
- NS_ASSERT (m_start <= m_data->m_size);
-}
-
-Buffer &
-Buffer::operator = (Buffer const&o)
+void
+Buffer::Iterator::WriteU8 (uint8_t data)
{
- if (m_data != o.m_data)
- {
- // not assignment to self.
- m_data->m_count--;
- if (m_data->m_count == 0)
- {
- Recycle (m_data);
- }
- m_data = o.m_data;
- m_data->m_count++;
- }
- m_zeroAreaSize = o.m_zeroAreaSize;
- m_start = o.m_start;
- m_size = o.m_size;
- NS_ASSERT (m_start <= m_data->m_size);
- return *this;
-}
-
-Buffer::~Buffer ()
-{
- m_data->m_count--;
- if (m_data->m_count == 0)
- {
- Recycle (m_data);
- }
-}
-
-
-uint8_t *
-Buffer::GetStart (void) const
-{
- return m_data->m_data + m_start;
-}
-
-uint32_t
-Buffer::GetSize (void) const
-{
- return m_size + m_zeroAreaSize;
-}
-
-Buffer::Iterator
-Buffer::Begin (void) const
-{
- return Buffer::Iterator (this, 0);
-}
-Buffer::Iterator
-Buffer::End (void) const
-{
- return Buffer::Iterator (this, GetSize ());
-}
-
+ NS_ASSERT (Check (m_current));
-Buffer::Iterator::Iterator ()
- : m_zeroStart (0),
- m_zeroEnd (0),
- m_dataEnd (0),
- m_current (0),
- m_data (0)
-{}
-Buffer::Iterator::Iterator (Buffer const*buffer, uint32_t current)
- : m_zeroStart (buffer->m_data->m_initialStart-buffer->m_start),
- m_zeroEnd (m_zeroStart+buffer->m_zeroAreaSize),
- m_dataEnd (buffer->GetSize ()),
- m_current (current),
- m_data (buffer->m_data->m_data+buffer->m_start)
-{}
-
-void
-Buffer::Iterator::Next (void)
-{
- NS_ASSERT (m_current + 1 <= m_dataEnd);
- m_current++;
-}
-void
-Buffer::Iterator::Prev (void)
-{
- NS_ASSERT (m_current >= 1);
- m_current--;
-}
-void
-Buffer::Iterator::Next (uint32_t delta)
-{
- NS_ASSERT (m_current + delta <= m_dataEnd);
- m_current += delta;
-}
-void
-Buffer::Iterator::Prev (uint32_t delta)
-{
- NS_ASSERT (m_current >= delta);
- m_current -= delta;
-}
-int32_t
-Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
-{
- NS_ASSERT (m_data == o.m_data);
- int32_t start = m_current;
- int32_t end = o.m_current;
- return end - start;
-}
-
-bool
-Buffer::Iterator::IsEnd (void) const
-{
- return m_current == m_dataEnd;
-}
-bool
-Buffer::Iterator::IsStart (void) const
-{
- return m_current == 0;
-}
-
-uint32_t
-Buffer::Iterator::GetIndex (uint32_t n)
-{
- NS_ASSERT (
- (m_current + n <= m_dataEnd) &&
- ((m_current + n <= m_zeroStart) ||
- (m_current >= m_zeroEnd) ||
- m_zeroStart == m_zeroEnd)
- );
- uint32_t index;
- if (m_current < m_zeroStart)
+ if (m_current < m_zeroStart)
{
- index = m_current;
- }
- else
- {
- index = m_current - (m_zeroEnd-m_zeroStart);
+ m_data[m_current] = data;
+ m_current++;
}
- return index;
-}
-
-
-void
-Buffer::Iterator::Write (Iterator start, Iterator end)
-{
- NS_ASSERT (start.m_data == end.m_data);
- NS_ASSERT (start.m_current <= end.m_current);
- NS_ASSERT (m_data != start.m_data);
- uint32_t size = end.m_current - start.m_current;
- uint8_t *src = start.m_data + start.GetIndex (size);
- uint8_t *dest = m_data + GetIndex (size);
- memcpy (dest, src, size);
- m_current += size;
+ else
+ {
+ m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
+ m_current++;
+ }
}
void
Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
{
- uint8_t *current = m_data + GetIndex (len);
- memset (current, data, len);
- m_current += len;
-}
-void
-Buffer::Iterator::WriteU8 (uint8_t data)
-{
- m_data[GetIndex (1)] = data;
- m_current++;
-}
-void
-Buffer::Iterator::WriteU16 (uint16_t data)
-{
- uint16_t *buffer = (uint16_t *)(m_data + GetIndex (2));
- *buffer = data;
- m_current += 2;
-}
-void
-Buffer::Iterator::WriteU32 (uint32_t data)
-{
- uint32_t *buffer = (uint32_t *)(m_data + GetIndex (4));
- *buffer = data;
- m_current += 4;
-}
-void
-Buffer::Iterator::WriteU64 (uint64_t data)
-{
- uint64_t *buffer = (uint64_t *)(m_data + GetIndex (8));
- *buffer = data;
- m_current += 8;
-}
-void
-Buffer::Iterator::WriteHtonU16 (uint16_t data)
-{
- uint8_t *current = m_data + GetIndex (2);
- *(current+0) = (data >> 8) & 0xff;
- *(current+1) = (data >> 0) & 0xff;
- m_current += 2;
-}
-void
-Buffer::Iterator::WriteHtonU32 (uint32_t data)
-{
- uint8_t *current = m_data + GetIndex (4);
- *(current+0) = (data >> 24) & 0xff;
- *(current+1) = (data >> 16) & 0xff;
- *(current+2) = (data >> 8) & 0xff;
- *(current+3) = (data >> 0) & 0xff;
- m_current += 4;
-}
-void
-Buffer::Iterator::WriteHtonU64 (uint64_t data)
-{
- uint8_t *current = m_data + GetIndex (8);
- *(current+0) = (data >> 56) & 0xff;
- *(current+1) = (data >> 48) & 0xff;
- *(current+2) = (data >> 40) & 0xff;
- *(current+3) = (data >> 32) & 0xff;
- *(current+4) = (data >> 24) & 0xff;
- *(current+5) = (data >> 16) & 0xff;
- *(current+6) = (data >> 8) & 0xff;
- *(current+7) = (data >> 0) & 0xff;
- m_current += 8;
-}
-void
-Buffer::Iterator::Write (uint8_t const*buffer, uint16_t size)
-{
- uint8_t *current = m_data + GetIndex (size);
- memcpy (current, buffer, size);
- m_current += size;
+ NS_ASSERT (CheckNoZero (m_current, m_current + len));
+ if (m_current <= m_zeroStart)
+ {
+ memset (&(m_data[m_current]), data, len);
+ m_current += len;
+ }
+ else
+ {
+ uint8_t *buffer = &m_data[m_current - (m_zeroEnd-m_zeroStart)];
+ memset (buffer, data, len);
+ m_current += len;
+ }
}
uint8_t
Buffer::Iterator::ReadU8 (void)
{
- uint8_t data = m_data[GetIndex(1)];
- m_current++;
- return data;
-}
-uint16_t
-Buffer::Iterator::ReadU16 (void)
-{
- uint16_t *buffer = reinterpret_cast<uint16_t *>(m_data + GetIndex (2));
- m_current += 2;
- return *buffer;
-}
-uint32_t
-Buffer::Iterator::ReadU32 (void)
-{
- uint32_t *buffer = reinterpret_cast<uint32_t *>(m_data + GetIndex (4));
- m_current += 4;
- return *buffer;
-}
-uint64_t
-Buffer::Iterator::ReadU64 (void)
-{
- uint64_t *buffer = reinterpret_cast<uint64_t *>(m_data + GetIndex (8));
- m_current += 8;
- return *buffer;
-}
-uint16_t
-Buffer::Iterator::ReadNtohU16 (void)
-{
- uint8_t *current = m_data + GetIndex (2);
- uint16_t retval = 0;
- retval |= static_cast<uint16_t> (current[0]) << 8;
- retval |= static_cast<uint16_t> (current[1]) << 0;
- m_current += 2;
- return retval;
-}
-uint32_t
-Buffer::Iterator::ReadNtohU32 (void)
-{
- uint8_t *current = m_data + GetIndex (4);
- uint32_t retval = 0;
- retval |= static_cast<uint32_t> (current[0]) << 24;
- retval |= static_cast<uint32_t> (current[1]) << 16;
- retval |= static_cast<uint32_t> (current[2]) << 8;
- retval |= static_cast<uint32_t> (current[3]) << 0;
- m_current += 4;
- return retval;
-}
-uint64_t
-Buffer::Iterator::ReadNtohU64 (void)
-{
- uint8_t *current = m_data + GetIndex (8);
- uint64_t retval = 0;
- retval |= static_cast<uint64_t> (current[0]) << 56;
- retval |= static_cast<uint64_t> (current[1]) << 48;
- retval |= static_cast<uint64_t> (current[2]) << 40;
- retval |= static_cast<uint64_t> (current[3]) << 32;
- retval |= static_cast<uint64_t> (current[4]) << 24;
- retval |= static_cast<uint64_t> (current[5]) << 16;
- retval |= static_cast<uint64_t> (current[6]) << 8;
- retval |= static_cast<uint64_t> (current[7]) << 0;
- m_current += 8;
- return retval;
-}
-void
-Buffer::Iterator::Read (uint8_t *buffer, uint16_t size)
-{
- uint8_t *current = m_data + GetIndex (size);
- memcpy (buffer, current, size);
- m_current += size;
+ NS_ASSERT (m_current >= m_dataStart &&
+ m_current <= m_dataEnd);
+
+ if (m_current < m_zeroStart)
+ {
+ uint8_t data = m_data[m_current];
+ m_current++;
+ return data;
+ }
+ else if (m_current < m_zeroEnd)
+ {
+ m_current++;
+ return 0;
+ }
+ else
+ {
+ uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
+ m_current++;
+ return data;
+ }
}
-}; // namespace ns3
+} // namespace ns3
+
+#endif /* BUFFER_USE_INLINE */
#endif /* BUFFER_H */
--- a/src/common/callback-trace-source.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "callback-trace-source.h"
-#include "ns3/test.h"
-
-namespace ns3 {
-
-class CallbackTraceSourceTest : public Test
-{
-public:
- CallbackTraceSourceTest ();
- virtual ~CallbackTraceSourceTest ();
- virtual bool RunTests (void);
-private:
- void CbOne (TraceContext const &context, uint8_t a, double b);
- void CbTwo (TraceContext const &context, uint8_t a, double b);
-
- bool m_one;
- bool m_two;
-};
-
-CallbackTraceSourceTest::CallbackTraceSourceTest ()
- : Test ("CallbackTraceSource")
-{}
-CallbackTraceSourceTest::~CallbackTraceSourceTest ()
-{}
-void
-CallbackTraceSourceTest::CbOne (TraceContext const &context, uint8_t a, double b)
-{
- m_one = true;
-}
-void
-CallbackTraceSourceTest::CbTwo (TraceContext const &context, uint8_t a, double b)
-{
- m_two = true;
-}
-bool
-CallbackTraceSourceTest::RunTests (void)
-{
- bool ok = true;
- TraceContext ctx;
-
- CallbackTraceSource<uint8_t,double> trace;
- trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
- trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
- m_one = false;
- m_two = false;
- trace (1, 2);
- if (!m_one || !m_two)
- {
- ok = false;
- }
- trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this));
- m_one = false;
- m_two = false;
- trace (1, 2);
- if (m_one || !m_two)
- {
- ok = false;
- }
- trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this));
- m_one = false;
- m_two = false;
- trace (1, 2);
- if (m_one || m_two)
- {
- ok = false;
- }
-
- return ok;
-}
-
-CallbackTraceSourceTest g_callbackTraceTest;
-
-
-
-}//namespace ns3
--- a/src/common/callback-trace-source.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005,2006,2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef CALLBACK_TRACE_H
-#define CALLBACK_TRACE_H
-
-#include <list>
-#include "ns3/callback.h"
-#include "ns3/fatal-error.h"
-#include "trace-context.h"
-
-namespace ns3 {
-
-
-/**
- * \brief log arbitrary number of parameters to a matching ns3::Callback
- * \ingroup lowleveltracing
- *
- * Whenever operator () is invoked on this class, the call and its arguments
- * are forwarded to the internal matching ns3::Callback.
- */
-template<typename T1 = empty, typename T2 = empty,
- typename T3 = empty, typename T4 = empty>
-class CallbackTraceSource {
-public:
- CallbackTraceSource ();
- void AddCallback (CallbackBase const & callback, TraceContext const & context);
- void RemoveCallback (CallbackBase const & callback);
- void operator() (void);
- void operator() (T1 a1);
- void operator() (T1 a1, T2 a2);
- void operator() (T1 a1, T2 a2, T3 a3);
- void operator() (T1 a1, T2 a2, T3 a3, T4 a4);
-
-private:
- typedef std::list<Callback<void,TraceContext const &,T1,T2,T3,T4> > CallbackList;
- TraceContext m_context;
- CallbackList m_callbackList;
-};
-
-}; // namespace ns3
-
-// implementation below.
-
-namespace ns3 {
-
-template<typename T1, typename T2,
- typename T3, typename T4>
-CallbackTraceSource<T1,T2,T3,T4>::CallbackTraceSource ()
- : m_callbackList ()
-{}
-template<typename T1, typename T2,
- typename T3, typename T4>
-void
-CallbackTraceSource<T1,T2,T3,T4>::AddCallback (CallbackBase const & callback,
- TraceContext const &context)
-{
- Callback<void,TraceContext const &,T1,T2,T3,T4> cb;
- cb.Assign (callback);
- m_context.Add (context);
- m_callbackList.push_back (cb);
-}
-template<typename T1, typename T2,
- typename T3, typename T4>
-void
-CallbackTraceSource<T1,T2,T3,T4>::RemoveCallback (CallbackBase const & callback)
-{
- for (typename CallbackList::iterator i = m_callbackList.begin ();
- i != m_callbackList.end (); /* empty */)
- {
- if ((*i).IsEqual (callback))
- {
- i = m_callbackList.erase (i);
- }
- else
- {
- i++;
- }
- }
-}
-template<typename T1, typename T2,
- typename T3, typename T4>
-void
-CallbackTraceSource<T1,T2,T3,T4>::operator() (void)
-{
- for (typename CallbackList::iterator i = m_callbackList.begin ();
- i != m_callbackList.end (); i++)
- {
- (*i) (m_context);
- }
-}
-template<typename T1, typename T2,
- typename T3, typename T4>
-void
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1)
-{
- for (typename CallbackList::iterator i = m_callbackList.begin ();
- i != m_callbackList.end (); i++)
- {
- (*i) (m_context, a1);
- }
-}
-template<typename T1, typename T2,
- typename T3, typename T4>
-void
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2)
-{
- for (typename CallbackList::iterator i = m_callbackList.begin ();
- i != m_callbackList.end (); i++)
- {
- (*i) (m_context, a1, a2);
- }
-}
-template<typename T1, typename T2,
- typename T3, typename T4>
-void
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3)
-{
- for (typename CallbackList::iterator i = m_callbackList.begin ();
- i != m_callbackList.end (); i++)
- {
- (*i) (m_context, a1, a2, a3);
- }
-}
-template<typename T1, typename T2,
- typename T3, typename T4>
-void
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3, T4 a4)
-{
- for (typename CallbackList::iterator i = m_callbackList.begin ();
- i != m_callbackList.end (); i++)
- {
- (*i) (m_context, a1, a2, a3, a4);
- }
-}
-
-}//namespace ns3
-
-#endif /* CALLBACK_TRACE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,117 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "chunk-registry.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+ChunkRegistry::InfoVector *
+ChunkRegistry::GetInfoVector (void)
+{
+ static InfoVector vec;
+ return &vec;
+}
+
+std::string
+ChunkRegistry::GetUidStringFromUid (uint32_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.uidString;
+}
+uint32_t
+ChunkRegistry::GetUidFromUidString (std::string uidString)
+{
+ uint32_t uid = 1;
+ InfoVector *vec = GetInfoVector ();
+ for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<<
+ "You could try calling NS_HEADER_ENSURE_REGISTER somewhere.");
+ return 0;
+}
+
+uint8_t *
+ChunkRegistry::GetStaticInstance (uint32_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.getStaticInstance ();
+}
+bool
+ChunkRegistry::IsHeader (uint32_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.isHeader;
+}
+bool
+ChunkRegistry::IsTrailer (uint32_t uid)
+{
+ return !IsHeader (uid);
+}
+uint32_t
+ChunkRegistry::Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.deserialize (instance, i);
+}
+void
+ChunkRegistry::Print (uint32_t uid, uint8_t *instance, std::ostream &os)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.print (instance, os);
+}
+std::string
+ChunkRegistry::GetName (uint32_t uid, uint8_t *instance)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.getName (instance);
+}
+void
+ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ info.invokePrintCallback (instance, os, packetUid, size, callback);
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,180 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef CHUNK_REGISTRY_H
+#define CHUNK_REGISTRY_H
+
+#include <stdint.h>
+#include <ostream>
+#include "buffer.h"
+#include "ns3/ptr.h"
+#include "ns3/callback.h"
+
+namespace ns3 {
+
+/**
+ * \brief this registry keeps track of all different
+ * types of headers and trailers and assigns to each of them
+ * a unique integer.
+ * \internal
+ */
+class ChunkRegistry
+{
+public:
+ template <typename T>
+ static uint32_t RegisterHeader (std::string uuid);
+ template <typename T>
+ static uint32_t RegisterTrailer (std::string uuid);
+
+ static std::string GetUidStringFromUid (uint32_t uid);
+ static uint32_t GetUidFromUidString (std::string uidString);
+ static uint8_t *GetStaticInstance (uint32_t uid);
+ static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i);
+ static void Print (uint32_t uid, uint8_t *instance, std::ostream &os);
+ static std::string GetName (uint32_t uid, uint8_t *instance);
+ static bool IsHeader (uint32_t uid);
+ static bool IsTrailer (uint32_t uid);
+ static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback);
+private:
+ typedef uint8_t *(*GetStaticInstanceCb) (void);
+ typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+ typedef void (*PrintCb) (uint8_t *,std::ostream &);
+ typedef std::string (*GetNameCb) (uint8_t *);
+ typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback);
+ struct Info {
+ std::string uidString;
+ bool isHeader;
+ GetStaticInstanceCb getStaticInstance;
+ DeserializeCb deserialize;
+ PrintCb print;
+ GetNameCb getName;
+ InvokePrintCallbackCb invokePrintCallback;
+ };
+ typedef std::vector<struct Info> InfoVector;
+ static InfoVector *GetInfoVector (void);
+ template <typename T>
+ static uint8_t *DoGetStaticInstance (void);
+ template <typename T>
+ static uint32_t DoDeserialize (uint8_t *instance, Buffer::Iterator i);
+ template <typename T>
+ static void DoPrint (uint8_t *instance, std::ostream &os);
+ template <typename T>
+ static std::string DoGetName (uint8_t *instance);
+ template <typename T>
+ static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback);
+ template <typename T>
+ static uint32_t GetUid (bool isHeader, std::string uidString);
+
+};
+
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+ChunkRegistry::RegisterHeader (std::string uuid)
+{
+ return GetUid<T> (true, uuid);
+}
+template <typename T>
+uint32_t
+ChunkRegistry::RegisterTrailer (std::string uuid)
+{
+ return GetUid<T> (false, uuid);
+}
+
+template <typename T>
+uint32_t
+ChunkRegistry::GetUid (bool isHeader, std::string uidString)
+{
+ InfoVector *vec = GetInfoVector ();
+ uint32_t uid = 1;
+ for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ Info info;
+ info.getStaticInstance = &ChunkRegistry::DoGetStaticInstance<T>;
+ info.print = &ChunkRegistry::DoPrint<T>;
+ info.getName = &ChunkRegistry::DoGetName<T>;
+ info.deserialize = &ChunkRegistry::DoDeserialize<T>;
+ info.invokePrintCallback = &ChunkRegistry::DoInvokePrintCallback<T>;
+ info.uidString = uidString;
+ info.isHeader = isHeader;
+ vec->push_back (info);
+ return vec->size ();
+}
+
+template <typename T>
+uint8_t *
+ChunkRegistry::DoGetStaticInstance ()
+{
+ static T instance;
+ return reinterpret_cast<uint8_t *> (&instance);
+}
+template <typename T>
+uint32_t
+ChunkRegistry::DoDeserialize (uint8_t *instance, Buffer::Iterator i)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ return obj->Deserialize (i);
+}
+template <typename T>
+void
+ChunkRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ obj->Print (os);
+}
+template <typename T>
+std::string
+ChunkRegistry::DoGetName (uint8_t *instance)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ return obj->GetName ();
+}
+template <typename T>
+void
+ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ Callback<void,std::ostream&,uint32_t,uint32_t,const T*> cb;
+ cb.Assign (callback);
+ cb (os, packetUid, size, obj);
+}
+
+} // namespace ns3
+
+#endif /* CHUNK_H */
--- a/src/common/chunk.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "chunk.h"
-#include "ns3/assert.h"
-
-namespace ns3 {
-
-Chunk::Chunk ()
-{}
-
-Chunk::~Chunk ()
-{}
-
-void
-Chunk::Print (std::ostream &os) const
-{
- PrintTo (os);
-}
-uint32_t
-Chunk::GetSize (void) const
-{
- return GetSerializedSize ();
-}
-void
-Chunk::Serialize (Buffer::Iterator start) const
-{
- SerializeTo (start);
-}
-uint32_t
-Chunk::Deserialize (Buffer::Iterator start)
-{
- uint32_t deserialized = DeserializeFrom (start);
- return deserialized;
-}
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk)
-{
- chunk.Print (os);
- return os;
-}
-
-}; // namespace ns3
--- a/src/common/chunk.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef CHUNK_H
-#define CHUNK_H
-
-#include <stdint.h>
-#include <ostream>
-#include "buffer.h"
-
-namespace ns3 {
-
-class Chunk {
-public:
- Chunk ();
- virtual ~Chunk ();
-
- void Print (std::ostream &os) const;
- uint32_t GetSize (void) const;
- void Serialize (Buffer::Iterator start) const;
- uint32_t Deserialize (Buffer::Iterator start);
-private:
- virtual void PrintTo (std::ostream &os) const = 0;
- virtual uint32_t GetSerializedSize (void) const = 0;
- virtual void SerializeTo (Buffer::Iterator i) const = 0;
- virtual uint32_t DeserializeFrom (Buffer::Iterator i) = 0;
-};
-
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk);
-
-}; // namespace ns3
-
-#endif /* CHUNK_H */
--- a/src/common/composite-trace-resolver.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,331 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "composite-trace-resolver.h"
-
-namespace ns3 {
-
-CompositeTraceResolver::CompositeTraceResolver (TraceContext const &context)
- : TraceResolver (context)
-{}
-
-CompositeTraceResolver::~CompositeTraceResolver ()
-{}
-
-void
-CompositeTraceResolver::DoAdd (std::string name,
- Callback<TraceResolver *,TraceContext const &> createResolver,
- TraceContext const &context)
-{
- struct CallbackTraceSourceItem item;
- item.name = name;
- item.createResolver = createResolver;
- item.context = context;
- m_items.push_back (item);
-}
-
-TraceResolver::TraceResolverList
-CompositeTraceResolver::DoLookup (std::string id) const
-{
- if (id == "*")
- {
- TraceResolver::TraceResolverList list;
- for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
- {
- list.push_back (i->createResolver (i->context));
- }
- return list;
- }
- std::string::size_type start, end;
- start = id.find_first_of ("(", 0);
- end = id.find_first_of (")", 0);
- if (start != 0 || end != (id.size ()-1))
- {
- for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
- {
- if (i->name == id)
- {
- TraceResolver::TraceResolverList list;
- list.push_back (i->createResolver (i->context));
- return list;
- }
- }
- }
- std::list<std::string> names;
- std::string alternatives = std::string (id, start+1, end-1);
- std::string::size_type next, cur;
- next = 0;
- cur = 0;
- while (true)
- {
- std::string element;
- next = alternatives.find ("|", cur);
- if (next == std::string::npos)
- {
- element = std::string (alternatives, cur, alternatives.size ());
- names.push_back (element);
- break;
- }
- element = std::string (alternatives, cur, next);
- names.push_back (element);
- cur = next + 1;
- }
- TraceResolver::TraceResolverList list;
- for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
- {
- for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
- {
- if (j->name == *i)
- {
- list.push_back (j->createResolver (j->context));
- break;
- }
- }
- }
- return list;
-}
-
-}//namespace ns3
-
-#ifdef RUN_SELF_TESTS
-
-#include "ns3/test.h"
-
-namespace ns3 {
-
-class CompositeTraceResolverTest : public Test
-{
-public:
- enum TraceSources {
- TEST_TRACE_DOUBLEA,
- TEST_TRACE_DOUBLEB,
- TEST_TRACE_SUBRESOLVER,
- };
- enum SubTraceSources {
- TEST_SUBTRACE_INT,
- };
- CompositeTraceResolverTest ();
- virtual ~CompositeTraceResolverTest ();
- virtual bool RunTests (void);
-private:
- void TraceDouble (TraceContext const &context, double v);
- void TraceInt (TraceContext const &context, int v);
- TraceResolver *CreateSubResolver (TraceContext const &context);
-
-
- bool m_gotDoubleA;
- bool m_gotDoubleB;
- CallbackTraceSource<int> m_traceInt;
- bool m_gotInt;
-};
-
-CompositeTraceResolverTest::CompositeTraceResolverTest ()
- : Test ("CompositeTraceResolver")
-{}
-CompositeTraceResolverTest::~CompositeTraceResolverTest ()
-{}
-void
-CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
-{
- enum CompositeTraceResolverTest::TraceSources source;
- context.Get (source);
- switch (source)
- {
- case TEST_TRACE_DOUBLEA:
- m_gotDoubleA = true;
- break;
- case TEST_TRACE_DOUBLEB:
- m_gotDoubleB = true;
- break;
- default:
- NS_FATAL_ERROR ("should not get any other trace source in this sink");
- break;
- }
-
-}
-
-void
-CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
-{
- m_gotInt = true;
-}
-
-TraceResolver *
-CompositeTraceResolverTest::CreateSubResolver (TraceContext const &context)
-{
- CompositeTraceResolver *subresolver = new CompositeTraceResolver (context);
- subresolver->Add ("trace-int", m_traceInt, TEST_SUBTRACE_INT);
- return subresolver;
-}
-bool
-CompositeTraceResolverTest::RunTests (void)
-{
- bool ok = true;
-
- CallbackTraceSource<double> traceDoubleA;
- CallbackTraceSource<double> traceDoubleB;
- TraceContext context;
-
- CompositeTraceResolver resolver (context) ;
-
- resolver.Add ("trace-double-a", traceDoubleA, TEST_TRACE_DOUBLEA);
- resolver.Add ("trace-double-b", traceDoubleB, TEST_TRACE_DOUBLEB);
-
- resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
- m_gotDoubleA = false;
- m_gotDoubleB = false;
- traceDoubleA (0);
- if (!m_gotDoubleA || m_gotDoubleB)
- {
- ok = false;
- }
- m_gotDoubleA = false;
- traceDoubleA (0);
- traceDoubleB (0);
- if (!m_gotDoubleA || !m_gotDoubleB)
- {
- ok = false;
- }
- m_gotDoubleA = false;
- m_gotDoubleB = false;
-
- resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
- m_gotDoubleA = false;
- m_gotDoubleB = false;
- traceDoubleA (0);
- traceDoubleB (0);
- if (m_gotDoubleA || m_gotDoubleB)
- {
- ok = false;
- }
-
- resolver.Connect ("/trace-double-a",
- MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
- m_gotDoubleA = false;
- m_gotDoubleB = false;
- traceDoubleA (0);
- traceDoubleB (0);
- if (!m_gotDoubleA || m_gotDoubleB)
- {
- ok = false;
- }
- resolver.Disconnect ("/trace-double-a",
- MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
- resolver.Connect ("/(trace-double-a)",
- MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
- m_gotDoubleA = false;
- m_gotDoubleB = false;
- traceDoubleA (0);
- traceDoubleB (0);
- if (!m_gotDoubleA || m_gotDoubleB)
- {
- ok = false;
- }
- resolver.Disconnect ("/trace-double-a",
- MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
- resolver.Connect ("/(trace-double-a|trace-double-b)",
- MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
- m_gotDoubleA = false;
- m_gotDoubleB = false;
- traceDoubleA (0);
- traceDoubleB (0);
- if (!m_gotDoubleA || !m_gotDoubleB)
- {
- ok = false;
- }
- resolver.Disconnect ("/trace-double-a",
- MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
- m_gotDoubleA = false;
- m_gotDoubleB = false;
- traceDoubleA (0);
- traceDoubleB (0);
- if (m_gotDoubleA || !m_gotDoubleB)
- {
- ok = false;
- }
-
-
- resolver.Disconnect ("/(trace-double-a|trace-double-b)",
- MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
- m_gotDoubleA = false;
- m_gotDoubleB = false;
- traceDoubleA (0);
- traceDoubleB (0);
- if (m_gotDoubleA || m_gotDoubleB)
- {
- ok = false;
- }
-
- resolver.Add ("subresolver",
- MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this),
- TEST_TRACE_SUBRESOLVER);
-
- resolver.Connect ("/subresolver/trace-int",
- MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
- m_gotInt = false;
- m_traceInt (1);
- if (!m_gotInt)
- {
- ok = false;
- }
-
- resolver.Disconnect ("/subresolver/trace-int",
- MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
- m_gotInt = false;
- m_traceInt (1);
- if (m_gotInt)
- {
- ok = false;
- }
-
- resolver.Connect ("/*/trace-int",
- MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
- m_gotInt = false;
- m_traceInt (1);
- if (!m_gotInt)
- {
- ok = false;
- }
-
- resolver.Disconnect ("/subresolver/trace-int",
- MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
- m_gotInt = false;
- m_traceInt (1);
- if (m_gotInt)
- {
- ok = false;
- }
-
-
-
-
- return ok;
-}
-
-static CompositeTraceResolverTest g_compositeTraceResolverTest;
-
-}//namespace ns3
-
-
-#endif /* RUN_SELF_TESTS */
--- a/src/common/composite-trace-resolver.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef COMPOSITE_TRACE_RESOLVER_H
-#define COMPOSITE_TRACE_RESOLVER_H
-
-#include "ns3/callback.h"
-#include "trace-resolver.h"
-#include "callback-trace-source.h"
-#include "uv-trace-source.h"
-#include "sv-trace-source.h"
-#include "fv-trace-source.h"
-#include "terminal-trace-resolver.h"
-
-namespace ns3 {
-
-/**
- * \brief a helper class to aggregate contained TraceResolver and other trace sources.
- * \ingroup lowleveltracing
- */
-class CompositeTraceResolver : public TraceResolver
-{
-public:
- CompositeTraceResolver (TraceContext const &context);
- virtual ~CompositeTraceResolver ();
- /**
- * \param name name of trace source
- * \param trace a callback trace source
- * \param context the context associated to this trace source
- *
- * Add a callback trace source in this resolver. This trace
- * source will match the name specified during namespace
- * resolution. The TraceContext of this trace source will also
- * be automatically extended to contain the input context.
- */
- template <typename T1, typename T2,
- typename T3, typename T4,
- typename T>
- void Add (std::string name,
- CallbackTraceSource<T1,T2,T3,T4> &trace, T const &context);
- /**
- * \param name name of trace source
- * \param trace a signed variable trace source
- * \param context the context associated to this trace source
- *
- * Add a signed variable trace source in this resolver.
- * This trace source will match the name specified during namespace
- * resolution. The TraceContext of this trace source will also
- * be automatically extended to contain the input context.
- */
- template <typename T>
- void Add (std::string name,
- SVTraceSource<T> &trace, T const &context);
- /**
- * \param name name of trace source
- * \param trace an unsigned variable trace source
- * \param context the context associated to this trace source
- *
- * Add an unsigned variable trace source in this resolver.
- * This trace source will match the name specified during namespace
- * resolution. The TraceContext of this trace source will also
- * be automatically extended to contain the input context.
- */
- template <typename T>
- void Add (std::string name,
- UVTraceSource<T> &trace, T const &context);
- /**
- * \param name name of trace source
- * \param trace a floating-point variable trace source
- * \param context the context associated to this trace source
- *
- * Add a floating-point variable trace source in this resolver.
- * This trace source will match the name specified during namespace
- * resolution. The TraceContext of this trace source will also
- * be automatically extended to contain the input context.
- */
- template <typename T>
- void Add (std::string name,
- FVTraceSource<T> &trace, T const &context);
-
- /**
- * \param name name of child trace resolver
- * \param createResolver a trace resolver constructor
- * \param context the context associated to this entry
- *
- * Add a child trace resolver to this resolver. This child
- * trace resolver will match the name specified during
- * namespace resolution. When this happens, the constructor
- * will be invoked to create the child trace resolver and
- * the associated TraceContext will be automatically extended
- * to contain the input context.
- */
- template <typename T>
- void Add (std::string name,
- Callback<TraceResolver *,TraceContext const &> createResolver,
- T const &context);
-private:
- template <typename SOURCE, typename CONTEXT>
- void DoAddTraceSource (std::string name,
- SOURCE &traceSource, CONTEXT const &context);
- template <typename SOURCE>
- static TraceResolver *CreateTerminalTraceResolver (SOURCE *trace,
- TraceContext const &context);
- void DoAdd (std::string name,
- Callback<TraceResolver *,TraceContext const &> createResolver,
- TraceContext const &context);
- virtual TraceResolverList DoLookup (std::string id) const;
-
- struct CallbackTraceSourceItem
- {
- std::string name;
- Callback<TraceResolver *,TraceContext const &> createResolver;
- TraceContext context;
- };
-
- typedef std::list<struct CallbackTraceSourceItem> TraceItems;
- TraceItems m_items;
-};
-
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename SOURCE, typename CONTEXT>
-void
-CompositeTraceResolver::DoAddTraceSource (std::string name,
- SOURCE &traceSource, CONTEXT const &context)
-{
- TraceContext traceContext = GetContext ();
- traceContext.Add (context);
- TraceResolver *(*create) (SOURCE *trace, TraceContext const &context);
- create = &CompositeTraceResolver::CreateTerminalTraceResolver<SOURCE>;
- Callback<TraceResolver *,TraceContext const &> createResolver =
- MakeBoundCallback (create, &traceSource);
- DoAdd (name, createResolver, traceContext);
-}
-
-template <typename SOURCE>
-TraceResolver *
-CompositeTraceResolver::CreateTerminalTraceResolver (SOURCE *traceSource,
- TraceContext const &context)
-{
- return new TerminalTraceResolver<SOURCE> (*traceSource, context);
-}
-
-
-
-
-template <typename T1, typename T2,
- typename T3, typename T4,
- typename T>
-void
-CompositeTraceResolver::Add (std::string name,
- CallbackTraceSource<T1,T2,T3,T4> &trace,
- T const &context)
-{
- DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void
-CompositeTraceResolver::Add (std::string name,
- SVTraceSource<T> &trace, T const &context)
-{
- DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void
-CompositeTraceResolver::Add (std::string name,
- UVTraceSource<T> &trace, T const &context)
-{
- DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void
-CompositeTraceResolver::Add (std::string name,
- FVTraceSource<T> &trace, T const &context)
-{
- DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void
-CompositeTraceResolver::Add (std::string name,
- Callback<TraceResolver *,TraceContext const &> createResolver,
- T const &context)
-{
- TraceContext traceContext = GetContext ();
- traceContext.Add (context);
- DoAdd (name, createResolver, traceContext);
-}
-
-
-}//namespace ns3
-
-#endif /* COMPOSITE_TRACE_RESOLVER_H */
--- a/src/common/data-rate.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/data-rate.cc Fri Sep 28 11:59:46 2007 +0100
@@ -23,9 +23,8 @@
#include "ns3/nstime.h"
#include "ns3/fatal-error.h"
-namespace {
-bool
+static bool
DoParse (const std::string s, uint64_t *v)
{
std::string::size_type n = s.find_first_not_of("0123456789.");
@@ -123,7 +122,6 @@
return true;
}
-}
namespace ns3 {
--- a/src/common/empty-trace-resolver.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "empty-trace-resolver.h"
-
-ns3::EmptyTraceResolver::EmptyTraceResolver (TraceContext const &context)
- : TraceResolver (context)
-{}
--- a/src/common/empty-trace-resolver.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef EMPTY_TRACE_RESOLVER_H
-#define EMPTY_TRACE_RESOLVER_H
-
-#include "trace-resolver.h"
-
-namespace ns3 {
-
-class TraceContext;
-
-/**
- * \brief a TraceResolver instance which does not resolve anything.
- * \ingroup tracing
- *
- * Trying to resolve against this class will yield no matches and no
- * connections. Returning an instance of this class from a
- * CreateTraceResolver method is a hand way of not implementing
- * any Tracing code.
- */
-class EmptyTraceResolver : public TraceResolver
-{
-public:
- /**
- * \param o necessary context for this class.
- *
- * The only constructor exported by this class.
- */
- EmptyTraceResolver (TraceContext const &o);
-};
-
-}//namespace ns3
-
-#endif /* EMPTY_TRACE_RESOLVER_H */
--- a/src/common/fv-trace-source.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef F_VARIABLE_TRACER_H
-#define F_VARIABLE_TRACER_H
-
-#include "callback-trace-source.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class FVTraceSourceBase {
-public:
- typedef CallbackTraceSource<double, double> ChangeNotifyCallback;
-
- FVTraceSourceBase () {}
- FVTraceSourceBase (FVTraceSourceBase const &o) {}
- FVTraceSourceBase &operator = (FVTraceSourceBase const &o) {
- return *this;
- }
-
- ~FVTraceSourceBase () {}
-
- void AddCallback (CallbackBase const & callback, TraceContext const & context) {
- m_callback.AddCallback (callback, context);
- }
- void RemoveCallback (CallbackBase const & callback) {
- m_callback.RemoveCallback (callback);
- }
-protected:
- void notify (double oldVal, double newVal) {
- if (oldVal != newVal)
- {
- m_callback (oldVal, newVal);
- }
- }
-private:
- ChangeNotifyCallback m_callback;
-};
-
-template <typename T>
-class FVTraceSource : public FVTraceSourceBase
-{
-public:
-};
-
-}; // namespace ns3
-
-#endif /* F_VARIABLE_TRACER_H */
--- a/src/common/header.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "header.h"
-
-namespace ns3 {
-
-Header::~Header ()
-{}
-
-}; // namespace ns3
--- a/src/common/header.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/header.h Fri Sep 28 11:59:46 2007 +0100
@@ -22,7 +22,29 @@
#ifndef HEADER_H
#define HEADER_H
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Header
+ * \brief this macro should be instantiated exactly once for each
+ * new type of Header
+ *
+ * This macro will ensure that your new Header type is registered
+ * within the packet header registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_HEADER_ENSURE_REGISTERED(x) \
+static class thisisaveryverylongclassname ##x \
+{ \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+} g_thisisanotherveryveryverylongname ## x;
+
namespace ns3 {
@@ -30,51 +52,64 @@
* \brief Protocol header serialization and deserialization.
*
* Every Protocol header which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- * - ns3::Header::SerializeTo
- * - ns3::Header::DeserializeFrom
- * - ns3::Header::GetSerializedSize
- * - ns3::Header::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ * - a default constructor: is used by the internal implementation
+ * if the Packet class.
+ * - a static method named GetUid: is used to uniquely identify
+ * the type of each header. This method shall return a unique
+ * integer allocated with Header::AllocateUid.
+ * - a method named Serialize: is used by Packet::AddHeader to
+ * store a header into the byte buffer of a packet.
+ * The input iterator points to the start of the byte buffer in
+ * which the header should write its data. The data written
+ * is expected to match bit-for-bit the representation of this
+ * header in a real network.
+ * - a method named GetSerializedSize: is used by Packet::AddHeader
+ * to store a header into the byte buffer of a packet. This method
+ * should return the number of bytes which are needed to store
+ * the full header data by Serialize.
+ * - a method named Deserialize: is used by Packet::RemoveHeader to
+ * re-create a header from the byte buffer of a packet. The input
+ * iterator points to the start of the byte buffer from which
+ * the header should read its data. The data read is expected to
+ * match bit-for-bit the representation of this header in real
+ * networks. This method shall return an integer which identifies
+ * the number of bytes read.
+ * - a method named Print: is used by Packet::Print to print the
+ * content of a header as ascii data to a c++ output stream.
+ * Although the header is free to format its output as it
+ * wishes, it is recommended to follow a few rules to integrate
+ * with the packet pretty printer: start with flags, small field
+ * values located between a pair of parens. Values should be separated
+ * by whitespace. Follow the parens with the important fields,
+ * separated by whitespace.
+ * i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ * - a method named GetName: is used by Packet::Print to print
+ * header fragments. This method should return a user-readable
+ * single word as all capitalized letters.
+ *
+ * Sample code which shows how to create a new type of Header, and how to use it,
+ * is shown in the sample file samples/main-packet-header.cc
*/
-class Header : public Chunk {
-public:
- virtual ~Header ();
-private:
- /**
- * \param os the std output stream in which this
- * protocol header must print itself.
- */
- virtual void PrintTo (std::ostream &os) const = 0;
-
- /**
- * \returns the size of the serialized Header.
- *
- * This method is used by Packet::AddHeader to reserve
- * enough room in the packet byte buffer prior to calling
- * Header::Serialize.
- */
- virtual uint32_t GetSerializedSize (void) const = 0;
-
- /**
- * \param start the buffer iterator in which the protocol header
- * must serialize itself. This iterator identifies
- * the start of the buffer.
- */
- virtual void SerializeTo (Buffer::Iterator start) const = 0;
- /**
- * \param start the buffer iterator from which the protocol header must
- * deserialize itself. This iterator identifies
- * the start of the buffer.
- * \returns the number of bytes read from the buffer
- *
- * The value returned is used to trim the packet byte buffer of the
- * corresponding amount when this method is invoked from
- * Packet::RemoveHeader
- */
- virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0;
+class Header
+{
+protected:
+ template <typename T>
+ static uint32_t AllocateUid (std::string uuid);
};
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Header::AllocateUid (std::string uuid)
+{
+ return ChunkRegistry::RegisterHeader<T> (uuid);
+}
+
+} // namespace ns3
#endif /* HEADER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata-test.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,690 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifdef RUN_SELF_TESTS
+
+#include <stdarg.h>
+#include <iostream>
+#include <sstream>
+#include "ns3/test.h"
+#include "header.h"
+#include "trailer.h"
+#include "packet.h"
+#include "packet-metadata.h"
+#include "packet-printer.h"
+
+namespace ns3 {
+
+template <int N>
+class HistoryHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
+ HistoryHeader ();
+ bool IsOk (void) const;
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
+private:
+ bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryHeader<N>::GetUid (void)
+{
+ std::ostringstream oss;
+ oss << N << "HistoryHeader.ns3";
+ static uint32_t uid = AllocateUid<HistoryHeader<N> > (oss.str());
+ return uid;
+}
+
+template <int N>
+HistoryHeader<N>::HistoryHeader ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryHeader<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+std::string
+HistoryHeader<N>::GetName (void) const
+{
+ std::ostringstream oss;
+ oss << N;
+ return oss.str ();
+}
+
+template <int N>
+void
+HistoryHeader<N>::Print (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+HistoryHeader<N>::Serialize (Buffer::Iterator start) const
+{
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::Deserialize (Buffer::Iterator start)
+{
+ m_ok = true;
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+template <int N>
+class HistoryTrailer : public Trailer
+{
+public:
+ static uint32_t GetUid (void);
+ HistoryTrailer ();
+ bool IsOk (void) const;
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
+private:
+ bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryTrailer<N>::GetUid (void)
+{
+ std::ostringstream oss;
+ oss << N << "HistoryTrailer.ns3";
+ static uint32_t uid = AllocateUid<HistoryTrailer<N> > (oss.str ());
+ return uid;
+}
+
+
+template <int N>
+HistoryTrailer<N>::HistoryTrailer ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryTrailer<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+std::string
+HistoryTrailer<N>::GetName (void) const
+{
+ std::ostringstream oss;
+ oss << N;
+ return oss.str ();
+}
+template <int N>
+void
+HistoryTrailer<N>::Print (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+HistoryTrailer<N>::Serialize (Buffer::Iterator start) const
+{
+ start.Prev (N);
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::Deserialize (Buffer::Iterator start)
+{
+ m_ok = true;
+ start.Prev (N);
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+
+
+class PacketMetadataTest : public Test {
+public:
+ PacketMetadataTest ();
+ virtual ~PacketMetadataTest ();
+ bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
+ virtual bool RunTests (void);
+private:
+ template <int N>
+ void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader<N> *header);
+ template <int N>
+ void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer<N> *trailer);
+ void PrintFragment (std::ostream &os,uint32_t packetUid,
+ uint32_t size,std::string & name,
+ struct PacketPrinter::FragmentInformation info);
+ void PrintPayload (std::ostream &os,uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info);
+ template <int N>
+ void RegisterHeader (void);
+ template <int N>
+ void RegisterTrailer (void);
+ void CleanupPrints (void);
+ Packet DoAddHeader (Packet p);
+ bool Check (const char *file, int line, std::list<int> expected);
+
+
+ bool m_headerError;
+ bool m_trailerError;
+ std::list<int> m_prints;
+ PacketPrinter m_printer;
+};
+
+PacketMetadataTest::PacketMetadataTest ()
+ : Test ("PacketMetadata")
+{
+ m_printer.SetPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this));
+ m_printer.SetSeparator ("");
+}
+
+PacketMetadataTest::~PacketMetadataTest ()
+{}
+
+template <int N>
+void
+PacketMetadataTest::RegisterHeader (void)
+{
+ static bool registered = false;
+ if (!registered)
+ {
+ m_printer.SetHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader<N>, this),
+ MakeCallback (&PacketMetadataTest::PrintFragment, this));
+ registered = true;
+ }
+}
+
+template <int N>
+void
+PacketMetadataTest::RegisterTrailer (void)
+{
+ static bool registered = false;
+ if (!registered)
+ {
+ m_printer.SetTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer<N>, this),
+ MakeCallback (&PacketMetadataTest::PrintFragment, this));
+ registered = true;
+ }
+}
+
+
+template <int N>
+void
+PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size,
+ const HistoryHeader<N> *header)
+{
+ if (!header->IsOk ())
+ {
+ m_headerError = true;
+ }
+ m_prints.push_back (N);
+}
+
+template <int N>
+void
+PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size,
+ const HistoryTrailer<N> *trailer)
+{
+ if (!trailer->IsOk ())
+ {
+ m_trailerError = true;
+ }
+ m_prints.push_back (N);
+}
+void
+PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid,
+ uint32_t size,std::string & name,
+ struct PacketPrinter::FragmentInformation info)
+{
+ m_prints.push_back (size - (info.end + info.start));
+}
+void
+PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info)
+{
+ m_prints.push_back (size - (info.end + info.start));
+}
+
+
+void
+PacketMetadataTest::CleanupPrints (void)
+{
+ m_prints.clear ();
+}
+
+bool
+PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
+{
+ if (m_headerError)
+ {
+ Failure () << "PacketMetadata header error. file=" << file
+ << ", line=" << line << std::endl;
+ return false;
+ }
+ if (m_trailerError)
+ {
+ Failure () << "PacketMetadata trailer error. file=" << file
+ << ", line=" << line << std::endl;
+ return false;
+ }
+ if (expected.size () != m_prints.size ())
+ {
+ goto error;
+ }
+ for (std::list<int>::iterator i = m_prints.begin (),
+ j = expected.begin ();
+ i != m_prints.end (); i++, j++)
+ {
+ NS_ASSERT (j != expected.end ());
+ if (*j != *i)
+ {
+ goto error;
+ }
+ }
+ return true;
+ error:
+ Failure () << "PacketMetadata error. file="<< file
+ << ", line=" << line << ", got:\"";
+ for (std::list<int>::iterator i = m_prints.begin ();
+ i != m_prints.end (); i++)
+ {
+ Failure () << *i << ", ";
+ }
+ Failure () << "\", expected: \"";
+ for (std::list<int>::iterator j = expected.begin ();
+ j != expected.end (); j++)
+ {
+ Failure () << *j << ", ";
+ }
+ Failure () << "\"" << std::endl;
+ return false;
+}
+
+bool
+PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
+{
+ m_headerError = false;
+ m_trailerError = false;
+ std::list<int> expected;
+ va_list ap;
+ va_start (ap, n);
+ for (uint32_t j = 0; j < n; j++)
+ {
+ int v = va_arg (ap, int);
+ expected.push_back (v);
+ }
+ va_end (ap);
+
+ m_printer.PrintForward ();
+ p.Print (Failure (), m_printer);
+ bool ok = Check (file, line, expected);
+ CleanupPrints ();
+ if (!ok)
+ {
+ return false;
+ }
+
+ m_printer.PrintBackward ();
+ p.Print (Failure (), m_printer);
+ expected.reverse ();
+ ok = Check (file, line, expected);
+ CleanupPrints ();
+ return ok;
+}
+
+#define ADD_HEADER(p, n) \
+ { \
+ HistoryHeader<n> header; \
+ RegisterHeader<n> (); \
+ p.AddHeader (header); \
+ }
+#define ADD_TRAILER(p, n) \
+ { \
+ HistoryTrailer<n> trailer; \
+ RegisterTrailer<n> (); \
+ p.AddTrailer (trailer); \
+ }
+#define REM_HEADER(p, n) \
+ { \
+ HistoryHeader<n> header; \
+ RegisterHeader<n> (); \
+ p.RemoveHeader (header); \
+ }
+#define REM_TRAILER(p, n) \
+ { \
+ HistoryTrailer<n> trailer; \
+ RegisterTrailer<n> (); \
+ p.RemoveTrailer (trailer); \
+ }
+#define CHECK_HISTORY(p, ...) \
+ { \
+ if (!CheckHistory (p, __FILE__, \
+ __LINE__, __VA_ARGS__)) \
+ { \
+ ok = false; \
+ } \
+ Buffer buffer; \
+ buffer = p.Serialize (); \
+ Packet otherPacket; \
+ otherPacket.Deserialize (buffer); \
+ if (!CheckHistory (otherPacket, __FILE__, \
+ __LINE__, __VA_ARGS__)) \
+ { \
+ ok = false; \
+ } \
+ }
+
+
+Packet
+PacketMetadataTest::DoAddHeader (Packet p)
+{
+ ADD_HEADER (p, 10);
+ return p;
+}
+
+bool
+PacketMetadataTest::RunTests (void)
+{
+ bool ok = true;
+
+ PacketMetadata::Enable ();
+
+ Packet p = Packet (0);
+ Packet p1 = Packet (0);
+
+ p = Packet (10);
+ ADD_TRAILER (p, 100);
+ CHECK_HISTORY (p, 2, 10, 100);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p, 5);
+ CHECK_HISTORY (p, 5,
+ 5, 3, 2, 1, 10);
+ ADD_HEADER (p, 6);
+ CHECK_HISTORY (p, 6,
+ 6, 5, 3, 2, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ CHECK_HISTORY (p, 3,
+ 2, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ REM_HEADER (p, 2);
+ CHECK_HISTORY (p, 2,
+ 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ REM_HEADER (p, 2);
+ REM_HEADER (p, 1);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ p1 = p;
+ REM_HEADER (p1, 3);
+ REM_HEADER (p1, 2);
+ REM_HEADER (p1, 1);
+ CHECK_HISTORY (p1, 1, 10);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p1, 1);
+ ADD_HEADER (p1, 2);
+ CHECK_HISTORY (p1, 3,
+ 2, 1, 10);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 5,
+ 3, 3, 2, 1, 10);
+ ADD_TRAILER (p, 4);
+ CHECK_HISTORY (p, 6,
+ 3, 3, 2, 1, 10, 4);
+ ADD_TRAILER (p, 5);
+ CHECK_HISTORY (p, 7,
+ 3, 3, 2, 1, 10, 4, 5);
+ REM_HEADER (p, 3);
+ CHECK_HISTORY (p, 6,
+ 3, 2, 1, 10, 4, 5);
+ REM_TRAILER (p, 5);
+ CHECK_HISTORY (p, 5,
+ 3, 2, 1, 10, 4);
+ p1 = p;
+ REM_TRAILER (p, 4);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ CHECK_HISTORY (p1, 5,
+ 3, 2, 1, 10, 4);
+ p1.RemoveAtStart (3);
+ CHECK_HISTORY (p1, 4,
+ 2, 1, 10, 4);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 4,
+ 1, 1, 10, 4);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 3,
+ 1, 10, 4);
+ p1.RemoveAtEnd (4);
+ CHECK_HISTORY (p1, 2,
+ 1, 10);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 8);
+ ADD_TRAILER (p, 8);
+ ADD_TRAILER (p, 8);
+ p.RemoveAtStart (8+10+8);
+ CHECK_HISTORY (p, 1, 8);
+
+ p = Packet (10);
+ ADD_HEADER (p, 10);
+ ADD_HEADER (p, 8);
+ ADD_TRAILER (p, 6);
+ ADD_TRAILER (p, 7);
+ ADD_TRAILER (p, 9);
+ p.RemoveAtStart (5);
+ p.RemoveAtEnd (12);
+ CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
+
+ p = Packet (10);
+ ADD_HEADER (p, 10);
+ ADD_TRAILER (p, 6);
+ p.RemoveAtEnd (18);
+ ADD_TRAILER (p, 5);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 3, 3, 8, 5);
+ p.RemoveAtStart (12);
+ CHECK_HISTORY (p, 1, 4);
+ p.RemoveAtEnd (2);
+ CHECK_HISTORY (p, 1, 2);
+ ADD_HEADER (p, 10);
+ CHECK_HISTORY (p, 2, 10, 2);
+ p.RemoveAtEnd (5);
+ CHECK_HISTORY (p, 1, 7);
+
+ Packet p2 = Packet (0);
+ Packet p3 = Packet (0);
+
+ p = Packet (40);
+ ADD_HEADER (p, 5);
+ ADD_HEADER (p, 8);
+ CHECK_HISTORY (p, 3, 8, 5, 40);
+ p1 = p.CreateFragment (0, 5);
+ p2 = p.CreateFragment (5, 5);
+ p3 = p.CreateFragment (10, 43);
+ CHECK_HISTORY (p1, 1, 5);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ CHECK_HISTORY (p3, 2, 3, 40);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 8, 2);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ p1.AddAtEnd (p3);
+ CHECK_HISTORY (p1, 3, 8, 5, 40);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ CHECK_HISTORY (p3, 2, 3, 40);
+ p1 = p.CreateFragment (0, 5);
+ CHECK_HISTORY (p1, 1, 5);
+
+ p3 = Packet (50);
+ ADD_HEADER (p3, 8);
+ CHECK_HISTORY (p3, 2, 8, 50);
+ CHECK_HISTORY (p1, 1, 5);
+ p1.AddAtEnd (p3);
+ CHECK_HISTORY (p1, 3, 5, 8, 50);
+ ADD_HEADER (p1, 5);
+ CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
+ ADD_TRAILER (p1, 2);
+ CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
+ REM_HEADER (p1, 5);
+ CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
+ p1.RemoveAtEnd (60);
+ CHECK_HISTORY (p1, 1, 5);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 8, 2);
+ CHECK_HISTORY (p2, 2, 3, 2);
+
+ p3 = Packet (40);
+ ADD_HEADER (p3, 5);
+ ADD_HEADER (p3, 5);
+ CHECK_HISTORY (p3, 3, 5, 5, 40);
+ p1 = p3.CreateFragment (0, 5);
+ p2 = p3.CreateFragment (5, 5);
+ CHECK_HISTORY (p1, 1, 5);
+ CHECK_HISTORY (p2, 1, 5);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 5, 5);
+
+ p = Packet (0);
+ CHECK_HISTORY (p, 0);
+
+ p3 = Packet (0);
+ ADD_HEADER (p3, 5);
+ ADD_HEADER (p3, 5);
+ CHECK_HISTORY (p3, 2, 5, 5);
+ p1 = p3.CreateFragment (0, 4);
+ p2 = p3.CreateFragment (9, 1);
+ CHECK_HISTORY (p1, 1, 4);
+ CHECK_HISTORY (p2, 1, 1);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 4, 1);
+
+
+ p = Packet (2000);
+ CHECK_HISTORY (p, 1, 2000);
+
+ p = Packet ();
+ ADD_TRAILER (p, 10);
+ ADD_HEADER (p, 5);
+ p1 = p.CreateFragment (0, 8);
+ p2 = p.CreateFragment (8, 7);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p, 2, 5, 10);
+
+ p = Packet ();
+ ADD_TRAILER (p, 10);
+ REM_TRAILER (p, 10);
+ ADD_TRAILER (p, 10);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet ();
+ ADD_HEADER (p, 10);
+ REM_HEADER (p, 10);
+ ADD_HEADER (p, 10);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet ();
+ ADD_HEADER (p, 10);
+ p = DoAddHeader (p);
+ CHECK_HISTORY (p, 2, 10, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 8);
+ ADD_TRAILER (p, 8);
+ ADD_TRAILER (p, 8);
+ p.RemoveAtStart (8+10+8);
+ CHECK_HISTORY (p, 1, 8);
+
+ return ok;
+}
+
+static PacketMetadataTest g_packetHistoryTest;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1250 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include <utility>
+#include <list>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/log.h"
+#include "packet-metadata.h"
+#include "buffer.h"
+#include "chunk-registry.h"
+
+NS_LOG_COMPONENT_DEFINE ("PacketMetadata");
+
+namespace ns3 {
+
+bool PacketMetadata::m_enable = false;
+bool PacketMetadata::m_metadataSkipped = false;
+uint32_t PacketMetadata::m_maxSize = 0;
+uint16_t PacketMetadata::m_chunkUid = 0;
+PacketMetadata::DataFreeList PacketMetadata::m_freeList;
+bool g_optOne = false;
+
+PacketMetadata::DataFreeList::~DataFreeList ()
+{
+ for (iterator i = begin (); i != end (); i++)
+ {
+ PacketMetadata::Deallocate (*i);
+ }
+}
+
+void
+PacketMetadata::Enable (void)
+{
+ NS_ASSERT_MSG (!m_metadataSkipped,
+ "Error: attempting to enable the packet metadata "
+ "subsystem too late in the simulation, which is not allowed.\n"
+ "A common cause for this problem is to enable ASCII tracing "
+ "after sending any packets. One way to fix this problem is "
+ "to call ns3::PacketMetadata::Enable () near the beginning of"
+ " the program, before any packets are sent.");
+ m_enable = true;
+}
+
+void
+PacketMetadata::SetOptOne (bool optOne)
+{
+ g_optOne = optOne;
+}
+
+void
+PacketMetadata::ReserveCopy (uint32_t size)
+{
+ struct PacketMetadata::Data *newData = PacketMetadata::Create (m_used + size);
+ memcpy (newData->m_data, m_data->m_data, m_used);
+ newData->m_dirtyEnd = m_used;
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ PacketMetadata::Recycle (m_data);
+ }
+ m_data = newData;
+ if (m_head != 0xffff)
+ {
+ uint8_t *start;
+ NS_ASSERT (m_tail != 0xffff);
+ // clear the next field of the tail
+ start = &m_data->m_data[m_tail];
+ Append16 (0xffff, start);
+ // clear the prev field of the head
+ start = &m_data->m_data[m_head] + 2;
+ Append16 (0xffff, start);
+ }
+}
+void
+PacketMetadata::Reserve (uint32_t size)
+{
+ NS_ASSERT (m_data != 0);
+ if (m_data->m_size >= m_used + size &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_data->m_dirtyEnd == m_used))
+ {
+ /* enough room, not dirty. */
+ }
+ else
+ {
+ /* (enough room and dirty) or (not enough room) */
+ ReserveCopy (size);
+ }
+}
+
+uint32_t
+PacketMetadata::GetUleb128Size (uint32_t value) const
+{
+ if (value < 0x80)
+ {
+ return 1;
+ }
+ if (value < 0x4000)
+ {
+ return 2;
+ }
+ if (value < 0x200000)
+ {
+ return 3;
+ }
+ if (value < 0x10000000)
+ {
+ return 4;
+ }
+ return 5;
+}
+uint32_t
+PacketMetadata::ReadUleb128 (const uint8_t **pBuffer) const
+{
+ const uint8_t *buffer = *pBuffer;
+ uint32_t result = 0;
+ uint8_t byte;
+ result = 0;
+ byte = buffer[0];
+ result = (byte & (~0x80));
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 1;
+ return result;
+ }
+ byte = buffer[1];
+ result |= (byte & (~0x80)) << 7;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 2;
+ return result;
+ }
+ byte = buffer[2];
+ result |= (byte & (~0x80)) << 14;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 3;
+ return result;
+ }
+ byte = buffer[3];
+ result |= (byte & (~0x80)) << 21;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 4;
+ return result;
+ }
+ byte = buffer[4];
+ result |= (byte & (~0x80)) << 28;
+ if (!(byte & 0x80))
+ {
+ *pBuffer = buffer + 5;
+ return result;
+ }
+ /* This means that the LEB128 number was not valid.
+ * ie: the last (5th) byte did not have the high-order bit zeroed.
+ */
+ NS_ASSERT (false);
+ return 0;
+}
+
+void
+PacketMetadata::Append16 (uint16_t value, uint8_t *buffer)
+{
+ buffer[0] = value & 0xff;
+ value >>= 8;
+ buffer[1] = value;
+}
+bool
+PacketMetadata::TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (value < 0x80 && start < end)
+ {
+ start[0] = value;
+ *pBuffer = start + 1;
+ return true;
+ }
+ if (value < 0x4000 && start + 1 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ start[1] = value;
+ *pBuffer = start + 2;
+ return true;
+ }
+ return false;
+}
+bool
+PacketMetadata::TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (start + 1 < end)
+ {
+ start[0] = value & 0xff;
+ start[1] = value >> 8;
+ *pBuffer = start + 2;
+ return true;
+ }
+ return false;
+}
+bool
+PacketMetadata::TryToAppend32 (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (start + 3 < end)
+ {
+ start[0] = value & 0xff;
+ start[1] = (value >> 8) & 0xff;
+ start[2] = (value >> 16) & 0xff;
+ start[3] = (value >> 24) & 0xff;
+ *pBuffer = start + 4;
+ return true;
+ }
+ return false;
+}
+bool
+PacketMetadata::TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+ uint8_t *start = *pBuffer;
+ if (value < 0x80 && start < end)
+ {
+ start[0] = value;
+ *pBuffer = start + 1;
+ return true;
+ }
+ if (value < 0x4000 && start + 1 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ start[1] = value;
+ *pBuffer = start + 2;
+ return true;
+ }
+ if (value < 0x200000 && start + 2 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[2] = value;
+ *pBuffer = start + 3;
+ return true;
+ }
+ if (value < 0x10000000 && start + 3 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[2] = 0x80 | byte;
+ value >>= 7;
+ start[3] = value;
+ *pBuffer = start + 4;
+ return true;
+ }
+ if (start + 4 < end)
+ {
+ uint8_t byte = value & (~0x80);
+ start[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[2] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ start[3] = 0x80 | byte;
+ value >>= 7;
+ start[4] = value;
+ *pBuffer = start + 5;
+ return true;
+ }
+ return false;
+}
+
+void
+PacketMetadata::AppendValueExtra (uint32_t value, uint8_t *buffer)
+{
+ if (value < 0x200000)
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[2] = value;
+ return;
+ }
+ if (value < 0x10000000)
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[2] = 0x80 | byte;
+ value >>= 7;
+ buffer[3] = value;
+ return;
+ }
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[1] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[2] = 0x80 | byte;
+ value >>= 7;
+ byte = value & (~0x80);
+ buffer[3] = 0x80 | byte;
+ value >>= 7;
+ buffer[4] = value;
+ }
+}
+
+void
+PacketMetadata::AppendValue (uint32_t value, uint8_t *buffer)
+{
+ if (value < 0x80)
+ {
+ buffer[0] = value;
+ return;
+ }
+ if (value < 0x4000)
+ {
+ uint8_t byte = value & (~0x80);
+ buffer[0] = 0x80 | byte;
+ value >>= 7;
+ buffer[1] = value;
+ return;
+ }
+ AppendValueExtra (value, buffer);
+}
+
+void
+PacketMetadata::UpdateTail (uint16_t written)
+{
+ if (m_head == 0xffff)
+ {
+ NS_ASSERT (m_tail == 0xffff);
+ m_head = m_used;
+ m_tail = m_used;
+ }
+ else
+ {
+ NS_ASSERT (m_tail != 0xffff);
+ // overwrite the next field of the previous tail of the list.
+ uint8_t *previousTail = &m_data->m_data[m_tail];
+ Append16 (m_used, previousTail);
+ // update the tail of the list to the new node.
+ m_tail = m_used;
+ }
+ NS_ASSERT (m_tail != 0xffff);
+ NS_ASSERT (m_head != 0xffff);
+ NS_ASSERT (written >= 8);
+ m_used += written;
+ m_data->m_dirtyEnd = m_used;
+}
+
+
+void
+PacketMetadata::UpdateHead (uint16_t written)
+{
+ if (m_head == 0xffff)
+ {
+ NS_ASSERT (m_tail == 0xffff);
+ m_head = m_used;
+ m_tail = m_used;
+ }
+ else
+ {
+ NS_ASSERT (m_head != 0xffff);
+ // overwrite the prev field of the previous head of the list.
+ uint8_t *previousHead = &m_data->m_data[m_head + 2];
+ Append16 (m_used, previousHead);
+ // update the head of list to the new node.
+ m_head = m_used;
+ }
+ NS_ASSERT (m_tail != 0xffff);
+ NS_ASSERT (m_head != 0xffff);
+ NS_ASSERT (written >= 8);
+ m_used += written;
+ m_data->m_dirtyEnd = m_used;
+}
+
+uint16_t
+PacketMetadata::AddSmall (const struct PacketMetadata::SmallItem *item)
+{
+ NS_ASSERT (m_data != 0);
+ NS_ASSERT (m_used != item->prev && m_used != item->next);
+ if (g_optOne)
+ {
+ uint32_t typeUidSize = GetUleb128Size (item->typeUid);
+ uint32_t sizeSize = GetUleb128Size (item->size);
+ uint32_t n = typeUidSize + sizeSize + 2 + 2 + 2;
+ restart:
+ if (m_used + n <= m_data->m_size &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_used == m_data->m_dirtyEnd))
+ {
+ uint8_t *buffer = &m_data->m_data[m_used];
+ Append16 (item->next, buffer);
+ buffer += 2;
+ Append16 (item->prev, buffer);
+ buffer += 2;
+ AppendValue (item->typeUid, buffer);
+ buffer += typeUidSize;
+ AppendValue (item->size, buffer);
+ buffer += sizeSize;
+ Append16 (item->chunkUid, buffer);
+ }
+ else
+ {
+ ReserveCopy (n);
+ goto restart;
+ }
+ return n;
+ }
+ append:
+ uint8_t *start = &m_data->m_data[m_used];
+ uint8_t *end = &m_data->m_data[m_data->m_size];
+ if (end - start >= 8 &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_used == m_data->m_dirtyEnd))
+ {
+ uint8_t *buffer = start;
+
+ Append16 (item->next, buffer);
+ buffer += 2;
+ Append16 (item->prev, buffer);
+ buffer += 2;
+ if (TryToAppendFast (item->typeUid, &buffer, end) &&
+ TryToAppendFast (item->size, &buffer, end) &&
+ TryToAppend16 (item->chunkUid, &buffer, end))
+ {
+ uintptr_t written = buffer - start;
+ NS_ASSERT (written <= 0xffff);
+ NS_ASSERT (written >= 8);
+ return written;
+ }
+ }
+ uint32_t n = GetUleb128Size (item->typeUid);
+ n += GetUleb128Size (item->size);
+ n += 2;
+ n += 2 + 2;
+ Reserve (n);
+ goto append;
+}
+
+uint16_t
+PacketMetadata::AddBig (uint32_t next, uint32_t prev,
+ const PacketMetadata::SmallItem *item,
+ const PacketMetadata::ExtraItem *extraItem)
+{
+ NS_ASSERT (m_data != 0);
+ uint32_t typeUid = ((item->typeUid & 0x1) == 0x1)?item->typeUid:item->typeUid+1;
+ NS_ASSERT (m_used != prev && m_used != next);
+ append:
+ uint8_t *start = &m_data->m_data[m_used];
+ uint8_t *end = &m_data->m_data[m_data->m_size];
+ if (end - start >= 14 &&
+ (m_head == 0xffff ||
+ m_data->m_count == 1 ||
+ m_used == m_data->m_dirtyEnd))
+ {
+ uint8_t *buffer = start;
+
+ Append16 (next, buffer);
+ buffer += 2;
+ Append16 (prev, buffer);
+ buffer += 2;
+ if (TryToAppend (typeUid, &buffer, end) &&
+ TryToAppend (item->size, &buffer, end) &&
+ TryToAppend16 (item->chunkUid, &buffer, end) &&
+ TryToAppend (extraItem->fragmentStart, &buffer, end) &&
+ TryToAppend (extraItem->fragmentEnd, &buffer, end) &&
+ TryToAppend32 (extraItem->packetUid, &buffer, end))
+ {
+ uintptr_t written = buffer - start;
+ NS_ASSERT (written <= 0xffff);
+ NS_ASSERT (written >= 14);
+ return written;
+ }
+ }
+
+ uint32_t n = GetUleb128Size (typeUid);
+ n += GetUleb128Size (item->size);
+ n += 2;
+ n += GetUleb128Size (extraItem->fragmentStart);
+ n += GetUleb128Size (extraItem->fragmentEnd);
+ n += 4;
+ n += 2 + 2;
+ ReserveCopy (n);
+ goto append;
+}
+
+void
+PacketMetadata::ReplaceTail (PacketMetadata::SmallItem *item,
+ PacketMetadata::ExtraItem *extraItem,
+ uint32_t available)
+{
+ NS_ASSERT (m_data != 0);
+ if (available >= 14 &&
+ m_data->m_count == 1)
+ {
+ uint8_t *buffer = &m_data->m_data[m_tail];
+ uint8_t *end = buffer + available;
+
+ Append16 (item->next, buffer);
+ buffer += 2;
+ Append16 (item->prev, buffer);
+ buffer += 2;
+ if (TryToAppend (item->typeUid, &buffer, end) &&
+ TryToAppend (item->size, &buffer, end) &&
+ TryToAppend16 (item->chunkUid, &buffer, end) &&
+ TryToAppend (extraItem->fragmentStart, &buffer, end) &&
+ TryToAppend (extraItem->fragmentEnd, &buffer, end) &&
+ TryToAppend32 (extraItem->packetUid, &buffer, end))
+ {
+ m_used = buffer - &m_data->m_data[0];
+ m_data->m_dirtyEnd = m_used;
+ return;
+ }
+ }
+
+ // create a copy of the packet.
+ PacketMetadata h (m_packetUid, 0);
+ uint16_t current = m_head;
+ while (current != 0xffff && current != m_tail)
+ {
+ struct PacketMetadata::SmallItem tmpItem;
+ PacketMetadata::ExtraItem tmpExtraItem;
+ ReadItems (current, &tmpItem, &tmpExtraItem);
+ uint16_t written = h.AddBig (0xffff, h.m_tail,
+ &tmpItem, &tmpExtraItem);
+ h.UpdateTail (written);
+ }
+ // append new tail.
+ uint16_t written = h.AddBig (0xffff, h.m_tail, item, extraItem);
+ h.UpdateTail (written);
+
+ *this = h;
+}
+
+uint32_t
+PacketMetadata::ReadItems (uint16_t current,
+ struct PacketMetadata::SmallItem *item,
+ struct PacketMetadata::ExtraItem *extraItem) const
+{
+ const uint8_t *buffer = &m_data->m_data[current];
+ item->next = buffer[0];
+ item->next |= (buffer[1]) << 8;
+ item->prev = buffer[2];
+ item->prev |= (buffer[3]) << 8;
+ buffer += 4;
+ item->typeUid = ReadUleb128 (&buffer);
+ item->size = ReadUleb128 (&buffer);
+ item->chunkUid = buffer[0];
+ item->chunkUid |= (buffer[1]) << 8;
+ buffer += 2;
+
+ bool isExtra = (item->typeUid & 0x1) == 0x1;
+ if (isExtra)
+ {
+ extraItem->fragmentStart = ReadUleb128 (&buffer);
+ extraItem->fragmentEnd = ReadUleb128 (&buffer);
+ extraItem->packetUid = buffer[0];
+ extraItem->packetUid |= buffer[1] << 8;
+ extraItem->packetUid |= buffer[2] << 16;
+ extraItem->packetUid |= buffer[3] << 24;
+ buffer += 4;
+ }
+ else
+ {
+ extraItem->fragmentStart = 0;
+ extraItem->fragmentEnd = item->size;
+ extraItem->packetUid = m_packetUid;
+ }
+ NS_ASSERT (buffer <= &m_data->m_data[m_data->m_size]);
+ return buffer - &m_data->m_data[current];
+}
+
+struct PacketMetadata::Data *
+PacketMetadata::Create (uint32_t size)
+{
+ NS_LOG_LOGIC ("create size="<<size<<", max="<<m_maxSize);
+ if (size > m_maxSize)
+ {
+ m_maxSize = size;
+ }
+ while (!m_freeList.empty ())
+ {
+ struct PacketMetadata::Data *data = m_freeList.back ();
+ m_freeList.pop_back ();
+ if (data->m_size >= size)
+ {
+ NS_LOG_LOGIC ("create found size="<<data->m_size);
+ data->m_count = 1;
+ return data;
+ }
+ PacketMetadata::Deallocate (data);
+ NS_LOG_LOGIC ("create dealloc size="<<data->m_size);
+ }
+ NS_LOG_LOGIC ("create alloc size="<<m_maxSize);
+ return PacketMetadata::Allocate (m_maxSize);
+}
+
+void
+PacketMetadata::Recycle (struct PacketMetadata::Data *data)
+{
+ NS_LOG_LOGIC ("recycle size="<<data->m_size<<", list="<<m_freeList.size ());
+ NS_ASSERT (data->m_count == 0);
+ if (m_freeList.size () > 1000 ||
+ data->m_size < m_maxSize)
+ {
+ PacketMetadata::Deallocate (data);
+ }
+ else
+ {
+ m_freeList.push_back (data);
+ }
+}
+
+struct PacketMetadata::Data *
+PacketMetadata::Allocate (uint32_t n)
+{
+ uint32_t size = sizeof (struct Data);
+ if (n <= 10)
+ {
+ n = 10;
+ }
+ size += n - 10;
+ uint8_t *buf = new uint8_t [size];
+ struct PacketMetadata::Data *data = (struct PacketMetadata::Data *)buf;
+ data->m_size = n;
+ data->m_count = 1;
+ data->m_dirtyEnd = 0;
+ return data;
+}
+void
+PacketMetadata::Deallocate (struct PacketMetadata::Data *data)
+{
+ uint8_t *buf = (uint8_t *)data;
+ delete [] buf;
+}
+
+
+PacketMetadata
+PacketMetadata::CreateFragment (uint32_t start, uint32_t end) const
+{
+ PacketMetadata fragment = *this;
+ fragment.RemoveAtStart (start);
+ fragment.RemoveAtEnd (end);
+ return fragment;
+}
+
+void
+PacketMetadata::DoAddHeader (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+ NS_LOG_PARAM ("(uid=" << uid << ", size=" << size << ")");
+
+ struct PacketMetadata::SmallItem item;
+ item.next = m_head;
+ item.prev = 0xffff;
+ item.typeUid = uid;
+ item.size = size;
+ item.chunkUid = m_chunkUid;
+ m_chunkUid++;
+ uint16_t written = AddSmall (&item);
+ UpdateHead (written);
+}
+void
+PacketMetadata::DoRemoveHeader (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+ NS_LOG_PARAM ("(uid=" << uid << ", size=" << size << ")");
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t read = ReadItems (m_head, &item, &extraItem);
+ if ((item.typeUid & 0xfffffffe) != uid ||
+ item.size != size)
+ {
+ NS_FATAL_ERROR ("Removing unexpected header.");
+ }
+ else if (item.typeUid != uid &&
+ (extraItem.fragmentStart != 0 ||
+ extraItem.fragmentEnd != size))
+ {
+ NS_FATAL_ERROR ("Removing incomplete header.");
+ }
+ if (m_head + read == m_used)
+ {
+ m_used = m_head;
+ }
+ if (item.next == 0xffff)
+ {
+ m_head = 0xffff;
+ m_tail = 0xffff;
+ }
+ else
+ {
+ m_head = item.next;
+ }
+}
+void
+PacketMetadata::DoAddTrailer (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+ struct PacketMetadata::SmallItem item;
+ item.next = 0xffff;
+ item.prev = m_tail;
+ item.typeUid = uid;
+ item.size = size;
+ item.chunkUid = m_chunkUid;
+ m_chunkUid++;
+ uint16_t written = AddSmall (&item);
+ UpdateTail (written);
+}
+void
+PacketMetadata::DoRemoveTrailer (uint32_t uid, uint32_t size)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t read = ReadItems (m_tail, &item, &extraItem);
+ if ((item.typeUid & 0xfffffffe) != uid ||
+ item.size != size)
+ {
+ NS_FATAL_ERROR ("Removing unexpected trailer.");
+ }
+ else if (item.typeUid != uid &&
+ (extraItem.fragmentStart != 0 ||
+ extraItem.fragmentEnd != size))
+ {
+ NS_FATAL_ERROR ("Removing incomplete trailer.");
+ }
+ if (m_tail + read == m_used)
+ {
+ m_used = m_tail;
+ }
+ if (item.prev == 0xffff)
+ {
+ m_head = 0xffff;
+ m_tail = 0xffff;
+ }
+ else
+ {
+ m_tail = item.prev;
+ }
+}
+void
+PacketMetadata::AddAtEnd (PacketMetadata const&o)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+ if (m_tail == 0xffff)
+ {
+ *this = o;
+ return;
+ }
+ NS_ASSERT (m_head != 0xffff && m_tail != 0xffff);
+
+ uint16_t lastTail;
+ lastTail = m_tail;
+ struct PacketMetadata::SmallItem lastItem;
+ PacketMetadata::ExtraItem lastExtraItem;
+ uint32_t lastTailSize = ReadItems (m_tail, &lastItem, &lastExtraItem);
+ if (m_tail + lastTailSize == m_used &&
+ m_used == m_data->m_dirtyEnd)
+ {
+ lastTailSize = m_data->m_size - m_tail;
+ }
+
+ uint16_t current = o.m_head;
+ while (current != 0xffff)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ o.ReadItems (current, &item, &extraItem);
+ if (extraItem.packetUid == lastExtraItem.packetUid &&
+ item.typeUid == lastItem.typeUid &&
+ item.chunkUid == lastItem.chunkUid &&
+ item.size == lastItem.size &&
+ extraItem.fragmentStart == lastExtraItem.fragmentEnd)
+ {
+ // replace previous tail.
+ lastExtraItem.fragmentEnd = extraItem.fragmentEnd;
+ NS_ASSERT (m_tail == lastTail);
+ // XXX This call might be wrong.
+ ReplaceTail (&lastItem, &lastExtraItem, lastTailSize);
+ }
+ else
+ {
+ // append the extra items.
+ uint16_t written = AddBig (0xffff, m_tail, &item, &extraItem);
+ UpdateTail (written);
+ }
+ if (current == o.m_tail)
+ {
+ break;
+ }
+ current = item.next;
+ }
+}
+void
+PacketMetadata::AddPaddingAtEnd (uint32_t end)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+}
+void
+PacketMetadata::RemoveAtStart (uint32_t start)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+ NS_ASSERT (m_data != 0);
+ uint32_t leftToRemove = start;
+ uint16_t current = m_head;
+ while (current != 0xffff && leftToRemove > 0)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ ReadItems (current, &item, &extraItem);
+ uint32_t itemRealSize = extraItem.fragmentEnd - extraItem.fragmentStart;
+ if (itemRealSize <= leftToRemove)
+ {
+ // remove from list.
+ m_head = item.next;
+ leftToRemove -= itemRealSize;
+ }
+ else
+ {
+ // fragment the list item.
+ PacketMetadata fragment (m_packetUid, 0);
+ extraItem.fragmentStart += leftToRemove;
+ leftToRemove = 0;
+ uint16_t written = fragment.AddBig (0xffff, fragment.m_tail,
+ &item, &extraItem);
+ fragment.UpdateTail (written);
+ current = item.next;
+ while (current != 0xffff)
+ {
+ 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;
+ }
+ NS_ASSERT (item.size >= extraItem.fragmentEnd - extraItem.fragmentStart &&
+ extraItem.fragmentStart <= extraItem.fragmentEnd);
+ if (current == m_tail)
+ {
+ break;
+ }
+ current = item.next;
+ }
+ NS_ASSERT (leftToRemove == 0);
+}
+void
+PacketMetadata::RemoveAtEnd (uint32_t end)
+{
+ if (!m_enable)
+ {
+ m_metadataSkipped = true;
+ return;
+ }
+ NS_ASSERT (m_data != 0);
+
+ uint32_t leftToRemove = end;
+ uint16_t current = m_tail;
+ while (current != 0xffff && leftToRemove > 0)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ ReadItems (current, &item, &extraItem);
+ uint32_t itemRealSize = extraItem.fragmentEnd - extraItem.fragmentStart;
+ if (itemRealSize <= leftToRemove)
+ {
+ // remove from list.
+ m_tail = item.prev;
+ leftToRemove -= itemRealSize;
+ }
+ else
+ {
+ // fragment the list item.
+ PacketMetadata fragment (m_packetUid, 0);
+ NS_ASSERT (extraItem.fragmentEnd > leftToRemove);
+ extraItem.fragmentEnd -= leftToRemove;
+ leftToRemove = 0;
+ uint16_t written = fragment.AddBig (fragment.m_head, 0xffff,
+ &item, &extraItem);
+ fragment.UpdateHead (written);
+ current = item.prev;
+ while (current != 0xffff)
+ {
+ 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;
+ }
+ NS_ASSERT (item.size >= extraItem.fragmentEnd - extraItem.fragmentStart &&
+ extraItem.fragmentStart <= extraItem.fragmentEnd);
+ if (current == m_head)
+ {
+ break;
+ }
+ current = item.prev;
+ }
+ NS_ASSERT (leftToRemove == 0);
+}
+
+uint32_t
+PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item,
+ const struct PacketMetadata::ExtraItem *extraItem,
+ Buffer data, uint32_t offset, const PacketPrinter &printer,
+ std::ostream &os) const
+{
+ uint32_t uid = (item->typeUid & 0xfffffffe) >> 1;
+ if (uid == 0)
+ {
+ // payload.
+ printer.PrintPayload (os, extraItem->packetUid, item->size,
+ extraItem->fragmentStart,
+ item->size - extraItem->fragmentEnd);
+ }
+ else if (extraItem->fragmentStart != 0 ||
+ extraItem->fragmentEnd != item->size)
+ {
+ printer.PrintChunkFragment (uid, os, extraItem->packetUid, item->size,
+ extraItem->fragmentStart,
+ item->size - extraItem->fragmentEnd);
+ }
+ else if (ChunkRegistry::IsHeader (uid))
+ {
+ ns3::Buffer::Iterator j = data.Begin ();
+ j.Next (offset);
+ printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
+ }
+ else if (ChunkRegistry::IsTrailer (uid))
+ {
+ ns3::Buffer::Iterator j = data.End ();
+ j.Prev (data.GetSize () - (offset + item->size));
+ printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
+ }
+ else
+ {
+ NS_ASSERT (false);
+ }
+ return extraItem->fragmentEnd - extraItem->fragmentStart;
+}
+
+uint32_t
+PacketMetadata::GetTotalSize (void) const
+{
+ uint32_t totalSize = 0;
+ uint16_t current = m_head;
+ uint16_t tail = m_tail;
+ while (current != 0xffff)
+ {
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ ReadItems (current, &item, &extraItem);
+ totalSize += extraItem.fragmentEnd - extraItem.fragmentStart;
+ if (current == tail)
+ {
+ break;
+ }
+ NS_ASSERT (current != item.next);
+ current = item.next;
+ }
+ return totalSize;
+}
+
+uint32_t
+PacketMetadata::GetUid (void) const
+{
+ return m_packetUid;
+}
+
+void
+PacketMetadata::Print (std::ostream &os, Buffer data, const PacketPrinter &printer) const
+{
+ if (!m_enable)
+ {
+ return;
+ }
+ NS_ASSERT (m_data != 0);
+ NS_ASSERT (GetTotalSize () == data.GetSize ());
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ if (printer.m_forward)
+ {
+ uint32_t current = m_head;
+ uint32_t offset = 0;
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ uint32_t realSize = DoPrint (&item, &extraItem, data, offset, printer, os);
+ offset += realSize;
+ if (current == m_tail)
+ {
+ break;
+ }
+ if (item.next != 0xffff)
+ {
+ os << printer.m_separator;
+ }
+ NS_ASSERT (current != item.next);
+ current = item.next;
+ }
+ }
+ else
+ {
+ uint32_t current = m_tail;
+ uint32_t offset = data.GetSize ();
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ uint32_t realSize = DoPrint (&item, &extraItem, data, offset - item.size, printer, os);
+ offset -= realSize;
+ if (current == m_head)
+ {
+ break;
+ }
+ if (item.prev != 0xffff)
+ {
+ os << printer.m_separator;
+ }
+ NS_ASSERT (current != item.prev);
+ current = item.prev;
+ }
+ }
+}
+
+uint32_t
+PacketMetadata::GetSerializedSize (void) const
+{
+ uint32_t totalSize = 0;
+ totalSize += 4;
+ if (!m_enable)
+ {
+ return totalSize;
+ }
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t current = m_head;
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+ if (uid == 0)
+ {
+ totalSize += 4;
+ }
+ else
+ {
+ totalSize += 4 + ChunkRegistry::GetUidStringFromUid (uid).size ();
+ }
+ totalSize += 1 + 4 + 2 + 4 + 4 + 4;
+ if (current == m_tail)
+ {
+ break;
+ }
+ NS_ASSERT (current != item.next);
+ current = item.next;
+ }
+ return totalSize;
+}
+void
+PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const
+{
+ uint32_t bytesWritten = 0;
+ i.WriteU32 (size);
+ bytesWritten += 4;
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t current = m_head;
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ NS_LOG_LOGIC ("bytesWritten=" << bytesWritten << ", typeUid="<<
+ item.typeUid << ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+ ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<
+ extraItem.fragmentEnd<< ", packetUid="<<extraItem.packetUid);
+ uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+ if (uid != 0)
+ {
+ std::string uidString = ChunkRegistry::GetUidStringFromUid (uid);
+ i.WriteU32 (uidString.size ());
+ bytesWritten += 4;
+ i.Write ((uint8_t *)uidString.c_str (), uidString.size ());
+ bytesWritten += uidString.size ();
+ }
+ else
+ {
+ i.WriteU32 (0);
+ bytesWritten += 4;
+ }
+ uint8_t isBig = item.typeUid & 0x1;
+ i.WriteU8 (isBig);
+ bytesWritten += 1;
+ i.WriteU32 (item.size);
+ bytesWritten += 4;
+ i.WriteU16 (item.chunkUid);
+ bytesWritten += 2;
+ i.WriteU32 (extraItem.fragmentStart);
+ bytesWritten += 4;
+ i.WriteU32 (extraItem.fragmentEnd);
+ bytesWritten += 4;
+ i.WriteU32 (extraItem.packetUid);
+ bytesWritten += 4;
+ if (current == m_tail)
+ {
+ break;
+ }
+
+ NS_ASSERT (current != item.next);
+ current = item.next;
+ }
+ NS_ASSERT (bytesWritten == size);
+}
+uint32_t
+PacketMetadata::Deserialize (Buffer::Iterator i)
+{
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t totalSize = i.ReadU32 ();
+ uint32_t size = totalSize;
+ size -= 4;
+ while (size > 0)
+ {
+ uint32_t uidStringSize = i.ReadU32 ();
+ size -= 4;
+ uint32_t uid;
+ if (uidStringSize == 0)
+ {
+ // uid zero for payload.
+ uid = 0;
+ }
+ else
+ {
+ std::string uidString;
+ for (uint32_t j = 0; j < uidStringSize; j++)
+ {
+ uidString.push_back (i.ReadU8 ());
+ size --;
+ }
+ uid = ChunkRegistry::GetUidFromUidString (uidString);
+ }
+ uint8_t isBig = i.ReadU8 ();
+ size --;
+ item.typeUid = (uid << 1) | isBig;
+ item.size = i.ReadU32 ();
+ size -= 4;
+ item.chunkUid = i.ReadU16 ();
+ size -= 2;
+ extraItem.fragmentStart = i.ReadU32 ();
+ size -= 4;
+ extraItem.fragmentEnd = i.ReadU32 ();
+ size -= 4;
+ extraItem.packetUid = i.ReadU32 ();
+ size -= 4;
+ NS_LOG_LOGIC ("size=" << size << ", typeUid="<<item.typeUid <<
+ ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+ ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<
+ extraItem.fragmentEnd<< ", packetUid="<<extraItem.packetUid);
+ uint32_t tmp = AddBig (0xffff, m_tail, &item, &extraItem);
+ UpdateTail (tmp);
+ }
+ NS_ASSERT (size == 0);
+ return totalSize;
+}
+
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,347 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_METADATA_H
+#define PACKET_METADATA_H
+
+#include <stdint.h>
+#include <vector>
+#include "ns3/callback.h"
+#include "ns3/assert.h"
+#include "packet-printer.h"
+
+namespace ns3 {
+
+class Chunk;
+class Buffer;
+
+/**
+ * \internal
+ * \brief handle packet metadata about packet headers and trailers
+ *
+ * This class is used by the Packet class to record every operation
+ * performed on the packet's buffer. This class also provides
+ * an implementation of the Packet::Print methods which uses
+ * the metadata to analyse the content of the packet's buffer.
+ *
+ * To achieve this, this class maintains a linked list of so-called
+ * "items", each of which represents a header or a trailer, or
+ * payload, or a fragment of any of these. Each item contains a "next"
+ * and a "prev" field which point to the next and previous entries
+ * in the linked list. The PacketMetadata class maintains a pair
+ * of pointers to the head and the tail of the linked list.
+ *
+ * Each entry in the list also maintains:
+ * - its native size (the size it had when it was first added
+ * to the packet)
+ * - its type: identifies what kind of header, what kind of trailer,
+ * if it is payload or not
+ * - the uid of the packet to which it was first added
+ * - the start and end of the area represented by a fragment
+ * if it is one.
+ *
+ * This linked list is flattened in a byte buffer stored in
+ * struct PacketMetadata::Data. Each entry of the linked list is
+ * identified by an offset which identifies the first byte of the
+ * entry from the start of the data buffer. The size of this data
+ * buffer is 2^16-1 bytes maximum which somewhat limits the number
+ * of entries which can be stored in this linked list but it is
+ * quite unlikely to hit this limit in practice.
+ *
+ * Each item of the linked list is a variable-sized byte buffer
+ * made of a number of fields. Some of these fields are stored
+ * as fixed-size 32 bit integers, others as fixed-size 16 bit
+ * integers, and some others as variable-size 32-bit integers.
+ * The variable-size 32 bit integers are stored using the uleb128
+ * encoding.
+ */
+class PacketMetadata {
+public:
+ static void Enable (void);
+ static void SetOptOne (bool optOne);
+
+ inline PacketMetadata (uint32_t uid, uint32_t size);
+ inline PacketMetadata (PacketMetadata const &o);
+ inline PacketMetadata &operator = (PacketMetadata const& o);
+ inline ~PacketMetadata ();
+
+ template <typename T>
+ void AddHeader (T const &header, uint32_t size);
+ template <typename T>
+ void RemoveHeader (T const &header, uint32_t size);
+
+ template <typename T>
+ void AddTrailer (T const &trailer, uint32_t size);
+ template <typename T>
+ void RemoveTrailer (T const &trailer, uint32_t size);
+
+ PacketMetadata CreateFragment (uint32_t start, uint32_t end) const;
+ void AddAtEnd (PacketMetadata const&o);
+ void AddPaddingAtEnd (uint32_t end);
+ void RemoveAtStart (uint32_t start);
+ void RemoveAtEnd (uint32_t end);
+
+ uint32_t GetUid (void) const;
+
+ void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const;
+
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator i, uint32_t size) const;
+ uint32_t Deserialize (Buffer::Iterator i);
+
+ static void PrintStats (void);
+
+private:
+ struct Data {
+ /* number of references to this struct Data instance. */
+ uint16_t m_count;
+ /* size (in bytes) of m_data buffer below */
+ uint16_t m_size;
+ /* max of the m_used field over all objects which
+ * reference this struct Data instance */
+ uint16_t m_dirtyEnd;
+ /* variable-sized buffer of bytes */
+ uint8_t m_data[10];
+ };
+ /* Note that since the next and prev fields are 16 bit integers
+ and since the value 0xffff is reserved to identify the
+ fact that the end or the start of the list is reached,
+ only a limited number of elements can be stored in
+ a m_data byte buffer.
+ */
+ struct SmallItem {
+ /* offset (in bytes) from start of m_data buffer
+ to next element in linked list. value is 0xffff
+ if next element does not exist.
+ stored as a fixed-size 16 bit integer.
+ */
+ uint16_t next;
+ /* offset (in bytes) from start of m_data buffer
+ to previous element in linked list. value is 0xffff
+ if previous element does not exist.
+ stored as a fixed-size 16 bit integer.
+ */
+ uint16_t prev;
+ /* the high 31 bits of this field identify the
+ type of the header or trailer represented by
+ this item: the value zero represents payload.
+ If the low bit of this uid is one, an ExtraItem
+ structure follows this SmallItem structure.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t typeUid;
+ /* the size (in bytes) of the header or trailer represented
+ by this element.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t size;
+ /* this field tries to uniquely identify each header or
+ trailer _instance_ while the typeUid field uniquely
+ identifies each header or trailer _type_. This field
+ is used to test whether two items are equal in the sense
+ that they represent the same header or trailer instance.
+ That equality test is based on the typeUid and chunkUid
+ fields so, the likelyhood that two header instances
+ share the same chunkUid _and_ typeUid is very small
+ unless they are really representations of the same header
+ instance.
+ stored as a fixed-size 16 bit integer.
+ */
+ uint16_t chunkUid;
+ };
+ struct ExtraItem {
+ /* offset (in bytes) from start of original header to
+ the start of the fragment still present.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t fragmentStart;
+ /* offset (in bytes) from start of original header to
+ the end of the fragment still present.
+ stored as a variable-size 32 bit integer.
+ */
+ uint32_t fragmentEnd;
+ /* the packetUid of the packet in which this header or trailer
+ was first added. It could be different from the m_packetUid
+ field if the user has aggregated multiple packets into one.
+ stored as a fixed-size 32 bit integer.
+ */
+ uint32_t packetUid;
+ };
+
+ class DataFreeList : public std::vector<struct Data *>
+ {
+ public:
+ ~DataFreeList ();
+ };
+
+ PacketMetadata ();
+ void DoAddHeader (uint32_t uid, uint32_t size);
+ void DoRemoveHeader (uint32_t uid, uint32_t size);
+ void DoAddTrailer (uint32_t uid, uint32_t size);
+ void DoRemoveTrailer (uint32_t uid, uint32_t size);
+
+ inline uint16_t AddSmall (const PacketMetadata::SmallItem *item);
+ uint16_t AddBig (uint32_t head, uint32_t tail,
+ const PacketMetadata::SmallItem *item,
+ const PacketMetadata::ExtraItem *extraItem);
+ void ReplaceTail (PacketMetadata::SmallItem *item,
+ PacketMetadata::ExtraItem *extraItem,
+ uint32_t available);
+ inline void UpdateHead (uint16_t written);
+ inline void UpdateTail (uint16_t written);
+ uint32_t GetUleb128Size (uint32_t value) const;
+ uint32_t ReadUleb128 (const uint8_t **pBuffer) const;
+ inline void Append16 (uint16_t value, uint8_t *buffer);
+ inline bool TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+ inline bool TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+ inline bool TryToAppend32 (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+ inline bool TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end);
+ void AppendValue (uint32_t value, uint8_t *buffer);
+ void AppendValueExtra (uint32_t value, uint8_t *buffer);
+ inline void Reserve (uint32_t n);
+ void ReserveCopy (uint32_t n);
+ uint32_t DoPrint (const struct PacketMetadata::SmallItem *item,
+ const struct PacketMetadata::ExtraItem *extraItem,
+ Buffer data, uint32_t offset, const PacketPrinter &printer,
+ std::ostream &os) const;
+ uint32_t GetTotalSize (void) const;
+ uint32_t ReadItems (uint16_t current,
+ struct PacketMetadata::SmallItem *item,
+ struct PacketMetadata::ExtraItem *extraItem) const;
+
+
+ static struct PacketMetadata::Data *Create (uint32_t size);
+ static void Recycle (struct PacketMetadata::Data *data);
+ static struct PacketMetadata::Data *Allocate (uint32_t n);
+ static void Deallocate (struct PacketMetadata::Data *data);
+
+ static DataFreeList m_freeList;
+ static bool m_enable;
+
+ // set to true when adding metadata to a packet is skipped because
+ // m_enable is false; used to detect enabling of metadata in the
+ // middle of a simulation, which isn't allowed.
+ static bool m_metadataSkipped;
+
+ static uint32_t m_maxSize;
+ static uint16_t m_chunkUid;
+
+ struct Data *m_data;
+ /**
+ head -(next)-> tail
+ ^ |
+ \---(prev)---|
+ */
+ uint16_t m_head;
+ uint16_t m_tail;
+ uint16_t m_used;
+ uint32_t m_packetUid;
+};
+
+}; // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+PacketMetadata::AddHeader (T const &header, uint32_t size)
+{
+ DoAddHeader (T::GetUid () << 1, size);
+}
+
+template <typename T>
+void
+PacketMetadata::RemoveHeader (T const &header, uint32_t size)
+{
+ DoRemoveHeader (T::GetUid () << 1, size);
+}
+template <typename T>
+void
+PacketMetadata::AddTrailer (T const &trailer, uint32_t size)
+{
+ DoAddTrailer (T::GetUid () << 1, size);
+}
+template <typename T>
+void
+PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size)
+{
+ DoRemoveTrailer (T::GetUid () << 1, size);
+}
+
+
+PacketMetadata::PacketMetadata (uint32_t uid, uint32_t size)
+ : m_data (m_data = PacketMetadata::Create (10)),
+ m_head (0xffff),
+ m_tail (0xffff),
+ m_used (0),
+ m_packetUid (uid)
+{
+ memset (m_data->m_data, 0xff, 4);
+ if (size > 0)
+ {
+ DoAddHeader (0, size);
+ }
+}
+PacketMetadata::PacketMetadata (PacketMetadata const &o)
+ : m_data (o.m_data),
+ m_head (o.m_head),
+ m_tail (o.m_tail),
+ m_used (o.m_used),
+ m_packetUid (o.m_packetUid)
+{
+ NS_ASSERT (m_data != 0);
+ m_data->m_count++;
+}
+PacketMetadata &
+PacketMetadata::operator = (PacketMetadata const& o)
+{
+ if (m_data != o.m_data)
+ {
+ // not self assignment
+ NS_ASSERT (m_data != 0);
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ PacketMetadata::Recycle (m_data);
+ }
+ m_data = o.m_data;
+ NS_ASSERT (m_data != 0);
+ m_data->m_count++;
+ }
+ m_head = o.m_head;
+ m_tail = o.m_tail;
+ m_used = o.m_used;
+ m_packetUid = o.m_packetUid;
+ return *this;
+}
+PacketMetadata::~PacketMetadata ()
+{
+ NS_ASSERT (m_data != 0);
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ PacketMetadata::Recycle (m_data);
+ }
+}
+
+}; // namespace ns3
+
+
+#endif /* PACKET_METADATA_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-printer.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,135 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "packet-printer.h"
+#include "chunk-registry.h"
+
+namespace ns3 {
+
+PacketPrinter::PacketPrinter ()
+ : m_forward (true),
+ m_separator (" ")
+{}
+
+void
+PacketPrinter::PrintForward (void)
+{
+ m_forward = true;
+}
+void
+PacketPrinter::PrintBackward (void)
+{
+ m_forward = false;
+}
+void
+PacketPrinter::SetSeparator (std::string separator)
+{
+ m_separator = separator;
+}
+void
+PacketPrinter::SetPayloadPrinter (PayloadPrinter printer)
+{
+ m_payloadPrinter = printer;
+}
+
+void
+PacketPrinter::PrintChunk (uint32_t chunkUid,
+ Buffer::Iterator start,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size) const
+{
+ uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+ ChunkRegistry::Deserialize (chunkUid, instance, start);
+
+ for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
+ {
+ if (i->m_chunkUid == chunkUid)
+ {
+ ChunkRegistry::InvokePrintCallback (chunkUid, instance, os, packetUid, size, i->m_printer);
+ return;
+ }
+ }
+ // if the over did not override this type of chunk,
+ // we print something by default.
+ std::string name = ChunkRegistry::GetName (chunkUid, instance);
+ os << name;
+ ChunkRegistry::Print (chunkUid, instance, os);
+}
+void
+PacketPrinter::PrintChunkFragment (uint32_t chunkUid,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size,
+ uint32_t fragmentStart,
+ uint32_t fragmentEnd) const
+{
+ uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+ std::string name = ChunkRegistry::GetName (chunkUid, instance);
+ struct PacketPrinter::FragmentInformation info;
+ info.start = fragmentStart;
+ info.end = fragmentEnd;
+ for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
+ {
+ if (i->m_chunkUid == chunkUid)
+ {
+
+ i->m_fragmentPrinter (os, packetUid, size, name, info);
+ return;
+ }
+ }
+ // if the user did not override this type of chunk,
+ // we print something by default.
+ NS_ASSERT (info.start != 0 || info.end != 0);
+ os << name << " "
+ << "("
+ << "length " << size - (info.end + info.start) << " "
+ << "trim_start " << info.start << " "
+ << "trim_end " << info.end
+ << ")";
+}
+void
+PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
+ uint32_t fragmentStart, uint32_t fragmentEnd) const
+{
+ struct PacketPrinter::FragmentInformation info;
+ info.start = fragmentStart;
+ info.end = fragmentEnd;
+ if (!m_payloadPrinter.IsNull ())
+ {
+ m_payloadPrinter (os, packetUid, size, info);
+ return;
+ }
+ // if the user did not override the payload printer,
+ // we print something anyway.
+ os << "DATA ("
+ << "length " << size - (info.end + info.start);
+ if (info.start != 0 || info.end != 0)
+ {
+ os << " "
+ << "trim_start " << info.start << " "
+ << "trim_end " << info.end;
+ }
+ os << ")";
+
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-printer.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,181 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_PRINTER_H
+#define PACKET_PRINTER_H
+
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "buffer.h"
+#include <vector>
+
+namespace ns3 {
+
+/**
+ * \brief hold a list of print callbacks for packet headers and trailers
+ *
+ * Users can register in instances of this class print callbacks
+ * which are used by Packet::Print to print the content of a packet.
+ */
+class PacketPrinter
+{
+public:
+ /**
+ * \brief indicates how many bytes were trimmed from a header
+ * or a trailer.
+ */
+ struct FragmentInformation
+ {
+ /**
+ * The number of bytes trimmed from the start of the header or the trailer.
+ */
+ uint32_t start;
+ /**
+ * The number of bytes trimmed from the end of the header or the trailer.
+ */
+ uint32_t end;
+ };
+ /**
+ * \brief callback to print payload.
+ *
+ * Arguments: output stream, packet uid, size, fragment information
+ */
+ typedef Callback<void,std::ostream &,uint32_t,uint32_t,struct PacketPrinter::FragmentInformation>
+ PayloadPrinter;
+
+ /**
+ * \brief callback to print fragmented chunks.
+ *
+ * Arguments: output stream, packet uid, size, header/trailer name, fragment information
+ */
+ typedef Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
+ ChunkFragmentPrinter;
+
+ /**
+ * \brief callback to print chunks for which no specific callback was specified.
+ *
+ * Arguments: output stream, packet uid, size, header/trailer name, fragment information
+ */
+ typedef Callback<void,std::ostream&,uint32_t,uint32_t,std::string&,struct PacketPrinter::FragmentInformation>
+ DefaultPrinter;
+
+ PacketPrinter ();
+
+ /**
+ * Print the content of the packet forward.
+ */
+ void PrintForward (void);
+ /**
+ * Print the content of the packet backward.
+ */
+ void PrintBackward (void);
+ /**
+ * \param separator the new separator
+ *
+ * The default separator is a single space character.
+ */
+ void SetSeparator (std::string separator);
+ /**
+ * \param printer printer for payload
+ */
+ void SetPayloadPrinter (PayloadPrinter printer);
+ /**
+ * \param printer printer for the specified chunk
+ * \param fragmentPrinter printer for a fragment of the specified chunk
+ *
+ * If the user does not force a user-specific printing function through
+ * a call to SetHeaderPrinter, the default print output is generated.
+ */
+ template <typename T>
+ void SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter);
+ /**
+ * \param printer printer for the specified chunk
+ * \param fragmentPrinter printer for a fragment of the specified chunk
+ *
+ * If the user does not force a user-specific printing function through
+ * a call to SetTrailerPrinter, the default print output is generated.
+ */
+ template <typename T>
+ void SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter);
+private:
+ friend class PacketMetadata;
+ void PrintChunk (uint32_t uid,
+ Buffer::Iterator i,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size) const;
+ void PrintChunkFragment (uint32_t uid,
+ std::ostream &os,
+ uint32_t packetUid,
+ uint32_t size,
+ uint32_t fragmentStart,
+ uint32_t fragmentEnd) const;
+ void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
+ uint32_t fragmentStart, uint32_t fragmentEnd) const;
+ struct Printer
+ {
+ uint32_t m_chunkUid;
+ Ptr<CallbackImplBase> m_printer;
+ Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,
+ struct PacketPrinter::FragmentInformation> m_fragmentPrinter;
+ };
+ typedef std::vector<struct PacketPrinter::Printer> PrinterList;
+
+ PrinterList m_printerList;
+ PayloadPrinter m_payloadPrinter;
+ DefaultPrinter m_defaultPrinter;
+ bool m_forward;
+ std::string m_separator;
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+PacketPrinter::SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter)
+{
+ Printer p;
+ p.m_chunkUid = T::GetUid ();
+ p.m_printer = printer.GetImpl ();
+ p.m_fragmentPrinter = fragmentPrinter;
+ m_printerList.push_back (p);
+}
+
+template <typename T>
+void
+PacketPrinter::SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter)
+{
+ Printer p;
+ p.m_chunkUid = T::GetUid ();
+ p.m_printer = printer.GetImpl ();
+ p.m_fragmentPrinter = fragmentPrinter;
+ m_printerList.push_back (p);
+}
+
+
+} // namespace ns3
+
+#endif /* PACKET_PRINTER_H */
--- a/src/common/packet.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/packet.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,6 +19,7 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "packet.h"
+#include "packet-printer.h"
#include "ns3/assert.h"
namespace ns3 {
@@ -27,20 +28,20 @@
Packet::Packet ()
: m_buffer (),
- m_uid (m_globalUid)
+ m_metadata (m_globalUid, 0)
{
m_globalUid++;
}
Packet::Packet (uint32_t size)
: m_buffer (size),
- m_uid (m_globalUid)
+ m_metadata (m_globalUid, size)
{
m_globalUid++;
}
Packet::Packet (uint8_t const*buffer, uint32_t size)
: m_buffer (),
- m_uid (m_globalUid)
+ m_metadata (m_globalUid, size)
{
m_globalUid++;
m_buffer.AddAtStart (size);
@@ -48,17 +49,20 @@
i.Write (buffer, size);
}
-Packet::Packet (Buffer buffer, Tags tags, uint32_t uid)
+Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
: m_buffer (buffer),
m_tags (tags),
- m_uid (uid)
+ m_metadata (metadata)
{}
Packet
Packet::CreateFragment (uint32_t start, uint32_t length) const
{
Buffer buffer = m_buffer.CreateFragment (start, length);
- return Packet (buffer, m_tags, m_uid);
+ NS_ASSERT (m_buffer.GetSize () >= start + length);
+ uint32_t end = m_buffer.GetSize () - (start + length);
+ PacketMetadata metadata = m_metadata.CreateFragment (start, end);
+ return Packet (buffer, m_tags, metadata);
}
uint32_t
@@ -70,30 +74,37 @@
void
Packet::AddAtEnd (Packet packet)
{
- Buffer src = packet.m_buffer;
- m_buffer.AddAtEnd (src.GetSize ());
- Buffer::Iterator destStart = m_buffer.End ();
+ Buffer src = packet.m_buffer.CreateFullCopy ();
+ Buffer dst = m_buffer.CreateFullCopy ();
+
+ dst.AddAtEnd (src.GetSize ());
+ Buffer::Iterator destStart = dst.End ();
destStart.Prev (src.GetSize ());
destStart.Write (src.Begin (), src.End ());
+ m_buffer = dst;
/**
* XXX: we might need to merge the tag list of the
* other packet into the current packet.
*/
+ m_metadata.AddAtEnd (packet.m_metadata);
}
void
Packet::AddPaddingAtEnd (uint32_t size)
{
m_buffer.AddAtEnd (size);
+ m_metadata.AddPaddingAtEnd (size);
}
void
Packet::RemoveAtEnd (uint32_t size)
{
m_buffer.RemoveAtEnd (size);
+ m_metadata.RemoveAtEnd (size);
}
void
Packet::RemoveAtStart (uint32_t size)
{
m_buffer.RemoveAtStart (size);
+ m_metadata.RemoveAtStart (size);
}
void
@@ -111,14 +122,91 @@
uint32_t
Packet::GetUid (void) const
{
- return m_uid;
+ return m_metadata.GetUid ();
+}
+
+void
+Packet::PrintTags (std::ostream &os) const
+{
+ m_tags.Print (os, " ");
}
void
Packet::Print (std::ostream &os) const
-{}
+{
+ m_metadata.Print (os, m_buffer, PacketPrinter ());
+}
+
+void
+Packet::Print (std::ostream &os, const PacketPrinter &printer) const
+{
+ m_metadata.Print (os, m_buffer, printer);
+}
+
+void
+Packet::EnableMetadata (void)
+{
+ PacketMetadata::Enable ();
+}
+
+Buffer
+Packet::Serialize (void) const
+{
+ Buffer buffer;
+ uint32_t reserve;
+
+ // write metadata
+ reserve = m_metadata.GetSerializedSize ();
+ buffer.AddAtStart (reserve);
+ m_metadata.Serialize (buffer.Begin (), reserve);
-}; // namespace ns3
+ // write tags
+ reserve = m_tags.GetSerializedSize ();
+ buffer.AddAtStart (reserve);
+ m_tags.Serialize (buffer.Begin (), reserve);
+
+ // aggregate byte buffer, metadata, and tags
+ Buffer tmp = m_buffer.CreateFullCopy ();
+ buffer.AddAtStart (tmp.GetSize ());
+ buffer.Begin ().Write (tmp.Begin (), tmp.End ());
+
+ // write byte buffer size.
+ buffer.AddAtStart (4);
+ buffer.Begin ().WriteU32 (m_buffer.GetSize ());
+
+ return buffer;
+}
+void
+Packet::Deserialize (Buffer buffer)
+{
+ Buffer buf = buffer;
+ // read size
+ uint32_t packetSize = buf.Begin ().ReadU32 ();
+ buf.RemoveAtStart (4);
+
+ // read buffer.
+ buf.RemoveAtEnd (buf.GetSize () - packetSize);
+ m_buffer = buf;
+
+ // read tags
+ buffer.RemoveAtStart (4 + packetSize);
+ uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
+ buffer.RemoveAtStart (tagsDeserialized);
+
+ // read metadata
+ uint32_t metadataDeserialized =
+ m_metadata.Deserialize (buffer.Begin ());
+ buffer.RemoveAtStart (metadataDeserialized);
+}
+
+std::ostream& operator<< (std::ostream& os, const Packet &packet)
+{
+ packet.Print (os);
+ return os;
+}
+
+
+} // namespace ns3
@@ -161,7 +249,7 @@
packet.GetSize ());
if (msg != "hello world")
{
- Failure () << "expected size 'hello world', got " << msg << std::endl;
+ Failure () << "expected 'hello world', got '" << msg << "'" << std::endl;
ok = false;
}
--- a/src/common/packet.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/packet.h Fri Sep 28 11:59:46 2007 +0100
@@ -26,20 +26,27 @@
#include "header.h"
#include "trailer.h"
#include "tags.h"
+#include "packet-metadata.h"
+#include "tag.h"
#include "ns3/callback.h"
#include "ns3/assert.h"
namespace ns3 {
+class PacketPrinter;
+
/**
* \brief network packets
*
- * Each network packet contains a byte buffer and a list of tags.
+ * Each network packet contains a byte buffer, a list of tags, and
+ * metadata.
+ *
* - The byte buffer stores the serialized content of the headers and trailers
* added to a packet. The serialized representation of these headers is expected
* to match that of real network packets bit for bit (although nothing
* forces you to do this) which means that the content of a packet buffer
* is expected to be that of a real packet.
+ *
* - The list of tags stores an arbitrarily large set of arbitrary
* user-provided data structures in the packet: only one instance of
* each type of data structure is allowed in a list of tags.
@@ -48,43 +55,22 @@
* 16 bytes big. Trying to attach bigger data structures will trigger
* crashes at runtime.
*
- * Implementing a new type of Header for a new protocol is pretty easy
- * and is a matter of creating a subclass of the ns3::Header base class,
- * and implementing the 4 pure virtual methods defined in ns3::Header.
- * Sample code which shows how to create such a new Header, how to use
- * it, and how to manipulate tags is shown below:
- * \include samples/main-packet.cc
- *
- * The current implementation of the byte buffers and tag list is based
- * on COW (Copy On Write. An introduction to COW can be found in Scott
- * Meyer's "More Effective C++", items 17 and 29). What this means is that
- * copying packets without modifying them is very cheap (in terms of cpu
- * and memory usage) and modifying them can be also very cheap. What is
- * key for proper COW implementations is being
- * able to detect when a given modification of the state of a packet triggers
- * a full copy of the data prior to the modification: COW systems need
- * to detect when an operation is "dirty".
+ * - The metadata describes the type of the headers and trailers which
+ * were serialized in the byte buffer. The maintenance of metadata is
+ * optional and disabled by default. To enable it, you must call
+ * Packet::EnableMetadata and this will allow you to get non-empty
+ * output from Packet::Print and Packet::Print.
*
- * Dirty operations:
- * - ns3::Packet::RemoveTag
- * - ns3::Packet::Add
- * - both versions of ns3::Packet::AddAtEnd
+ * Implementing a new type of Header or Trailer for a new protocol is
+ * pretty easy and is a matter of creating a subclass of the ns3::Header
+ * or of the ns3::Trailer base class, and implementing the methods
+ * described in their respective API documentation.
*
- * Non-dirty operations:
- * - ns3::Packet::AddTag
- * - ns3::Packet::RemoveAllTags
- * - ns3::Packet::PeekTag
- * - ns3::Packet::Peek
- * - ns3::Packet::Remove
- * - ns3::Packet::CreateFragment
- * - ns3::Packet::RemoveAtStart
- * - ns3::Packet::RemoveAtEnd
+ * Implementing a new type of Tag requires roughly the same amount of
+ * work and this work is described in the ns3::Tag API documentation.
*
- * Dirty operations will always be slower than non-dirty operations,
- * sometimes by several orders of magnitude. However, even the
- * dirty operations have been optimized for common use-cases which
- * means that most of the time, these operations will not trigger
- * data copies and will thus be still very fast.
+ * The performance aspects of the Packet API are discussed in
+ * \ref packetperf
*/
class Packet {
public:
@@ -129,7 +115,7 @@
uint32_t GetSize (void) const;
/**
* Add header to this packet. This method invokes the
- * ns3::Header::GetSerializedSize and ns3::Header::SerializeTo
+ * GetSerializedSize and Serialize
* methods to reserve space in the buffer and request the
* header to serialize itself in the packet buffer.
*
@@ -139,8 +125,7 @@
void AddHeader (T const &header);
/**
* Deserialize and remove the header from the internal buffer.
- * This method invokes ns3::Header::DeserializeFrom
- * and then removes the deserialized bytes from the buffer.
+ * This method invokes Deserialize.
*
* \param header a reference to the header to remove from the internal buffer.
* \returns the number of bytes removed from the packet.
@@ -149,7 +134,7 @@
uint32_t RemoveHeader (T &header);
/**
* Add trailer to this packet. This method invokes the
- * ns3::Trailer::GetSerializedSize and ns3::Trailer::serializeTo
+ * GetSerializedSize and Serialize
* methods to reserve space in the buffer and request the trailer
* to serialize itself in the packet buffer.
*
@@ -159,8 +144,7 @@
void AddTrailer (T const &trailer);
/**
* Remove a deserialized trailer from the internal buffer.
- * This method invokes the ns3::Trailer::DeserializeFrom method
- * and then removes the deserialized bytes from the buffer.
+ * This method invokes the Deserialize method.
*
* \param trailer a reference to the trailer to remove from the internal buffer.
* \returns the number of bytes removed from the end of the packet.
@@ -170,7 +154,8 @@
/**
* Attach a tag to this packet. The tag is fully copied
* in a packet-specific internal buffer. This operation
- * is expected to be really fast.
+ * is expected to be really fast. The copy constructor of the
+ * tag is invoked to copy it into the tag buffer.
*
* \param tag a pointer to the tag to attach to this packet.
*/
@@ -197,6 +182,8 @@
/**
* Copy a tag stored internally to the input tag. If no instance
* of this tag is present internally, the input tag is not modified.
+ * The copy constructor of the tag is invoked to copy it into the
+ * input tag variable.
*
* \param tag a pointer to the tag to read from this packet
* \returns true if an instance of this tag type is stored
@@ -210,6 +197,14 @@
*/
void RemoveAllTags (void);
/**
+ * \param os output stream in which the data should be printed.
+ *
+ * Iterate over the tags present in this packet, and
+ * invoke the Print method of each tag stored in the packet.
+ */
+ void PrintTags (std::ostream &os) const;
+
+ /**
* Concatenate the input packet at the end of the current
* packet. This does not alter the uid of either packet.
*
@@ -254,16 +249,123 @@
*/
uint32_t GetUid (void) const;
+ /**
+ * \param os output stream in which the data should be printed.
+ *
+ * Iterate over the headers and trailers present in this packet,
+ * from the first header to the last trailer and invoke, for
+ * each of them, the user-provided method Header::DoPrint or
+ * Trailer::DoPrint methods.
+ */
void Print (std::ostream &os) const;
+ /**
+ * \param os output stream in which the data should be printed.
+ * \param printer the output formatter to use to print
+ * the content of this packet.
+ *
+ * Iterate over the headers and trailers present in this packet,
+ * either in the "forward" (first header to last trailer) or in
+ * the "backward" (last trailer to first header) direction, as
+ * specified by the PacketPrinter::PrintForward or the
+ * PacketPrinter::PrintBackward methods. For each header, trailer,
+ * or fragment of a header or a trailer, invoke the user-specified
+ * print callback stored in the specified PacketPrinter.
+ */
+ void Print (std::ostream &os, const PacketPrinter &printer) const;
+
+ /**
+ * 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.
+ *
+ * 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
+ * when you remove a header from a packet, this same header
+ * was actually present at the front of the packet. These
+ * errors will be detected and will abort the program.
+ */
+ static void EnableMetadata (void);
+
+ /**
+ * \returns a byte buffer
+ *
+ * This method creates a serialized representation of a Packet object
+ * ready to be transmitted over a network to another system. This
+ * serialized representation contains a copy of the packet byte buffer,
+ * the tag list, and the packet metadata (if there is one).
+ *
+ * This method will trigger calls to the Serialize and GetSerializedSize
+ * methods of each tag stored in this packet.
+ *
+ * This method will typically be used by parallel simulations where
+ * the simulated system is partitioned and each partition runs on
+ * a different CPU.
+ */
+ Buffer Serialize (void) const;
+ /**
+ * \param buffer a byte buffer
+ *
+ * This method reads a byte buffer as created by Packet::Serialize
+ * and restores the state of the Packet to what it was prior to
+ * calling Serialize.
+ *
+ * This method will trigger calls to the Deserialize method
+ * of each tag stored in this packet.
+ *
+ * This method will typically be used by parallel simulations where
+ * the simulated system is partitioned and each partition runs on
+ * a different CPU.
+ */
+ void Deserialize (Buffer buffer);
private:
- Packet (Buffer buffer, Tags tags, uint32_t uid);
+ Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
Buffer m_buffer;
Tags m_tags;
- uint32_t m_uid;
+ PacketMetadata m_metadata;
static uint32_t m_globalUid;
};
-}; // namespace ns3
+std::ostream& operator<< (std::ostream& os, const Packet &packet);
+
+/**
+ * \defgroup packetperf Packet Performance
+ * The current implementation of the byte buffers and tag list is based
+ * on COW (Copy On Write. An introduction to COW can be found in Scott
+ * Meyer's "More Effective C++", items 17 and 29). What this means is that
+ * copying packets without modifying them is very cheap (in terms of cpu
+ * and memory usage) and modifying them can be also very cheap. What is
+ * key for proper COW implementations is being
+ * able to detect when a given modification of the state of a packet triggers
+ * a full copy of the data prior to the modification: COW systems need
+ * to detect when an operation is "dirty".
+ *
+ * Dirty operations:
+ * - ns3::Packet::RemoveTag
+ * - ns3::Packet::AddHeader
+ * - ns3::Packet::AddTrailer
+ * - both versions of ns3::Packet::AddAtEnd
+ *
+ * Non-dirty operations:
+ * - ns3::Packet::AddTag
+ * - ns3::Packet::RemoveAllTags
+ * - ns3::Packet::PeekTag
+ * - ns3::Packet::RemoveHeader
+ * - ns3::Packet::RemoveTrailer
+ * - ns3::Packet::CreateFragment
+ * - ns3::Packet::RemoveAtStart
+ * - ns3::Packet::RemoveAtEnd
+ *
+ * Dirty operations will always be slower than non-dirty operations,
+ * sometimes by several orders of magnitude. However, even the
+ * dirty operations have been optimized for common use-cases which
+ * means that most of the time, these operations will not trigger
+ * data copies and will thus be still very fast.
+ */
+
+} // namespace ns3
/**************************************************
@@ -277,41 +379,53 @@
void
Packet::AddHeader (T const &header)
{
- NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0,
- "Must pass Header subclass to Packet::AddHeader");
- uint32_t size = header.GetSize ();
+ const Header *testHeader;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Header class
+ testHeader = &header;
+ uint32_t size = header.GetSerializedSize ();
m_buffer.AddAtStart (size);
header.Serialize (m_buffer.Begin ());
+ m_metadata.AddHeader (header, size);
}
template <typename T>
uint32_t
Packet::RemoveHeader (T &header)
{
- NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0,
- "Must pass Header subclass to Packet::RemoveHeader");
+ Header *testHeader;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Header class
+ testHeader = &header;
uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
m_buffer.RemoveAtStart (deserialized);
+ m_metadata.RemoveHeader (header, deserialized);
return deserialized;
}
template <typename T>
void
Packet::AddTrailer (T const &trailer)
{
- NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0,
- "Must pass Trailer subclass to Packet::AddTrailer");
- uint32_t size = trailer.GetSize ();
+ const Trailer *testTrailer;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Trailer class
+ testTrailer = &trailer;
+ uint32_t size = trailer.GetSerializedSize ();
m_buffer.AddAtEnd (size);
Buffer::Iterator end = m_buffer.End ();
trailer.Serialize (end);
+ m_metadata.AddTrailer (trailer, size);
}
template <typename T>
uint32_t
Packet::RemoveTrailer (T &trailer)
{
- NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0,
- "Must pass Trailer subclass to Packet::RemoveTrailer");
+ Trailer *testTrailer;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Trailer class
+ testTrailer = &trailer;
uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
m_buffer.RemoveAtEnd (deserialized);
+ m_metadata.RemoveTrailer (trailer, deserialized);
return deserialized;
}
@@ -319,18 +433,31 @@
template <typename T>
void Packet::AddTag (T const& tag)
{
+ const Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
m_tags.Add (tag);
}
template <typename T>
bool Packet::RemoveTag (T & tag)
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
return m_tags.Remove (tag);
}
template <typename T>
bool Packet::PeekTag (T & tag) const
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
return m_tags.Peek (tag);
}
-}; // namespace ns3
+
+} // namespace ns3
#endif /* PACKET_H */
--- a/src/common/stream-tracer-test.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "stream-tracer.h"
-#include "ns3/test.h"
-#include <iostream>
-
-#ifdef RUN_SELF_TESTS
-
-namespace {
-
-class TestStreamTracer : public ns3::Test {
-public:
- TestStreamTracer ();
- virtual bool RunTests (void);
-};
-
-static TestStreamTracer gTestStream;
-
-TestStreamTracer::TestStreamTracer ()
- : Test ("StreamTracer")
-{}
-
-bool
-TestStreamTracer::RunTests (void)
-{
- bool ok = true;
- ns3::StreamTracer trace;
- //trace.setStream (&std::cout);
- trace << 1;
- trace << " X ";
- trace << 1.0;
- trace << std::endl;
- trace << "test ";
- trace << 1 << " test";
- trace << "test "
- << 1.0 << " "
- << 0xdeadbead
- << std::endl;
- trace << "0x" << std::hex
- << 0xdeadbeaf
- << std::dec << " "
- << 0xdeadbeaf
- << std::endl;
- return ok;
-}
-
-
-}; // namespace ns3
-
-#endif /* RUN_SELF_TESTS */
--- a/src/common/stream-tracer.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef STREAM_TRACER_H
-#define STREAM_TRACER_H
-
-#include <ostream>
-
-namespace ns3 {
-
-/**
- * \brief log arbitrary data to std::ostreams
- *
- * Whenever operator << is invoked on this class,
- * it is forwarded to the stored std::ostream output
- * stream (if there is one).
- */
-class StreamTracer {
-public:
- StreamTracer ()
- : m_os (0) {}
- template <typename T>
- StreamTracer &operator << (T const&v) {
- if (m_os != 0)
- {
- (*m_os) << v;
- }
- return *this;
- }
- template <typename T>
- StreamTracer &operator << (T &v) {
- if (m_os != 0)
- {
- (*m_os) << v;
- }
- return *this;
- }
- StreamTracer &operator << (std::ostream &(*v) (std::ostream &)) {
- if (m_os != 0)
- {
- (*m_os) << v;
- }
- return *this;
- }
-
- /**
- * \param os the output stream to store
- */
- void SetStream (std::ostream * os) {
- m_os = os;
- }
-private:
- std::ostream *m_os;
-};
-
-}; // namespace ns3
-
-
-#endif /* TRACER_STREAM_H */
--- a/src/common/sv-trace-source.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef SV_TRACE_SOURCE_H
-#define SV_TRACE_SOURCE_H
-
-#include "callback-trace-source.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class SVTraceSourceBase {
-public:
- typedef CallbackTraceSource<int64_t, int64_t> ChangeNotifyCallback;
-
- SVTraceSourceBase () {}
- SVTraceSourceBase (SVTraceSourceBase const &o) {}
- SVTraceSourceBase &operator = (SVTraceSourceBase const &o) {
- return *this;
- }
-
- ~SVTraceSourceBase () {}
-
- void AddCallback (CallbackBase const & callback, TraceContext const & context) {
- m_callback.AddCallback (callback, context);
- }
- void RemoveCallback (CallbackBase const & callback) {
- m_callback.RemoveCallback (callback);
- }
-protected:
- void Notify (int64_t oldVal, int64_t newVal) {
- if (oldVal != newVal)
- {
- m_callback (oldVal, newVal);
- }
- }
-private:
- ChangeNotifyCallback m_callback;
-};
-
-template <typename T>
-class UVTraceSource;
-
-
-/**
- * \brief trace variables of type "signed integer"
- * \ingroup lowleveltracing
- *
- * This template class implements a POD type: it
- * behaves like any other variable of type "signed integer"
- * except that it also reports any changes to its
- * value with its internal callback.
- *
- * To instantiate a 32-bit signed variable (to store
- * a TCP counter for example), you would create a variable of type
- * ns3::UVTraceSource<int32_t> :
- \code
- #include <stdint.h>
- #include "ns3/sv-trace-source.h"
-
- ns3::SVTraceSource<uint16_t> var;
- \endcode
- * and you would use it like any other variable of type int32_t:
- \code
- var += 12;
- var = 10;
- var = -10;
- \endcode
- */
-template <typename T>
-class SVTraceSource : public SVTraceSourceBase {
-public:
- SVTraceSource ()
- : m_var (0)
- {}
- SVTraceSource (T const &var)
- : m_var (var)
- {}
-
- SVTraceSource &operator = (SVTraceSource const &o) {
- Assign (o.Get ());
- return *this;
- }
- template <typename TT>
- SVTraceSource &operator = (SVTraceSource<TT> const &o) {
- Assign (o.Get ());
- return *this;
- }
- template <typename TT>
- SVTraceSource &operator = (UVTraceSource<TT> const &o) {
- Assign (o.Get ());
- return *this;
- }
- SVTraceSource &operator++ () {
- Assign (Get () + 1);
- return *this;
- }
- SVTraceSource &operator-- () {
- Assign (Get () - 1);
- return *this;
- }
- SVTraceSource operator++ (int) {
- SVTraceSource old (*this);
- ++*this;
- return old;
- }
- SVTraceSource operator-- (int) {
- SVTraceSource old (*this);
- --*this;
- return old;
- }
- operator T () const {
- return Get ();
- }
-
-
- void Assign (T var) {
- Notify (m_var, var);
- m_var = var;
- }
- T Get (void) const {
- return m_var;
- }
-
-private:
- T m_var;
-};
-
-template <typename T>
-SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () + rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () - rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () * rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () / rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () << rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () >> rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () & rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () | rhs.Get ());
- return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () ^ rhs.Get ());
- return lhs;
-}
-
-
-template <typename T, typename U>
-SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () + rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () - rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () * rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () / rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () << rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () >> rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () & rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () | rhs);
- return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () ^ rhs);
- return lhs;
-}
-
-}; // namespace ns3
-
-#endif /* SV_TRACE_SOURCE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "tag-registry.h"
+#include "ns3/fatal-error.h"
+
+namespace ns3 {
+
+TagRegistry::TagInfoVector *
+TagRegistry::GetInfo (void)
+{
+ static TagRegistry::TagInfoVector vector;
+ return &vector;
+}
+
+std::string
+TagRegistry::GetUidString (uint32_t uid)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ return info.uidString;
+}
+uint32_t
+TagRegistry::GetUidFromUidString (std::string uidString)
+{
+ TagInfoVector *vec = GetInfo ();
+ uint32_t uid = 1;
+ for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work.");
+ return 0;
+}
+
+void
+TagRegistry::Destruct (uint32_t uid, uint8_t *data)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ info.destruct (data);
+}
+void
+TagRegistry::Print (uint32_t uid, uint8_t *data, std::ostream &os)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ info.print (data, os);
+}
+uint32_t
+TagRegistry::GetSerializedSize (uint32_t uid, uint8_t *data)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ return info.getSerializedSize (data);
+}
+void
+TagRegistry::Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ info.serialize (data, start);
+}
+uint32_t
+TagRegistry::Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ return info.deserialize (data, start);
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAG_REGISTRY_H
+#define TAG_REGISTRY_H
+
+#include <string>
+#include <stdint.h>
+#include "buffer.h"
+
+namespace ns3 {
+
+/**
+ * \brief a registry of all existing tag types.
+ * \internal
+ *
+ * This class is used to give polymorphic access to the methods
+ * exported by a tag. It also is used to associate a single
+ * reliable uid to each unique type.
+ */
+class TagRegistry
+{
+public:
+ template <typename T>
+ static uint32_t Register (std::string uidString);
+ static std::string GetUidString (uint32_t uid);
+ static uint32_t GetUidFromUidString (std::string uidString);
+ static void Destruct (uint32_t uid, uint8_t *data);
+ static void Print (uint32_t uid, uint8_t *data, std::ostream &os);
+ static uint32_t GetSerializedSize (uint32_t uid, uint8_t *data);
+ static void Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+ static uint32_t Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+private:
+ typedef void (*DestructCb) (uint8_t *);
+ typedef void (*PrintCb) (uint8_t *, std::ostream &);
+ typedef uint32_t (*GetSerializedSizeCb) (uint8_t *);
+ typedef void (*SerializeCb) (uint8_t *, Buffer::Iterator);
+ typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+ struct TagInfo
+ {
+ std::string uidString;
+ DestructCb destruct;
+ PrintCb print;
+ GetSerializedSizeCb getSerializedSize;
+ SerializeCb serialize;
+ DeserializeCb deserialize;
+ };
+ typedef std::vector<struct TagInfo> TagInfoVector;
+
+ template <typename T>
+ static void DoDestruct (uint8_t *data);
+ template <typename T>
+ static void DoPrint (uint8_t *data, std::ostream &os);
+ template <typename T>
+ static uint32_t DoGetSerializedSize (uint8_t *data);
+ template <typename T>
+ static void DoSerialize (uint8_t *data, Buffer::Iterator start);
+ template <typename T>
+ static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start);
+
+ static TagInfoVector *GetInfo (void);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+TagRegistry::DoDestruct (uint8_t *data)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ tag->~T ();
+}
+template <typename T>
+void
+TagRegistry::DoPrint (uint8_t *data, std::ostream &os)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ tag->Print (os);
+}
+template <typename T>
+uint32_t
+TagRegistry::DoGetSerializedSize (uint8_t *data)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ return tag->GetSerializedSize ();
+}
+template <typename T>
+void
+TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ tag->Serialize (start);
+}
+template <typename T>
+uint32_t
+TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ return tag->Deserialize (start);
+}
+
+template <typename T>
+uint32_t
+TagRegistry::Register (std::string uidString)
+{
+ TagInfoVector *vec = GetInfo ();
+ uint32_t j = 0;
+ for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return j;
+ }
+ j++;
+ }
+ TagInfo info;
+ info.uidString = uidString;
+ info.destruct = &TagRegistry::DoDestruct<T>;
+ info.print = &TagRegistry::DoPrint<T>;
+ info.getSerializedSize = &TagRegistry::DoGetSerializedSize<T>;
+ info.serialize = &TagRegistry::DoSerialize<T>;
+ info.deserialize = &TagRegistry::DoDeserialize<T>;
+ vec->push_back (info);
+ uint32_t uid = vec->size ();
+ return uid;
+}
+
+} // namespace ns3
+
+#endif /* TAG_REGISTRY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,126 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAG_H
+#define TAG_H
+
+#include <stdint.h>
+#include <string>
+
+/**
+ * \relates ns3::Tag
+ * \brief this macro should be instantiated exactly once for each
+ * new type of Tag
+ *
+ * This macro will ensure that your new Tag type is registered
+ * within the tag registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TAG_ENSURE_REGISTERED(x) \
+static class thisisaveryverylongclassname ##x \
+{ \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+} g_thisisanotherveryveryverylongname ## x;
+
+namespace ns3 {
+
+/**
+ * \brief a tag can be stored in a packet.
+ *
+ * A tag is a blob of 16 bytes of data which can be stored in
+ * a packet: a packet can contain an arbitrary number of tags
+ * and these tags are considered as "on-the-side" per-packet
+ * data structures which are not taken into account when calculating
+ * the size of the payload of a packet. They exist solely as
+ * simulation-specific objects.
+ *
+ * Tags are typically used to:
+ * - implement per-packet cross-layer communication
+ * - implement packet coloring: you could store a "color" tag
+ * in a packet to mark various types of packet for
+ * simulation analysis
+ *
+ * To create a new type of tag, you must create a subclass
+ * of the Tag base class which defines:
+ * - a public default constructor: needed for implementation
+ * purposes of the Packet code.
+ * - a public copy constructor: needed to copy a tag into
+ * a packet tag buffer when the user invokes Packet::AddTag
+ * - a public destructor: needed to destroy the copy of a tag
+ * stored in a packet buffer when the user invokes Packet::RemoveTag
+ * or when the packet is destroyed and the last reference to
+ * a tag instance disapears.
+ * - a public static method named GetUid: needed to uniquely
+ * the type of each tag instance.
+ * - a public method named Print: needed to print the content
+ * of a tag when the user calls Packet::PrintTags
+ * - a public method named GetSerializedSize: needed to serialize
+ * the content of a tag to a byte buffer when a packet must
+ * be sent from one computing node to another in a parallel
+ * simulation. If this method returns 0, it means that the
+ * tag does not need to be transfered from computing node to
+ * computing node
+ * - a public method named Serialize: perform the serialization
+ * to a byte buffer upon transfer to a new computing node in a
+ * parallel simulation.
+ * - a public method named Deserialize: invert the serialization
+ * from a byte buffer after being transfered to a new computing
+ * node in a parallel simulation.
+ *
+ * A detailed example of what these methods should look like
+ * and how they should be implemented is described in samples/main-packet-tag.cc
+ */
+class Tag
+{
+protected:
+ /**
+ * \param name the unique name of the new type of tag
+ * \returns a newly-allocated uid
+ *
+ * This method should be used by subclasses to implement
+ * their static public GetUid method.
+ */
+ template <typename T>
+ static uint32_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+// implementation below.
+#include "tag-registry.h"
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Tag::AllocateUid (std::string name)
+{
+ return TagRegistry::Register<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TAG_H */
--- a/src/common/tags.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/tags.cc Fri Sep 28 11:59:46 2007 +0100
@@ -20,84 +20,10 @@
*/
#include "tags.h"
#include <string.h>
+#include "ns3/fatal-error.h"
namespace ns3 {
-TagRegistry *
-TagRegistry::GetInstance (void)
-{
- static TagRegistry registry;
- return ®istry;
-}
-
-TagRegistry::TagRegistry ()
- : m_sorted (false)
-{}
-
-
-void
-TagRegistry::Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor)
-{
- NS_ASSERT (!m_sorted);
- struct TagInfoItem item;
- item.uuid = uuid;
- item.printer = prettyPrinter;
- item.destructor = destructor;
- m_registry.push_back (item);
-}
-bool
-TagRegistry::CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b)
-{
- return a.uuid < b.uuid;
-}
-uint32_t
-TagRegistry::LookupUid (std::string uuid)
-{
- if (!m_sorted)
- {
- std::sort (m_registry.begin (), m_registry.end (), &TagRegistry::CompareItem);
- m_sorted = true;
- }
- NS_ASSERT (m_sorted);
- uint32_t uid = 1;
- for (TagsDataCI i = m_registry.begin (); i != m_registry.end (); i++)
- {
- if (i->uuid == uuid)
- {
- return uid;
- }
- uid++;
- }
- // someone asked for a uid for an unregistered uuid.
- NS_ASSERT (!"You tried to use unregistered tag: make sure you create an instance of type TagRegistration<YouTagType>.");
- // quiet compiler
- return 0;
-}
-void
-TagRegistry::PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os)
-{
- NS_ASSERT (uid > 0);
- uint32_t index = uid - 1;
- NS_ASSERT (m_registry.size () > index);
- PrettyPrinter prettyPrinter = m_registry[index].printer;
- if (prettyPrinter != 0)
- {
- prettyPrinter (buf, os);
- }
-}
-void
-TagRegistry::Destruct (uint32_t uid, uint8_t buf[Tags::SIZE])
-{
- NS_ASSERT (uid > 0);
- uint32_t index = uid - 1;
- NS_ASSERT (m_registry.size () > index);
- Destructor destructor = m_registry[index].destructor;
- NS_ASSERT (destructor != 0);
- destructor (buf);
-}
-
-
-
#ifdef USE_FREE_LIST
struct Tags::TagData *Tags::gFree = 0;
@@ -193,13 +119,102 @@
}
void
-Tags::PrettyPrint (std::ostream &os)
+Tags::Print (std::ostream &os, std::string separator) const
{
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
{
- TagRegistry::GetInstance ()->PrettyPrint (cur->m_id, cur->m_data, os);
+ TagRegistry::Print (cur->m_id, cur->m_data, os);
+ if (cur->m_next != 0)
+ {
+ os << separator;
+ }
+ }
+}
+
+uint32_t
+Tags::GetSerializedSize (void) const
+{
+ uint32_t totalSize = 4; // reserve space for the size of the tag data.
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
+ {
+ uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+ if (size != 0)
+ {
+ std::string uidString = TagRegistry::GetUidString (cur->m_id);
+ totalSize += 4; // for the size of the string itself.
+ totalSize += uidString.size ();
+ totalSize += size;
+ }
+ }
+ return totalSize;
+}
+
+void
+Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const
+{
+ i.WriteU32 (totalSize);
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
+ {
+ uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+ if (size != 0)
+ {
+ std::string uidString = TagRegistry::GetUidString (cur->m_id);
+ i.WriteU32 (uidString.size ());
+ uint8_t *buf = (uint8_t *)uidString.c_str ();
+ i.Write (buf, uidString.size ());
+ TagRegistry::Serialize (cur->m_id, cur->m_data, i);
+ }
}
}
+uint32_t
+Tags::Deserialize (Buffer::Iterator i)
+{
+ uint32_t totalSize = i.ReadU32 ();
+ uint32_t bytesRead = 4;
+ while (bytesRead < totalSize)
+ {
+ uint32_t uidStringSize = i.ReadU32 ();
+ bytesRead += 4;
+ std::string uidString;
+ uidString.reserve (uidStringSize);
+ for (uint32_t j = 0; j < uidStringSize; j++)
+ {
+ uint32_t c = i.ReadU8 ();
+ uidString.push_back (c);
+ }
+ bytesRead += uidStringSize;
+ uint32_t uid = TagRegistry::GetUidFromUidString (uidString);
+ struct TagData *newStart = AllocData ();
+ newStart->m_count = 1;
+ newStart->m_next = 0;
+ newStart->m_id = uid;
+ bytesRead += TagRegistry::Deserialize (uid, newStart->m_data, i);
+ newStart->m_next = m_next;
+ m_next = newStart;
+ }
+ NS_ASSERT (bytesRead == totalSize);
+ /**
+ * The process of serialization/deserialization
+ * results in an inverted linked-list after
+ * deserialization so, we invert the linked-list
+ * in-place here.
+ * Note: the algorithm below is pretty classic
+ * but whenever I get to code it, it makes my
+ * brain hurt :)
+ */
+ struct TagData *prev = 0;
+ struct TagData *cur = m_next;
+ while (cur != 0)
+ {
+ struct TagData *next = cur->m_next;
+ cur->m_next = prev;
+ prev = cur;
+ cur = next;
+ }
+ m_next = prev;
+ return totalSize;
+}
+
}; // namespace ns3
@@ -224,25 +239,67 @@
virtual bool RunTests (void);
};
-struct myTagA {
+class myTagA : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagA> ("myTagA.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_a = true;}
+ uint32_t GetSerializedSize (void) const {return 1;}
+ void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);}
+ uint32_t Deserialize (Buffer::Iterator i) {a = i.ReadU8 (); return 1;}
+
uint8_t a;
};
-struct myTagB {
+class myTagB : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagB> ("myTagB.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_b = true;}
+ uint32_t GetSerializedSize (void) const {return 4;}
+ void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);}
+ uint32_t Deserialize (Buffer::Iterator i) {b = i.ReadU32 (); return 4;}
+
uint32_t b;
};
-struct myTagC {
+class myTagC : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagC> ("myTagC.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_c = true;}
+ uint32_t GetSerializedSize (void) const {return Tags::SIZE;}
+ void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);}
+ uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;}
uint8_t c [Tags::SIZE];
};
-struct myInvalidTag {
+class myInvalidTag : public Tag
+{
+public:
+ static uint32_t GetUid (void)
+ {static uint32_t uid = AllocateUid<myInvalidTag> ("myinvalidTag.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {}
+ uint32_t GetSerializedSize (void) const {return 0;}
+ void Serialize (Buffer::Iterator i) const {}
+ uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
uint8_t invalid [Tags::SIZE+1];
};
-struct myTagZ {
+class myTagZ : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagZ> ("myTagZ.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_z = true;}
+ uint32_t GetSerializedSize (void) const {return 0;}
+ void Serialize (Buffer::Iterator i) const {}
+ uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
uint8_t z;
};
-class MySmartTag
+class MySmartTag : public Tag
{
public:
+ static uint32_t GetUid (void)
+ {static uint32_t uid = AllocateUid<MySmartTag> ("MySmartTag.test.nsnam.org"); return uid;}
MySmartTag ()
{
//std::cout << "construct" << std::endl;
@@ -260,43 +317,12 @@
//std::cout << "assign" << std::endl;
return *this;
}
- static void PrettyPrinterCb (const MySmartTag *a, std::ostream &os)
- {}
+ void Print (std::ostream &os) const {}
+ uint32_t GetSerializedSize (void) const {return 0;}
+ void Serialize (Buffer::Iterator i) const {}
+ uint32_t Deserialize (Buffer::Iterator i) {return 0;}
};
-static void
-myTagAPrettyPrinterCb (struct myTagA const*a, std::ostream &os)
-{
- //os << "struct myTagA, a="<<(uint32_t)a->a<<std::endl;
- g_a = true;
-}
-static void
-myTagBPrettyPrinterCb (struct myTagB const*b, std::ostream &os)
-{
- //os << "struct myTagB, b="<<b->b<<std::endl;
- g_b = true;
-}
-static void
-myTagCPrettyPrinterCb (struct myTagC const*c, std::ostream &os)
-{
- //os << "struct myTagC, c="<<(uint32_t)c->c[0]<<std::endl;
- g_c = true;
-}
-static void
-myTagZPrettyPrinterCb (struct myTagZ const*z, std::ostream &os)
-{
- //os << "struct myTagZ" << std::endl;
- g_z = true;
-}
-
-
-static TagRegistration<struct myTagA> gMyTagARegistration ("A", &myTagAPrettyPrinterCb);
-static TagRegistration<struct myTagB> gMyTagBRegistration ("B", &myTagBPrettyPrinterCb);
-static TagRegistration<struct myTagC> gMyTagCRegistration ("C", &myTagCPrettyPrinterCb);
-static TagRegistration<struct myTagZ> g_myTagZRegistration ("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
- &myTagZPrettyPrinterCb);
-static TagRegistration<MySmartTag> g_myTagSmartRegistration ("SmartTag", &MySmartTag::PrettyPrinterCb);
-
TagsTest::TagsTest ()
: Test ("Tags")
@@ -311,7 +337,7 @@
// build initial tag.
Tags tags;
- struct myTagA a;
+ myTagA a;
a.a = 10;
tags.Add (a);
a.a = 0;
@@ -321,12 +347,12 @@
ok = false;
}
g_a = false;
- tags.PrettyPrint (std::cout);
+ tags.Print (std::cout, "");
if (!g_a)
{
ok = false;
}
- struct myTagB b;
+ myTagB b;
b.b = 0xff;
tags.Add (b);
b.b = 0;
@@ -337,7 +363,7 @@
}
g_b = false;
g_a = false;
- tags.PrettyPrint (std::cout);
+ tags.Print (std::cout, "");
if (!g_a || !g_b)
{
ok = false;
@@ -346,26 +372,26 @@
Tags other = tags;
g_b = false;
g_a = false;
- other.PrettyPrint (std::cout);
+ other.Print (std::cout, "");
if (!g_a || !g_b)
{
ok = false;
}
g_b = false;
g_a = false;
- tags.PrettyPrint (std::cout);
+ tags.Print (std::cout, "");
if (!g_a || !g_b)
{
ok = false;
}
- struct myTagA oA;
+ myTagA oA;
oA.a = 0;
other.Peek (oA);
if (oA.a != 10)
{
ok = false;
}
- struct myTagB oB;
+ myTagB oB;
oB.b = 1;
other.Peek (oB);
if (oB.b != 0xff)
@@ -380,7 +406,7 @@
}
g_b = false;
g_a = false;
- other.PrettyPrint (std::cout);
+ other.Print (std::cout, "");
if (g_a || !g_b)
{
ok = false;
@@ -401,7 +427,7 @@
other = tags;
Tags another = other;
- struct myTagC c;
+ myTagC c;
memset (c.c, 0x66, 16);
another.Add (c);
c.c[0] = 0;
@@ -421,12 +447,12 @@
//struct myInvalidTag invalid;
//tags.add (&invalid);
- struct myTagZ tagZ;
+ myTagZ tagZ;
Tags testLastTag;
tagZ.z = 0;
testLastTag.Add (tagZ);
g_z = false;
- testLastTag.PrettyPrint (std::cout);
+ testLastTag.Print (std::cout, "");
if (!g_z)
{
ok = false;
@@ -440,6 +466,58 @@
tmp.Remove (smartTag);
}
+ {
+ Tags source;
+ myTagA aSource;
+ aSource.a = 0x66;
+ source.Add (aSource);
+ Buffer buffer;
+ uint32_t serialized = source.GetSerializedSize ();
+ buffer.AddAtStart (serialized);
+ source.Serialize (buffer.Begin (), serialized);
+ Tags dest;
+ dest.Deserialize (buffer.Begin ());
+ myTagA aDest;
+ aDest.a = 0x55;
+ dest.Peek (aDest);
+ if (aDest.a != 0x66)
+ {
+ ok = false;
+ }
+ }
+
+ {
+ Tags source;
+ myTagA aSource;
+ aSource.a = 0x66;
+ source.Add (aSource);
+ myTagZ zSource;
+ zSource.z = 0x77;
+ source.Add (zSource);
+
+ Buffer buffer;
+ uint32_t serialized = source.GetSerializedSize ();
+ buffer.AddAtStart (serialized);
+ source.Serialize (buffer.Begin (), serialized);
+ Tags dest;
+ dest.Deserialize (buffer.Begin ());
+
+ myTagA aDest;
+ aDest.a = 0x55;
+ dest.Peek (aDest);
+ if (aDest.a != 0x66)
+ {
+ ok = false;
+ }
+ myTagZ zDest;
+ zDest.z = 0x44;
+ dest.Peek (zDest);
+ if (zDest.z != 0x44)
+ {
+ ok = false;
+ }
+ }
+
return ok;
}
--- a/src/common/tags.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/tags.h Fri Sep 28 11:59:46 2007 +0100
@@ -24,12 +24,10 @@
#include <stdint.h>
#include <ostream>
#include <vector>
+#include "buffer.h"
namespace ns3 {
-template <typename T>
-class TagPrettyPrinter;
-
/**
* \ingroup constants
* \brief Tag maximum size
@@ -54,7 +52,10 @@
template <typename T>
bool Peek (T &tag) const;
- void PrettyPrint (std::ostream &os);
+ void Print (std::ostream &os, std::string separator) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator i, uint32_t size) const;
+ uint32_t Deserialize (Buffer::Iterator i);
inline void RemoveAll (void);
@@ -79,161 +80,39 @@
struct TagData *m_next;
};
-/**
- * \brief pretty print packet tags
- *
- * This class is used to register a pretty-printer
- * callback function to print in a nice user-friendly
- * way the content of the target type. To register
- * such a type, all you need to do is instantiate
- * an instance of this type as a static variable.
- */
-template <typename T>
-class TagRegistration {
-public:
- /**
- * \param uuid a uuid generated with uuidgen
- * \param fn a function which can pretty-print an instance
- * of type T in the output stream.
- */
- TagRegistration<T> (std::string uuid, void(*fn) (T const*, std::ostream &));
-private:
- static void PrettyPrinterCb (uint8_t *buf, std::ostream &os);
- static void DestructorCb (uint8_t *buf);
- static void(*m_prettyPrinter) (T const*, std::ostream &);
-};
-
-}; // namespace ns3
+} // namespace ns3
/**************************************************************
An implementation of the templates defined above
*************************************************************/
+#include "tag-registry.h"
+#include "tag.h"
#include "ns3/assert.h"
#include <string>
namespace ns3 {
-class TagRegistry {
-public:
- typedef void (*PrettyPrinter) (uint8_t [Tags::SIZE], std::ostream &);
- typedef void (*Destructor) (uint8_t [Tags::SIZE]);
- void Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor);
- /**
- * returns a numeric integer which uniquely identifies the input string.
- * that integer cannot be zero which is a reserved value.
- */
- uint32_t LookupUid (std::string uuid);
- void PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os);
- void Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]);
-
- static TagRegistry *GetInstance (void);
-private:
- TagRegistry ();
- struct TagInfoItem
- {
- std::string uuid;
- PrettyPrinter printer;
- Destructor destructor;
- };
- typedef std::vector<struct TagInfoItem> TagsData;
- typedef std::vector<struct TagInfoItem>::const_iterator TagsDataCI;
- static bool CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b);
- bool m_sorted;
- TagsData m_registry;
-};
-/**
- * The TypeUid class is used to create a mapping Type --> uid
- * Note that we use a static getUuid function which contains a
- * static std::string variable rather than a simpler static
- * member std::string variable to ensure the proper order
- * of initialization when these methods are invoked
- * from the constructor of another static variable.
- */
-template <typename T>
-class TypeUid {
-public:
- static void Record (std::string uuid);
- static const uint32_t GetUid (void);
-private:
- static std::string *GetUuid (void);
- T m_realType;
-};
-
-template <typename T>
-void TypeUid<T>::Record (std::string uuid)
-{
- *(GetUuid ()) = uuid;
-}
-
-template <typename T>
-const uint32_t TypeUid<T>::GetUid (void)
-{
- static const uint32_t uid = TagRegistry::GetInstance ()->
- LookupUid (*(GetUuid ()));
- return uid;
-}
-
-template <typename T>
-std::string *TypeUid<T>::GetUuid (void)
-{
- static std::string uuid;
- return &uuid;
-}
-
-
-
-/**
- * Implementation of the TagRegistration registration class.
- * It records a callback with the TagRegistry
- * This callback performs type conversion before forwarding
- * the call to the user-provided function.
- */
-template <typename T>
-TagRegistration<T>::TagRegistration (std::string uuid, void (*prettyPrinter) (T const*, std::ostream &))
-{
- NS_ASSERT (sizeof (T) <= Tags::SIZE);
- m_prettyPrinter = prettyPrinter;
- TagRegistry::GetInstance ()->
- Record (uuid, &TagRegistration<T>::PrettyPrinterCb, &TagRegistration<T>::DestructorCb);
- TypeUid<T>::Record (uuid);
-}
-template <typename T>
-void
-TagRegistration<T>::PrettyPrinterCb (uint8_t *buf, std::ostream &os)
-{
- NS_ASSERT (sizeof (T) <= Tags::SIZE);
- T *tag = reinterpret_cast<T *> (buf);
- (*m_prettyPrinter) (tag, os);
-}
-template <typename T>
-void
-TagRegistration<T>::DestructorCb (uint8_t *buf)
-{
- T *tag = reinterpret_cast<T *> (buf);
- tag->~T ();
-}
-template <typename T>
-void (*TagRegistration<T>::m_prettyPrinter) (T const*, std::ostream &) = 0;
-
-
-
-
template <typename T>
void
Tags::Add (T const&tag)
{
+ const Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
+
NS_ASSERT (sizeof (T) <= Tags::SIZE);
// ensure this id was not yet added
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
{
- NS_ASSERT (cur->m_id != TypeUid<T>::GetUid ());
+ NS_ASSERT (cur->m_id != T::GetUid ());
}
struct TagData *newStart = AllocData ();
newStart->m_count = 1;
newStart->m_next = 0;
- newStart->m_id = TypeUid<T>::GetUid ();
+ newStart->m_id = T::GetUid ();
void *buf = &newStart->m_data;
new (buf) T (tag);
newStart->m_next = m_next;
@@ -244,18 +123,26 @@
bool
Tags::Remove (T &tag)
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
NS_ASSERT (sizeof (T) <= Tags::SIZE);
- return Remove (TypeUid<T>::GetUid ());
+ return Remove (T::GetUid ());
}
template <typename T>
bool
Tags::Peek (T &tag) const
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
NS_ASSERT (sizeof (T) <= Tags::SIZE);
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
{
- if (cur->m_id == TypeUid<T>::GetUid ())
+ if (cur->m_id == T::GetUid ())
{
/* found tag */
T *data = reinterpret_cast<T *> (&cur->m_data);
@@ -315,16 +202,14 @@
}
if (prev != 0)
{
- TagRegistry::GetInstance ()->
- Destruct (prev->m_id, prev->m_data);
+ TagRegistry::Destruct (prev->m_id, prev->m_data);
FreeData (prev);
}
prev = cur;
}
if (prev != 0)
{
- TagRegistry::GetInstance ()->
- Destruct (prev->m_id, prev->m_data);
+ TagRegistry::Destruct (prev->m_id, prev->m_data);
FreeData (prev);
}
m_next = 0;
--- a/src/common/terminal-trace-resolver.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef TERMINAL_TRACE_RESOLVER_H
-#define TERMINAL_TRACE_RESOLVER_H
-
-#include "trace-resolver.h"
-
-namespace ns3 {
-
-class TraceContext;
-
-template <typename T>
-class TerminalTraceResolver : public TraceResolver
-{
- public:
- TerminalTraceResolver (T &traceSource, TraceContext const &context);
- private:
- virtual void DoConnect (CallbackBase const &cb);
- virtual void DoDisconnect (CallbackBase const &cb);
- T &m_traceSource;
-};
-
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename T>
-TerminalTraceResolver<T>::TerminalTraceResolver (T &traceSource,
- TraceContext const &context)
- : TraceResolver (context),
- m_traceSource (traceSource)
-{}
-template <typename T>
-void
-TerminalTraceResolver<T>::DoConnect (CallbackBase const &cb)
-{
- m_traceSource.AddCallback (cb, GetContext ());
-}
-template <typename T>
-void
-TerminalTraceResolver<T>::DoDisconnect (CallbackBase const &cb)
-{
- m_traceSource.RemoveCallback (cb);
-}
-
-}//namespace ns3
-
-#endif /* TERMINAL_TRACE_RESOLVER_H */
--- a/src/common/trace-context.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,320 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "trace-context.h"
-#include "ns3/assert.h"
-
-namespace ns3 {
-
-std::vector<uint8_t> TraceContext::m_sizes;
-
-TraceContext::TraceContext ()
- : m_data (0)
-{}
-TraceContext::TraceContext (TraceContext const &o)
- : m_data (o.m_data)
-{
- if (m_data != 0)
- {
- m_data->count++;
- }
-}
-TraceContext const &
-TraceContext::operator = (TraceContext const &o)
-{
- if (m_data != 0)
- {
- m_data->count--;
- if (m_data->count == 0)
- {
- uint8_t *buffer = (uint8_t *)m_data;
- delete [] buffer;
- }
- }
- m_data = o.m_data;
- if (m_data != 0)
- {
- m_data->count++;
- }
- return *this;
-}
-TraceContext::~TraceContext ()
-{
- if (m_data != 0)
- {
- m_data->count--;
- if (m_data->count == 0)
- {
- uint8_t *buffer = (uint8_t *)m_data;
- delete [] buffer;
- }
- }
-}
-
-uint8_t
-TraceContext::GetSize (uint8_t uid)
-{
- return m_sizes[uid];
-}
-
-void
-TraceContext::Add (TraceContext const &o)
-{
- if (o.m_data == 0)
- {
- return;
- }
- uint8_t currentUid;
- uint16_t i = 0;
- while (i < o.m_data->size)
- {
- currentUid = o.m_data->data[i];
- uint8_t size = TraceContext::GetSize (currentUid);
- uint8_t *selfBuffer = CheckPresent (currentUid);
- uint8_t *otherBuffer = &(o.m_data->data[i+1]);
- if (selfBuffer != 0)
- {
- if (memcmp (selfBuffer, otherBuffer, size) != 0)
- {
- NS_FATAL_ERROR ("You cannot add TraceContexts which "<<
- "have different values stored in them.");
- }
- }
- else
- {
- DoAdd (currentUid, otherBuffer);
- }
- i += 1 + size;
- }
-}
-
-uint8_t *
-TraceContext::CheckPresent (uint8_t uid) const
-{
- if (m_data == 0)
- {
- return false;
- }
- uint8_t currentUid;
- uint16_t i = 0;
- do {
- currentUid = m_data->data[i];
- uint8_t size = TraceContext::GetSize (currentUid);
- if (currentUid == uid)
- {
- return &m_data->data[i+1];
- }
- i += 1 + size;
- } while (i < m_data->size && currentUid != 0);
- return 0;
-}
-
-
-bool
-TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
-{
- NS_ASSERT (uid != 0);
- uint8_t size = TraceContext::GetSize (uid);
- uint8_t *present = CheckPresent (uid);
- if (present != 0) {
- if (memcmp (present, buffer, size) == 0)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- if (m_data == 0)
- {
- uint16_t newSize = 1 + size;
- uint16_t allocatedSize;
- if (newSize > 4)
- {
- allocatedSize = sizeof (struct Data) + newSize - 4;
- }
- else
- {
- allocatedSize = sizeof (struct Data);
- }
- struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
- data->size = newSize;
- data->count = 1;
- data->data[0] = uid;
- memcpy (data->data + 1, buffer, size);
- m_data = data;
- }
- else
- {
- uint16_t newSize = m_data->size + 1 + size;
- uint16_t allocatedSize;
- if (newSize > 4)
- {
- allocatedSize = sizeof (struct Data) + newSize - 4;
- }
- else
- {
- allocatedSize = sizeof (struct Data);
- }
- struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
- data->size = newSize;
- data->count = 1;
- memcpy (data->data, m_data->data, m_data->size);
- data->data[m_data->size] = uid;
- memcpy (data->data + m_data->size + 1, buffer, size);
- m_data->count--;
- if (m_data->count == 0)
- {
- uint8_t *buffer = (uint8_t *)m_data;
- delete [] buffer;
- }
- m_data = data;
- }
- return true;
-}
-bool
-TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const
-{
- if (m_data == 0)
- {
- return false;
- }
- uint8_t currentUid;
- uint16_t i = 0;
- do {
- currentUid = m_data->data[i];
- uint8_t size = TraceContext::GetSize (currentUid);
- if (currentUid == uid)
- {
- memcpy (buffer, &m_data->data[i+1], size);
- return true;
- }
- i += 1 + size;
- } while (i < m_data->size && currentUid != 0);
- return false;
-}
-
-uint8_t
-TraceContext::DoGetNextUid (void)
-{
- static uint8_t uid = 0;
- if (uid == 0)
- {
- m_sizes.push_back (0);
- }
- uid++;
- return uid;
-}
-
-
-}//namespace ns3
-
-#include "ns3/test.h"
-
-namespace ns3 {
-
-template <int N>
-class Ctx
-{
-public:
- Ctx () : m_v (0) {}
- Ctx (int v) : m_v (v) {}
- int Get (void) const { return N;}
-private:
- int m_v;
-};
-
-class TraceContextTest : public Test
-{
-public:
- TraceContextTest ();
- virtual bool RunTests (void);
-};
-
-TraceContextTest::TraceContextTest ()
- : Test ("TraceContext")
-{}
-bool
-TraceContextTest::RunTests (void)
-{
- bool ok = true;
-
- TraceContext ctx;
- Ctx<0> v0;
- Ctx<0> v01 = Ctx<0> (1);
- Ctx<1> v1;
- Ctx<2> v2;
- Ctx<3> v3;
-
- if (ctx.SafeGet (v0))
- {
- ok = false;
- }
- ctx.Add (v0);
- ctx.Add (v0);
- if (ctx.SafeAdd (v01))
- {
- ok = false;
- }
- ctx.Get (v0);
- ctx.Add (v1);
- ctx.Get (v1);
- ctx.Get (v0);
- ctx.Get (v1);
-
- TraceContext copy = ctx;
- ctx.Get (v0);
- ctx.Get (v1);
- copy.Get (v0);
- copy.Get (v1);
- copy.Add (v2);
- copy.Get (v0);
- copy.Get (v1);
- copy.Get (v2);
- ctx.Add (v3);
- ctx.Get (v0);
- ctx.Get (v1);
- ctx.Get (v3);
-
- if (ctx.SafeGet (v2))
- {
- ok = false;
- }
- if (copy.SafeGet (v3))
- {
- ok = false;
- }
- ctx.Add (copy);
- ctx.Get (v2);
- if (copy.SafeGet (v3))
- {
- ok = false;
- }
- copy.Add (ctx);
- copy.Get (v3);
-
- return ok;
-}
-
-static TraceContextTest g_traceContextTest;
-
-
-}//namespace ns3
--- a/src/common/trace-context.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef TRACE_CONTEXT_H
-#define TRACE_CONTEXT_H
-
-#include <stdint.h>
-#include <vector>
-#include "ns3/fatal-error.h"
-
-namespace ns3 {
-
-/**
- * \brief Provide context to trace sources
- * \ingroup lowleveltracing
- *
- * Instances of this class are used to hold context
- * for each trace source. Each instance holds a list of
- * 'contexts'. Trace sinks can lookup these contexts
- * from this list with the ns3::TraceContext::Get method.
- *
- * This class is implemented
- * using Copy On Write which means that copying unmodified
- * versions of this class is very cheap. However, modifying
- * the content of this class through a call
- * to ns3::TraceContext::Add will trigger a costly memory
- * reallocation if needed.
- */
-class TraceContext
-{
-public:
- TraceContext ();
- TraceContext (TraceContext const &o);
- TraceContext const & operator = (TraceContext const &o);
- ~TraceContext ();
-
- /**
- * \param context add context to list of trace contexts.
- */
- template <typename T>
- void Add (T const &context);
-
- /**
- * \param o the other context
- *
- * Perform the Union operation (in the sense of set theory) on the
- * two input lists of elements. This method is used in the
- * ns3::CallbackTraceSourceSource class when multiple sinks are connected
- * to a single source to ensure that the source does not need
- * to store a single TraceContext instance per connected sink.
- * Instead, all sinks share the same TraceContext.
- */
- void Add (TraceContext const &o);
-
- /**
- * \param context context to get from this list of trace contexts.
- *
- * This method cannot fail. If the requested trace context is not
- * stored in this TraceContext, then, the program will halt.
- */
- template <typename T>
- void Get (T &context) const;
-private:
- friend class TraceContextTest;
- // used exclusively for testing code.
- template <typename T>
- bool SafeGet (T &context) const;
- template <typename T>
- bool SafeAdd (T &context);
-
- template <typename T>
- static uint8_t GetUid (void);
- template <typename T>
- static uint8_t GetNextUid (void);
- static uint8_t DoGetNextUid (void);
- static uint8_t GetSize (uint8_t uid);
- uint8_t *CheckPresent (uint8_t uid) const;
- bool DoAdd (uint8_t uid, uint8_t const *buffer);
- bool DoGet (uint8_t uid, uint8_t *buffer) const;
-
- static std::vector<uint8_t> m_sizes;
- struct Data {
- uint16_t count;
- uint16_t size;
- uint8_t data[4];
- } * m_data;
-};
-
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename T>
-void
-TraceContext::Add (T const &context)
-{
- uint8_t *data = (uint8_t *) &context;
- bool ok = DoAdd (TraceContext::GetUid<T> (), data);
- if (!ok)
- {
- NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid.");
- }
-}
-template <typename T>
-void
-TraceContext::Get (T &context) const
-{
- uint8_t *data = (uint8_t *) &context;
- bool found = DoGet (TraceContext::GetUid<T> (), data);
- if (!found)
- {
- NS_FATAL_ERROR ("Type not stored in TraceContext");
- }
-}
-template <typename T>
-bool
-TraceContext::SafeGet (T &context) const
-{
- uint8_t *data = (uint8_t *) &context;
- bool found = DoGet (TraceContext::GetUid<T> (), data);
- return found;
-}
-template <typename T>
-bool
-TraceContext::SafeAdd (T &context)
-{
- uint8_t *data = (uint8_t *) &context;
- bool ok = DoAdd (TraceContext::GetUid<T> (), data);
- return ok;
-}
-template <typename T>
-uint8_t
-TraceContext::GetUid (void)
-{
- static uint8_t uid = GetNextUid<T> ();
- return uid;
-}
-
-template <typename T>
-uint8_t
-TraceContext::GetNextUid (void)
-{
- uint8_t uid = DoGetNextUid ();
- m_sizes.push_back (sizeof (T));
- return uid;
-}
-
-}//namespace ns3
-
-#endif /* TRACE_CONTEXT_H */
--- a/src/common/trace-resolver.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "trace-resolver.h"
-
-namespace ns3 {
-
-TraceResolver::TraceResolver (TraceContext const &context)
- : m_context (context)
-{}
-
-TraceResolver::~TraceResolver ()
-{}
-
-TraceContext const &
-TraceResolver::GetContext (void) const
-{
- return m_context;
-}
-
-void
-TraceResolver::Connect (std::string path, CallbackBase const &cb)
-{
- std::string::size_type cur = 1;
- // check that first char is "/"
- std::string::size_type next = path.find ("/", cur);
- std::string element = std::string (path, cur, next-1);
- TraceResolverList resolverList = DoLookup (element);
- for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
- {
- TraceResolver *resolver = *i;
- if (next == std::string::npos)
- {
- // we really break the recursion here.
- resolver->DoConnect (cb);
- }
- else
- {
- std::string subpath = std::string (path, next, std::string::npos);
- resolver->Connect (subpath, cb);
- }
- delete resolver;
- }
- resolverList.erase (resolverList.begin (), resolverList.end ());
-}
-
-void
-TraceResolver::Disconnect (std::string path, CallbackBase const &cb)
-{
- std::string::size_type cur = 1;
- // check that first char is "/"
- std::string::size_type next = path.find ("/", cur);
- std::string element = std::string (path, cur, next-1);
- TraceResolverList resolverList = DoLookup (element);
- for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
- {
- TraceResolver *resolver = *i;
- if (next == std::string::npos)
- {
- // we really break the recursion here.
- resolver->DoDisconnect (cb);
- }
- else
- {
- std::string subpath = std::string (path, next, std::string::npos);
- resolver->Disconnect (subpath, cb);
- }
- delete resolver;
- }
- resolverList.erase (resolverList.begin (), resolverList.end ());
-}
-
-TraceResolver::TraceResolverList
-TraceResolver::DoLookup (std::string id) const
-{
- return TraceResolverList ();
-}
-void
-TraceResolver::DoConnect (CallbackBase const &cb)
-{}
-
-void
-TraceResolver::DoDisconnect (CallbackBase const &cb)
-{}
-
-
-}//namespace ns3
--- a/src/common/trace-resolver.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef TRACE_RESOLVER_H
-#define TRACE_RESOLVER_H
-
-#include <string>
-#include <list>
-#include "trace-context.h"
-
-namespace ns3 {
-
-class CallbackBase;
-
-/**
- * \brief the base class which is used to incremental perform trace
- * namespace resolution.
- * \ingroup lowleveltracing
- *
- * This class provides a public API to the ns3::TraceRoot object:
- * - ns3::TraceResolver::Connect
- * - ns3::TraceResolver::Disconnect
- *
- * It also provides an API for its subclasses. Each subclass should
- * implement one of:
- * - ns3::TraceResolver::DoLookup
- * - ns3::TraceResolver::DoConnect and ns3::TraceResolver::DoDisconnect
- * Each subclass must also provide an ns3::TraceContext to the TraceResolver
- * constructor. Finally, each subclass can access the ns3::TraceContext
- * associated to this ns3::TraceResolver through the
- * ns3::TraceResolver::GetContext method.
- */
-class TraceResolver
-{
-public:
- virtual ~TraceResolver ();
- /**
- * \param path the namespace path to resolver
- * \param cb the callback to connect to the matching namespace
- *
- * This method is typically invoked by ns3::TraceRoot but advanced
- * users could also conceivably call it directly if they want to
- * skip the ns3::TraceRoot.
- */
- void Connect (std::string path, CallbackBase const &cb);
- /**
- * \param path the namespace path to resolver
- * \param cb the callback to disconnect in the matching namespace
- *
- * This method is typically invoked by ns3::TraceRoot but advanced
- * users could also conceivably call it directly if they want to
- * skip the ns3::TraceRoot.
- */
- void Disconnect (std::string path, CallbackBase const &cb);
-protected:
- /**
- * \param context the context used to initialize this TraceResolver.
- *
- * Every subclass must call this constructor
- */
- TraceResolver (TraceContext const &context);
- /**
- * \returns the ns3::TraceContext stored in this ns3::TraceResolver.
- *
- * Subclasses usually invoke this method to get access to the
- * TraceContext stored here to pass it down to the TraceResolver
- * constructors invoked from within the DoLookup method.
- */
- TraceContext const &GetContext (void) const;
- typedef std::list<TraceResolver *> TraceResolverList;
-private:
- TraceResolver ();
- /**
- * \param id the id to resolve. This is supposed to be
- * one element of the global tracing namespace.
- * \returns a list of reslvers which match the input namespace element
- *
- * A subclass which overrides this method should return a potentially
- * empty list of pointers to ns3::TraceResolver instances which match
- * the input namespace element. Each of these TraceResolver should be
- * instanciated with a TraceContext which holds enough context
- * information to identify the type of the TraceResolver.
- */
- virtual TraceResolverList DoLookup (std::string id) const;
- /**
- * \param cb callback to connect
- *
- * This method is invoked on leaf trace resolvers.
- */
- virtual void DoConnect (CallbackBase const &cb);
- /**
- * \param cb callback to disconnect
- *
- * This method is invoked on leaf trace resolvers.
- */
- virtual void DoDisconnect (CallbackBase const &cb);
- TraceContext m_context;
-};
-
-}//namespace ns3
-
-#endif /* TRACE_RESOLVER_H */
--- a/src/common/trace-root.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "trace-root.h"
-#include "ns3/composite-trace-resolver.h"
-#include "ns3/trace-context.h"
-
-namespace ns3 {
-
-void
-TraceRoot::Connect (std::string path, CallbackBase const &cb)
-{
- TraceResolver *resolver = GetComposite ();
- resolver->Connect (path, cb);
-}
-void
-TraceRoot::Disconnect (std::string path, CallbackBase const &cb)
-{
- TraceResolver *resolver = GetComposite ();
- resolver->Disconnect (path, cb);
-}
-void
-TraceRoot::Register (std::string name,
- Callback<TraceResolver *,TraceContext const &> createResolver)
-{
- CompositeTraceResolver *resolver = GetComposite ();
- resolver->Add (name, createResolver, TraceRoot::NOTHING);
-}
-
-CompositeTraceResolver *
-TraceRoot::GetComposite (void)
-{
- static CompositeTraceResolver resolver = CompositeTraceResolver (TraceContext ());
- return &resolver;
-}
-
-} // namespace ns3
--- a/src/common/trace-root.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,338 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef TRACE_ROOT_H
-#define TRACE_ROOT_H
-
-#include <string>
-#include "ns3/callback.h"
-
-/**
- * \defgroup lowleveltracing Low-level tracing
- *
- * This low-level API is built around a few concepts:
- * - There can be any number of trace source objects. Each trace source
- * object can generate any number of trace events. The current
- * trace source objects are: ns3::CallbackTraceSourceSource, ns3::UVTraceSource,
- * ns3::SVTraceSource, and, ns3::FVTraceSource.
- * - Each trace source can be connected to any number of trace sinks.
- * A trace sink is a ns3::Callback with a very special signature. Its
- * first argument is always a ns3::TraceContext.
- * - Every trace source is uniquely identified by a ns3::TraceContext. Every
- * trace sink can query a ns3::TraceContext for information. This allows
- * a trace sink which is connected to multiple trace sources to identify
- * from which source each event is coming from.
- *
- * To define new trace sources, a model author needs to instante one trace source
- * object for each kind of tracing event he wants to export. The trace source objects
- * currently defined are:
- * - ns3::CallbackTraceSourceSource: this trace source can be used to convey any kind of
- * trace event to the user. It is a functor, that is, it is a variable
- * which behaves like a function which will forward every event to every
- * connected trace sink (i.e., ns3::Callback). This trace source takes
- * up to four arguments and forwards these 4 arguments together with the
- * ns3::TraceContext which identifies this trace source to the connected
- * trace sinks.
- * - ns3::UVTraceSource: this trace source is used to convey key state variable
- * changes to the user. It behaves like a normal integer unsigned variable:
- * you can apply every normal arithmetic operator to it. It will forward
- * every change in the value of the variable back to every connected trace
- * sink by providing a TraceContext, the old value and the new value.
- * - ns3::SVTraceSource: this is the signed integer equivalent of
- * ns3::UVTraceSource.
- * - ns3::FVTraceSource: this is the floating point equivalent of
- * ns3::UVTraceSource and ns3::SVTraceSource.
- *
- * For example, to define a trace source which notifies you of a new packet
- * being transmitted, you would have to:
- * \code
- * class MyModel
- * {
- * public:
- * void Tx (Packet const &p);
- * private:
- * CallbackTraceSource<Packet const &> m_txTrace;
- * };
- *
- * void
- * MyModel::Tx (Packet const &p)
- * {
- * // trace packet tx event.
- * m_txTrace (p);
- * // ... send the packet for real.
- * }
- * \endcode
- *
- * Once the model author has instantiated these objects and has wired them
- * in his simulation code (that is, he calls them wherever he wants to trigger
- * a trace event), he needs to make these trace sources available to users
- * to allow them to connect any number of trace sources to any number
- * of user trace sinks. While it would be possible to make each model
- * export directly each of his trace source instances and request users to
- * invoke a source->Connect (callback) method to perform the connection
- * explicitely, it was felt that this was a bit cumbersome to do.
- *
- * As such, the ``connection'' between a set of sources and a sink is
- * performed through a third-party class, the TraceResolver, which
- * can be used to automate the connection of multiple matching trace sources
- * to a single sink. This TraceResolver works by defining a hierarchical
- * tracing namespace: the root of this namespace is accessed through the
- * ns3::TraceRoot class. The namespace is represented as a string made of
- * multiple elements, each of which is separated from the other elements
- * by the '/' character. A namespace string always starts with a '/'.
- *
- * By default, the current simulation models provide a '/nodes' tracing root.
- * This '/nodes' namespace is structured as follows:
- * \code
- * /nodes/n/arp
- * /nodes/n/udp
- * /nodes/n/ipv4
- * /tx
- * /rx
- * /drop
- * /interfaces/n/netdevice
- * /queue/
- * /enque
- * /deque
- * /drop
- * \endcode
- *
- * The 'n' element which follows the /nodes and /interfaces namespace elements
- * identify a specific node and interface through their index within the
- * ns3::NodeList and ns3::Ipv4 objects respectively.
- *
- * To connect a trace sink to a trace source identified by a namespace string,
- * a user can call the ns3::TraceRoot::Connect method (the ns3::TraceRoot::Disconnect
- * method does the symmetric operation). This connection method can accept
- * fully-detailed namespace strings but it can also perform pattern matching
- * on the user-provided namespace strings to connect multiple trace sources
- * to a single trace sink in a single connection operation.
- *
- * The syntax of the pattern matching rules are loosely based on regular
- * expressions:
- * - the '*' character matches every element
- * - the (a|b) construct matches element 'a' or 'b'
- * - the [ss-ee] construct matches all numerical values which belong
- * to the interval which includes ss and ee
- *
- * For example, the user could use the following to connect a single sink
- * to the ipv4 tx, rx, and drop trace events:
- *
- * \code
- * void MyTraceSink (TraceContext const &context, Packet &packet);
- * TraceRoot::Connect ("/nodes/ * /ipv4/ *", MakeCallback (&MyTraceSink));
- * \endcode
- *
- * Of course, this code would work only if the signature of the trace sink
- * is exactly equal to the signature of all the trace sources which match
- * the namespace string (if one of the matching trace source does not match
- * exactly, a fatal error will be triggered at runtime during the connection
- * process). The ns3::TraceContext extra argument contains
- * information on where the trace source is located in the namespace tree.
- * In that example, if there are multiple nodes in this scenario, each
- * call to the MyTraceSink function would receive a different TraceContext,
- * each of which would contain a different NodeList::Index object.
- *
- * It is important to understand exactly what an ns3::TraceContext
- * is. It is a container for a number of type instances. Each instance of
- * a ns3::TraceContext contains one and only one instance of a given type.
- * ns3::TraceContext::Add can be called to add a type instance into a
- * TraceContext instance and ns3::TraceContext::Get can be called to get
- * a copy of a type instance stored into the ns3::TraceContext. If ::Get
- * cannot retrieve the requested type, a fatal error is triggered at
- * runtime. The values stored into an ns3::TraceContext attached to a
- * trace source are automatically determined during the namespace
- * resolution process. To retrieve a value from a ns3::TraceContext, the
- * code can be as simple as this:
- * \code
- * void MyTraceSink (TraceContext const &context, Packet &packet)
- * {
- * NodeList::Index index;
- * context.Get (index);
- * std::cout << "node id=" << NodeList::GetNode (index)->GetId () << std::endl;
- * }
- * \endcode
- *
- * The hierarchical global namespace described here is not implemented
- * in a single central location: it was felt that doing this would make
- * it too hard to introduce user-specific models which could hook
- * automatically into the overal tracing system. If the tracing
- * namespace was implemented in a single central location, every model
- * author would have had to modify this central component to make
- * his own model available to trace users.
- *
- * Instead, the handling of the namespace is distributed across every relevant
- * model: every model implements only the part of the namespace it is
- * really responsible for. To do this, every model is expected
- * to provide an instance of a TraceResolver whose
- * responsability is to recursively provide access to the trace sources
- * defined in its model. Each TraceResolver instance should be a subclass
- * of the TraceResolver base class which implements either the DoLookup
- * or the DoConnect and DoDisconnect methods. Because implementing these
- * methods can be a bit tedious, our tracing framework provides a number
- * of helper template classes which should save the model author from
- * having to implement his own in most cases:
- * - ns3::CompositeTraceResolver: this subclass of ns3::TraceResolver can
- * be used to aggregate together multiple trace sources and multiple other
- * ns3::TraceResolver instances.
- * - ns3::ArrayTraceResolver: this subclass of ns3::TraceResolver can be
- * used to match any number of elements within an array where every element
- * is identified by its index.
- *
- * Once you can instantiate your own ns3::TraceResolver object instance, you
- * have to hook it up into the global namespace. There are two ways to do this:
- * - you can hook your ns3::TraceResolver creation method as a new trace
- * root by using the ns3::TraceRoot::Register method
- * - you can hook your new ns3::TraceResolver creation method into the
- * container of your model. This step will obvsiouly depend on which model
- * contains your own model but, if you wrote a new l3 protocol, all you
- * would have to do to hook into your container L3Demux class is to implement
- * the pure virtual method inherited from the L3Protocol class whose name is
- * ns3::L3protocol::CreateTraceResolver.
- *
- * So, in most cases, exporting a model's trace sources is a matter of
- * implementing a method CreateTraceResolver as shown below:
- * \code
- * class MyModel
- * {
- * public:
- * enum TraceType {
- * TX,
- * RX,
- * ...
- * };
- * TraceResolver *CreateTraceResolver (TraceContext const &context);
- * void Tx (Packet const &p);
- * private:
- * CallbackTraceSource<Packet const &> m_txTrace;
- * };
- *
- * TraceResolver *
- * MyModel::CreateTraceResolver (TraceContext const &context)
- * {
- * CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- * resolver->Add ("tx", m_txTrace, MyModel::TX);
- * return resolver;
- * }
- * void
- * MyModel::Tx (Packet const &p)
- * {
- * m_txTrace (p);
- * }
- * \endcode
- *
- * If you really want to have fun and implement your own ns3::TraceResolver
- * subclass, you need to understand the basic Connection and Disconnection
- * algorithm. The code of that algorithm is wholy contained in the
- * ns3::TraceResolver::Connect and ns3::TraceResolver::Disconnect methods.
- * The idea is that we recursively parse the input namespace string by removing
- * the first namespace element. This element is 'resolved' is calling
- * the ns3::TraceResolver::DoLookup method which returns a list of
- * TraceResolver instances. Each of the returned TraceResolver instance is
- * then given what is left of the namespace by calling ns3::TraceResolver::Connect
- * until the last namespace element is processed. At this point, we invoke
- * the ns3::TraceResolver::DoConnect or ns3::TraceResolver::DoDisconnect
- * methods to break the recursion. A good way to understand this algorithm
- * is to trace its behavior. Let's say that you want to connect to
- * '/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *'. It would generate
- * the following call traces:
- *
- * \code
- * TraceRoot::Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
- * traceContext = TraceContext ();
- * rootResolver = CompositeTraceResolver (traceContext);
- * rootResolver->Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
- * resolver = CompositeTraceResolver::DoLookup ("nodes");
- * return NodeList::CreateTraceResolver (GetContext ());
- * return ArrayTraceResolver (context);
- * resolver->Connect ("/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
- * ArrayTraceResolver::DoLookup ("*");
- * for (i = 0; i < n_nodes; i++)
- * resolver = nodes[i]->CreateTraceResolver (GetContext ());
- * return CompositeTraceResolver (context);
- * resolvers.add (resolver);
- * return resolvers;
- * for resolver in (resolvers)
- * resolver->Connect ("/ipv4/interfaces/ * /netdevice/queue/ *", callback);
- * CompositeTraceResolver::DoLookup ("ipv4");
- * resolver = ipv4->CreateTraceResolver (GetContext ());
- * return CompositeTraceResolver (context);
- * return resolver;
- * resolver->Connect ("/interfaces/ * /netdevice/queue/ *", callback);
- * CompositeTraceResolver::DoLookup ("interfaces");
- * resolver = ArrayTraceResolver (GetContext ());
- * resolver->Connect ("/ * /netdevice/queue/ *", callback);
- * ArrayTraceResolver::DoLookup ("*");
- * for (i = 0; i < n_interfaces; i++)
- * resolver = interfaces[i]->CreateTraceResolver (GetContext ());
- * return CompositeTraceResolver ()
- * resolvers.add (resolver);
- * return resolvers;
- * resolver->Connect ("/netdevice/queue/ *", callback);
- * CompositeTraceResolver::DoLookup ("netdevice");
- * resolver = NetDevice::CreateTraceResolver (GetContext ());
- * return CompositeTraceResolver ();
- * return resolver;
- * resolver->Connect ("/queue/ *", callback);
- * CompositeTraceResolver::DoLookup ("queue");
- * resolver = Queue::CreateTraceResolver (GetContext ());
- * return CompositeTraceResolver ();
- * return resolver
- * resolver->Connect ("*", callback);
- * CompositeTraceResolver::DoLookup ("*");
- * for match in (matches)
- * resolver = TerminalTraceResolver ("match");
- * resolvers.add (resolver)
- * return resolvers;
- * for resolver in (resolvers)
- * TerminalTraceResolver->DoConnect (callback);
- * \endcode
- */
-
-namespace ns3 {
-
-class CompositeTraceResolver;
-class TraceResolver;
-class TraceContext;
-class CallbackBase;
-
-/**
- * \brief The main class used to access tracing functionality for
- * a user.
- *
- * \ingroup lowleveltracing
- */
-class TraceRoot
-{
-public:
- static void Connect (std::string path, CallbackBase const &cb);
- static void Disconnect (std::string path, CallbackBase const &cb);
- static void Register (std::string name,
- Callback<TraceResolver *,TraceContext const &> createResolver);
-private:
- static CompositeTraceResolver *GetComposite (void);
- enum TraceType {
- NOTHING,
- };
-};
-
-}// namespace ns3
-
-#endif /* TRACE_ROOT_H */
--- a/src/common/trailer.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "trailer.h"
-
-namespace ns3 {
-
-Trailer::~Trailer ()
-{}
-
-}; // namespace ns3
--- a/src/common/trailer.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/trailer.h Fri Sep 28 11:59:46 2007 +0100
@@ -22,7 +22,28 @@
#ifndef TRAILER_H
#define TRAILER_H
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Trailer
+ * \brief this macro should be instantiated exactly once for each
+ * new type of Trailer
+ *
+ * This macro will ensure that your new Trailer type is registered
+ * within the packet trailer registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TRAILER_ENSURE_REGISTERED(x) \
+static class thisisaveryverylongclassname ##x \
+{ \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+} g_thisisanotherveryveryverylongname ##x;
namespace ns3 {
@@ -30,81 +51,66 @@
* \brief Protocol trailer serialization and deserialization.
*
* Every Protocol trailer which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- * - ns3::Trailer::SerializeTo
- * - ns3::Trailer::DeserializeFrom
- * - ns3::Trailer::GetSerializedSize
- * - ns3::Trailer::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ * - a default constructor: is used by the internal implementation
+ * if the Packet class.
+ * - a static method named GetUid: is used to uniquely identify
+ * the type of each trailer. This method shall return a unique
+ * integer allocated with Trailer::AllocateUid.
+ * - a method named Serialize: is used by Packet::AddTrailer to
+ * store a trailer into the byte buffer of a packet.
+ * The input iterator points to the end of the byte buffer in
+ * which the trailer should write its data: the user is thus
+ * required to call Buffer::Iterator::Prev prior to writing
+ * any data in the buffer. The data written is expected to
+ * match bit-for-bit the representation of this trailer in a
+ * real network.
+ * - a method named GetSerializedSize: is used by Packet::AddTrailer
+ * to store a trailer into the byte buffer of a packet. This method
+ * should return the number of bytes which are needed to store
+ * the full trailer data by Serialize.
+ * - a method named Deserialize: is used by Packet::RemoveTrailer to
+ * re-create a trailer from the byte buffer of a packet. The input
+ * iterator points to the end of the byte buffer from which
+ * the trailer should read its data: the user is thus required to
+ * call Buffer::Iterator::Prev prior to reading any data from the
+ * buffer. The data read is expected to match bit-for-bit the
+ * representation of this trailer in real networks. This method
+ * shall return an integer which identifies the number of bytes read.
+ * - a method named Print: is used by Packet::Print to print the
+ * content of a trailer as ascii data to a c++ output stream.
+ * Although the trailer is free to format its output as it
+ * wishes, it is recommended to follow a few rules to integrate
+ * with the packet pretty printer: start with flags, small field
+ * values located between a pair of parens. Values should be separated
+ * by whitespace. Follow the parens with the important fields,
+ * separated by whitespace.
+ * i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ * - a method named GetName: is used by Packet::Print to print
+ * trailer fragments. This method should return a user-readable
+ * single word as all capitalized letters.
*
- * Note that the SerializeTo and DeserializeFrom methods behave
- * in a way which might seem surprising to users: the input iterator
- * really points to the end of the buffer to which and from which
- * the user is expected to write and read respectively. This means that
- * if the trailer has a fixed size and if the user wishes to read or
- * write that trailer from front to back, the user must rewind the
- * iterator by hand to go to the start of the trailer. Typical code
- * looks like this:
- * \code
- * void CrcTrailer::SerializeTo (Buffer::Iterator end)
- * {
- * end.Prev (4);
- * end.WriteHtonU32 (m_crc);
- * }
- * \endcode
- *
- * Some users would have expected that the iterator would be rewinded
- * to the "start" of the trailer before calling SerializeTo and DeserializeFrom.
- * However, this behavior was not implemented because it cannot be made to
- * work reliably for trailers which have a variable size. i.e., if the trailer
- * contains options, the code which calls DeserializeFrom cannot rewind
- * to the start of the trailer because it does not know the real size of the
- * trailer. Hence, to make this legitimate use-case work (variable-sized
- * trailers), the input iterator to DeserializeFrom and SerializeTo points
- * to the end of the trailer, and not its start.
*/
-class Trailer : public Chunk {
-public:
- virtual ~Trailer ();
-private:
- /**
- * \param os the std output stream in which this
- * protocol trailer must print itself.
- */
- virtual void PrintTo (std::ostream &os) const = 0;
-
- /**
- * \returns the size of the serialized Trailer.
- *
- * This method is used by Packet::AddTrailer to reserve
- * enough room in the packet byte buffer prior to calling
- * Trailer::Serialize.
- */
- virtual uint32_t GetSerializedSize (void) const = 0;
-
- /**
- * \param end the buffer iterator in which the protocol trailer
- * must serialize itself. This iterator identifies
- * the end of the buffer.
- *
- * This iterator must be typically moved with the Buffer::Iterator::Prev
- * method before writing any byte in the buffer.
- */
- virtual void SerializeTo (Buffer::Iterator end) const = 0;
- /**
- * \param end the buffer iterator from which the protocol trailer must
- * deserialize itself. This iterator identifies
- * the end of the buffer.
- * \returns the number of bytes read from the buffer
- *
- * This iterator must be typically moved with the Buffer::Iterator::Prev
- * method before reading any byte in the buffer. The value returned
- * is used to trim the packet byte buffer of the corresponding
- * amount when this method is invoked from Packet::RemoveTrailer
- */
- virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0;
+class Trailer
+{
+protected:
+ template <typename T>
+ static uint32_t AllocateUid (std::string uidString);
};
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Trailer::AllocateUid (std::string uidString)
+{
+ return ChunkRegistry::RegisterTrailer<T> (uidString);
+}
+
+
+} // namespace ns3
#endif /* TRAILER_H */
--- a/src/common/uv-trace-source.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef UV_TRACE_SOURCE_H
-#define UV_TRACE_SOURCE_H
-
-#include "callback-trace-source.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class UVTraceSourceBase {
-public:
- typedef CallbackTraceSource<uint64_t, uint64_t> ChangeNotifyCallback;
-
- UVTraceSourceBase ()
- : m_callback () {}
- /* We don't want to copy the base callback. Only setCallback on
- * a specific instance will do something to it. */
- UVTraceSourceBase (UVTraceSourceBase const &o)
- : m_callback () {}
- UVTraceSourceBase &operator = (UVTraceSourceBase const &o) {
- return *this;
- }
- ~UVTraceSourceBase () {}
-
- void AddCallback (CallbackBase const & callback, TraceContext const & context) {
- m_callback.AddCallback (callback, context);
- }
- void RemoveCallback (CallbackBase const & callback) {
- m_callback.RemoveCallback (callback);
- }
-
-protected:
- void Notify (uint64_t oldVal, uint64_t newVal) {
- if (oldVal != newVal)
- {
- m_callback (oldVal, newVal);
- }
- }
-private:
- ChangeNotifyCallback m_callback;
-};
-
-template <typename T>
-class SVTraceSource;
-
-
-/**
- * \brief trace variables of type "unsigned integer"
- * \ingroup lowleveltracing
- *
- * This template class implements a POD type: it
- * behaves like any other variable of type "unsigned integer"
- * except that it also reports any changes to its
- * value with its internal callback.
- *
- * To instantiate a 32-bit unsigned variable (to store
- * a TCP counter for example), you would create a variable of type
- * ns3::UVTraceSource<uint32_t> :
- \code
- #include <stdint.h>
- #include "ns3/uv-trace-source.h"
-
- ns3::UVTraceSource<uint32_t> var;
- \endcode
- * and you would use it like any other variable of type uint32_t:
- \code
- var += 12;
- var = 10;
- \endcode
- */
-template <typename T>
-class UVTraceSource : public UVTraceSourceBase {
-public:
- UVTraceSource ()
- : m_var ()
- {}
- UVTraceSource (T const &var)
- : m_var (var)
- {}
-
- UVTraceSource &operator = (UVTraceSource const &o) {
- Assign (o.Get ());
- return *this;
- }
- template <typename TT>
- UVTraceSource &operator = (UVTraceSource<TT> const &o) {
- Assign (o.Get ());
- return *this;
- }
- template <typename TT>
- UVTraceSource &operator = (SVTraceSource<TT> const &o) {
- Assign (o.Get ());
- return *this;
- }
- UVTraceSource &operator++ () {
- Assign (Get () + 1);
- return *this;
- }
- UVTraceSource &operator-- () {
- Assign (Get () - 1);
- return *this;
- }
- UVTraceSource operator++ (int) {
- UVTraceSource old (*this);
- ++*this;
- return old;
- }
- UVTraceSource operator-- (int) {
- UVTraceSource old (*this);
- --*this;
- return old;
- }
- operator T () const {
- return Get ();
- }
-
-
- void Assign (T var) {
- Notify (m_var, var);
- m_var = var;
- }
- T Get (void) const {
- return m_var;
- }
-
-private:
- T m_var;
-};
-
-template <typename T>
-UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () + rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () - rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () * rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () / rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () << rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () >> rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () & rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () | rhs.Get ());
- return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
- lhs.Assign (lhs.Get () ^ rhs.Get ());
- return lhs;
-}
-
-
-template <typename T, typename U>
-UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () + rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () - rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () * rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () / rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () << rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () >> rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () & rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () | rhs);
- return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, U const &rhs) {
- lhs.Assign (lhs.Get () ^ rhs);
- return lhs;
-}
-
-}; // namespace ns3
-
-#endif /* UV_TRACE_SOURCE_H */
--- a/src/common/variable-tracer-test.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "uv-trace-source.h"
-#include "sv-trace-source.h"
-#include "trace-context.h"
-#include "ns3/test.h"
-#include "ns3/callback.h"
-
-
-namespace ns3 {
-
-class Foo {
-public:
- void Notify (TraceContext const &contex, uint64_t oldVal, uint64_t newVal) {}
-};
-
-class VariableTracerTest: public Test {
-public:
- VariableTracerTest ();
- void RunUnsignedTests (void);
- void RunSignedUnsignedTests (void);
- virtual bool RunTests (void);
-};
-void
-VariableTracerTest::RunUnsignedTests (void)
-{
- UVTraceSource<uint32_t> var, ovar, tmp;
- uint32_t utmp;
- Foo *foo = new Foo ();
-
- var.AddCallback (MakeCallback (&Foo::Notify, foo), TraceContext ());
-
- var = 10;
- ovar = var;
-
- if (var == ovar)
- {
- }
- if (var != ovar)
- {
- }
- if (var > ovar)
- {
- }
- if (var >= ovar)
- {
- }
- if (var < ovar)
- {
- }
-
- if (var <= ovar)
-
- if (var == 1)
- {
- }
- if (var != 1)
- {
- }
- if (var > 1)
- {
- }
- if (var >= 1)
- {
- }
- if (var < 1)
- {
- }
- if (var <= 1)
- {
- }
-
- if (1 == ovar)
- {
- }
- if (1 != ovar)
- {
- }
- if (1 > ovar)
- {
- }
- if (1 >= ovar)
- {
- }
- if (1 < ovar)
- {
- }
- if (1 <= ovar)
- {
- }
-
- var++;
- ++var;
- var--;
- --var;
-
- tmp = var + ovar;
- tmp = var - ovar;
- tmp = var / ovar;
- tmp = var * ovar;
- tmp = var << ovar;
- tmp = var >> ovar;
- tmp = var & ovar;
- tmp = var | ovar;
- tmp = var ^ ovar;
-
- tmp = var + 1;
- tmp = var - 1;
- tmp = var / 1;
- tmp = var * 1;
- tmp = var << 1;
- tmp = var >> 1;
- tmp = var & 1;
- tmp = var | 1;
- tmp = var ^ 1;
-
- tmp = 1 + ovar;
- tmp = 1 - ovar;
- tmp = 1 / ovar;
- tmp = 1 * ovar;
- tmp = 1 << ovar;
- tmp = 1 >> ovar;
- tmp = 1 & ovar;
- tmp = 1 | ovar;
- tmp = 1 ^ ovar;
-
- tmp += var;
- tmp -= var;
- tmp /= var;
- tmp *= var;
- tmp <<= var;
- tmp >>= var;
- tmp &= var;
- tmp |= var;
- tmp ^= var;
-
- tmp += 1;
- tmp -= 1;
- tmp /= 1;
- tmp *= 1;
- tmp <<= 1;
- tmp >>= 1;
- tmp &= 1;
- tmp |= 1;
- tmp ^= 1;
-
-
- utmp = var + ovar;
- utmp = var - ovar;
- utmp = var / ovar;
- utmp = var * ovar;
- utmp = var << ovar;
- utmp = var >> ovar;
- utmp = var & ovar;
- utmp = var | ovar;
- utmp = var ^ ovar;
-
- utmp = var + 1;
- utmp = var - 1;
- utmp = var / 1;
- utmp = var * 1;
- utmp = var << 1;
- utmp = var >> 1;
- utmp = var & 1;
- utmp = var | 1;
- utmp = var ^ 1;
-
- utmp = 1 + ovar;
- utmp = 1 - ovar;
- utmp = 1 / ovar;
- utmp = 1 * ovar;
- utmp = 1 << ovar;
- utmp = 1 >> ovar;
- utmp = 1 & ovar;
- utmp = 1 | ovar;
- utmp = 1 ^ ovar;
-
- utmp += var;
- utmp -= var;
- utmp /= var;
- utmp *= var;
- utmp <<= var;
- utmp >>= var;
- utmp &= var;
- utmp |= var;
- utmp ^= var;
-
- utmp += 1;
- utmp -= 1;
- utmp /= 1;
- utmp *= 1;
- utmp <<= 1;
- utmp >>= 1;
- utmp &= 1;
- utmp |= 1;
- utmp ^= 1;
-
- delete foo;
-}
-
-void
-VariableTracerTest::RunSignedUnsignedTests (void)
-{
- unsigned short utmp = 10;
- unsigned int uitmp = 7;
- short stmp = 5;
- utmp = stmp;
- utmp += stmp;
- uitmp = utmp;
- utmp = uitmp;
-
- UVTraceSource<unsigned short> uvar = 10;
- UVTraceSource<unsigned int> uivar = 5;
- SVTraceSource<short> svar = 5;
- SVTraceSource<int> sivar = 5;
- uvar = svar;
- svar = uvar;
- uvar += svar;
- svar += uvar;
-
- uvar = sivar;
- sivar = uvar;
- uvar += sivar;
- sivar += uvar;
-
- uivar = uvar;
- uvar = uivar;
- uivar += uvar;
- uvar += uivar;
-
- sivar = svar;
- svar = sivar;
- sivar += svar;
- svar += sivar;
-}
-
-bool
-VariableTracerTest::RunTests (void)
-{
- RunUnsignedTests ();
- RunSignedUnsignedTests ();
-
- return true;
-}
-
-VariableTracerTest::VariableTracerTest ()
- : Test ("VariableTracer") {}
-
-static VariableTracerTest gVariableTracerTest;
-
-}; // namespace ns3
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/common/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -1,49 +1,32 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-def configure(conf):
- conf.env.append_value('NS3_MODULES', 'ns3-common')
-
def build(bld):
- common = bld.create_obj('cpp', 'shlib')
- common.name = 'ns3-common'
- common.target = common.name
- common.uselib_local = ['ns3-core', 'ns3-simulator']
+ common = bld.create_ns3_module('common', ['core', 'simulator'])
common.source = [
'buffer.cc',
- 'header.cc',
- 'chunk.cc',
- 'trailer.cc',
+ 'chunk-registry.cc',
+ 'packet-printer.cc',
+ 'packet-metadata.cc',
+ 'packet-metadata-test.cc',
'packet.cc',
'tags.cc',
+ 'tag-registry.cc',
'pcap-writer.cc',
- 'variable-tracer-test.cc',
- 'trace-context.cc',
- 'trace-resolver.cc',
- 'callback-trace-source.cc',
- 'empty-trace-resolver.cc',
- 'composite-trace-resolver.cc',
- 'trace-root.cc',
'data-rate.cc',
]
+
headers = bld.create_obj('ns3header')
headers.source = [
'buffer.h',
+ 'chunk-registry.h',
'header.h',
- 'chunk.h',
'trailer.h',
'tags.h',
+ 'tag-registry.h',
+ 'tag.h',
'packet.h',
- 'uv-trace-source.h',
- 'sv-trace-source.h',
- 'fv-trace-source.h',
+ 'packet-printer.h',
+ 'packet-metadata.h',
'pcap-writer.h',
- 'callback-trace-source.h',
- 'trace-context.h',
- 'trace-resolver.h',
- 'empty-trace-resolver.h',
- 'composite-trace-resolver.h',
- 'array-trace-resolver.h',
- 'trace-root.h',
- 'terminal-trace-resolver.h',
'data-rate.h',
]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/array-trace-resolver.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,205 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef ARRAY_TRACE_RESOLVER_H
+#define ARRAY_TRACE_RESOLVER_H
+
+#include <stdint.h>
+#include <string>
+#include "callback.h"
+#include "trace-resolver.h"
+#include "object.h"
+
+namespace ns3 {
+
+/**
+ * \brief a helper class to offer trace resolution for an array of objects.
+ * \ingroup tracing
+ *
+ * \class ArrayTraceResolver
+ *
+ * An ArrayTraceResolver is a resolver which can match any input integer
+ * against an element in an array. The array is accessed using a
+ * pair iterators. Each element of the array is expected
+ * to be a subclass of the Object base class.
+ *
+ * When the Connect method is called, this trace resolver will
+ * automatically store in the TraceContext of each resolved object
+ * its index through an object of type INDEX specified during the
+ * instanciation of the ArrayTraceResolver template.
+ */
+template <typename INDEX>
+class ArrayTraceResolver : public TraceResolver
+{
+public:
+ ArrayTraceResolver ();
+ ~ArrayTraceResolver ();
+
+ /**
+ * \param begin an iterator which points to the start of the array.
+ * \param end an iterator which points to the end of the array.
+ */
+ template <typename T>
+ void SetIterators (T begin, T end);
+
+ // inherited from TraceResolver
+ virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
+ virtual void Disconnect (std::string path, CallbackBase const &cb);
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection);
+ virtual void TraceAll (std::ostream &os, const TraceContext &context);
+
+private:
+ class IteratorBase
+ {
+ public:
+ virtual ~IteratorBase () {}
+ virtual void Next (void) = 0;
+ virtual bool HasNext (void) = 0;
+ virtual Ptr<Object> Get (void) = 0;
+ virtual void Rewind (void) = 0;
+ };
+ IteratorBase *m_iter;
+};
+}//namespace ns3
+
+
+// implementation
+namespace ns3 {
+
+template <typename INDEX>
+ArrayTraceResolver<INDEX>::ArrayTraceResolver ()
+ : m_iter (0)
+{}
+
+template <typename INDEX>
+ArrayTraceResolver<INDEX>::~ArrayTraceResolver ()
+{
+ delete m_iter;
+}
+
+template <typename INDEX>
+template <typename T>
+void
+ArrayTraceResolver<INDEX>::SetIterators (T begin, T end)
+{
+ class Iterator : public IteratorBase
+ {
+ public:
+ Iterator (T begin, T end)
+ : m_begin (begin), m_end (end), m_cur (begin)
+ {}
+ virtual void Next (void)
+ {m_cur++;}
+ virtual bool HasNext (void)
+ {return m_cur != m_end;}
+ virtual Ptr<Object> Get (void)
+ {return *m_cur;}
+ virtual void Rewind (void)
+ {m_cur = m_begin;}
+ private:
+ T m_begin;
+ T m_end;
+ T m_cur;
+ };
+ delete m_iter;
+ m_iter = new Iterator (begin, end);
+}
+
+template <typename INDEX>
+void
+ArrayTraceResolver<INDEX>::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
+{
+ if (path == "")
+ {
+ return;
+ }
+ std::string id = GetElement (path);
+ std::string subpath = GetSubpath (path);
+ if (id == "*")
+ {
+ uint32_t j = 0;
+ for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+ {
+ TraceContext tmp = context;
+ INDEX index = j;
+ tmp.AddElement (index);
+ Ptr<Object> obj = m_iter->Get ();
+ obj->GetTraceResolver ()->Connect (subpath, cb, tmp);
+ j++;
+ }
+ }
+}
+template <typename INDEX>
+void
+ArrayTraceResolver<INDEX>::Disconnect (std::string path, CallbackBase const &cb)
+{
+ if (path == "")
+ {
+ return;
+ }
+ std::string id = GetElement (path);
+ std::string subpath = GetSubpath (path);
+ if (id == "*")
+ {
+ for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+ {
+ Ptr<Object> obj = m_iter->Get ();
+ obj->TraceDisconnect (subpath, cb);
+ }
+ }
+}
+template <typename INDEX>
+void
+ArrayTraceResolver<INDEX>::CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection)
+{
+ path.append ("/[0-n]");
+ uint32_t j = 0;
+ for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+ {
+ TraceContext tmp = context;
+ INDEX index = j;
+ tmp.AddElement (index);
+ Ptr<Object> obj = m_iter->Get ();
+ obj->GetTraceResolver ()->CollectSources (path, tmp, collection);
+ j++;
+ }
+}
+
+template <typename INDEX>
+void
+ArrayTraceResolver<INDEX>::TraceAll (std::ostream &os, const TraceContext &context)
+{
+ uint32_t j = 0;
+ for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+ {
+ TraceContext tmp = context;
+ INDEX index = j;
+ tmp.AddElement (index);
+ Ptr<Object> obj = m_iter->Get ();
+ obj->GetTraceResolver ()->TraceAll (os, tmp);
+ j++;
+ }
+}
+
+}//namespace ns3
+
+#endif /* ARRAY_TRACE_RESOLVER_H */
--- a/src/core/assert.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "assert.h"
-
-namespace ns3 {
-
-void
-AssertBreakpoint (void)
-{
- int *a = 0;
- /**
- * we test here to allow a debugger to change the value of
- * the variable 'a' to allow the debugger to avoid the
- * subsequent segfault.
- */
- if (a == 0)
- {
- *a = 0;
- }
-}
-
-}//namespace ns3
--- a/src/core/assert.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/assert.h Fri Sep 28 11:59:46 2007 +0100
@@ -21,6 +21,12 @@
#ifndef ASSERT_H
#define ASSERT_H
+#ifdef NS3_ASSERT_ENABLE
+
+#include <iostream>
+
+#include "breakpoint.h"
+
/**
* \defgroup assert Assert
* \brief assert functions and macros
@@ -32,25 +38,6 @@
* removed in optimized builds.
*/
-namespace ns3 {
-
-/**
- * \ingroup debugging
- *
- * When an NS_ASSERT cannot verify its condition,
- * this function is called. This is where you should
- * be able to put a breakpoint with a debugger if
- * you want to catch assertions before the program
- * halts.
- */
-void AssertBreakpoint (void);
-
-}//namespace ns3
-
-#ifdef NS3_ASSERT_ENABLE
-
-#include <iostream>
-
/**
* \ingroup assert
* \param condition condition to verifiy.
@@ -65,10 +52,10 @@
{ \
if (!(condition)) \
{ \
- std::cout << "assert failed. file=" << __FILE__ << \
+ std::cerr << "assert failed. file=" << __FILE__ << \
", line=" << __LINE__ << ", cond=\""#condition << \
"\"" << std::endl; \
- ns3::AssertBreakpoint (); \
+ NS_BREAKPOINT (); \
} \
} \
while (false)
@@ -88,8 +75,8 @@
{ \
if (!(condition)) \
{ \
- std::cout << message << std::endl; \
- ns3::AssertBreakpoint (); \
+ std::cerr << message << std::endl; \
+ NS_BREAKPOINT (); \
} \
} \
while (false)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,58 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA, INESC Porto
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ */
+
+#include "breakpoint.h"
+#include "ns3/core-config.h"
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+namespace ns3 {
+
+#if defined (HAVE_SIGNAL_H) && defined (SIGTRAP)
+
+void
+BreakpointFallback (void)
+{
+ raise (SIGTRAP);
+}
+
+#else
+
+void
+BreakpointFallback (void)
+{
+ int *a = 0;
+ /**
+ * we test here to allow a debugger to change the value of
+ * the variable 'a' to allow the debugger to avoid the
+ * subsequent segfault.
+ */
+ if (a == 0)
+ {
+ *a = 0;
+ }
+}
+
+#endif // HAVE_SIGNAL_H
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INESC Porto, INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef BREAKPOINT_H
+#define BREAKPOINT_H
+
+namespace ns3 {
+
+/* Hacker macro to place breakpoints for selected machines.
+ * Actual use is strongly discouraged of course ;)
+ * Copied from GLib 2.12.9.
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/**
+ * \ingroup debugging
+ *
+ * Inserts a breakpoint instruction (or equivalent system call) into
+ * the code for selected machines. When an NS_ASSERT cannot verify its condition,
+ * this macro is used. Falls back to calling
+ * AssertBreakpoint() for architectures where breakpoint assembly
+ * instructions are not supported.
+ */
+#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2
+# define NS_BREAKPOINT() \
+ do{ __asm__ __volatile__ ("int $03"); }while(false)
+#elif defined (_MSC_VER) && defined (_M_IX86)
+# define NS_BREAKPOINT() \
+ do{ __asm int 3h }while(false)
+#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2
+# define NS_BREAKPOINT() \
+ do{ __asm__ __volatile__ ("bpt"); }while(false)
+#else /* !__i386__ && !__alpha__ */
+# define NS_BREAKPOINT() ns3::BreakpointFallback ()
+#endif
+
+/**
+ * \brief fallback breakpoint function
+ *
+ * This function is used by the NS_BREAKPOINT() macro as a fallback
+ * for when breakpoint assembly instructions are not available. It
+ * attempts to halt program execution either by a raising SIGTRAP, on
+ * unix systems, or by dereferencing a null pointer.
+ *
+ * Normally you should not call this function directly.
+ */
+void BreakpointFallback (void);
+
+
+}//namespace ns3
+
+
+#endif /* BREAKPOINT_H */
--- a/src/core/callback-test.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/callback-test.cc Fri Sep 28 11:59:46 2007 +0100
@@ -57,6 +57,21 @@
return a;
}
+void TestFZero (void) {}
+void TestFOne (int) {}
+void TestFTwo (int, int) {}
+void TestFThree (int, int, int) {}
+void TestFFour (int, int, int, int) {}
+void TestFFive (int, int, int, int, int) {}
+void TestFSix (int, int, int, int, int, int) {}
+
+void TestFROne (int &) {}
+void TestFRTwo (int &, int &) {}
+void TestFRThree (int &, int &, int &) {}
+void TestFRFour (int &, int &, int &, int &) {}
+void TestFRFive (int &, int &, int &, int &, int &) {}
+void TestFRSix (int &, int &, int &, int &, int &, int &) {}
+
class CallbackTest : public ns3::Test {
private:
bool m_test1;
@@ -73,6 +88,22 @@
void Test3 (double a);
int Test4 (double a, int b);
void Test8 (Callback<void, int> callback);
+
+ void TestZero (void) {}
+ void TestOne (int) {}
+ void TestTwo (int, int) {}
+ void TestThree (int, int, int) {}
+ void TestFour (int, int, int, int) {}
+ void TestFive (int, int, int, int, int) {}
+ void TestSix (int, int, int, int, int, int) {}
+
+ void TestCZero (void) const {}
+ void TestCOne (int) const {}
+ void TestCTwo (int, int) const {}
+ void TestCThree (int, int, int) const {}
+ void TestCFour (int, int, int, int) const {}
+ void TestCFive (int, int, int, int, int) const {}
+ void TestCSix (int, int, int, int, int, int) const {}
};
CallbackTest::CallbackTest ()
@@ -110,6 +141,7 @@
{
callback (3);
}
+
bool
CallbackTest::IsWrong (void)
{
@@ -216,6 +248,53 @@
MakeBoundCallback (&Test9, &v);
MakeBoundCallback (&Test10, &v);
+
+ MakeCallback (&CallbackTest::TestZero, this);
+ MakeCallback (&CallbackTest::TestOne, this);
+ MakeCallback (&CallbackTest::TestTwo, this);
+ MakeCallback (&CallbackTest::TestThree, this);
+ MakeCallback (&CallbackTest::TestFour, this);
+ MakeCallback (&CallbackTest::TestFive, this);
+ MakeCallback (&CallbackTest::TestSix, this);
+
+ MakeCallback (&CallbackTest::TestCZero, this);
+ MakeCallback (&CallbackTest::TestCOne, this);
+ MakeCallback (&CallbackTest::TestCTwo, this);
+ MakeCallback (&CallbackTest::TestCThree, this);
+ MakeCallback (&CallbackTest::TestCFour, this);
+ MakeCallback (&CallbackTest::TestCFive, this);
+ MakeCallback (&CallbackTest::TestCSix, this);
+
+ MakeCallback (&TestFZero);
+ MakeCallback (&TestFOne);
+ MakeCallback (&TestFTwo);
+ MakeCallback (&TestFThree);
+ MakeCallback (&TestFFour);
+ MakeCallback (&TestFFive);
+ MakeCallback (&TestFSix);
+
+ MakeCallback (&TestFROne);
+ MakeCallback (&TestFRTwo);
+ MakeCallback (&TestFRThree);
+ MakeCallback (&TestFRFour);
+ MakeCallback (&TestFRFive);
+ MakeCallback (&TestFRSix);
+
+
+ MakeBoundCallback (&TestFOne, 1);
+ MakeBoundCallback (&TestFTwo, 1);
+ MakeBoundCallback (&TestFThree, 1);
+ MakeBoundCallback (&TestFFour, 1);
+ MakeBoundCallback (&TestFFive, 1);
+
+ MakeBoundCallback (&TestFROne, 1);
+ MakeBoundCallback (&TestFRTwo, 1);
+ MakeBoundCallback (&TestFRThree, 1);
+ MakeBoundCallback (&TestFRFour, 1);
+ MakeBoundCallback (&TestFRFive, 1);
+
+
+
return ok;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/callback-trace-source.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,101 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "callback-trace-source.h"
+
+#ifdef RUN_SELF_TESTS
+
+#include "test.h"
+
+namespace ns3 {
+
+class CallbackTraceSourceTest : public Test
+{
+public:
+ CallbackTraceSourceTest ();
+ virtual ~CallbackTraceSourceTest ();
+ virtual bool RunTests (void);
+private:
+ void CbOne (TraceContext const &context, uint8_t a, double b);
+ void CbTwo (TraceContext const &context, uint8_t a, double b);
+
+ bool m_one;
+ bool m_two;
+};
+
+CallbackTraceSourceTest::CallbackTraceSourceTest ()
+ : Test ("CallbackTraceSource")
+{}
+CallbackTraceSourceTest::~CallbackTraceSourceTest ()
+{}
+void
+CallbackTraceSourceTest::CbOne (TraceContext const &context, uint8_t a, double b)
+{
+ m_one = true;
+}
+void
+CallbackTraceSourceTest::CbTwo (TraceContext const &context, uint8_t a, double b)
+{
+ m_two = true;
+}
+bool
+CallbackTraceSourceTest::RunTests (void)
+{
+ bool result = true;
+ TraceContext ctx;
+
+ CallbackTraceSource<uint8_t,double> trace;
+ trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
+ trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
+ m_one = false;
+ m_two = false;
+ trace (1, 2);
+ NS_TEST_ASSERT (m_one);
+ NS_TEST_ASSERT (m_two);
+
+ trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this));
+ m_one = false;
+ m_two = false;
+ trace (1, 2);
+ NS_TEST_ASSERT (!m_one);
+ NS_TEST_ASSERT (m_two);
+ trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this));
+ m_one = false;
+ m_two = false;
+ trace (1, 2);
+ NS_TEST_ASSERT (!m_one);
+ NS_TEST_ASSERT (!m_two);
+
+ trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
+ trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
+ m_one = false;
+ m_two = false;
+ trace (1, 2);
+ NS_TEST_ASSERT (m_one);
+ NS_TEST_ASSERT (m_two);
+
+ return result;
+}
+
+CallbackTraceSourceTest g_callbackTraceTest;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/callback-trace-source.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,251 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef CALLBACK_TRACE_H
+#define CALLBACK_TRACE_H
+
+#include <list>
+#include "callback.h"
+#include "fatal-error.h"
+#include "trace-context.h"
+#include "trace-source.h"
+
+namespace ns3 {
+
+/**
+ * \brief log arbitrary number of parameters to a matching ns3::Callback
+ * \ingroup tracing
+ *
+ * Whenever operator () is invoked on this class, the call and its arguments
+ * are forwarded to the internal matching ns3::Callback.
+ */
+template<typename T1 = empty, typename T2 = empty,
+ typename T3 = empty, typename T4 = empty>
+class CallbackTraceSource : public TraceSource {
+public:
+ CallbackTraceSource ();
+ virtual void AddCallback (CallbackBase const & callback, TraceContext const & context);
+ virtual void RemoveCallback (CallbackBase const & callback);
+ virtual void ConnectPrinter (std::ostream &os, const TraceContext &context);
+ void operator() (void) const;
+ void operator() (T1 a1) const;
+ void operator() (T1 a1, T2 a2) const;
+ void operator() (T1 a1, T2 a2, T3 a3) const;
+ void operator() (T1 a1, T2 a2, T3 a3, T4 a4) const;
+
+private:
+ typedef std::list<Callback<void,TraceContext const &,T1,T2,T3,T4> > CallbackList;
+ TraceContext m_context;
+ CallbackList m_callbackList;
+};
+
+}; // namespace ns3
+
+// implementation below.
+
+namespace ns3 {
+
+namespace internal {
+
+template<typename T1, typename T2,
+ typename T3, typename T4>
+class TraceSinkPrint;
+
+template<typename T1, typename T2,
+ typename T3, typename T4>
+class TraceSinkPrint
+{
+public:
+ static Callback<void,const TraceContext &,T1,T2,T3,T4> Make (std::ostream &os)
+ {
+ return ns3::MakeBoundCallback (&DoPrint, &os);
+ }
+private:
+ static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2, T3 a3, T4 a4)
+ {
+ *os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\" arg3=\"" << a3 << "\" arg4=\"" << a4 << "\"" << std::endl;
+ }
+};
+
+template<typename T1, typename T2,
+ typename T3>
+class TraceSinkPrint<T1,T2,T3,empty>
+{
+public:
+ static Callback<void,const TraceContext &,T1,T2,T3> Make (std::ostream &os)
+ {
+ return ns3::MakeBoundCallback (&DoPrint, &os);
+ }
+private:
+ static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2, T3 a3)
+ {
+ *os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\" arg3=\"" << a3 << "\"" << std::endl;
+ }
+};
+
+template<typename T1, typename T2>
+class TraceSinkPrint<T1,T2,empty,empty>
+{
+public:
+ static Callback<void,const TraceContext &,T1,T2> Make (std::ostream &os)
+ {
+ return ns3::MakeBoundCallback (&DoPrint, &os);
+ }
+private:
+ static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2)
+ {
+ *os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\"" << std::endl;
+ }
+};
+
+template<typename T1>
+class TraceSinkPrint<T1,empty,empty,empty>
+{
+public:
+ static Callback<void,const TraceContext &,T1> Make (std::ostream &os)
+ {
+ return ns3::MakeBoundCallback (&DoPrint, &os);
+ }
+private:
+ static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1)
+ {
+ *os << "context=\"" << context << "\" arg1=\"" << a1 << "\"" << std::endl;
+ }
+};
+
+template <>
+class TraceSinkPrint<empty,empty,empty,empty>
+{
+public:
+ static Callback<void,const TraceContext &> Make (std::ostream &os)
+ {
+ return ns3::MakeBoundCallback (&DoPrint, &os);
+ }
+private:
+ static void DoPrint (std::ostream *os, const TraceContext &context)
+ {
+ *os << "context=\"" << context << std::endl;
+ }
+};
+
+} // namespace internal
+
+
+template<typename T1, typename T2,
+ typename T3, typename T4>
+CallbackTraceSource<T1,T2,T3,T4>::CallbackTraceSource ()
+ : m_callbackList ()
+{}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::AddCallback (CallbackBase const & callback,
+ TraceContext const &context)
+{
+ Callback<void,TraceContext const &,T1,T2,T3,T4> cb;
+ cb.Assign (callback);
+ m_context.Union (context);
+ m_callbackList.push_back (cb);
+}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::RemoveCallback (CallbackBase const & callback)
+{
+ for (typename CallbackList::iterator i = m_callbackList.begin ();
+ i != m_callbackList.end (); /* empty */)
+ {
+ if ((*i).IsEqual (callback))
+ {
+ i = m_callbackList.erase (i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::ConnectPrinter (std::ostream &os, const TraceContext &context)
+{
+ AddCallback (ns3::internal::TraceSinkPrint<T1,T2,T3,T4>::Make (os), context);
+}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::operator() (void) const
+{
+ for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+ i != m_callbackList.end (); i++)
+ {
+ (*i) (m_context);
+ }
+}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1) const
+{
+ for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+ i != m_callbackList.end (); i++)
+ {
+ (*i) (m_context, a1);
+ }
+}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2) const
+{
+ for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+ i != m_callbackList.end (); i++)
+ {
+ (*i) (m_context, a1, a2);
+ }
+}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3) const
+{
+ for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+ i != m_callbackList.end (); i++)
+ {
+ (*i) (m_context, a1, a2, a3);
+ }
+}
+template<typename T1, typename T2,
+ typename T3, typename T4>
+void
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3, T4 a4) const
+{
+ for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+ i != m_callbackList.end (); i++)
+ {
+ (*i) (m_context, a1, a2, a3, a4);
+ }
+}
+
+}//namespace ns3
+
+#endif /* CALLBACK_TRACE_H */
--- a/src/core/callback.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/callback.h Fri Sep 28 11:59:46 2007 +0100
@@ -25,6 +25,7 @@
#include "ptr.h"
#include "fatal-error.h"
#include "empty.h"
+#include "type-traits.h"
namespace ns3 {
@@ -89,55 +90,62 @@
};
// declare the CallbackImpl class
-template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class CallbackImpl;
// define CallbackImpl for 0 params
template <typename R>
-class CallbackImpl<R,empty,empty,empty,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,empty,empty,empty,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (void) = 0;
};
// define CallbackImpl for 1 params
template <typename R, typename T1>
-class CallbackImpl<R,T1,empty,empty,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,empty,empty,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1) = 0;
};
// define CallbackImpl for 2 params
template <typename R, typename T1, typename T2>
-class CallbackImpl<R,T1,T2,empty,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,empty,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2) = 0;
};
// define CallbackImpl for 3 params
template <typename R, typename T1, typename T2, typename T3>
-class CallbackImpl<R,T1,T2,T3,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,T3,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2, T3) = 0;
};
// define CallbackImpl for 4 params
template <typename R, typename T1, typename T2, typename T3, typename T4>
-class CallbackImpl<R,T1,T2,T3,T4,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,T3,T4,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2, T3, T4) = 0;
};
// define CallbackImpl for 5 params
template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
-class CallbackImpl : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,T3,T4,T5,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2, T3, T4, T5) = 0;
};
+// define CallbackImpl for 6 params
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+class CallbackImpl : public CallbackImplBase {
+public:
+ virtual ~CallbackImpl () {}
+ virtual R operator() (T1, T2, T3, T4, T5, T6) = 0;
+};
// an impl for Functors:
-template <typename T, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
-class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
+template <typename T, typename R, typename T1, typename T2, typename T3, typename T4,typename T5, typename T6>
+class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,T6> {
public:
FunctorCallbackImpl (T const &functor)
: m_functor (functor) {}
@@ -160,9 +168,12 @@
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
return m_functor (a1,a2,a3,a4,a5);
}
+ R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
+ return m_functor (a1,a2,a3,a4,a5,a6);
+ }
virtual bool IsEqual (CallbackImplBase const *other) const {
- FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *otherDerived =
- dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *> (other);
+ FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *otherDerived =
+ dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *> (other);
if (otherDerived == 0)
{
return false;
@@ -178,8 +189,8 @@
};
// an impl for pointer to member functions
-template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
-class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
+template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,T6> {
public:
MemPtrCallbackImpl (OBJ_PTR const&objPtr, MEM_PTR mem_ptr)
: m_objPtr (objPtr), m_memPtr (mem_ptr) {}
@@ -202,9 +213,12 @@
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5);
}
+ R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
+ return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5, a6);
+ }
virtual bool IsEqual (CallbackImplBase const *other) const {
- MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *otherDerived =
- dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *> (other);
+ MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *otherDerived =
+ dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *> (other);
if (otherDerived == 0)
{
return false;
@@ -225,6 +239,7 @@
public:
virtual ~CallbackBase () {}
virtual CallbackImplBase *PeekImpl (void) const = 0;
+ virtual Ptr<CallbackImplBase> GetImpl (void) const = 0;
};
/**
@@ -259,26 +274,26 @@
template<typename R,
typename T1 = empty, typename T2 = empty,
typename T3 = empty, typename T4 = empty,
- typename T5 = empty>
+ typename T5 = empty, typename T6 = empty>
class Callback : public CallbackBase {
public:
// There are two dummy args below to ensure that this constructor is
// always properly disambiguited by the c++ compiler
template <typename FUNCTOR>
Callback (FUNCTOR const &functor, bool, bool)
- : m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5> > (functor))
+ : m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5,T6> > (functor))
{}
template <typename OBJ_PTR, typename MEM_PTR>
Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr)
- : m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> > (objPtr, mem_ptr))
+ : m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> > (objPtr, mem_ptr))
{}
- Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > const &impl)
+ Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > const &impl)
: m_impl (impl)
{}
- bool IsNull (void) {
+ bool IsNull (void) const {
return (PeekImpl () == 0)?true:false;
}
void Nullify (void) {
@@ -304,14 +319,17 @@
R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const {
return (*(PeekImpl ())) (a1,a2,a3,a4,a5);
}
+ R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6) const {
+ return (*(PeekImpl ())) (a1,a2,a3,a4,a5,a6);
+ }
- bool IsEqual (CallbackBase const &other) {
+ bool IsEqual (CallbackBase const &other) const {
return PeekImpl ()->IsEqual (other.PeekImpl ());
}
- bool CheckType (CallbackBase const& other) {
+ bool CheckType (CallbackBase const& other) const {
CallbackImplBase *otherBase = other.PeekImpl ();
- if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (otherBase) != 0)
+ if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (otherBase) != 0)
{
return true;
}
@@ -327,14 +345,27 @@
" got=" << typeid (other).name () <<
", expected=" << typeid (*this).name ());
}
- const Callback<R, T1,T2,T3,T4,T5> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5> *> (&other);
+ const Callback<R, T1,T2,T3,T4,T5,T6> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5,T6> *> (&other);
*this = *goodType;
}
+ void Assign (Ptr<CallbackImplBase> other) {
+ CallbackImpl<R,T1,T2,T3,T4,T5,T6> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (PeekPointer (other));
+ if (other == 0)
+ {
+ NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
+ " got=" << typeid (other).name () <<
+ ", expected=" << typeid (*impl).name ());
+ }
+ *this = Callback<R,T1,T2,T3,T4,T5,T6> (impl);
+ }
+ virtual Ptr<CallbackImplBase>GetImpl (void) const {
+ return m_impl;
+ }
private:
- virtual CallbackImpl<R,T1,T2,T3,T4,T5> *PeekImpl (void) const {
+ virtual CallbackImpl<R,T1,T2,T3,T4,T5,T6> *PeekImpl (void) const {
return PeekPointer (m_impl);
}
- Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > m_impl;
+ Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > m_impl;
};
/**
@@ -344,7 +375,7 @@
/**
* \ingroup MakeCallback
- * \param mem_ptr class method member pointer
+ * \param memPtr class method member pointer
* \param objPtr class instance
* \return a wrapper Callback
* Build Callbacks for class method members which takes no arguments
@@ -355,7 +386,7 @@
return Callback<R> (objPtr, memPtr);
}
template <typename T, typename OBJ, typename R>
-Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ const objPtr) {
+Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ objPtr) {
return Callback<R> (objPtr, mem_ptr);
}
/**
@@ -367,11 +398,11 @@
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1>
-Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ *const objPtr) {
+Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ objPtr) {
return Callback<R,T1> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1>
-Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ const *const objPtr) {
+Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ objPtr) {
return Callback<R,T1> (objPtr, mem_ptr);
}
/**
@@ -383,11 +414,11 @@
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1, typename T2>
-Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ *const objPtr) {
+Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ objPtr) {
return Callback<R,T1,T2> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1, typename T2>
-Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) {
+Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ objPtr) {
return Callback<R,T1,T2> (objPtr, mem_ptr);
}
/**
@@ -399,11 +430,11 @@
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
-Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) {
+Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ objPtr) {
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
-Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) {
+Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ objPtr) {
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
}
/**
@@ -415,11 +446,11 @@
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
-Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) {
+Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ objPtr) {
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
-Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) {
+Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ objPtr) {
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
}
/**
@@ -431,13 +462,29 @@
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
-Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) {
+Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ objPtr) {
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
-Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) {
+Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ objPtr) {
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
}
+/**
+ * \ingroup MakeCallback
+ * \param mem_ptr class method member pointer
+ * \param objPtr class instance
+ * \return a wrapper Callback
+ * Build Callbacks for class method members which takes five arguments
+ * and potentially return a value.
+ */
+template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5,typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6), OBJ objPtr) {
+ return Callback<R,T1,T2,T3,T4,T5,T6> (objPtr, mem_ptr);
+}
+template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5, typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6) const, OBJ objPtr) {
+ return Callback<R,T1,T2,T3,T4,T5,T6> (objPtr, mem_ptr);
+}
/**
* \ingroup MakeCallback
@@ -505,6 +552,17 @@
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5)) {
return Callback<R,T1,T2,T3,T4,T5> (fnPtr, true, true);
}
+/**
+ * \ingroup MakeCallback
+ * \param fnPtr function pointer
+ * \return a wrapper Callback
+ * Build Callbacks for functions which takes five arguments
+ * and potentially return a value.
+ */
+template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5,typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5,T6)) {
+ return Callback<R,T1,T2,T3,T4,T5,T6> (fnPtr, true, true);
+}
@@ -573,6 +631,17 @@
Callback<R,T1,T2,T3,T4,T5> MakeNullCallback (void) {
return Callback<R,T1,T2,T3,T4,T5> ();
}
+/**
+ * \ingroup MakeCallback
+ * \overload Callback<R> MakeNullCallback (void)
+ * \return a wrapper Callback
+ * Build a null callback which takes five arguments
+ * and potentially return a value.
+ */
+template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5,typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeNullCallback (void) {
+ return Callback<R,T1,T2,T3,T4,T5,T6> ();
+}
/*
@@ -582,9 +651,10 @@
*/
// an impl for Bound Functors:
template <typename T, typename R, typename TX, typename T1, typename T2, typename T3, typename T4,typename T5>
-class BoundFunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
+class BoundFunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,empty> {
public:
- BoundFunctorCallbackImpl (T const &functor, TX a)
+ template <typename FUNCTOR, typename ARG>
+ BoundFunctorCallbackImpl (FUNCTOR functor, ARG a)
: m_functor (functor), m_a (a) {}
virtual ~BoundFunctorCallbackImpl () {}
R operator() (void) {
@@ -621,38 +691,48 @@
}
private:
T m_functor;
- TX m_a;
+ typename TypeTraits<TX>::ReferencedType m_a;
};
-template <typename R, typename TX>
-Callback<R> MakeBoundCallback (R (*fnPtr) (TX), TX a) {
- Ptr<CallbackImpl<R,empty,empty,empty,empty,empty> > impl =
+template <typename R, typename TX, typename ARG>
+Callback<R> MakeBoundCallback (R (*fnPtr) (TX), ARG a) {
+ Ptr<CallbackImpl<R,empty,empty,empty,empty,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX),R,TX,empty,empty,empty,empty,empty> >(fnPtr, a);
return Callback<R> (impl);
}
-template <typename R, typename TX, typename T1>
-Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), TX a) {
- Ptr<CallbackImpl<R,T1,empty,empty,empty,empty> > impl =
+template <typename R, typename TX, typename ARG,
+ typename T1>
+Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), ARG a) {
+ Ptr<CallbackImpl<R,T1,empty,empty,empty,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1),R,TX,T1,empty,empty,empty,empty> > (fnPtr, a);
return Callback<R,T1> (impl);
}
-template <typename R, typename TX, typename T1, typename T2>
-Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), TX a) {
- Ptr<CallbackImpl<R,T1,T2,empty,empty,empty> > impl =
+template <typename R, typename TX, typename ARG,
+ typename T1, typename T2>
+Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), ARG a) {
+ Ptr<CallbackImpl<R,T1,T2,empty,empty,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2),R,TX,T1,T2,empty,empty,empty> > (fnPtr, a);
return Callback<R,T1,T2> (impl);
}
-template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4>
-Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), TX a) {
- Ptr<CallbackImpl<R,T1,T2,T3,T4,empty> > impl =
+template <typename R, typename TX, typename ARG,
+ typename T1, typename T2,typename T3>
+Callback<R,T1,T2,T3> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3), ARG a) {
+ Ptr<CallbackImpl<R,T1,T2,T3,empty,empty,empty> > impl =
+ Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3),R,TX,T1,T2,T3,empty,empty> > (fnPtr, a);
+ return Callback<R,T1,T2,T3> (impl);
+}
+template <typename R, typename TX, typename ARG,
+ typename T1, typename T2,typename T3,typename T4>
+Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), ARG a) {
+ Ptr<CallbackImpl<R,T1,T2,T3,T4,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4),R,TX,T1,T2,T3,T4,empty> > (fnPtr, a);
return Callback<R,T1,T2,T3,T4> (impl);
}
-
-template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4,typename T5>
-Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), TX a) {
- Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > impl =
+template <typename R, typename TX, typename ARG,
+ typename T1, typename T2,typename T3,typename T4,typename T5>
+Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), ARG a) {
+ Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4,T5),R,TX,T1,T2,T3,T4,T5> > (fnPtr, a);
return Callback<R,T1,T2,T3,T4,T5> (impl);
}
--- a/src/core/component-manager.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/component-manager.h Fri Sep 28 11:59:46 2007 +0100
@@ -348,7 +348,7 @@
* result.
*/
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
- static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5);
+ static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
private:
friend void RegisterCallback (ClassId classId, CallbackBase *callback,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/composite-trace-resolver.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,595 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "composite-trace-resolver.h"
+#include "log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CompositeTraceResolver");
+
+namespace ns3 {
+
+CompositeTraceResolver::CompositeTraceResolver ()
+{}
+
+CompositeTraceResolver::~CompositeTraceResolver ()
+{
+ for (TraceItems::iterator i = m_items.begin (); i != m_items.end (); i++)
+ {
+ delete *i;
+ }
+ m_items.clear ();
+}
+
+void
+CompositeTraceResolver::AddItem (ResolveItem *item)
+{
+ m_items.push_back (item);
+}
+
+void
+CompositeTraceResolver::Add (std::string name,
+ Callback<Ptr<TraceResolver> > createResolver)
+{
+ class MakerResolveItem : public ResolveItem
+ {
+ public:
+ virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+ {maker ()->Connect (subpath, cb, context);}
+ virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+ {maker ()->Disconnect (subpath, cb);}
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection)
+ {
+ path.append ("/");
+ path.append (this->name);
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ this->maker ()->CollectSources (path, ctx, collection);
+ }
+ virtual void TraceAll (std::ostream &os, const TraceContext &context)
+ {
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ this->maker ()->TraceAll (os, ctx);
+ }
+ Callback<Ptr<TraceResolver> > maker;
+ } *item = new MakerResolveItem ();
+ item->name = name;
+ item->context = TraceContext ();
+ item->maker = createResolver;
+ AddItem (item);
+}
+
+void
+CompositeTraceResolver::AddSource (std::string name,
+ const TraceDoc &doc,
+ const TraceSource &trace)
+{
+ DoAddSource (name, doc, trace, TraceContext ());
+}
+
+void
+CompositeTraceResolver::DoAddSource (std::string name,
+ const TraceDoc &doc,
+ const TraceSource &trace,
+ const TraceContext &context)
+{
+ class SourceResolveItem : public ResolveItem
+ {
+ public:
+ virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+ {if (subpath == "") {trace->AddCallback (cb, context);}}
+ virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+ {if (subpath == "") {trace->RemoveCallback (cb);}}
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection)
+ {
+ path.append ("/");
+ path.append (this->name);
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ collection->AddUnique (path, ctx, this->doc);
+ }
+ virtual void TraceAll (std::ostream &os, const TraceContext &context)
+ {
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ this->trace->ConnectPrinter (os, ctx);
+ }
+ TraceSource *trace;
+ TraceDoc doc;
+ } *item = new SourceResolveItem ();
+ item->name = name;
+ item->context = context;
+ item->trace = const_cast<TraceSource *> (&trace);
+ item->doc = doc;
+ AddItem (item);
+}
+
+
+
+
+void
+CompositeTraceResolver::AddComposite (std::string name, Ptr<Object> composite)
+{
+ DoAddComposite (name, composite, TraceContext ());
+}
+void
+CompositeTraceResolver::DoAddComposite (std::string name, Ptr<Object> composite, const TraceContext &context)
+{
+ class CompositeResolveItem : public ResolveItem
+ {
+ public:
+ virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+ {composite->GetTraceResolver ()->Connect (subpath, cb, context);}
+ virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+ {composite->TraceDisconnect (subpath, cb);}
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection)
+ {
+ path.append ("/");
+ path.append (this->name);
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ this->composite->GetTraceResolver ()->CollectSources (path, ctx, collection);
+ }
+ virtual void TraceAll (std::ostream &os, const TraceContext &context)
+ {
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ this->composite->GetTraceResolver ()->TraceAll (os, ctx);
+ }
+
+ Ptr<Object> composite;
+ } *item = new CompositeResolveItem ();
+ item->name = name;
+ item->context = context;
+ item->composite = composite;
+ AddItem (item);
+}
+
+void
+CompositeTraceResolver::SetParentResolver (Ptr<TraceResolver> resolver)
+{
+ m_parent = resolver;
+}
+
+void
+CompositeTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
+{
+ NS_LOG_LOGIC ("connect path="<<path);
+ class ConnectOperation : public Operation
+ {
+ public:
+ ConnectOperation (const CallbackBase &cb, const TraceContext &context)
+ : m_cb (cb), m_context (context)
+ {}
+ virtual void Do (std::string subpath, ResolveItem *item) const
+ {
+ NS_LOG_LOGIC ("connect to path="<<subpath<<" name="<<item->name);
+ TraceContext context = m_context;
+ context.Union (item->context);
+ item->Connect (subpath, m_cb, context);
+ }
+ virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
+ {
+ if (parent != 0)
+ {
+ parent->Connect (path, m_cb, m_context);
+ }
+ }
+ private:
+ const CallbackBase &m_cb;
+ const TraceContext &m_context;
+ } operation = ConnectOperation (cb, context);
+ DoRecursiveOperation (path, operation);
+}
+void
+CompositeTraceResolver::DoRecursiveOperation (std::string path,
+ const Operation &operation)
+{
+ if (path == "")
+ {
+ return;
+ }
+ std::string id = GetElement (path);
+ std::string subpath = GetSubpath (path);
+
+ if (id == "*")
+ {
+ for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+ {
+ operation.Do (subpath, *i);
+ }
+ operation.DoParent (path, m_parent);
+ return;
+ }
+ std::string::size_type start, end;
+ start = id.find_first_of ("(", 0);
+ end = id.find_first_of (")", 0);
+ if (start != 0 || end != (id.size ()-1))
+ {
+ for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+ {
+ if ((*i)->name == id)
+ {
+ operation.Do (subpath, *i);
+ operation.DoParent (path, m_parent);
+ return;
+ }
+ }
+ }
+ std::list<std::string> names;
+ std::string alternatives = std::string (id, start+1, end-1);
+ std::string::size_type next_pos, cur_pos;
+ next_pos = 0;
+ cur_pos = 0;
+ while (true)
+ {
+ std::string element;
+ next_pos = alternatives.find ("|", cur_pos);
+ if (next_pos == std::string::npos)
+ {
+ element = std::string (alternatives, cur_pos, alternatives.size ());
+ names.push_back (element);
+ break;
+ }
+ element = std::string (alternatives, cur_pos, next_pos);
+ names.push_back (element);
+ cur_pos = next_pos + 1;
+ }
+ for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
+ {
+ for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
+ {
+ if ((*j)->name == *i)
+ {
+ operation.Do (subpath, *j);
+ break;
+ }
+ }
+ }
+ operation.DoParent (path, m_parent);
+}
+
+void
+CompositeTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
+{
+ NS_LOG_LOGIC ("disconnect path="<<path);
+ class DisconnectOperation : public Operation
+ {
+ public:
+ DisconnectOperation (const CallbackBase &cb)
+ : m_cb (cb)
+ {}
+ virtual void Do (std::string subpath, ResolveItem *item) const
+ {
+ NS_LOG_LOGIC ("disconnect from path="<<subpath<<" name="<<item->name);
+ item->Disconnect (subpath, m_cb);
+ }
+ virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
+ {
+ if (parent != 0)
+ {
+ parent->Disconnect (path, m_cb);
+ }
+ }
+ private:
+ const CallbackBase &m_cb;
+ } operation = DisconnectOperation (cb);
+ DoRecursiveOperation (path, operation);
+}
+
+void
+CompositeTraceResolver::CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection)
+{
+ for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+ {
+ NS_LOG_LOGIC ("print " << (*i)->name);
+ (*i)->CollectSources (path, context, collection);
+ }
+ if (m_parent != 0)
+ {
+ m_parent->CollectSources (path, context, collection);
+ }
+}
+void
+CompositeTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
+{
+ for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+ {
+ NS_LOG_LOGIC ("print " << (*i)->name);
+ (*i)->TraceAll (os, context);
+ }
+ if (m_parent != 0)
+ {
+ m_parent->TraceAll (os, context);
+ }
+}
+
+
+}//namespace ns3
+
+#ifdef RUN_SELF_TESTS
+
+#include "test.h"
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+class TraceSourceTest : public TraceContextElement
+{
+public:
+ enum Sources {
+ DOUBLEA,
+ DOUBLEB,
+ UINT16_T
+ };
+ static uint16_t GetUid (void)
+ {static uint16_t uid = AllocateUid<TraceSourceTest> ("TraceSourceTest"); return uid;}
+ void Print (std::ostream &os)
+ {os << "tracesource=";
+ if (m_sources == DOUBLEA) {os << "doubleA";}
+ else if (m_sources == DOUBLEB) {os << "doubleB";}
+ else if (m_sources == UINT16_T) {os << "uint16_t";}
+ }
+ std::string GetTypeName (void) {return "ns3::TraceSourceTest";}
+ TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {}
+ TraceSourceTest (enum Sources sources) :m_sources (sources) {}
+ bool IsDoubleA (void) const {return m_sources == TraceSourceTest::DOUBLEA;}
+ bool IsDoubleB (void) const {return m_sources == TraceSourceTest::DOUBLEB;}
+ bool IsUint16 (void) const {return m_sources == TraceSourceTest::UINT16_T;}
+private:
+ enum TraceSourceTest::Sources m_sources;
+};
+
+class SubTraceSourceTest : public TraceContextElement
+{
+public:
+ enum Sources {
+ INT,
+ };
+ static uint16_t GetUid (void)
+ {static uint16_t uid = AllocateUid<SubTraceSourceTest> ("SubTraceSourceTest"); return uid;}
+ void Print (std::ostream &os)
+ {os << "subtracesource=int";}
+ std::string GetTypeName (void) const {return "ns3::SubTraceSourceTest";}
+ SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {}
+ SubTraceSourceTest (enum Sources sources) : m_sources (sources) {}
+private:
+ enum Sources m_sources;
+};
+
+class CompositeTraceResolverTest : public Test
+{
+public:
+ CompositeTraceResolverTest ();
+ virtual ~CompositeTraceResolverTest ();
+ virtual bool RunTests (void);
+private:
+ void TraceDouble (TraceContext const &context, double v);
+ void TraceInt (TraceContext const &context, int v);
+ Ptr<TraceResolver> CreateSubResolver ();
+
+
+ bool m_gotDoubleA;
+ bool m_gotDoubleB;
+ CallbackTraceSource<int> m_traceInt;
+ bool m_gotInt;
+};
+
+CompositeTraceResolverTest::CompositeTraceResolverTest ()
+ : Test ("CompositeTraceResolver")
+{}
+CompositeTraceResolverTest::~CompositeTraceResolverTest ()
+{}
+void
+CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
+{
+ TraceSourceTest source;
+ context.GetElement (source);
+ if (source.IsDoubleA ())
+ {
+ m_gotDoubleA = true;
+ }
+ else if (source.IsDoubleB ())
+ {
+ m_gotDoubleB = true;
+ }
+ else
+ {
+ NS_FATAL_ERROR ("should not get any other trace source in this sink");
+ }
+
+}
+
+void
+CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
+{
+ m_gotInt = true;
+}
+
+Ptr<TraceResolver>
+CompositeTraceResolverTest::CreateSubResolver (void)
+{
+ Ptr<CompositeTraceResolver> subresolver = Create<CompositeTraceResolver> ();
+ subresolver->AddSource ("trace-int", TraceDoc ("test source"), m_traceInt,
+ SubTraceSourceTest (SubTraceSourceTest::INT));
+ return subresolver;
+}
+bool
+CompositeTraceResolverTest::RunTests (void)
+{
+ bool ok = true;
+
+ CallbackTraceSource<double> traceDoubleA;
+ CallbackTraceSource<double> traceDoubleB;
+ TraceContext context;
+
+ CompositeTraceResolver resolver;
+
+ resolver.AddSource ("trace-double-a", TraceDoc ("test source"), traceDoubleA,
+ TraceSourceTest (TraceSourceTest::DOUBLEA));
+ resolver.AddSource ("trace-double-b", TraceDoc ("test source"), traceDoubleB,
+ TraceSourceTest (TraceSourceTest::DOUBLEB));
+
+ resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+ traceDoubleA (0);
+ if (!m_gotDoubleA || m_gotDoubleB)
+ {
+ ok = false;
+ }
+ m_gotDoubleA = false;
+ traceDoubleA (0);
+ traceDoubleB (0);
+ if (!m_gotDoubleA || !m_gotDoubleB)
+ {
+ ok = false;
+ }
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+
+ resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+ traceDoubleA (0);
+ traceDoubleB (0);
+ if (m_gotDoubleA || m_gotDoubleB)
+ {
+ ok = false;
+ }
+
+ resolver.Connect ("/trace-double-a",
+ MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+ traceDoubleA (0);
+ traceDoubleB (0);
+ if (!m_gotDoubleA || m_gotDoubleB)
+ {
+ ok = false;
+ }
+ resolver.Disconnect ("/trace-double-a",
+ MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+
+ resolver.Connect ("/(trace-double-a)",
+ MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+ traceDoubleA (0);
+ traceDoubleB (0);
+ if (!m_gotDoubleA || m_gotDoubleB)
+ {
+ ok = false;
+ }
+ resolver.Disconnect ("/trace-double-a",
+ MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+
+ resolver.Connect ("/(trace-double-a|trace-double-b)",
+ MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+ traceDoubleA (0);
+ traceDoubleB (0);
+ if (!m_gotDoubleA || !m_gotDoubleB)
+ {
+ ok = false;
+ }
+ resolver.Disconnect ("/trace-double-a",
+ MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+ traceDoubleA (0);
+ traceDoubleB (0);
+ if (m_gotDoubleA || !m_gotDoubleB)
+ {
+ ok = false;
+ }
+
+
+ resolver.Disconnect ("/(trace-double-a|trace-double-b)",
+ MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+ m_gotDoubleA = false;
+ m_gotDoubleB = false;
+ traceDoubleA (0);
+ traceDoubleB (0);
+ if (m_gotDoubleA || m_gotDoubleB)
+ {
+ ok = false;
+ }
+
+ resolver.Add ("subresolver",
+ MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this));
+
+ resolver.Connect ("/subresolver/trace-int",
+ MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
+ m_gotInt = false;
+ m_traceInt (1);
+ if (!m_gotInt)
+ {
+ ok = false;
+ }
+
+ resolver.Disconnect ("/subresolver/trace-int",
+ MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
+ m_gotInt = false;
+ m_traceInt (1);
+ if (m_gotInt)
+ {
+ ok = false;
+ }
+
+ resolver.Connect ("/*/trace-int",
+ MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
+ m_gotInt = false;
+ m_traceInt (1);
+ if (!m_gotInt)
+ {
+ ok = false;
+ }
+
+ resolver.Disconnect ("/subresolver/trace-int",
+ MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
+ m_gotInt = false;
+ m_traceInt (1);
+ if (m_gotInt)
+ {
+ ok = false;
+ }
+
+ SVTraceSource<uint16_t> source;
+
+ resolver.AddSource ("uint16_t", TraceDoc ("test source"), source, TraceSourceTest (TraceSourceTest::UINT16_T));
+
+
+ return ok;
+}
+
+static CompositeTraceResolverTest g_compositeTraceResolverTest;
+
+}//namespace ns3
+
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/composite-trace-resolver.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,233 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef COMPOSITE_TRACE_RESOLVER_H
+#define COMPOSITE_TRACE_RESOLVER_H
+
+#include <vector>
+#include "callback.h"
+#include "ptr.h"
+#include "trace-resolver.h"
+#include "callback-trace-source.h"
+#include "uv-trace-source.h"
+#include "sv-trace-source.h"
+#include "fv-trace-source.h"
+#include "array-trace-resolver.h"
+#include "trace-doc.h"
+
+namespace ns3 {
+
+/**
+ * \brief a helper class to aggregate contained TraceResolver and other trace sources.
+ * \ingroup tracing
+ */
+class CompositeTraceResolver : public TraceResolver
+{
+public:
+ CompositeTraceResolver ();
+ virtual ~CompositeTraceResolver ();
+ /**
+ * \param name name of trace source
+ * \param doc the documentation associated to this trace source
+ * \param trace a callback trace source
+ * \param context the context associated to this trace source
+ *
+ * Add a callback trace source in this resolver. This trace
+ * source will match the name specified during namespace
+ * resolution. The TraceContext of this trace source will also
+ * be automatically extended to contain the input context.
+ */
+ template <typename T>
+ void AddSource (std::string name, const TraceDoc &doc,
+ const TraceSource &trace, T const &context);
+ /**
+ * \param name name of trace source
+ * \param doc the documentation associated to this trace source
+ * \param trace a callback trace source
+ *
+ * Add a callback trace source in this resolver. This trace
+ * source will match the name specified during namespace
+ * resolution.
+ */
+ void AddSource (std::string name,
+ const TraceDoc &doc,
+ const TraceSource &trace);
+
+ /**
+ * \param name the name of the composite element
+ * \param composite the composite object
+ *
+ * The input composite object will be used to resolve a connection
+ * of a disconnection attempt if its name matches the trace path.
+ *
+ */
+ void AddComposite (std::string name, Ptr<Object> composite);
+
+ /**
+ * \param name the name of the composite element
+ * \param composite the composite object
+ * \param contextElement the context element associated to the composite
+ *
+ * The input composite object will be used to resolve a connection
+ * of a disconnection attempt if its name matches the trace path.
+ * The contextElement will be appended to the TraceContext during connection.
+ */
+ template <typename T>
+ void AddComposite (std::string name, Ptr<Object> composite, const T &contextElement);
+
+ /**
+ * \param name the name of the array
+ * \param begin an iterator which points to the first element of the array
+ * \param end an iterator which points to the last element of the array
+ * \param index an object which can store the index of an element in the
+ * array. In practice, this object should support a constructor
+ * whose single argument is an array index.
+ */
+ template <typename ITERATOR, typename INDEX>
+ void AddArray (std::string name,
+ ITERATOR begin, ITERATOR end, INDEX index);
+
+ /**
+ * \param parent the parent trace resolver
+ *
+ * The parent trace resolver is the trace resolver returned by the
+ * GetTraceResolver method of the base class of the caller. It is
+ * used during connection and disconnection to chain up the connect
+ * and disconnect calls to the parent.
+ */
+ void SetParentResolver (Ptr<TraceResolver> parent);
+
+
+private:
+ virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
+ virtual void Disconnect (std::string path, CallbackBase const &cb);
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection);
+ virtual void TraceAll (std::ostream &os, const TraceContext &context);
+ friend class CompositeTraceResolverTest;
+ class ResolveItem
+ {
+ public:
+ virtual ~ResolveItem () {}
+ virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context) = 0;
+ virtual void Disconnect (std::string subpath, const CallbackBase &cb) = 0;
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection) = 0;
+ virtual void TraceAll (std::ostream &os, const TraceContext &context) = 0;
+
+ std::string name;
+ TraceContext context;
+ };
+ typedef std::vector<ResolveItem *> TraceItems;
+ class Operation
+ {
+ public:
+ virtual ~Operation () {}
+ virtual void Do (std::string subpath, ResolveItem *item) const = 0;
+ virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const = 0;
+ };
+
+ void AddItem (ResolveItem *item);
+ void DoRecursiveOperation (std::string path,
+ const Operation &operation);
+ void DoRecursiveOperationForParent (std::string path,
+ const Operation &operation);
+ void DoAddComposite (std::string name, Ptr<Object> composite, const TraceContext &context);
+ void DoAddSource (std::string name,
+ const TraceDoc &doc,
+ const TraceSource &trace,
+ const TraceContext &context);
+ void Add (std::string name,
+ Callback<Ptr<TraceResolver> > createResolver);
+
+
+ CompositeTraceResolver::TraceItems m_items;
+ Ptr<TraceResolver> m_parent;
+};
+
+}//namespace ns3
+
+namespace ns3 {
+
+
+
+template <typename T>
+void
+CompositeTraceResolver::AddSource (std::string name,
+ const TraceDoc &doc,
+ const TraceSource &trace,
+ T const &context)
+{
+ TraceContext ctx;
+ ctx.AddElement (context);
+ DoAddSource (name, doc, trace, ctx);
+}
+
+template <typename ITERATOR, typename INDEX>
+void
+CompositeTraceResolver::AddArray (std::string name,
+ ITERATOR begin, ITERATOR end, INDEX index)
+{
+ class ArrayResolveItem : public ResolveItem
+ {
+ public:
+ virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+ {array->Connect (subpath, cb, context);}
+ virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+ {array->Disconnect (subpath, cb);}
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection)
+ {
+ path.append ("/");
+ path.append (this->name);
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ array->CollectSources (path, ctx, collection);
+ }
+ virtual void TraceAll (std::ostream &os, const TraceContext &context)
+ {
+ TraceContext ctx = context;
+ ctx.Union (this->context);
+ array->TraceAll (os, ctx);
+ }
+
+ Ptr<ArrayTraceResolver<INDEX> > array;
+ } *item = new ArrayResolveItem ();
+ item->name = name;
+ item->context = TraceContext ();
+ item->array = Create<ArrayTraceResolver<INDEX> > ();
+ item->array->SetIterators (begin, end);
+ AddItem (item);
+}
+
+template <typename T>
+void
+CompositeTraceResolver::AddComposite (std::string name, Ptr<Object> composite, const T &contextElement)
+{
+ TraceContext context;
+ context.AddElement (contextElement);
+ DoAddComposite (name, composite, context);
+}
+
+
+
+}//namespace ns3
+
+#endif /* COMPOSITE_TRACE_RESOLVER_H */
--- a/src/core/debug.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/debug.cc Fri Sep 28 11:59:46 2007 +0100
@@ -24,6 +24,7 @@
#include "debug.h"
#include "assert.h"
#include "ns3/core-config.h"
+#include "fatal-error.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -53,6 +54,7 @@
{
return;
}
+ bool allFound = true;
std::string env = envVar;
std::string::size_type cur = 0;
std::string::size_type next = 0;
@@ -88,7 +90,7 @@
}
if (!found)
{
- std::cout << "No debug component named=\"" << tmp << "\"" << std::endl;
+ allFound = false;
}
if (next == std::string::npos)
{
@@ -100,6 +102,11 @@
break;
}
}
+ if (allFound)
+ {
+ g_firstDebug = true;
+ }
+
#endif
}
@@ -122,7 +129,6 @@
if (g_firstDebug)
{
DebugComponentEnableEnvVar ();
- g_firstDebug = false;
}
return m_isEnabled;
}
--- a/src/core/debug.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/debug.h Fri Sep 28 11:59:46 2007 +0100
@@ -110,7 +110,7 @@
{ \
if (g_debug.IsEnabled ()) \
{ \
- std::cout << msg << std::endl; \
+ std::cerr << msg << std::endl; \
} \
} \
while (false)
@@ -125,7 +125,7 @@
#define NS_DEBUG_UNCOND(msg) \
do \
{ \
- std::cout << msg << std::endl; \
+ std::cerr << msg << std::endl; \
} \
while (false)
--- a/src/core/default-value.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/default-value.cc Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,52 @@
namespace ns3 {
+namespace DefaultValue {
+
+enum BindStatus {
+ OK,
+ INVALID_VALUE,
+ NOT_FOUND
+};
+
+
+static
+enum BindStatus
+BindSafe (std::string name, std::string value)
+{
+ for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
+ i != DefaultValueList::End (); i++)
+ {
+ DefaultValueBase *cur = *i;
+ if (cur->GetName () == name)
+ {
+ if (!cur->ParseValue (value))
+ {
+ return INVALID_VALUE;
+ }
+ return OK;
+ }
+ }
+ return NOT_FOUND;
+}
+
+void
+Bind (std::string name, std::string value)
+{
+ switch (BindSafe (name, value)) {
+ case INVALID_VALUE:
+ NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
+ break;
+ case NOT_FOUND:
+ NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
+ break;
+ case OK:
+ break;
+ }
+}
+
+}
+
DefaultValueBase::DefaultValueBase (const std::string &name,
const std::string &help)
: m_name (name),
@@ -112,48 +158,6 @@
return &list;
}
-enum BindStatus {
- OK,
- INVALID_VALUE,
- NOT_FOUND
-};
-
-
-static
-enum BindStatus
-BindSafe (std::string name, std::string value)
-{
- for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
- i != DefaultValueList::End (); i++)
- {
- DefaultValueBase *cur = *i;
- if (cur->GetName () == name)
- {
- if (!cur->ParseValue (value))
- {
- return INVALID_VALUE;
- }
- return OK;
- }
- }
- return NOT_FOUND;
-}
-
-void
-Bind (std::string name, std::string value)
-{
- switch (BindSafe (name, value)) {
- case INVALID_VALUE:
- NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
- break;
- case NOT_FOUND:
- NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
- break;
- case OK:
- break;
- }
-}
-
BooleanDefaultValue::BooleanDefaultValue (std::string name,
std::string help,
bool defaultValue)
@@ -341,104 +345,53 @@
bool
DefaultValueTest::RunTests (void)
{
- bool ok = true;
+ bool result = true;
BooleanDefaultValue a ("bool-a", "help a", true);
- if (!a.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-a", "false");
- if (a.GetValue ())
- {
- ok = false;
- }
+ NS_TEST_ASSERT (a.GetValue ());
+ DefaultValue::Bind ("bool-a", "false");
+ NS_TEST_ASSERT (!a.GetValue ());
BooleanDefaultValue b ("bool-b", "help b", false);
- Bind ("bool-b", "true");
- if (!b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "0");
- if (b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "1");
- if (!b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "f");
- if (b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "t");
- if (!b.GetValue ())
- {
- ok = false;
- }
+ DefaultValue::Bind ("bool-b", "true");
+ NS_TEST_ASSERT (b.GetValue ());
+ DefaultValue::Bind ("bool-b", "0");
+ NS_TEST_ASSERT (!b.GetValue ());
+ DefaultValue::Bind ("bool-b", "1");
+ NS_TEST_ASSERT (b.GetValue ());
+ DefaultValue::Bind ("bool-b", "f");
+ NS_TEST_ASSERT (!b.GetValue ());
+ DefaultValue::Bind ("bool-b", "t");
+ NS_TEST_ASSERT (b.GetValue ());
- Bind ("bool-b", "false");
- if (b.GetValue ())
- {
- ok = false;
- }
- if (BindSafe ("bool-b", "tr") != INVALID_VALUE)
- {
- ok = false;
- }
+ DefaultValue::Bind ("bool-b", "false");
+ NS_TEST_ASSERT (!b.GetValue ());
+ NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("bool-b", "tr"), DefaultValue::INVALID_VALUE)
- IntegerDefaultValue<int> i ("test-i", "help-i", -1);
- if (i.GetValue () != -1)
- {
- ok = false;
- }
- Bind ("test-i", "-2");
- if (i.GetValue () != -2)
- {
- ok = false;
- }
- Bind ("test-i", "+2");
- if (i.GetValue () != 2)
- {
- ok = false;
- }
- if (i.GetType () != "int32_t(-2147483648:2147483647)")
- {
- ok = false;
- }
- IntegerDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
- if (ui32.GetType () != "uint32_t(0:4294967295)")
- {
- ok = false;
- }
- IntegerDefaultValue<char> c ("test-c", "help-c", 10);
- if (c.GetValue () != 10)
- {
- ok = false;
- }
- Bind ("test-c", "257");
+ NumericDefaultValue<int32_t> i ("test-i", "help-i", -1);
+ NS_TEST_ASSERT_EQUAL (i.GetValue (), -1);
+ DefaultValue::Bind ("test-i", "-2");
+ NS_TEST_ASSERT_EQUAL (i.GetValue (), -2);
+ DefaultValue::Bind ("test-i", "+2");
+ NS_TEST_ASSERT_EQUAL (i.GetValue (), 2);
+ NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)");
+ NumericDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
+ NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)");
+ NumericDefaultValue<int8_t> c ("test-c", "help-c", 10);
+ NS_TEST_ASSERT_EQUAL (c.GetValue (), 10);
+ DefaultValue::Bind ("test-c", "257");
+ NumericDefaultValue<float> x ("test-x", "help-x", 10.0);
+ NumericDefaultValue<double> y ("test-y", "help-y", 10.0);
+
EnumDefaultValue<enum MyEnum> e ("test-e", "help-e",
MY_ENUM_C, "C",
MY_ENUM_A, "A",
MY_ENUM_B, "B",
0, (void*)0);
- if (e.GetValue () != MY_ENUM_C)
- {
- ok = false;
- }
- Bind ("test-e", "B");
- if (e.GetValue () != MY_ENUM_B)
- {
- ok = false;
- }
- if (BindSafe ("test-e", "D") != INVALID_VALUE)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_C);
+ DefaultValue::Bind ("test-e", "B");
+ NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_B);
+ NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("test-e", "D"), DefaultValue::INVALID_VALUE);
class MyEnumSubclass : public EnumDefaultValue<enum MyEnum>
{
@@ -453,15 +406,9 @@
AddPossibleValue (MY_ENUM_D, "D");
}
} e1 ;
- if (e1.GetValue () != MY_ENUM_B)
- {
- ok = false;
- }
- Bind ("test-e1", "D");
- if (e1.GetValue () != MY_ENUM_D)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_B);
+ DefaultValue::Bind ("test-e1", "D");
+ NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_D);
DefaultValueList::Remove ("test-e1");
DefaultValueList::Remove ("test-e");
@@ -471,7 +418,7 @@
DefaultValueList::Remove ("test-c");
DefaultValueList::Remove ("test-ui32");
- return ok;
+ return result;
}
static DefaultValueTest g_default_value_tests;
--- a/src/core/default-value.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/default-value.h Fri Sep 28 11:59:46 2007 +0100
@@ -31,6 +31,25 @@
namespace ns3 {
+namespace DefaultValue
+{
+
+/**
+ * \ingroup config
+ * \param name name of variable to bind
+ * \param value value to bind to the specified variable
+ *
+ * If the variable name does not match any existing
+ * variable or if the value is not compatible with
+ * the variable type, this function will abort
+ * at runtime and print an error message detailing
+ * which variable or value triggered the problem.
+ */
+void Bind (std::string name, std::string value);
+
+}
+
+
class DefaultValueBase
{
public:
@@ -84,19 +103,6 @@
};
/**
- * \ingroup config
- * \param name name of variable to bind
- * \param value value to bind to the specified variable
- *
- * If the variable name does not match any existing
- * variable or if the value is not compatible with
- * the variable type, this function will abort
- * at runtime and print an error message detailing
- * which variable or value triggered the problem.
- */
-void Bind (std::string name, std::string value);
-
-/**
* \brief A Boolean variable for ns3::Bind
* \ingroup config
*
@@ -135,7 +141,7 @@
};
/**
- * \brief An Integer variable for ns3::Bind
+ * \brief A Numeric variable for ns3::Bind
* \ingroup config
*
* Every instance of this type is automatically
@@ -143,7 +149,7 @@
* by ns3::Bind.
*/
template <typename T>
-class IntegerDefaultValue : public DefaultValueBase
+class NumericDefaultValue : public DefaultValueBase
{
public:
/**
@@ -157,7 +163,7 @@
* of values which can be stored and retrieved from the underlying
* type.
*/
- IntegerDefaultValue (std::string name,
+ NumericDefaultValue (std::string name,
std::string help,
T defaultValue);
/**
@@ -169,7 +175,7 @@
* \param minValue the minimum value which can be set
* in this variable
*/
- IntegerDefaultValue (std::string name,
+ NumericDefaultValue (std::string name,
std::string help,
T defaultValue,
T minValue);
@@ -185,7 +191,7 @@
* \param maxValue the maximum value which can be set in this
* variable.
*/
- IntegerDefaultValue (std::string name,
+ NumericDefaultValue (std::string name,
std::string help,
T defaultValue,
T minValue,
@@ -351,7 +357,7 @@
template <typename T>
-IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+NumericDefaultValue<T>::NumericDefaultValue (std::string name,
std::string help,
T defaultValue)
: DefaultValueBase (name, help),
@@ -364,7 +370,7 @@
NS_ASSERT (m_minValue < m_maxValue);
}
template <typename T>
-IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+NumericDefaultValue<T>::NumericDefaultValue (std::string name,
std::string help,
T defaultValue,
T minValue)
@@ -380,7 +386,7 @@
m_defaultValue >= m_minValue);
}
template <typename T>
-IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+NumericDefaultValue<T>::NumericDefaultValue (std::string name,
std::string help,
T defaultValue,
T minValue,
@@ -399,7 +405,7 @@
template <typename T>
void
-IntegerDefaultValue<T>::SetValue (T v)
+NumericDefaultValue<T>::SetValue (T v)
{
NS_ASSERT (v <= m_maxValue &&
v >= m_minValue);
@@ -408,14 +414,14 @@
template <typename T>
T
-IntegerDefaultValue<T>::GetValue (void) const
+NumericDefaultValue<T>::GetValue (void) const
{
return m_value;
}
template <typename T>
bool
-IntegerDefaultValue<T>::DoParseValue (const std::string &value)
+NumericDefaultValue<T>::DoParseValue (const std::string &value)
{
std::istringstream iss;
iss.str (value);
@@ -430,7 +436,7 @@
template <typename T>
std::string
-IntegerDefaultValue<T>::DoGetType (void) const
+NumericDefaultValue<T>::DoGetType (void) const
{
std::ostringstream oss;
oss << TypeNameGet<T> () << "("
@@ -441,7 +447,7 @@
template <typename T>
std::string
-IntegerDefaultValue<T>::DoGetDefaultValue (void) const
+NumericDefaultValue<T>::DoGetDefaultValue (void) const
{
std::ostringstream oss;
oss << m_defaultValue;
--- a/src/core/fatal-error.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/fatal-error.h Fri Sep 28 11:59:46 2007 +0100
@@ -21,7 +21,7 @@
#ifndef FATAL_ERROR_H
#define FATAL_ERROR_H
-#include "assert.h"
+#include "breakpoint.h"
#include <iostream>
/**
@@ -32,15 +32,14 @@
*
* When this macro is hit at runtime, the user-specified
* error message is output and the program is halted by calling
- * the ns3::AssertBreakpoint function. This macro is enabled
- * unconditionally in all builds, including debug and optimized
- * builds.
+ * the NS_BREAKPOINT macro. This macro is enabled unconditionally
+ * in all builds, including debug and optimized builds.
*/
#define NS_FATAL_ERROR(msg) \
do \
{ \
- std::cout << msg << std::endl; \
- ns3::AssertBreakpoint (); \
+ std::cerr << msg << std::endl; \
+ NS_BREAKPOINT (); \
} \
while (false)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/fv-trace-source.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,71 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef F_VARIABLE_TRACER_H
+#define F_VARIABLE_TRACER_H
+
+#include "callback-trace-source.h"
+#include "trace-source.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+class FVTraceSourceBase : public TraceSource {
+public:
+ typedef CallbackTraceSource<double, double> ChangeNotifyCallback;
+
+ FVTraceSourceBase () {}
+ FVTraceSourceBase (FVTraceSourceBase const &o) {}
+ FVTraceSourceBase &operator = (FVTraceSourceBase const &o) {
+ return *this;
+ }
+
+ ~FVTraceSourceBase () {}
+
+ virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
+ m_callback.AddCallback (callback, context);
+ }
+ virtual void RemoveCallback (CallbackBase const & callback) {
+ m_callback.RemoveCallback (callback);
+ }
+ virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
+ m_callback.ConnectPrinter (os, context);
+ }
+protected:
+ void notify (double oldVal, double newVal) {
+ if (oldVal != newVal)
+ {
+ m_callback (oldVal, newVal);
+ }
+ }
+private:
+ ChangeNotifyCallback m_callback;
+};
+
+template <typename T>
+class FVTraceSource : public FVTraceSourceBase
+{
+public:
+};
+
+}; // namespace ns3
+
+#endif /* F_VARIABLE_TRACER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/log.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,331 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifdef NS3_LOG_ENABLE
+
+#include <list>
+#include <utility>
+#include <iostream>
+#include "log.h"
+#include "assert.h"
+#include "ns3/core-config.h"
+#include "fatal-error.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+namespace ns3 {
+
+typedef std::list<std::pair <std::string, LogComponent *> > ComponentList;
+typedef std::list<std::pair <std::string, LogComponent *> >::iterator ComponentListI;
+
+static
+ComponentList *GetComponentList (void)
+{
+ static ComponentList components;
+ return &components;
+}
+
+void
+LogComponentEnableEnvVar (void)
+{
+ static bool isFirstLog = true;
+ if (!isFirstLog)
+ {
+ return;
+ }
+#ifdef HAVE_GETENV
+ char *envVar = getenv("NS_LOG");
+ if (envVar == 0)
+ {
+ isFirstLog = false;
+ return;
+ }
+ std::string env = envVar;
+ if (env == "print-list")
+ {
+ LogComponentPrintList ();
+ isFirstLog = false;
+ return;
+ }
+ bool allFound = true;
+ std::string::size_type cur = 0;
+ std::string::size_type next = 0;
+ while (true)
+ {
+ next = env.find_first_of (";", cur);
+ std::string tmp = std::string (env, cur, next);
+ {
+ /* The following code is a workaround for a bug in the g++
+ * c++ string library. Its goal is to remove any trailing ';'
+ * from the string even though there should not be any in
+ * it. This code should be safe even if the bug is not there.
+ */
+ std::string::size_type trailing = tmp.find_first_of (";");
+ tmp = tmp.substr (0, trailing);
+ }
+ if (tmp.size () == 0)
+ {
+ break;
+ }
+ std::string::size_type equal = tmp.find ("=");
+ std::string component;
+ int level;
+ if (equal == std::string::npos)
+ {
+ component = tmp;
+ level = LOG_DEBUG;
+ }
+ else
+ {
+ component = tmp.substr (0, equal);
+ std::string::size_type cur_lev;
+ std::string::size_type next_lev = equal;
+ do
+ {
+ cur_lev = next_lev + 1;
+ next_lev = tmp.find ("|", cur_lev);
+ std::string lev = tmp.substr (cur_lev, next_lev - cur_lev);
+ if (lev == "error")
+ {
+ level |= LOG_ERROR;
+ }
+ else if (lev == "warn")
+ {
+ level |= LOG_WARN;
+ }
+ else if (lev == "debug")
+ {
+ level |= LOG_DEBUG;
+ }
+ else if (lev == "info")
+ {
+ level |= LOG_INFO;
+ }
+ else if (lev == "function")
+ {
+ level |= LOG_FUNCTION;
+ }
+ else if (lev == "param")
+ {
+ level |= LOG_PARAM;
+ }
+ else if (lev == "logic")
+ {
+ level |= LOG_LOGIC;
+ }
+ else if (lev == "all")
+ {
+ level |= LOG_ALL;
+ }
+ else if (lev == "errorlevel")
+ {
+ level |= LOG_LEVEL_ERROR;
+ }
+ else if (lev == "warnlevel")
+ {
+ level |= LOG_LEVEL_WARN;
+ }
+ else if (lev == "debuglevel")
+ {
+ level |= LOG_LEVEL_DEBUG;
+ }
+ else if (lev == "infolevel")
+ {
+ level |= LOG_LEVEL_INFO;
+ }
+ else if (lev == "functionlevel")
+ {
+ level |= LOG_LEVEL_FUNCTION;
+ }
+ else if (lev == "paramlevel")
+ {
+ level |= LOG_LEVEL_PARAM;
+ }
+ else if (lev == "logiclevel")
+ {
+ level |= LOG_LEVEL_LOGIC;
+ }
+ else if (lev == "alllevel")
+ {
+ level |= LOG_LEVEL_ALL;
+ }
+ } while (next_lev != std::string::npos);
+ }
+ bool found = false;
+ ComponentList *components = GetComponentList ();
+ for (ComponentListI i = components->begin ();
+ i != components->end ();
+ i++)
+ {
+ if (i->first.compare (component) == 0)
+ {
+ found = true;
+
+ i->second->Enable ((enum LogLevel)level);
+ break;
+ }
+ }
+ if (!found)
+ {
+ allFound = false;
+ }
+ if (next == std::string::npos)
+ {
+ break;
+ }
+ cur = next + 1;
+ if (cur >= env.size ())
+ {
+ break;
+ }
+ }
+ if (allFound)
+ {
+ isFirstLog = false;
+ }
+
+#endif
+}
+
+LogComponent::LogComponent (char const * name)
+ : m_levels (0)
+{
+ ComponentList *components = GetComponentList ();
+ for (ComponentListI i = components->begin ();
+ i != components->end ();
+ i++)
+ {
+ NS_ASSERT (i->first != name);
+ }
+ components->push_back (std::make_pair (name, this));
+}
+
+bool
+LogComponent::IsEnabled (enum LogLevel level) const
+{
+ LogComponentEnableEnvVar ();
+ return (level & m_levels) ? 1 : 0;
+}
+
+bool
+LogComponent::IsNoneEnabled (void) const
+{
+ return m_levels == 0;
+}
+
+void
+LogComponent::Enable (enum LogLevel level)
+{
+ m_levels |= level;
+}
+
+void
+LogComponent::Disable (enum LogLevel level)
+{
+ m_levels &= ~level;
+}
+
+void
+LogComponentEnable (char const *name, enum LogLevel level)
+{
+ ComponentList *components = GetComponentList ();
+ for (ComponentListI i = components->begin ();
+ i != components->end ();
+ i++)
+ {
+ if (i->first.compare (name) == 0)
+ {
+ i->second->Enable (level);
+ break;
+ }
+ }
+}
+
+void
+LogComponentDisable (char const *name, enum LogLevel level)
+{
+ ComponentList *components = GetComponentList ();
+ for (ComponentListI i = components->begin ();
+ i != components->end ();
+ i++)
+ {
+ if (i->first.compare (name) == 0)
+ {
+ i->second->Disable (level);
+ break;
+ }
+ }
+}
+
+void
+LogComponentPrintList (void)
+{
+ ComponentList *components = GetComponentList ();
+ for (ComponentListI i = components->begin ();
+ i != components->end ();
+ i++)
+ {
+ std::cout << i->first << "=";
+ if (i->second->IsNoneEnabled ())
+ {
+ std::cout << "0" << std::endl;
+ continue;
+ }
+ if (i->second->IsEnabled (LOG_ERROR))
+ {
+ std::cout << "error";
+ }
+ if (i->second->IsEnabled (LOG_WARN))
+ {
+ std::cout << "|warn";
+ }
+ if (i->second->IsEnabled (LOG_DEBUG))
+ {
+ std::cout << "|debug";
+ }
+ if (i->second->IsEnabled (LOG_INFO))
+ {
+ std::cout << "|info";
+ }
+ if (i->second->IsEnabled (LOG_FUNCTION))
+ {
+ std::cout << "|function";
+ }
+ if (i->second->IsEnabled (LOG_PARAM))
+ {
+ std::cout << "|param";
+ }
+ if (i->second->IsEnabled (LOG_LOGIC))
+ {
+ std::cout << "|logic";
+ }
+ if (i->second->IsEnabled (LOG_ALL))
+ {
+ std::cout << "|all";
+ }
+ std::cout << std::endl;
+ }
+}
+
+} // namespace ns3
+
+#endif // NS3_LOG_ENABLE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/log.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,251 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+#include <string>
+#include <iostream>
+
+/**
+ * \defgroup logging Logging
+ * \brief Logging functions and macros
+ *
+ * LOG functionality: macros which allow developers to
+ * send information out on screen. All logging messages
+ * are disabled by default. To enable selected logging
+ * messages, use the ns3::LogComponentEnable
+ * function.
+ *
+ * Alternatively, you can use the NS_LOG
+ * environment variable to define a ';'-separated list of
+ * logging components to enable. For example, NS_LOG=a;b;c;DAFD;GH
+ * would enable the components 'a', 'b', 'c', 'DAFD', and, 'GH'.
+ *
+ * For each component, the "debug" log level is enabled by default
+ * but more components can be enabled selectively with the following
+ * syntax: NS_LOG='Component1=func|param|warn;Component2=error|debug'
+ * This example would enable the 'func', 'param', and 'warn' log
+ * levels for 'Component1' and the 'error' and 'debug' log levels
+ * for 'Component2'.
+ *
+ * The list of available log components can be printed on stdout
+ * with the NS_LOG=print-list syntax.
+ */
+
+/**
+ * \ingroup logging
+ * \param name a string
+ *
+ * Define a Log component with a specific name. This macro
+ * should be used at the top of every file in which you want
+ * to use the NS_LOG macro. This macro defines a new
+ * "log component" which can be later selectively enabled
+ * or disabled with the ns3::LogComponentEnable and
+ * ns3::LogComponentDisable functions or with the NS_LOG
+ * environment variable.
+ */
+
+#ifdef NS3_LOG_ENABLE
+
+#define NS_LOG_COMPONENT_DEFINE(name) \
+ static ns3::LogComponent g_log = ns3::LogComponent (name)
+
+#else
+
+#define NS_LOG_COMPONENT_DEFINE(name)
+
+#endif
+
+/**
+ * \ingroup logging
+ * \param msg message to output
+ *
+ * Generate logging output in the "log component" of the
+ * current file. i.e., every call to NS_LOG from within
+ * a file implicitely generates out within the component
+ * defined with the NS_LOG_COMPONENT_DEFINE macro in the
+ * same file.
+ */
+
+#ifdef NS3_LOG_ENABLE
+
+#define NS_LOG(level, msg) \
+ do \
+ { \
+ if (g_log.IsEnabled (level)) \
+ { \
+ std::clog << __PRETTY_FUNCTION__ << " ==> " << \
+ msg << std::endl; \
+ } \
+ } \
+ while (false)
+
+#define NS_LOG_F(level) \
+ do \
+ { \
+ if (g_log.IsEnabled (level)) \
+ { \
+ std::clog << __PRETTY_FUNCTION__ << std::endl;\
+ } \
+ } \
+ while (false)
+
+#define NS_LOG_ERROR(msg) \
+ NS_LOG(ns3::LOG_ERROR, msg)
+
+#define NS_LOG_WARN(msg) \
+ NS_LOG(ns3::LOG_WARN, msg)
+
+#define NS_LOG_DEBUG(msg) \
+ NS_LOG(ns3::LOG_DEBUG, msg)
+
+#define NS_LOG_INFO(msg) \
+ NS_LOG(ns3::LOG_INFO, msg)
+
+#define NS_LOG_FUNCTION \
+ NS_LOG_F(ns3::LOG_FUNCTION)
+
+#define NS_LOG_PARAM(msg) \
+ NS_LOG(ns3::LOG_PARAM, msg)
+
+#define NS_LOG_LOGIC(msg) \
+ NS_LOG(ns3::LOG_LOGIC, msg)
+
+#define NS_LOG_ALL(msg) \
+ NS_LOG(ns3::LOG_ALL, msg)
+
+#define NS_LOG_UNCOND(msg) \
+ do \
+ { \
+ std::clog << msg << std::endl; \
+ } \
+ while (false)
+
+#else
+
+#define NS_LOG(level, msg)
+#define NS_LOG_F(level)
+#define NS_LOG_ERROR(msg)
+#define NS_LOG_WARN(msg)
+#define NS_LOG_DEBUG(msg)
+#define NS_LOG_INFO(msg)
+#define NS_LOG_FUNCTION
+#define NS_LOG_PARAM(msg)
+#define NS_LOG_LOGIC(msg)
+#define NS_LOG_ALL(msg)
+#define NS_LOG_UNCOND(msg)
+
+#endif
+
+namespace ns3 {
+
+#ifdef NS3_LOG_ENABLE
+
+enum LogLevel {
+ LOG_ERROR = 0x0001, // serious error messages only
+ LOG_LEVEL_ERROR = 0x0001,
+
+ LOG_WARN = 0x0002, // warning messages
+ LOG_LEVEL_WARN = 0x0003,
+
+ LOG_DEBUG = 0x0004, // rare ad-hoc debug messages
+ LOG_LEVEL_DEBUG = 0x0007,
+
+ LOG_INFO = 0x0008, // informational messages (e.g., banners)
+ LOG_LEVEL_INFO = 0x000f,
+
+ LOG_FUNCTION = 0x0010, // function tracing
+ LOG_LEVEL_FUNCTION = 0x001f,
+
+ LOG_PARAM = 0x0020, // parameters to functions
+ LOG_LEVEL_PARAM = 0x003f,
+
+ LOG_LOGIC = 0x0040, // control flow tracing within functions
+ LOG_LEVEL_LOGIC = 0x007f,
+
+ LOG_ALL = 0x4000, // print everything
+ LOG_LEVEL_ALL = 0x7fff
+};
+
+#endif
+
+/**
+ * \param name a log component name
+ * \ingroup logging
+ *
+ * Enable the logging output associated with that log component.
+ * The logging output can be later disabled with a call
+ * to ns3::LogComponentDisable.
+ */
+#ifdef NS3_LOG_ENABLE
+void LogComponentEnable (char const *name, enum LogLevel level);
+#else
+#define LogComponentEnable(a,b)
+#endif
+
+/**
+ * \param name a log component name
+ * \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.
+ */
+#ifdef NS3_LOG_ENABLE
+void LogComponentDisable (char const *name, enum LogLevel level);
+#else
+#define LogComponentDisable(a,b)
+#endif
+
+/**
+ * \ingroup logging
+ *
+ * Print the list of logging messages available.
+ * The output of this function can be obtained by setting
+ * the NS_LOG environment variable to the special value
+ * 'print-list'.
+ *
+ * For example: NS_LOG=print-list
+ */
+#ifdef NS3_LOG_ENABLE
+void LogComponentPrintList (void);
+#else
+#define LogComponentPrintList()
+#endif
+
+#ifdef NS3_LOG_ENABLE
+
+class LogComponent {
+public:
+ LogComponent (char const *name);
+ bool IsEnabled (enum LogLevel level) const;
+ bool IsNoneEnabled (void) const;
+ void Enable (enum LogLevel level);
+ void Disable (enum LogLevel level);
+private:
+ int32_t m_levels;
+};
+
+#endif
+
+} // namespace ns3
+
+#endif // __LOG_H__
--- a/src/core/object.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/object.cc Fri Sep 28 11:59:46 2007 +0100
@@ -22,8 +22,12 @@
#include "assert.h"
#include "singleton.h"
#include "uid-manager.h"
+#include "trace-resolver.h"
+#include "log.h"
#include <vector>
+NS_LOG_COMPONENT_DEFINE ("Object");
+
namespace {
class IidManager : public ns3::UidManager
@@ -34,6 +38,7 @@
public:
void SetParent (uint16_t child, const uint16_t *parent);
uint16_t LookupParent (uint16_t child);
+
private:
std::vector<const uint16_t *> m_parents;
};
@@ -55,6 +60,68 @@
namespace ns3 {
+class InterfaceIdTraceResolver : public TraceResolver
+{
+public:
+ InterfaceIdTraceResolver (Ptr<const Object> aggregate);
+ virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
+ virtual void Disconnect (std::string path, CallbackBase const &cb);
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection);
+ virtual void TraceAll (std::ostream &os, const TraceContext &context);
+private:
+ Ptr<const Object> ParseForInterface (std::string path);
+ Ptr<const Object> m_aggregate;
+};
+
+InterfaceIdTraceResolver::InterfaceIdTraceResolver (Ptr<const Object> aggregate)
+ : m_aggregate (aggregate)
+{}
+Ptr<const Object>
+InterfaceIdTraceResolver::ParseForInterface (std::string path)
+{
+ std::string element = GetElement (path);
+ std::string::size_type dollar_pos = element.find ("$");
+ if (dollar_pos != 0)
+ {
+ return 0;
+ }
+ std::string interfaceName = element.substr (1, std::string::npos);
+ InterfaceId interfaceId = InterfaceId::LookupByName (interfaceName);
+ Ptr<Object> interface = m_aggregate->QueryInterface<Object> (interfaceId);
+ return interface;
+}
+void
+InterfaceIdTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
+{
+ Ptr<const Object> interface = ParseForInterface (path);
+ if (interface != 0)
+ {
+ interface->GetTraceResolver ()->Connect (GetSubpath (path), cb, context);
+ }
+}
+void
+InterfaceIdTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
+{
+ Ptr<const Object> interface = ParseForInterface (path);
+ if (interface != 0)
+ {
+ interface->TraceDisconnect (GetSubpath (path), cb);
+ }
+}
+void
+InterfaceIdTraceResolver::CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection)
+{
+ m_aggregate->DoCollectSources (path, context, collection);
+}
+void
+InterfaceIdTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
+{
+ m_aggregate->DoTraceAll (os, context);
+}
+
+
InterfaceId::InterfaceId (uint16_t iid)
: m_iid (iid)
{}
@@ -72,6 +139,12 @@
{
return Singleton<IidTree>::Get ()->LookupParent (iid.m_iid);
}
+std::string
+InterfaceId::GetName (void) const
+{
+ std::string name = Singleton<IidManager>::Get ()->LookupByUid (m_iid);
+ return name;
+}
bool operator == (const InterfaceId &a, const InterfaceId &b)
{
@@ -109,6 +182,7 @@
: m_count (1),
m_iid (Object::iid),
m_disposed (false),
+ m_collecting (false),
m_next (this)
{}
Object::~Object ()
@@ -163,6 +237,17 @@
}
void
+Object::TraceConnect (std::string path, const CallbackBase &cb) const
+{
+ GetTraceResolver ()->Connect (path, cb, TraceContext ());
+}
+void
+Object::TraceDisconnect (std::string path, const CallbackBase &cb) const
+{
+ GetTraceResolver ()->Disconnect (path, cb);
+}
+
+void
Object::SetInterfaceId (InterfaceId iid)
{
NS_ASSERT (Check ());
@@ -175,6 +260,14 @@
NS_ASSERT (!m_disposed);
}
+Ptr<TraceResolver>
+Object::GetTraceResolver (void) const
+{
+ Ptr<InterfaceIdTraceResolver> resolver =
+ Create<InterfaceIdTraceResolver> (this);
+ return resolver;
+}
+
bool
Object::Check (void) const
{
@@ -208,12 +301,77 @@
} while (current != end);
}
+void
+Object::DoCollectSources (std::string path, const TraceContext &context,
+ TraceResolver::SourceCollection *collection) const
+{
+ const Object *current;
+ current = this;
+ do {
+ if (current->m_collecting)
+ {
+ return;
+ }
+ current = current->m_next;
+ } while (current != this);
+
+ m_collecting = true;
+
+ current = this->m_next;
+ while (current != this)
+ {
+ NS_ASSERT (current != 0);
+ NS_LOG_LOGIC ("collect current=" << current);
+ InterfaceId cur = current->m_iid;
+ while (cur != Object::iid)
+ {
+ std::string name = cur.GetName ();
+ std::string fullpath = path;
+ fullpath.append ("/$");
+ fullpath.append (name);
+ NS_LOG_LOGIC("collect: " << fullpath);
+ current->GetTraceResolver ()->CollectSources (fullpath, context, collection);
+ cur = InterfaceId::LookupParent (cur);
+ }
+ current = current->m_next;
+ }
+
+ m_collecting = false;
+}
+void
+Object::DoTraceAll (std::ostream &os, const TraceContext &context) const
+{
+ const Object *current;
+ current = this;
+ do {
+ if (current->m_collecting)
+ {
+ return;
+ }
+ current = current->m_next;
+ } while (current != this);
+
+ m_collecting = true;
+
+ current = this->m_next;
+ while (current != this)
+ {
+ NS_ASSERT (current != 0);
+ current->GetTraceResolver ()->TraceAll (os, context);
+ current = current->m_next;
+ }
+
+ m_collecting = false;
+}
+
} // namespace ns3
#ifdef RUN_SELF_TESTS
#include "test.h"
+#include "sv-trace-source.h"
+#include "composite-trace-resolver.h"
namespace {
@@ -225,7 +383,18 @@
{
SetInterfaceId (BaseA::iid);
}
+ void BaseGenerateTrace (int16_t v)
+ { m_source = v; }
virtual void Dispose (void) {}
+ virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+ {
+ ns3::Ptr<ns3::CompositeTraceResolver> resolver =
+ ns3::Create<ns3::CompositeTraceResolver> ();
+ resolver->AddSource ("basea-x", ns3::TraceDoc ("test source"), m_source);
+ resolver->SetParentResolver (Object::GetTraceResolver ());
+ return resolver;
+ }
+ ns3::SVTraceSource<int16_t> m_source;
};
class DerivedA : public BaseA
@@ -236,9 +405,20 @@
{
SetInterfaceId (DerivedA::iid);
}
+ void DerivedGenerateTrace (int16_t v)
+ { m_sourceDerived = v; }
virtual void Dispose (void) {
BaseA::Dispose ();
}
+ virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+ {
+ ns3::Ptr<ns3::CompositeTraceResolver> resolver =
+ ns3::Create<ns3::CompositeTraceResolver> ();
+ resolver->AddSource ("deriveda-x", ns3::TraceDoc ("test source"), m_sourceDerived);
+ resolver->SetParentResolver (BaseA::GetTraceResolver ());
+ return resolver;
+ }
+ ns3::SVTraceSource<int16_t> m_sourceDerived;
};
const ns3::InterfaceId BaseA::iid =
@@ -254,7 +434,18 @@
{
SetInterfaceId (BaseB::iid);
}
+ void BaseGenerateTrace (int16_t v)
+ { m_source = v; }
virtual void Dispose (void) {}
+ virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+ {
+ ns3::Ptr<ns3::CompositeTraceResolver> resolver =
+ ns3::Create<ns3::CompositeTraceResolver> ();
+ resolver->AddSource ("baseb-x", ns3::TraceDoc ("test source"), m_source);
+ resolver->SetParentResolver (Object::GetTraceResolver ());
+ return resolver;
+ }
+ ns3::SVTraceSource<int16_t> m_source;
};
class DerivedB : public BaseB
@@ -265,9 +456,20 @@
{
SetInterfaceId (DerivedB::iid);
}
+ void DerivedGenerateTrace (int16_t v)
+ { m_sourceDerived = v; }
virtual void Dispose (void) {
BaseB::Dispose ();
}
+ virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+ {
+ ns3::Ptr<ns3::CompositeTraceResolver> resolver =
+ ns3::Create<ns3::CompositeTraceResolver> ();
+ resolver->AddSource ("derivedb-x", ns3::TraceDoc ("test source"), m_sourceDerived);
+ resolver->SetParentResolver (BaseB::GetTraceResolver ());
+ return resolver;
+ }
+ ns3::SVTraceSource<int16_t> m_sourceDerived;
};
const ns3::InterfaceId BaseB::iid =
@@ -284,120 +486,82 @@
public:
ObjectTest ();
virtual bool RunTests (void);
+private:
+ void BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+ void DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+ void BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+ void DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+
+ bool m_baseATrace;
+ bool m_derivedATrace;
+ bool m_baseBTrace;
+ bool m_derivedBTrace;
};
ObjectTest::ObjectTest ()
: Test ("Object")
{}
+void
+ObjectTest::BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+ m_baseATrace = true;
+}
+void
+ObjectTest::DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+ m_derivedATrace = true;
+}
+void
+ObjectTest::BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+ m_baseBTrace = true;
+}
+void
+ObjectTest::DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+ m_derivedBTrace = true;
+}
+
bool
ObjectTest::RunTests (void)
{
- bool ok = true;
+ bool result = true;
Ptr<BaseA> baseA = Create<BaseA> ();
- if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
- {
- ok = false;
- }
- if (baseA->QueryInterface<BaseA> (DerivedA::iid) != 0)
- {
- ok = false;
- }
- if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
+ NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), 0);
+ NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
baseA = Create<DerivedA> (10);
- if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
- {
- ok = false;
- }
- if (baseA->QueryInterface<BaseA> (DerivedA::iid) != baseA)
- {
- ok = false;
- }
- if (baseA->QueryInterface<DerivedA> (DerivedA::iid) == 0)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
+ NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), baseA);
+ NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
baseA = Create<BaseA> ();
Ptr<BaseB> baseB = Create<BaseB> ();
Ptr<BaseB> baseBCopy = baseB;
baseA->AddInterface (baseB);
- if (baseA->QueryInterface<BaseA> (BaseA::iid) == 0)
- {
- ok = false;
- }
- if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
- {
- ok = false;
- }
- if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
- {
- ok = false;
- }
- if (baseA->QueryInterface<DerivedB> (DerivedB::iid) != 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<DerivedB> (DerivedB::iid) != 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<DerivedA> (DerivedA::iid) != 0)
- {
- ok = false;
- }
- if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), 0);
+ NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
+ NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0);
+ NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
+ NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
baseA = Create<DerivedA> (1);
baseB = Create<DerivedB> (1);
baseBCopy = baseB;
baseA->AddInterface (baseB);
- if (baseA->QueryInterface<DerivedB> (DerivedB::iid) == 0)
- {
- ok = false;
- }
- if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<DerivedA> (DerivedA::iid) == 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
- {
- ok = false;
- }
- if (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid) == 0)
- {
- ok = false;
- }
- if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<DerivedB> (DerivedB::iid) == 0)
- {
- ok = false;
- }
- if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
+ NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0)
baseA = Create<BaseA> ();
baseB = Create<BaseB> ();
@@ -405,7 +569,76 @@
baseA = 0;
baseA = baseB->QueryInterface<BaseA> (BaseA::iid);
- return ok;
+ baseA = Create<BaseA> ();
+ baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+ m_baseATrace = false;
+ baseA->BaseGenerateTrace (1);
+ NS_TEST_ASSERT (m_baseATrace);
+ baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+ baseB = Create<BaseB> ();
+ baseB->TraceConnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
+ m_baseBTrace = false;
+ baseB->BaseGenerateTrace (2);
+ NS_TEST_ASSERT (m_baseBTrace);
+ baseB->TraceDisconnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
+
+ baseA->AddInterface (baseB);
+
+ baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+ m_baseATrace = false;
+ baseA->BaseGenerateTrace (3);
+ NS_TEST_ASSERT (m_baseATrace);
+ baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+ baseA->TraceConnect ("/$BaseB/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
+ m_baseBTrace = false;
+ baseB->BaseGenerateTrace (4);
+ NS_TEST_ASSERT (m_baseBTrace);
+ baseA->TraceDisconnect ("/$BaseB/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
+ m_baseBTrace = false;
+ baseB->BaseGenerateTrace (5);
+ NS_TEST_ASSERT (!m_baseBTrace);
+
+ baseB->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+ m_baseATrace = false;
+ baseA->BaseGenerateTrace (6);
+ NS_TEST_ASSERT (m_baseATrace);
+ baseB->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+ baseA->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+ m_baseATrace = false;
+ baseA->BaseGenerateTrace (7);
+ NS_TEST_ASSERT (m_baseATrace);
+ baseA->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+ Ptr<DerivedA> derivedA;
+ derivedA = Create<DerivedA> (1);
+ baseB = Create<BaseB> ();
+ derivedA->AddInterface (baseB);
+ baseB->TraceConnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::DerivedATrace, this));
+ baseB->TraceConnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+ m_derivedATrace = false;
+ m_baseATrace = false;
+ derivedA->DerivedGenerateTrace (8);
+ derivedA->BaseGenerateTrace (9);
+ NS_TEST_ASSERT (m_derivedATrace);
+ NS_TEST_ASSERT (m_baseATrace);
+ baseB->TraceDisconnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::BaseATrace, this));
+ baseB->TraceDisconnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+ baseB->TraceConnect ("/$DerivedA/*", MakeCallback (&ObjectTest::DerivedATrace, this));
+ m_derivedATrace = false;
+ derivedA->DerivedGenerateTrace (10);
+ NS_TEST_ASSERT (m_derivedATrace);
+ // here, we have connected the derived trace sink to all
+ // trace sources, including the base trace source.
+ m_derivedATrace = false;
+ derivedA->BaseGenerateTrace (11);
+ NS_TEST_ASSERT (m_derivedATrace);
+ baseB->TraceDisconnect ("/$DerivedA/*", MakeCallback (&ObjectTest::BaseATrace, this));
+
+ return result;
}
static ObjectTest g_interfaceObjectTests;
--- a/src/core/object.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/object.h Fri Sep 28 11:59:46 2007 +0100
@@ -24,9 +24,13 @@
#include <stdint.h>
#include <string>
#include "ptr.h"
+#include "trace-resolver.h"
namespace ns3 {
+class TraceContext;
+class CallbackBase;
+
/**
* \brief a unique identifier for an interface.
*
@@ -56,6 +60,11 @@
* id is not a valid interface id.
*/
static InterfaceId LookupParent (InterfaceId iid);
+
+ /**
+ * \returns the name of this interface.
+ */
+ std::string GetName (void) const;
~InterfaceId ();
private:
InterfaceId (uint16_t iid);
@@ -131,6 +140,30 @@
* on one to get the other, and vice-versa.
*/
void AddInterface (Ptr<Object> other);
+
+ /**
+ * \param path the path to match for the callback
+ * \param cb callback to connect
+ *
+ * Connect the input callback to all trace sources which
+ * match the input path.
+ *
+ */
+ void TraceConnect (std::string path, const CallbackBase &cb) const;
+ /**
+ * \param path the path to match for the callback
+ * \param cb callback to disconnect
+ *
+ * Disconnect the input callback from all trace sources which
+ * match the input path.
+ */
+ void TraceDisconnect (std::string path, const CallbackBase &cb) const;
+ /**
+ * \returns the trace resolver associated to this object.
+ *
+ * This method should be rarely called by users.
+ */
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
protected:
/**
* \param iid an InterfaceId
@@ -147,12 +180,17 @@
*/
virtual void DoDispose (void);
private:
+ friend class InterfaceIdTraceResolver;
Ptr<Object> DoQueryInterface (InterfaceId iid) const;
+ void DoCollectSources (std::string path, const TraceContext &context,
+ TraceResolver::SourceCollection *collection) const;
+ void DoTraceAll (std::ostream &os, const TraceContext &context) const;
bool Check (void) const;
void MaybeDelete (void) const;
mutable uint32_t m_count;
InterfaceId m_iid;
bool m_disposed;
+ mutable bool m_collecting;
Object *m_next;
};
--- a/src/core/ptr.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/ptr.cc Fri Sep 28 11:59:46 2007 +0100
@@ -28,9 +28,14 @@
namespace ns3 {
+template <typename T>
+void Foo (void) {}
+
+
class NoCount : public Object
{
public:
+ NoCount (void (*fn) (void));
NoCount (Callback<void> cb);
~NoCount ();
void Nothing (void) const;
@@ -292,12 +297,22 @@
callback ();
}
+
#if 0
// as expected, fails compilation.
{
Ptr<const Object> p = Create<NoCount> (cb);
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
}
+ // local types are not allowed as arguments to a template.
+ {
+ class B
+ {
+ public:
+ B () {}
+ };
+ Foo<B> ();
+ }
#endif
--- a/src/core/ptr.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/ptr.h Fri Sep 28 11:59:46 2007 +0100
@@ -22,6 +22,7 @@
#ifndef PTR_H
#define PTR_H
+#include <iostream>
#include <stdint.h>
#include "assert.h"
@@ -64,7 +65,7 @@
template <typename U>
friend U *PeekPointer (const Ptr<U> &p);
- void Acquire (void) const;
+ inline void Acquire (void) const;
public:
/**
* Create an empty smart pointer
@@ -80,7 +81,16 @@
* same, so that object is deleted if no more references to it
* remain.
*/
- Ptr (T *ptr);
+ Ptr (T *ptr);
+ /**
+ * \param ptr raw pointer to manage
+ * \param ref if set to true, this method calls Ref, otherwise,
+ * it does not call Ref.
+ *
+ * Create a smart pointer which points to the object pointed to by
+ * the input raw pointer ptr.
+ */
+ Ptr (T *ptr, bool ref);
Ptr (Ptr const&o);
// allow conversions from T to T const.
template <typename U>
@@ -187,10 +197,10 @@
};
template <typename T>
-struct EventMemberImplTraits;
+struct EventMemberImplObjTraits;
template <typename T>
-struct EventMemberImplTraits<Ptr<T> >
+struct EventMemberImplObjTraits<Ptr<T> >
{
static T &GetReference (Ptr<T> p) {
return *PeekPointer (p);
@@ -378,6 +388,16 @@
}
template <typename T>
+Ptr<T>::Ptr (T *ptr, bool ref)
+ : m_ptr (ptr)
+{
+ if (ref)
+ {
+ Acquire ();
+ }
+}
+
+template <typename T>
Ptr<T>::Ptr (Ptr const&o)
: m_ptr (PeekPointer (o))
{
--- a/src/core/random-variable-default-value.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/random-variable-default-value.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,9 +19,9 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "random-variable-default-value.h"
-#include "ns3/debug.h"
+#include "log.h"
-NS_DEBUG_COMPONENT_DEFINE ("RandomVariableDefaultValue");
+NS_LOG_COMPONENT_DEFINE ("RandomVariableDefaultValue");
namespace ns3 {
@@ -43,7 +43,8 @@
RandomVariableDefaultValue::GetCopy (void)
{
RandomVariable *variable;
- bool ok = Parse (m_value, true, &variable);
+ bool ok;
+ ok = Parse (m_value, true, &variable);
NS_ASSERT (ok);
return variable;
}
@@ -74,12 +75,12 @@
double constant = ReadAsDouble (v, ok);
if (mustCreate)
{
- NS_DEBUG ("create Constant constant=" << constant);
+ NS_LOG_LOGIC ("create Constant constant=" << constant);
*pVariable = new ConstantVariable (constant);
}
else
{
- NS_DEBUG ("parse Constant constant=" << constant);
+ NS_LOG_LOGIC ("parse Constant constant=" << constant);
}
return ok;
}
@@ -98,12 +99,12 @@
maxVal = ReadAsDouble (max, ok);
if (mustCreate)
{
- NS_DEBUG ("create Uniform min=" << min << ", max=" << max);
+ NS_LOG_LOGIC ("create Uniform min=" << min << ", max=" << max);
*pVariable = new UniformVariable (minVal, maxVal);
}
else
{
- NS_DEBUG ("parse Uniform min=" << min << ", max=" << max);
+ NS_LOG_LOGIC ("parse Uniform min=" << min << ", max=" << max);
}
return ok;
}
--- a/src/core/random-variable.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/random-variable.cc Fri Sep 28 11:59:46 2007 +0100
@@ -108,8 +108,8 @@
{
if (RandomVariable::globalSeedSet)
{
- cout << "Random number generator already initialized!" << endl;
- cout << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
+ cerr << "Random number generator already initialized!" << endl;
+ cerr << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
return;
}
RandomVariable::globalSeed[0] = s0;
@@ -537,7 +537,7 @@
ValueCDF& current = emp[i];
if (current.value < prior.value || current.cdf < prior.cdf)
{ // Error
- cout << "Empirical Dist error,"
+ cerr << "Empirical Dist error,"
<< " current value " << current.value
<< " prior value " << prior.value
<< " current cdf " << current.cdf
@@ -684,6 +684,43 @@
return z;
}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// TriangularVariable methods
+TriangularVariable::TriangularVariable()
+ : m_min(0), m_max(1), m_mode(0.5) { }
+
+TriangularVariable::TriangularVariable(double s, double l, double mean)
+ : m_min(s), m_max(l), m_mode(3.0*mean-s-l) { }
+
+TriangularVariable::TriangularVariable(const TriangularVariable& c)
+ : RandomVariable(c), m_min(c.m_min), m_max(c.m_max), m_mode(c.m_mode) { }
+
+double TriangularVariable::GetValue()
+{
+ double u = m_generator->RandU01();
+ if(u <= (m_mode - m_min) / (m_max - m_min) )
+ return m_min + sqrt(u * (m_max - m_min) * (m_mode - m_min) );
+ else
+ return m_max - sqrt( (1-u) * (m_max - m_min) * (m_max - m_mode) );
+}
+
+RandomVariable* TriangularVariable::Copy() const
+{
+ return new TriangularVariable(*this);
+}
+
+double TriangularVariable::GetSingleValue(double s, double l, double mean)
+{
+ double mode = 3.0*mean-s-l;
+ double u = m_static_generator->RandU01();
+ if(u <= (mode - s) / (l - s) )
+ return s + sqrt(u * (l - s) * (mode - s) );
+ else
+ return l - sqrt( (1-u) * (l - s) * (l - mode) );
+}
+
+
}//namespace ns3
--- a/src/core/random-variable.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/random-variable.h Fri Sep 28 11:59:46 2007 +0100
@@ -737,6 +737,51 @@
double m_sigma;
};
+/**
+ * \brief Triangularly Distributed random var
+ * \ingroup randomvariable
+ *
+ * This distribution is a triangular distribution. The probablility density
+ * is in the shape of a triangle.
+ */
+class TriangularVariable : public RandomVariable {
+public:
+ /**
+ * Creates a triangle distribution random number generator in the
+ * range [0.0 .. 1.0), with mean of 0.5
+ */
+ TriangularVariable();
+
+ /**
+ * Creates a triangle distribution random number generator with the specified
+ * range
+ * \param s Low end of the range
+ * \param l High end of the range
+ * \param mean mean of the distribution
+ */
+ TriangularVariable(double s, double l, double mean);
+
+ TriangularVariable(const TriangularVariable& c);
+
+ /**
+ * \return A value from this distribution
+ */
+ virtual double GetValue();
+ virtual RandomVariable* Copy() const;
+public:
+ /**
+ * \param s Low end of the range
+ * \param l High end of the range
+ * \param mean mean of the distribution
+ * \return A triangularly distributed random number between s and l
+ */
+ static double GetSingleValue(double s, double l, double mean);
+private:
+ double m_min;
+ double m_max;
+ double m_mode; //easier to work with the mode internally instead of the mean
+ //they are related by the simple: mean = (min+max+mode)/3
+};
}//namespace ns3
#endif
--- a/src/core/rng-stream.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/rng-stream.cc Fri Sep 28 11:59:46 2007 +0100
@@ -269,11 +269,11 @@
}
for (i = 3; i < 6; ++i) {
if (seed[i] >= m2) {
- cout << "Seed[" << i << "] = " << seed[i] << endl;
- cerr << "*****************************************\n\n"
- << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
- << "\n\n*****************************************\n\n";
- return (false);
+ cerr << "Seed[" << i << "] = " << seed[i] << endl;
+ cerr << "*****************************************\n\n"
+ << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
+ << "\n\n*****************************************\n\n";
+ return (false);
}
}
if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/stream-tracer-test.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "stream-tracer.h"
+#include "test.h"
+#include <iostream>
+
+#ifdef RUN_SELF_TESTS
+
+namespace {
+
+class TestStreamTracer : public ns3::Test {
+public:
+ TestStreamTracer ();
+ virtual bool RunTests (void);
+};
+
+static TestStreamTracer gTestStream;
+
+TestStreamTracer::TestStreamTracer ()
+ : Test ("StreamTracer")
+{}
+
+bool
+TestStreamTracer::RunTests (void)
+{
+ bool ok = true;
+ ns3::StreamTracer trace;
+ //trace.setStream (&std::cout);
+ trace << 1;
+ trace << " X ";
+ trace << 1.0;
+ trace << std::endl;
+ trace << "test ";
+ trace << 1 << " test";
+ trace << "test "
+ << 1.0 << " "
+ << 0xdeadbead
+ << std::endl;
+ trace << "0x" << std::hex
+ << 0xdeadbeaf
+ << std::dec << " "
+ << 0xdeadbeaf
+ << std::endl;
+ return ok;
+}
+
+
+}; // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/stream-tracer.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef STREAM_TRACER_H
+#define STREAM_TRACER_H
+
+#include <ostream>
+
+namespace ns3 {
+
+/**
+ * \brief log arbitrary data to std::ostreams
+ *
+ * Whenever operator << is invoked on this class,
+ * it is forwarded to the stored std::ostream output
+ * stream (if there is one).
+ */
+class StreamTracer {
+public:
+ StreamTracer ()
+ : m_os (0) {}
+ template <typename T>
+ StreamTracer &operator << (T const&v) {
+ if (m_os != 0)
+ {
+ (*m_os) << v;
+ }
+ return *this;
+ }
+ template <typename T>
+ StreamTracer &operator << (T &v) {
+ if (m_os != 0)
+ {
+ (*m_os) << v;
+ }
+ return *this;
+ }
+ StreamTracer &operator << (std::ostream &(*v) (std::ostream &)) {
+ if (m_os != 0)
+ {
+ (*m_os) << v;
+ }
+ return *this;
+ }
+
+ /**
+ * \param os the output stream to store
+ */
+ void SetStream (std::ostream * os) {
+ m_os = os;
+ }
+private:
+ std::ostream *m_os;
+};
+
+}; // namespace ns3
+
+
+#endif /* TRACER_STREAM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/sv-trace-source.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,246 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef SV_TRACE_SOURCE_H
+#define SV_TRACE_SOURCE_H
+
+#include "callback-trace-source.h"
+#include "trace-source.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+class SVTraceSourceBase : public TraceSource {
+public:
+ typedef CallbackTraceSource<int64_t, int64_t> ChangeNotifyCallback;
+
+ SVTraceSourceBase () {}
+ SVTraceSourceBase (SVTraceSourceBase const &o) {}
+ SVTraceSourceBase &operator = (SVTraceSourceBase const &o) {
+ return *this;
+ }
+
+ virtual ~SVTraceSourceBase () {}
+
+ virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
+ m_callback.AddCallback (callback, context);
+ }
+ virtual void RemoveCallback (CallbackBase const & callback) {
+ m_callback.RemoveCallback (callback);
+ }
+ virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
+ m_callback.ConnectPrinter (os, context);
+ }
+protected:
+ void Notify (int64_t oldVal, int64_t newVal) {
+ if (oldVal != newVal)
+ {
+ m_callback (oldVal, newVal);
+ }
+ }
+private:
+ ChangeNotifyCallback m_callback;
+};
+
+template <typename T>
+class UVTraceSource;
+
+
+/**
+ * \brief trace variables of type "signed integer"
+ * \ingroup tracing
+ *
+ * This template class implements a POD type: it
+ * behaves like any other variable of type "signed integer"
+ * except that it also reports any changes to its
+ * value with its internal callback.
+ *
+ * To instantiate a 32-bit signed variable (to store
+ * a TCP counter for example), you would create a variable of type
+ * ns3::UVTraceSource<int32_t> :
+ \code
+ #include <stdint.h>
+ #include "sv-trace-source.h"
+
+ ns3::SVTraceSource<uint16_t> var;
+ \endcode
+ * and you would use it like any other variable of type int32_t:
+ \code
+ var += 12;
+ var = 10;
+ var = -10;
+ \endcode
+ */
+template <typename T>
+class SVTraceSource : public SVTraceSourceBase {
+public:
+ SVTraceSource ()
+ : m_var (0)
+ {}
+ SVTraceSource (T const &var)
+ : m_var (var)
+ {}
+
+ SVTraceSource &operator = (SVTraceSource const &o) {
+ Assign (o.Get ());
+ return *this;
+ }
+ template <typename TT>
+ SVTraceSource &operator = (SVTraceSource<TT> const &o) {
+ Assign (o.Get ());
+ return *this;
+ }
+ template <typename TT>
+ SVTraceSource &operator = (UVTraceSource<TT> const &o) {
+ Assign (o.Get ());
+ return *this;
+ }
+ SVTraceSource &operator++ () {
+ Assign (Get () + 1);
+ return *this;
+ }
+ SVTraceSource &operator-- () {
+ Assign (Get () - 1);
+ return *this;
+ }
+ SVTraceSource operator++ (int) {
+ SVTraceSource old (*this);
+ ++*this;
+ return old;
+ }
+ SVTraceSource operator-- (int) {
+ SVTraceSource old (*this);
+ --*this;
+ return old;
+ }
+ operator T () const {
+ return Get ();
+ }
+
+
+ void Assign (T var) {
+ Notify (m_var, var);
+ m_var = var;
+ }
+ T Get (void) const {
+ return m_var;
+ }
+
+private:
+ T m_var;
+};
+
+template <typename T>
+SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () + rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () - rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () * rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () / rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () << rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () >> rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () & rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () | rhs.Get ());
+ return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () ^ rhs.Get ());
+ return lhs;
+}
+
+
+template <typename T, typename U>
+SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () + rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () - rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () * rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () / rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () << rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () >> rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () & rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () | rhs);
+ return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () ^ rhs);
+ return lhs;
+}
+
+}; // namespace ns3
+
+#endif /* SV_TRACE_SOURCE_H */
--- a/src/core/test.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/test.h Fri Sep 28 11:59:46 2007 +0100
@@ -119,6 +119,23 @@
result = false; \
}
/**
+ * Convenience macro to check that a value returned by a test is what
+ * is expected. Note: this macro assumes a 'bool result = true'
+ * declaration exists in the test function body, and that the function
+ * returns that value.
+ *
+ * \param got value obtained from the test
+ * \param expected value that the test is expected to return
+ */
+#define NS_TEST_ASSERT_UNEQUAL(got, expected) \
+ if ((got) == (expected)) \
+ { \
+ Failure () << __FILE__ << ":" <<__LINE__ \
+ << ": did not want " << (expected) \
+ << ", got " << (got) << std::endl; \
+ result = false; \
+ }
+/**
* Convenience macro to check an assertion is held during an unit
* test. Note: this macro assumes a 'bool result = true' declaration
* exists in the test function body, and that the function returns
@@ -130,8 +147,8 @@
if (!(assertion)) \
{ \
Failure () << __FILE__ << ":" <<__LINE__ \
- << ": assertion `" << (assertion) \
- << "'failed." << std::endl; \
+ << ": assertion `" << #assertion \
+ << "' failed." << std::endl; \
result = false; \
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context-element.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,41 @@
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+std::string
+ElementRegistry::GetTypeName (uint16_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ struct Info info = (*vec)[uid - 1];
+ return info.getTypeName ();
+}
+uint32_t
+ElementRegistry::GetSize (uint16_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ struct Info info = (*vec)[uid - 1];
+ return info.size;
+}
+void
+ElementRegistry::Print (uint16_t uid, uint8_t *instance, std::ostream &os)
+{
+ InfoVector *vec = GetInfoVector ();
+ struct Info info = (*vec)[uid - 1];
+ info.print (instance, os);
+}
+void
+ElementRegistry::Destroy (uint16_t uid, uint8_t *instance)
+{
+ InfoVector *vec = GetInfoVector ();
+ struct Info info = (*vec)[uid - 1];
+ info.destroy (instance);
+}
+ElementRegistry::InfoVector *
+ElementRegistry::GetInfoVector (void)
+{
+ static InfoVector vector;
+ return &vector;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context-element.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,211 @@
+#ifndef TRACE_CONTEXT_ELEMENT_H
+#define TRACE_CONTEXT_ELEMENT_H
+
+#include <string>
+#include <vector>
+
+#define NS_TRACE_CONTEXT_ELEMENT_ENSURE_REGISTERED(x) \
+namespace { \
+static class thisisaveryverylongclassname ##x \
+ { \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+ } g_thisisanotherveryveryverylongname ##x ; \
+}
+
+namespace ns3 {
+
+/**
+ * \brief an item stored in a TraceContext
+ *
+ * To store trace context information in a TraceContext instance,
+ * users must subclass this base class and store subclass instances
+ * in a TraceContext with TraceContext::Add.
+ *
+ * Each subclass should define and implement:
+ * - a public default constructor: it is used by the internals
+ * of the implementation of TraceContext.
+ * - a public destructor: it is also used by the internals of
+ * the implementation of TraceContext.
+ * - a public static method named GetUid which returns a 16 bit
+ * integer. The integer returned from this method should be
+ * allocated with the protected AllocatedUid method.
+ * - a public Print method: this method is used by the
+ * TraceContext::Print method to print the content of each
+ * of the trace context element stored in the trace context.
+ * This method takes a c++ output stream and argument and is
+ * expected to write an ascii string describing its content
+ * in this output stream.
+ * - a public GetTypeName method which returns the fully-qualified
+ * c++ type name of this subclass as a string.
+ *
+ * A typical subclass should look like this:
+ * \code
+ * class MyContext : public TraceContextElement
+ * {
+ * public:
+ * // the _required_ public API
+ * static uint16_t GetUid (void);
+ * MyContext ();
+ * ~MyContext ();
+ * void Print (std::ostream &os) const;
+ * std::string GetTypeName (void) const;
+ *
+ * // the user-specific API to manipulate the context.
+ * void SetData (uint8_t data);
+ * uint8_t GetData (void) const;
+ * private:
+ * uint8_t m_myContextData;
+ * };
+ *
+ * uint16_t
+ * MyContext::GetUid (void)
+ * {
+ * static uint16_t uid = AllocateUid<MyContext> ("MyContext");
+ * return uid;
+ * }
+ * MyContext::MyContext ()
+ * {}
+ * MyContext::~MyContext ()
+ * {}
+ * void
+ * MyContext::Print (std::ostream &os) const
+ * {
+ * os << "mycontext=" << (uint32_t) m_myContextData;
+ * }
+ * std::string
+ * MyContext::GetTypeName (void) const
+ * {
+ * // return a fully-qualified c++ type name
+ * return "MyContext";
+ * }
+ * void
+ * MyContext::SetData (uint8_t data)
+ * {
+ * m_myContextData = data;
+ * }
+ * uint8_t
+ * MyContext::GetData (void) const
+ * {
+ * return m_myContextData;
+ * }
+ * \endcode
+ */
+class TraceContextElement
+{
+protected:
+ /**
+ * \param name a string which uniquely identifies the type
+ * of the subclass which is calling this method.
+ * \returns a unique 32 bit integer associated to the
+ * input string.
+ *
+ * Subclasses are expected to call this method from their
+ * public static GetUid method.
+ */
+ template <typename T>
+ static uint16_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+/**
+ * \brief a registry of TraceContextElement subclasses
+ * \internal
+ */
+class ElementRegistry
+{
+public:
+ template <typename T>
+ static uint16_t AllocateUid (std::string name);
+
+ static uint32_t GetSize (uint16_t uid);
+ static void Print (uint16_t uid, uint8_t *instance, std::ostream &os);
+ static std::string GetTypeName (uint16_t uid);
+ static void Destroy (uint16_t uid, uint8_t *instance);
+private:
+ typedef std::string (*GetTypeNameCb) (void);
+ typedef void (*PrintCb) (uint8_t *instance, std::ostream &os);
+ typedef void (*DestroyCb) (uint8_t *instance);
+ struct Info {
+ uint32_t size;
+ std::string uidString;
+ GetTypeNameCb getTypeName;
+ PrintCb print;
+ DestroyCb destroy;
+ };
+ typedef std::vector<struct Info> InfoVector;
+ static InfoVector *GetInfoVector (void);
+ template <typename T>
+ static std::string DoGetTypeName (void);
+ template <typename T>
+ static void DoPrint (uint8_t *instance, std::ostream &os);
+ template <typename T>
+ static void DoDestroy (uint8_t *instance);
+};
+
+template <typename T>
+void
+ElementRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+ static T obj;
+ // make sure we are aligned.
+ memcpy ((void*)&obj, instance, sizeof (T));
+ obj.Print (os);
+}
+template <typename T>
+std::string
+ElementRegistry::DoGetTypeName (void)
+{
+ static T obj;
+ return obj.GetTypeName ();
+}
+template <typename T>
+void
+ElementRegistry::DoDestroy (uint8_t *instance)
+{
+ static T obj;
+ // make sure we are aligned.
+ memcpy ((void*)&obj, instance, sizeof (T));
+ obj.~T ();
+}
+
+template <typename T>
+uint16_t
+ElementRegistry::AllocateUid (std::string name)
+{
+ InfoVector *vec = GetInfoVector ();
+ uint16_t uid = 1;
+ for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == name)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ struct Info info;
+ info.size = sizeof (T);
+ info.uidString = name;
+ info.getTypeName = &ElementRegistry::DoGetTypeName<T>;
+ info.print = &ElementRegistry::DoPrint<T>;
+ info.destroy = &ElementRegistry::DoDestroy<T>;
+ vec->push_back (info);
+ return vec->size ();
+}
+
+
+
+template <typename T>
+uint16_t
+TraceContextElement::AllocateUid (std::string name)
+{
+ return ElementRegistry::AllocateUid<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TRACE_CONTEXT_ELEMENT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,459 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "trace-context.h"
+#include "trace-context-element.h"
+#include "assert.h"
+
+namespace ns3 {
+
+TraceContext::Iterator::Iterator ()
+ : m_buffer (0),
+ m_size (0),
+ m_current (0)
+{}
+TraceContext::Iterator::Iterator (uint8_t *buffer, uint16_t size)
+ : m_buffer (buffer),
+ m_size (size),
+ m_current (0)
+{
+ m_uid = m_buffer[m_current];
+}
+bool
+TraceContext::Iterator::IsLast (void) const
+{
+ if (m_buffer == 0 || m_uid == 0 || m_current >= m_size)
+ {
+ return true;
+ }
+ return false;
+}
+void
+TraceContext::Iterator::Next (void)
+{
+ if (m_buffer == 0)
+ {
+ return;
+ }
+ if (m_uid == 0)
+ {
+ return;
+ }
+ else
+ {
+ uint8_t size = ElementRegistry::GetSize (m_uid);
+ m_current += 1 + size;
+ }
+ m_uid = m_buffer[m_current];
+}
+std::string
+TraceContext::Iterator::Get (void) const
+{
+ std::string name = ElementRegistry::GetTypeName (m_uid);
+ return name;
+}
+
+TraceContext::TraceContext ()
+ : m_data (0)
+{}
+TraceContext::TraceContext (TraceContext const &o)
+ : m_data (o.m_data)
+{
+ if (m_data != 0)
+ {
+ m_data->count++;
+ }
+}
+TraceContext const &
+TraceContext::operator = (TraceContext const &o)
+{
+ if (m_data != 0)
+ {
+ m_data->count--;
+ if (m_data->count == 0)
+ {
+ uint8_t *buffer = (uint8_t *)m_data;
+ delete [] buffer;
+ }
+ }
+ m_data = o.m_data;
+ if (m_data != 0)
+ {
+ m_data->count++;
+ }
+ return *this;
+}
+TraceContext::~TraceContext ()
+{
+ if (m_data != 0)
+ {
+ m_data->count--;
+ if (m_data->count == 0)
+ {
+ uint8_t *buffer = (uint8_t *)m_data;
+ delete [] buffer;
+ }
+ }
+}
+
+void
+TraceContext::Union (TraceContext const &o)
+{
+ if (o.m_data == 0)
+ {
+ return;
+ }
+ uint16_t currentUid;
+ uint16_t i = 0;
+ while (i < o.m_data->size)
+ {
+ currentUid = o.m_data->data[i];
+ uint8_t size = ElementRegistry::GetSize (currentUid);
+ uint8_t *selfBuffer = CheckPresent (currentUid);
+ uint8_t *otherBuffer = &(o.m_data->data[i+1]);
+ if (selfBuffer != 0)
+ {
+ if (memcmp (selfBuffer, otherBuffer, size) != 0)
+ {
+ NS_FATAL_ERROR ("You cannot add TraceContexts which "<<
+ "have different values stored in them.");
+ }
+ }
+ else
+ {
+ DoAdd (currentUid, otherBuffer);
+ }
+ i += 1 + size;
+ }
+}
+
+uint8_t *
+TraceContext::CheckPresent (uint8_t uid) const
+{
+ if (m_data == 0)
+ {
+ return false;
+ }
+ uint8_t currentUid;
+ uint16_t i = 0;
+ do {
+ currentUid = m_data->data[i];
+ uint8_t size = ElementRegistry::GetSize (currentUid);
+ if (currentUid == uid)
+ {
+ return &m_data->data[i+1];
+ }
+ i += 1 + size;
+ } while (i < m_data->size && currentUid != 0);
+ return 0;
+}
+
+
+bool
+TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
+{
+ NS_ASSERT (uid != 0);
+ uint8_t size = ElementRegistry::GetSize (uid);
+ uint8_t *present = CheckPresent (uid);
+ if (present != 0) {
+ if (memcmp (present, buffer, size) == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ if (m_data == 0)
+ {
+ uint16_t newSize = 1 + size;
+ uint16_t allocatedSize;
+ if (newSize > 4)
+ {
+ allocatedSize = sizeof (struct Data) + newSize - 4;
+ }
+ else
+ {
+ allocatedSize = sizeof (struct Data);
+ }
+ struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
+ data->size = newSize;
+ data->count = 1;
+ data->data[0] = uid;
+ memcpy (data->data + 1, buffer, size);
+ m_data = data;
+ }
+ else
+ {
+ uint16_t newSize = m_data->size + 1 + size;
+ uint16_t allocatedSize;
+ if (newSize > 4)
+ {
+ allocatedSize = sizeof (struct Data) + newSize - 4;
+ }
+ else
+ {
+ allocatedSize = sizeof (struct Data);
+ }
+ struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
+ data->size = newSize;
+ data->count = 1;
+ memcpy (data->data, m_data->data, m_data->size);
+ data->data[m_data->size] = uid;
+ memcpy (data->data + m_data->size + 1, buffer, size);
+ m_data->count--;
+ if (m_data->count == 0)
+ {
+ uint8_t *buffer = (uint8_t *)m_data;
+ delete [] buffer;
+ }
+ m_data = data;
+ }
+ return true;
+}
+bool
+TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const
+{
+ if (m_data == 0)
+ {
+ return false;
+ }
+ uint8_t currentUid;
+ uint16_t i = 0;
+ do {
+ currentUid = m_data->data[i];
+ uint8_t size = ElementRegistry::GetSize (currentUid);
+ if (currentUid == uid)
+ {
+ memcpy (buffer, &m_data->data[i+1], size);
+ return true;
+ }
+ i += 1 + size;
+ } while (i < m_data->size && currentUid != 0);
+ return false;
+}
+
+void
+TraceContext::Print (std::ostream &os) const
+{
+ if (m_data == 0)
+ {
+ return;
+ }
+ uint8_t currentUid;
+ uint16_t i = 0;
+ do {
+ currentUid = m_data->data[i];
+ uint8_t size = ElementRegistry::GetSize (currentUid);
+ uint8_t *instance = &m_data->data[i+1];
+ ElementRegistry::Print (currentUid, instance, os);
+ i += 1 + size;
+ if (i < m_data->size && currentUid != 0)
+ {
+ os << " ";
+ }
+ else
+ {
+ break;
+ }
+ } while (true);
+}
+TraceContext::Iterator
+TraceContext::Begin (void) const
+{
+ if (m_data == 0)
+ {
+ return Iterator ();
+ }
+ return Iterator (m_data->data, m_data->size);
+}
+
+void
+TraceContext::PrintAvailable (std::ostream &os, std::string separator) const
+{
+ if (m_data == 0)
+ {
+ return;
+ }
+ uint8_t currentUid;
+ uint16_t i = 0;
+ do {
+ currentUid = m_data->data[i];
+ uint8_t size = ElementRegistry::GetSize (currentUid);
+ os << ElementRegistry::GetTypeName (currentUid);
+ i += 1 + size;
+ if (i < m_data->size && currentUid != 0)
+ {
+ os << separator;
+ }
+ else
+ {
+ break;
+ }
+ } while (true);
+}
+
+bool
+TraceContext::IsSimilar (const TraceContext &o) const
+{
+ if (m_data == 0 && o.m_data == 0)
+ {
+ return true;
+ }
+ if ((m_data != 0 && o.m_data == 0) ||
+ (m_data == 0 && o.m_data != 0))
+ {
+ return false;
+ }
+ uint8_t myCurrentUid;
+ uint16_t myI = 0;
+ uint8_t otherCurrentUid;
+ uint16_t otherI = 0;
+
+ myCurrentUid = m_data->data[myI];
+ otherCurrentUid = o.m_data->data[otherI];
+
+ while (myCurrentUid == otherCurrentUid &&
+ myCurrentUid != 0 &&
+ otherCurrentUid != 0 &&
+ myI < m_data->size &&
+ otherI < o.m_data->size)
+ {
+ uint8_t mySize = ElementRegistry::GetSize (myCurrentUid);
+ uint8_t otherSize = ElementRegistry::GetSize (otherCurrentUid);
+ myI += 1 + mySize;
+ otherI += 1 + otherSize;
+ myCurrentUid = m_data->data[myI];
+ otherCurrentUid = o.m_data->data[otherI];
+ }
+ if (myCurrentUid == 0 && otherCurrentUid == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+std::ostream& operator<< (std::ostream& os, const TraceContext &context)
+{
+ context.Print (os);
+ return os;
+}
+
+}//namespace ns3
+
+#include "test.h"
+#include <sstream>
+
+namespace ns3 {
+
+template <int N>
+class Ctx : public TraceContextElement
+{
+public:
+ static uint16_t GetUid (void) {static uint16_t uid = AllocateUid<Ctx<N> > (GetTypeName ()); return uid;}
+ static std::string GetTypeName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();}
+ Ctx () : m_v (0) {}
+ Ctx (int v) : m_v (v) {}
+ void Print (std::ostream &os) {os << N;}
+ int Get (void) const { return N;}
+private:
+ int m_v;
+};
+
+class TraceContextTest : public Test
+{
+public:
+ TraceContextTest ();
+ virtual bool RunTests (void);
+};
+
+TraceContextTest::TraceContextTest ()
+ : Test ("TraceContext")
+{}
+bool
+TraceContextTest::RunTests (void)
+{
+ bool ok = true;
+
+ TraceContext ctx;
+ Ctx<0> v0;
+ Ctx<0> v01 = Ctx<0> (1);
+ Ctx<1> v1;
+ Ctx<2> v2;
+ Ctx<3> v3;
+
+ if (ctx.SafeGet (v0))
+ {
+ ok = false;
+ }
+ ctx.AddElement (v0);
+ ctx.AddElement (v0);
+ if (ctx.SafeAdd (v01))
+ {
+ ok = false;
+ }
+ ctx.GetElement (v0);
+ ctx.AddElement (v1);
+ ctx.GetElement (v1);
+ ctx.GetElement (v0);
+ ctx.GetElement (v1);
+
+ TraceContext copy = ctx;
+ ctx.GetElement (v0);
+ ctx.GetElement (v1);
+ copy.GetElement (v0);
+ copy.GetElement (v1);
+ copy.AddElement (v2);
+ copy.GetElement (v0);
+ copy.GetElement (v1);
+ copy.GetElement (v2);
+ ctx.AddElement (v3);
+ ctx.GetElement (v0);
+ ctx.GetElement (v1);
+ ctx.GetElement (v3);
+
+ if (ctx.SafeGet (v2))
+ {
+ ok = false;
+ }
+ if (copy.SafeGet (v3))
+ {
+ ok = false;
+ }
+ ctx.Union (copy);
+ ctx.GetElement (v2);
+ if (copy.SafeGet (v3))
+ {
+ ok = false;
+ }
+ copy.Union (ctx);
+ copy.GetElement (v3);
+
+ return ok;
+}
+
+static TraceContextTest g_traceContextTest;
+
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,204 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TRACE_CONTEXT_H
+#define TRACE_CONTEXT_H
+
+#include <stdint.h>
+#include <vector>
+#include "fatal-error.h"
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+/**
+ * \brief Provide context to trace sources
+ * \ingroup tracing
+ *
+ * Instances of this class are used to hold context
+ * for each trace source. Each instance holds a list of
+ * TraceContextElement. Trace sinks can lookup these contexts
+ * from this list with the ns3::TraceContext::Get method.
+ * They can also ask the TraceContext for the list of
+ * TraceContextElements it contains with the PrintAvailable method.
+ *
+ * This class is implemented
+ * using Copy On Write which means that copying unmodified
+ * versions of this class is very cheap. However, modifying
+ * the content of this class through a call
+ * to ns3::TraceContext::AddElement or ns3::TraceContext::Union
+ * will trigger a costly memory reallocation if needed.
+ */
+class TraceContext
+{
+public:
+ TraceContext ();
+ TraceContext (TraceContext const &o);
+ TraceContext const & operator = (TraceContext const &o);
+ ~TraceContext ();
+
+ /**
+ * \param context add context to list of trace contexts.
+ *
+ * A copy of the input context is appended at the end of the list
+ * stored in this TraceContext.
+ */
+ template <typename T>
+ void AddElement (T const &context);
+
+ /**
+ * \param o the other context
+ *
+ * Perform the Union operation (in the sense of set theory) on the
+ * two input lists of elements. This method is used in the
+ * ns3::CallbackTraceSource class when multiple sinks are connected
+ * to a single source to ensure that the source does not need
+ * to store a single TraceContext instance per connected sink.
+ * Instead, all sinks share the same TraceContext.
+ */
+ void Union (TraceContext const &o);
+
+ /**
+ * \param context context to get from this list of trace contexts.
+ * \returns true if the requested trace context element was found
+ * in this TraceContext, false otherwise.
+ */
+ template <typename T>
+ bool GetElement (T &context) const;
+
+ /**
+ * \param os a c++ STL output stream
+ *
+ * Iterate over the list of TraceContextElement stored in this
+ * TraceContext and invoke each of their Print method.
+ */
+ void Print (std::ostream &os) const;
+ /**
+ * \param os a c++ STL output stream
+ * \param separator the separator inserted between each TraceContextElement typename.
+ *
+ * Print the typename of each TraceContextElement stored in this TraceContext.
+ */
+ void PrintAvailable (std::ostream &os, std::string separator) const;
+ class Iterator
+ {
+ public:
+ void Next (void);
+ bool IsLast (void) const;
+ std::string Get (void) const;
+ private:
+ friend class TraceContext;
+ Iterator ();
+ Iterator (uint8_t *buffer, uint16_t index);
+ uint8_t *m_buffer;
+ uint16_t m_size;
+ uint16_t m_current;
+ uint8_t m_uid;
+ };
+ Iterator Begin (void) const;
+ /**
+ * \param o another trace context
+ * \returns true if the input trace context contains exactly the same set of
+ * TraceContextElement instances, false otherwise.
+ *
+ * This method does not test for equality: the content of each matching
+ * TraceContextElement could be different. It merely checks that both
+ * trace contexts contain the same types of TraceContextElements.
+ */
+ bool IsSimilar (const TraceContext &o) const;
+private:
+ friend class TraceContextTest;
+ // used exclusively for testing code.
+ template <typename T>
+ bool SafeGet (T &context) const;
+ template <typename T>
+ bool SafeAdd (const T &context);
+
+ uint8_t *CheckPresent (uint8_t uid) const;
+ bool DoAdd (uint8_t uid, uint8_t const *buffer);
+ bool DoGet (uint8_t uid, uint8_t *buffer) const;
+
+ struct Data {
+ uint16_t count;
+ uint16_t size;
+ uint8_t data[4];
+ } * m_data;
+};
+
+std::ostream& operator<< (std::ostream& os, const TraceContext &context);
+
+}//namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+TraceContext::AddElement (T const &context)
+{
+ const TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
+ uint8_t *data = (uint8_t *) &context;
+ bool ok = DoAdd (T::GetUid (), data);
+ if (!ok)
+ {
+ NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid.");
+ }
+}
+template <typename T>
+bool
+TraceContext::GetElement (T &context) const
+{
+ TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
+ uint8_t *data = (uint8_t *) &context;
+ bool found = DoGet (T::GetUid (), data);
+ return found;
+}
+template <typename T>
+bool
+TraceContext::SafeGet (T &context) const
+{
+ TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
+ uint8_t *data = (uint8_t *) &context;
+ bool found = DoGet (T::GetUid (), data);
+ return found;
+}
+template <typename T>
+bool
+TraceContext::SafeAdd (const T &context)
+{
+ const TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
+ uint8_t *data = (uint8_t *) &context;
+ bool ok = DoAdd (T::GetUid (), data);
+ return ok;
+}
+}//namespace ns3
+
+#endif /* TRACE_CONTEXT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-doc.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,74 @@
+#include "trace-doc.h"
+
+namespace ns3 {
+
+TraceDoc::TraceDoc ()
+ : m_help ("empty help")
+{}
+
+TraceDoc::TraceDoc (std::string help)
+ : m_help (help)
+{}
+TraceDoc::TraceDoc (std::string help,
+ std::string arg0Type,
+ std::string arg0Help)
+ : m_help (help)
+{
+ m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+}
+TraceDoc::TraceDoc (std::string help,
+ std::string arg0Type,
+ std::string arg0Help,
+ std::string arg1Type,
+ std::string arg1Help)
+ : m_help (help)
+{
+ m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+ m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
+}
+TraceDoc::TraceDoc (std::string help,
+ std::string arg0Type,
+ std::string arg0Help,
+ std::string arg1Type,
+ std::string arg1Help,
+ std::string arg2Type,
+ std::string arg2Help)
+ : m_help (help)
+{
+ m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+ m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
+ m_argVector.push_back (std::make_pair (arg2Type, arg2Help));
+}
+TraceDoc::TraceDoc (std::string help,
+ std::string arg0Type,
+ std::string arg0Help,
+ std::string arg1Type,
+ std::string arg1Help,
+ std::string arg2Type,
+ std::string arg2Help,
+ std::string arg3Type,
+ std::string arg3Help)
+ : m_help (help)
+{
+ m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+ m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
+ m_argVector.push_back (std::make_pair (arg2Type, arg2Help));
+ m_argVector.push_back (std::make_pair (arg3Type, arg3Help));
+}
+std::string
+TraceDoc::GetHelp (void) const
+{
+ return m_help;
+}
+TraceDoc::Iterator
+TraceDoc::ArgsBegin (void) const
+{
+ return m_argVector.begin ();
+}
+TraceDoc::Iterator
+TraceDoc::ArgsEnd (void) const
+{
+ return m_argVector.end ();
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-doc.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,103 @@
+#ifndef TRACE_DOC_H
+#define TRACE_DOC_H
+
+#include <vector>
+#include <string>
+
+namespace ns3 {
+
+/**
+ * \brief describe the signature of a trace source
+ */
+class TraceDoc
+{
+ typedef std::vector<std::pair<std::string,std::string> > ArgVector;
+public:
+ typedef ArgVector::const_iterator Iterator;
+ TraceDoc ();
+ /**
+ * \param help a description of the purpose of the trace source
+ */
+ TraceDoc (std::string help);
+ /**
+ * \param help a description of the purpose of the trace source
+ * \param arg1Type the fully-qualified typename of the first argument of the trace source
+ * \param arg1Help the purpose of the first argument of the trace source
+ */
+ TraceDoc (std::string help,
+ std::string arg1Type,
+ std::string arg1Help);
+ /**
+ * \param help a description of the purpose of the trace source
+ * \param arg1Type the fully-qualified typename of the first argument of the trace source
+ * \param arg1Help the purpose of the first argument of the trace source
+ * \param arg2Type the fully-qualified typename of the second argument of the trace source
+ * \param arg2Help the purpose of the second argument of the trace source
+ */
+ TraceDoc (std::string help,
+ std::string arg1Type,
+ std::string arg1Help,
+ std::string arg2Type,
+ std::string arg2Help);
+ /**
+ * \param help a description of the purpose of the trace source
+ * \param arg1Type the fully-qualified typename of the first argument of the trace source
+ * \param arg1Help the purpose of the first argument of the trace source
+ * \param arg2Type the fully-qualified typename of the second argument of the trace source
+ * \param arg2Help the purpose of the second argument of the trace source
+ * \param arg3Type the fully-qualified typename of the third argument of the trace source
+ * \param arg3Help the purpose of the third argument of the trace source
+ */
+ TraceDoc (std::string help,
+ std::string arg1Type,
+ std::string arg1Help,
+ std::string arg2Type,
+ std::string arg2Help,
+ std::string arg3Type,
+ std::string arg3Help);
+ /**
+ * \param help a description of the purpose of the trace source
+ * \param arg1Type the fully-qualified typename of the first argument of the trace source
+ * \param arg1Help the purpose of the first argument of the trace source
+ * \param arg2Type the fully-qualified typename of the second argument of the trace source
+ * \param arg2Help the purpose of the second argument of the trace source
+ * \param arg3Type the fully-qualified typename of the third argument of the trace source
+ * \param arg3Help the purpose of the third argument of the trace source
+ * \param arg4Type the fully-qualified typename of the fourth argument of the trace source
+ * \param arg4Help the purpose of the fourth argument of the trace source
+ */
+ TraceDoc (std::string help,
+ std::string arg1Type,
+ std::string arg1Help,
+ std::string arg2Type,
+ std::string arg2Help,
+ std::string arg3Type,
+ std::string arg3Help,
+ std::string arg4Type,
+ std::string arg4Help);
+ /**
+ * \returns the help string associated to this trace source
+ */
+ std::string GetHelp (void) const;
+ /**
+ * \returns an iterator which points to the first descriptor of the trace source.
+ *
+ * Each descriptor is a pair of strings. The first one describes the type of the argument
+ * while the second one describeds the purpose of the argument.
+ */
+ Iterator ArgsBegin (void) const;
+ /**
+ * \returns an iterator which points to the last descriptor of the trace source.
+ *
+ * Each descriptor is a pair of strings. The first one describes the type of the argument
+ * while the second one describeds the purpose of the argument.
+ */
+ Iterator ArgsEnd (void) const;
+private:
+ ArgVector m_argVector;
+ std::string m_help;
+};
+
+} // namespace ns3
+
+#endif /* TRACE_DOC_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-resolver.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,107 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "trace-resolver.h"
+#include "log.h"
+
+NS_LOG_COMPONENT_DEFINE ("TraceResolver");
+
+namespace ns3 {
+
+TraceResolver::TraceResolver ()
+ : m_count (1)
+{}
+
+TraceResolver::~TraceResolver ()
+{}
+
+void
+TraceResolver::Ref (void)
+{
+ m_count++;
+}
+void
+TraceResolver::Unref (void)
+{
+ m_count--;
+ if (m_count == 0)
+ {
+ NS_LOG_LOGIC ("delete "<<this);
+ delete this;
+ }
+}
+
+std::string
+TraceResolver::GetElement (std::string path)
+{
+ std::string::size_type cur = 1;
+ // check that first char is "/"
+ std::string::size_type next = path.find ("/", cur);
+ std::string id = std::string (path, cur, next-1);
+ return id;
+}
+std::string
+TraceResolver::GetSubpath (std::string path)
+{
+ std::string::size_type cur = 1;
+ // check that first char is "/"
+ std::string::size_type next = path.find ("/", cur);
+ std::string subpath;
+ if (next != std::string::npos)
+ {
+ subpath = std::string (path, next, std::string::npos);
+ }
+ else
+ {
+ subpath = "";
+ }
+ return subpath;
+}
+
+void
+TraceResolver::SourceCollection::AddUnique (std::string path,
+ const TraceContext &context,
+ const TraceDoc &doc)
+{
+ for (SourceVector::const_iterator i = m_sources.begin (); i != m_sources.end (); i++)
+ {
+ if (i->path == path &&
+ context.IsSimilar (i->context))
+ {
+ return;
+ }
+ }
+ struct Source source;
+ source.path = path;
+ source.context = context;
+ source.doc = doc;
+ m_sources.push_back (source);
+}
+TraceResolver::SourceCollection::Iterator
+TraceResolver::SourceCollection::Begin (void) const
+{
+ return m_sources.begin ();
+}
+TraceResolver::SourceCollection::Iterator
+TraceResolver::SourceCollection::End (void) const
+{
+ return m_sources.end ();
+}
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-resolver.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,159 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TRACE_RESOLVER_H
+#define TRACE_RESOLVER_H
+
+#include <string>
+#include <list>
+#include "trace-context.h"
+#include "trace-doc.h"
+
+namespace ns3 {
+
+class CallbackBase;
+
+/**
+ * \brief the base class which is used to recursively perform trace
+ * namespace resolution.
+ * \ingroup tracing
+ *
+ * Although users could conceivably implement their own trace resolver
+ * subclasses, doing so is complicated so, it is recommended to use
+ * the default implementation ns3::CompositeTraceResolver instead.
+ */
+class TraceResolver
+{
+public:
+
+ TraceResolver ();
+ virtual ~TraceResolver ();
+ void Ref (void);
+ void Unref (void);
+
+ /**
+ * \param path the namespace path to resolver
+ * \param cb the callback to connect to the matching namespace
+ * \param context the context in which to store the trace context
+ *
+ * First, extract the leading path element from the input path, and
+ * match this leading patch element against any terminal trace source
+ * contained in this trace resolver.
+ * Second, recursively resolve the rest of the path using other
+ * objects if there are any.
+ * If there is any TraceContextElement associated to one of the matching
+ * elements, it should be added to the input TraceContext.
+ */
+ virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context) = 0;
+ /**
+ * \param path the namespace path to resolver
+ * \param cb the callback to disconnect in the matching namespace
+ *
+ * This method should behave as Connect.
+ */
+ virtual void Disconnect (std::string path, CallbackBase const &cb) = 0;
+
+ /**
+ * \brief hold a list of trace sources
+ */
+ class SourceCollection
+ {
+ public:
+ /**
+ * \brief describe a single trace source
+ */
+ struct Source
+ {
+ /**
+ * The trace path associated to this trace source
+ */
+ std::string path;
+ /**
+ * The trace context associated to this trace source
+ */
+ TraceContext context;
+ /**
+ * Document the signature of this trace source
+ */
+ TraceDoc doc;
+ };
+ typedef std::vector<struct Source>::const_iterator Iterator;
+ void AddUnique (std::string path,
+ const TraceContext &context,
+ const TraceDoc &doc);
+
+ /**
+ * \returns an iterator which points to the first element of the set of
+ * trace sources collected in this SourceCollection object.
+ */
+ Iterator Begin (void) const;
+ /**
+ * \returns an iterator which points to the last element of the set of
+ * trace sources collected in this SourceCollection object.
+ */
+ Iterator End (void) const;
+ private:
+ typedef std::vector<struct Source> SourceVector;
+ SourceVector m_sources;
+ };
+ /**
+ * \param path the path to the current recursive level.
+ * \param context the trace context associated to the current recursive level
+ * \param collection the collection in which to gather every trace source found.
+ *
+ * This method is invoked recursively until all trace sources have been
+ * stored in the output SourceCollection argument.
+ */
+ virtual void CollectSources (std::string path, const TraceContext &context,
+ SourceCollection *collection) = 0;
+
+ /**
+ * \param os the output stream to which ascii output should be written.
+ * \param context the context associated to the current recursive level.
+ *
+ * This method is invoked recursively until each trace source has been
+ * connected to a trace sink which can output an ascii representation
+ * of each trace event on the output stream specified.
+ */
+ virtual void TraceAll (std::ostream &os, const TraceContext &context) = 0;
+protected:
+ /**
+ * \param path a namespace path
+ * \returns the initial element of the path.
+ *
+ * If the input path is "/foo/...", the return
+ * value is "foo".
+ */
+ std::string GetElement (std::string path);
+ /**
+ * \param path a namespace path
+ * \returns the subpath.
+ *
+ * If the input path is "/foo/bar/...", the return
+ * value is "/bar/...".
+ */
+ std::string GetSubpath (std::string path);
+private:
+ uint32_t m_count;
+};
+
+}//namespace ns3
+
+#endif /* TRACE_RESOLVER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-source.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,31 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "trace-source.h"
+#include "trace-context.h"
+
+namespace ns3 {
+
+void
+TraceSource::AddCallback (CallbackBase const & callback)
+{
+ AddCallback (callback, TraceContext ());
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-source.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,61 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TRACE_SOURCE_H
+#define TRACE_SOURCE_H
+
+#include <ostream>
+
+namespace ns3 {
+
+class CallbackBase;
+class TraceContext;
+
+/**
+ * \brief the base class for all trace sources
+ *
+ * Every trace source which wishes to be connectable and disconnectable with
+ * the TraceResolver system should derive from this base class and implement
+ * all three methods below.
+ */
+class TraceSource
+{
+public:
+ virtual ~TraceSource () {}
+ /**
+ * \param callback the callback to connect to this trace source
+ * \param context the context associated to the input callback which should be passed
+ * back to the user.
+ */
+ virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) = 0;
+ /**
+ * \param callback the callback to connect to this trace source
+ */
+ void AddCallback (CallbackBase const & callback);
+ /**
+ * \param callback the callback to disconnect from this trace source
+ */
+ virtual void RemoveCallback (CallbackBase const & callback) = 0;
+ virtual void ConnectPrinter (std::ostream &os, TraceContext const &context) = 0;
+};
+
+} // namespace ns3
+
+#endif /* TRACE_SOURCE_H */
--- a/src/core/type-name.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/type-name.cc Fri Sep 28 11:59:46 2007 +0100
@@ -22,4 +22,5 @@
DEF_TYPE (float);
DEF_TYPE (double);
+
}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/type-traits.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,26 @@
+#ifndef TYPE_TRAITS_H
+#define TYPE_TRAITS_H
+
+template <typename T>
+struct TypeTraits;
+
+template <typename T>
+struct TypeTraits
+{
+ typedef T ReferencedType;
+};
+
+template <typename T>
+struct TypeTraits<const T &>
+{
+ typedef T ReferencedType;
+};
+
+template <typename T>
+struct TypeTraits<T &>
+{
+ typedef T ReferencedType;
+};
+
+
+#endif /* TYPE_TRAITS_H */
--- a/src/core/uid-manager.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/uid-manager.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,7 +19,8 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "uid-manager.h"
-#include "ns3/fatal-error.h"
+#include "fatal-error.h"
+#include "assert.h"
namespace ns3 {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/uv-trace-source.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,249 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef UV_TRACE_SOURCE_H
+#define UV_TRACE_SOURCE_H
+
+#include "callback-trace-source.h"
+#include "trace-source.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+class UVTraceSourceBase : public TraceSource {
+public:
+ typedef CallbackTraceSource<uint64_t, uint64_t> ChangeNotifyCallback;
+
+ UVTraceSourceBase ()
+ : m_callback () {}
+ /* We don't want to copy the base callback. Only setCallback on
+ * a specific instance will do something to it. */
+ UVTraceSourceBase (UVTraceSourceBase const &o)
+ : m_callback () {}
+ UVTraceSourceBase &operator = (UVTraceSourceBase const &o) {
+ return *this;
+ }
+ ~UVTraceSourceBase () {}
+
+ virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
+ m_callback.AddCallback (callback, context);
+ }
+ virtual void RemoveCallback (CallbackBase const & callback) {
+ m_callback.RemoveCallback (callback);
+ }
+ virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
+ m_callback.ConnectPrinter (os, context);
+ }
+
+protected:
+ void Notify (uint64_t oldVal, uint64_t newVal) {
+ if (oldVal != newVal)
+ {
+ m_callback (oldVal, newVal);
+ }
+ }
+private:
+ ChangeNotifyCallback m_callback;
+};
+
+template <typename T>
+class SVTraceSource;
+
+
+/**
+ * \brief trace variables of type "unsigned integer"
+ * \ingroup tracing
+ *
+ * This template class implements a POD type: it
+ * behaves like any other variable of type "unsigned integer"
+ * except that it also reports any changes to its
+ * value with its internal callback.
+ *
+ * To instantiate a 32-bit unsigned variable (to store
+ * a TCP counter for example), you would create a variable of type
+ * ns3::UVTraceSource<uint32_t> :
+ \code
+ #include <stdint.h>
+ #include "uv-trace-source.h"
+
+ ns3::UVTraceSource<uint32_t> var;
+ \endcode
+ * and you would use it like any other variable of type uint32_t:
+ \code
+ var += 12;
+ var = 10;
+ \endcode
+ */
+template <typename T>
+class UVTraceSource : public UVTraceSourceBase {
+public:
+ UVTraceSource ()
+ : m_var ()
+ {}
+ UVTraceSource (T const &var)
+ : m_var (var)
+ {}
+
+ UVTraceSource &operator = (UVTraceSource const &o) {
+ Assign (o.Get ());
+ return *this;
+ }
+ template <typename TT>
+ UVTraceSource &operator = (UVTraceSource<TT> const &o) {
+ Assign (o.Get ());
+ return *this;
+ }
+ template <typename TT>
+ UVTraceSource &operator = (SVTraceSource<TT> const &o) {
+ Assign (o.Get ());
+ return *this;
+ }
+ UVTraceSource &operator++ () {
+ Assign (Get () + 1);
+ return *this;
+ }
+ UVTraceSource &operator-- () {
+ Assign (Get () - 1);
+ return *this;
+ }
+ UVTraceSource operator++ (int) {
+ UVTraceSource old (*this);
+ ++*this;
+ return old;
+ }
+ UVTraceSource operator-- (int) {
+ UVTraceSource old (*this);
+ --*this;
+ return old;
+ }
+ operator T () const {
+ return Get ();
+ }
+
+
+ void Assign (T var) {
+ Notify (m_var, var);
+ m_var = var;
+ }
+ T Get (void) const {
+ return m_var;
+ }
+
+private:
+ T m_var;
+};
+
+template <typename T>
+UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () + rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () - rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () * rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () / rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () << rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () >> rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () & rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () | rhs.Get ());
+ return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+ lhs.Assign (lhs.Get () ^ rhs.Get ());
+ return lhs;
+}
+
+
+template <typename T, typename U>
+UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () + rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () - rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () * rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () / rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () << rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () >> rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () & rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () | rhs);
+ return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, U const &rhs) {
+ lhs.Assign (lhs.Get () ^ rhs);
+ return lhs;
+}
+
+}; // namespace ns3
+
+#endif /* UV_TRACE_SOURCE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/variable-tracer-test.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,272 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "uv-trace-source.h"
+#include "sv-trace-source.h"
+#include "trace-context.h"
+#include "test.h"
+#include "callback.h"
+
+
+namespace ns3 {
+
+class Foo {
+public:
+ void Notify (TraceContext const &contex, uint64_t oldVal, uint64_t newVal) {}
+};
+
+class VariableTracerTest: public Test {
+public:
+ VariableTracerTest ();
+ void RunUnsignedTests (void);
+ void RunSignedUnsignedTests (void);
+ virtual bool RunTests (void);
+};
+void
+VariableTracerTest::RunUnsignedTests (void)
+{
+ UVTraceSource<uint32_t> var, ovar, tmp;
+ uint32_t utmp;
+ Foo *foo = new Foo ();
+
+ var.AddCallback (MakeCallback (&Foo::Notify, foo), TraceContext ());
+
+ var = 10;
+ ovar = var;
+
+ if (var == ovar)
+ {
+ }
+ if (var != ovar)
+ {
+ }
+ if (var > ovar)
+ {
+ }
+ if (var >= ovar)
+ {
+ }
+ if (var < ovar)
+ {
+ }
+
+ if (var <= ovar)
+
+ if (var == 1)
+ {
+ }
+ if (var != 1)
+ {
+ }
+ if (var > 1)
+ {
+ }
+ if (var >= 1)
+ {
+ }
+ if (var < 1)
+ {
+ }
+ if (var <= 1)
+ {
+ }
+
+ if (1 == ovar)
+ {
+ }
+ if (1 != ovar)
+ {
+ }
+ if (1 > ovar)
+ {
+ }
+ if (1 >= ovar)
+ {
+ }
+ if (1 < ovar)
+ {
+ }
+ if (1 <= ovar)
+ {
+ }
+
+ var++;
+ ++var;
+ var--;
+ --var;
+
+ tmp = var + ovar;
+ tmp = var - ovar;
+ tmp = var / ovar;
+ tmp = var * ovar;
+ tmp = var << ovar;
+ tmp = var >> ovar;
+ tmp = var & ovar;
+ tmp = var | ovar;
+ tmp = var ^ ovar;
+
+ tmp = var + 1;
+ tmp = var - 1;
+ tmp = var / 1;
+ tmp = var * 1;
+ tmp = var << 1;
+ tmp = var >> 1;
+ tmp = var & 1;
+ tmp = var | 1;
+ tmp = var ^ 1;
+
+ tmp = 1 + ovar;
+ tmp = 1 - ovar;
+ tmp = 1 / ovar;
+ tmp = 1 * ovar;
+ tmp = 1 << ovar;
+ tmp = 1 >> ovar;
+ tmp = 1 & ovar;
+ tmp = 1 | ovar;
+ tmp = 1 ^ ovar;
+
+ tmp += var;
+ tmp -= var;
+ tmp /= var;
+ tmp *= var;
+ tmp <<= var;
+ tmp >>= var;
+ tmp &= var;
+ tmp |= var;
+ tmp ^= var;
+
+ tmp += 1;
+ tmp -= 1;
+ tmp /= 1;
+ tmp *= 1;
+ tmp <<= 1;
+ tmp >>= 1;
+ tmp &= 1;
+ tmp |= 1;
+ tmp ^= 1;
+
+
+ utmp = var + ovar;
+ utmp = var - ovar;
+ utmp = var / ovar;
+ utmp = var * ovar;
+ utmp = var << ovar;
+ utmp = var >> ovar;
+ utmp = var & ovar;
+ utmp = var | ovar;
+ utmp = var ^ ovar;
+
+ utmp = var + 1;
+ utmp = var - 1;
+ utmp = var / 1;
+ utmp = var * 1;
+ utmp = var << 1;
+ utmp = var >> 1;
+ utmp = var & 1;
+ utmp = var | 1;
+ utmp = var ^ 1;
+
+ utmp = 1 + ovar;
+ utmp = 1 - ovar;
+ utmp = 1 / ovar;
+ utmp = 1 * ovar;
+ utmp = 1 << ovar;
+ utmp = 1 >> ovar;
+ utmp = 1 & ovar;
+ utmp = 1 | ovar;
+ utmp = 1 ^ ovar;
+
+ utmp += var;
+ utmp -= var;
+ utmp /= var;
+ utmp *= var;
+ utmp <<= var;
+ utmp >>= var;
+ utmp &= var;
+ utmp |= var;
+ utmp ^= var;
+
+ utmp += 1;
+ utmp -= 1;
+ utmp /= 1;
+ utmp *= 1;
+ utmp <<= 1;
+ utmp >>= 1;
+ utmp &= 1;
+ utmp |= 1;
+ utmp ^= 1;
+
+ delete foo;
+}
+
+void
+VariableTracerTest::RunSignedUnsignedTests (void)
+{
+ unsigned short utmp = 10;
+ unsigned int uitmp = 7;
+ short stmp = 5;
+ utmp = stmp;
+ utmp += stmp;
+ uitmp = utmp;
+ utmp = uitmp;
+
+ UVTraceSource<unsigned short> uvar = 10;
+ UVTraceSource<unsigned int> uivar = 5;
+ SVTraceSource<short> svar = 5;
+ SVTraceSource<int> sivar = 5;
+ uvar = svar;
+ svar = uvar;
+ uvar += svar;
+ svar += uvar;
+
+ uvar = sivar;
+ sivar = uvar;
+ uvar += sivar;
+ sivar += uvar;
+
+ uivar = uvar;
+ uvar = uivar;
+ uivar += uvar;
+ uvar += uivar;
+
+ sivar = svar;
+ svar = sivar;
+ sivar += svar;
+ svar += sivar;
+}
+
+bool
+VariableTracerTest::RunTests (void)
+{
+ RunUnsignedTests ();
+ RunSignedUnsignedTests ();
+
+ return true;
+}
+
+VariableTracerTest::VariableTracerTest ()
+ : Test ("VariableTracer") {}
+
+static VariableTracerTest gVariableTracerTest;
+
+}; // namespace ns3
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/core/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -3,8 +3,6 @@
def configure(conf):
- conf.env.append_value('NS3_MODULES', 'ns3-core')
-
e = conf.create_header_configurator()
e.mandatory = False
e.name = 'stdlib.h'
@@ -17,18 +15,23 @@
e.define = 'HAVE_GETENV'
e.run()
+ e = conf.create_header_configurator()
+ e.mandatory = False
+ e.name = 'signal.h'
+ e.define = 'HAVE_SIGNAL_H'
+ e.run()
+
conf.write_config_header('ns3/core-config.h')
def build(bld):
- core = bld.create_obj('cpp', 'shlib')
- core.name = 'ns3-core'
- core.target = core.name
+ core = bld.create_ns3_module('core')
core.source = [
'callback-test.cc',
'debug.cc',
- 'assert.cc',
+ 'log.cc',
+ 'breakpoint.cc',
'ptr.cc',
'object.cc',
'test.cc',
@@ -39,6 +42,15 @@
'command-line.cc',
'type-name.cc',
'component-manager.cc',
+ 'random-variable-default-value.cc',
+ 'variable-tracer-test.cc',
+ 'trace-context.cc',
+ 'trace-context-element.cc',
+ 'trace-resolver.cc',
+ 'callback-trace-source.cc',
+ 'composite-trace-resolver.cc',
+ 'trace-doc.cc',
+ 'trace-source.cc',
]
if sys.platform == 'win32':
@@ -58,7 +70,9 @@
'ptr.h',
'object.h',
'debug.h',
+ 'log.h',
'assert.h',
+ 'breakpoint.h',
'fatal-error.h',
'test.h',
'random-variable.h',
@@ -67,5 +81,18 @@
'command-line.h',
'type-name.h',
'component-manager.h',
+ 'type-traits.h',
+ 'random-variable-default-value.h',
+ 'trace-source.h',
+ 'uv-trace-source.h',
+ 'sv-trace-source.h',
+ 'fv-trace-source.h',
+ 'callback-trace-source.h',
+ 'trace-context.h',
+ 'trace-context-element.h',
+ 'trace-resolver.h',
+ 'composite-trace-resolver.h',
+ 'array-trace-resolver.h',
+ 'trace-doc.h',
]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007, Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "backoff.h"
+
+namespace ns3 {
+
+Backoff::Backoff()
+{
+ m_slotTime = MicroSeconds(1);
+ m_minSlots = 1;
+ m_maxSlots = 1000;
+ m_ceiling = 10;
+ m_maxRetries = 1000;
+
+ ResetBackoffTime();
+}
+
+Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+ uint32_t ceiling, uint32_t maxRetries)
+{
+ m_slotTime = slotTime;
+ m_minSlots = minSlots;
+ m_maxSlots = maxSlots;
+ m_ceiling = ceiling;
+ m_maxRetries = maxRetries;
+}
+
+Time
+Backoff::GetBackoffTime (void)
+{
+ Time backoff;
+ uint32_t ceiling;
+
+ if ((m_ceiling > 0) &&(m_numBackoffRetries > m_ceiling))
+ ceiling = m_ceiling;
+ else
+ ceiling = m_numBackoffRetries;
+
+ uint32_t minSlot = m_minSlots;
+ uint32_t maxSlot = (uint32_t)pow(2, ceiling) - 1;
+ if (maxSlot > m_maxSlots)
+ maxSlot = m_maxSlots;
+
+ uint32_t backoffSlots =
+ (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot);
+
+ backoff = Scalar(backoffSlots) * m_slotTime;
+ return (backoff);
+}
+
+void Backoff::ResetBackoffTime (void)
+{
+ m_numBackoffRetries = 0;
+}
+
+bool Backoff::MaxRetriesReached(void) {
+ return (m_numBackoffRetries >= m_maxRetries);
+}
+
+void Backoff::IncrNumRetries(void) {
+ m_numBackoffRetries++;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+Transmi */
+
+#ifndef BACKOFF_H
+#define BACKOFF_H
+
+#include <stdint.h>
+#include "ns3/nstime.h"
+#include "ns3/random-variable.h"
+
+namespace ns3 {
+
+ /**
+ * \brief The backoff class is used for calculating backoff times
+ * when many net devices can write to the same channel
+ *
+ */
+
+class Backoff {
+public:
+ uint32_t m_minSlots; // Minimum number of backoff slots (when
+ // multiplied by m_slotTime, determines minimum
+ // backoff time)
+ uint32_t m_maxSlots; // Maximim number of backoff slots (when
+ // multiplied by m_slotTime, determines
+ // maximum backoff time)
+ uint32_t m_ceiling; // Caps the exponential function when the
+ // number of retries reaches m_ceiling
+ uint32_t m_maxRetries; // Maximum number of transmission retries
+ // before the packet is dropped.
+ Time m_slotTime; // Length of one slot. A slot time, it usually
+ // the packet transmission time, if the packet
+ // size is fixed.
+
+ Backoff();
+ Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+ uint32_t ceiling, uint32_t maxRetries);
+
+ /**
+ * \return The amount of time that the net device should wait before
+ * trying to retransmit the packet
+ */
+ Time GetBackoffTime();
+ /**
+ * Indicates to the backoff object that the last packet was
+ * successfully transmitted and that the number of retries should be
+ * reset to 0.
+ */
+ void ResetBackoffTime();
+ /**
+ * \return True if the maximum number of retries has been reached
+ */
+ bool MaxRetriesReached();
+ /**
+ * Increments the number of retries by 1.
+ */
+ void IncrNumRetries();
+
+private:
+ uint32_t m_numBackoffRetries; // Number of times that the
+ // transmitter has tried to
+ // unsuccessfully transmit the current
+ // packet
+};
+
+}; // namespace ns3
+
+#endif // BACKOFF_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,374 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CsmaChannel");
+
+namespace ns3 {
+
+CsmaDeviceRec::CsmaDeviceRec()
+{
+ active = false;
+}
+
+CsmaDeviceRec::CsmaDeviceRec(Ptr<CsmaNetDevice> device)
+{
+ devicePtr = device;
+ active = true;
+}
+
+bool
+CsmaDeviceRec::IsActive() {
+ return active;
+}
+
+
+//
+// By default, you get a channel with the name "Csma Channel" that
+// has an "infitely" fast transmission speed and zero delay.
+CsmaChannel::CsmaChannel()
+:
+ Channel ("Csma Channel"),
+ m_bps (DataRate(0xffffffff)),
+ m_delay (Seconds(0))
+{
+ NS_LOG_FUNCTION;
+ Init();
+}
+
+CsmaChannel::CsmaChannel(
+ const DataRate& bps,
+ const Time& delay)
+:
+ Channel ("Csma Channel"),
+ m_bps (bps),
+ m_delay (delay)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << Channel::GetName() << ", " << bps.GetBitRate() <<
+ ", " << delay << ")");
+ Init();
+}
+
+CsmaChannel::CsmaChannel(
+ const std::string& name,
+ const DataRate& bps,
+ const Time& delay)
+:
+ Channel (name),
+ m_bps (bps),
+ m_delay (delay)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << name << ", " << bps.GetBitRate() << ", " << delay <<
+ ")");
+ Init();
+}
+
+void CsmaChannel::Init() {
+ m_state = IDLE;
+ m_deviceList.clear();
+}
+
+int32_t
+CsmaChannel::Attach(Ptr<CsmaNetDevice> device)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << device << ")");
+ NS_ASSERT(device != 0);
+
+ CsmaDeviceRec rec(device);
+
+ m_deviceList.push_back(rec);
+ return (m_deviceList.size() - 1);
+}
+
+bool
+CsmaChannel::Reattach(Ptr<CsmaNetDevice> device)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << device << ")");
+ NS_ASSERT(device != 0);
+
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->devicePtr == device)
+ {
+ if (!it->active)
+ {
+ it->active = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+CsmaChannel::Reattach(uint32_t deviceId)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << deviceId << ")");
+
+ if (deviceId < m_deviceList.size())
+ {
+ return false;
+ }
+
+ if (m_deviceList[deviceId].active)
+ {
+ return false;
+ }
+ else
+ {
+ m_deviceList[deviceId].active = true;
+ return true;
+ }
+}
+
+bool
+CsmaChannel::Detach(uint32_t deviceId)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << deviceId << ")");
+
+ if (deviceId < m_deviceList.size())
+ {
+ if (!m_deviceList[deviceId].active)
+ {
+ 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 << ")");
+ // Here we will need to place a warning in the packet
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+CsmaChannel::Detach(Ptr<CsmaNetDevice> device)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << device << ")");
+ NS_ASSERT(device != 0);
+
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if ((it->devicePtr == device) && (it->active))
+ {
+ it->active = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CsmaChannel::TransmitStart(Packet& p, uint32_t srcId)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ", " << srcId << ")");
+ NS_LOG_INFO ("UID is " << p.GetUid () << ")");
+
+ if (m_state != IDLE)
+ {
+ NS_LOG_WARN ("state is not IDLE");
+ return false;
+ }
+
+ if (!IsActive(srcId))
+ {
+ NS_LOG_ERROR ("Seclected source is not currently attached to network");
+ return false;
+ }
+
+ NS_LOG_LOGIC ("switch to TRANSMITTING");
+ m_currentPkt = p;
+ m_currentSrc = srcId;
+ m_state = TRANSMITTING;
+ return true;
+}
+
+bool
+CsmaChannel::IsActive(uint32_t deviceId)
+{
+ return (m_deviceList[deviceId].active);
+}
+
+bool
+CsmaChannel::TransmitEnd()
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &m_currentPkt << ", " << m_currentSrc << ")");
+ NS_LOG_INFO ("UID is " << m_currentPkt.GetUid () << ")");
+
+ NS_ASSERT(m_state == TRANSMITTING);
+ m_state = PROPAGATING;
+
+ bool retVal = true;
+
+ if (!IsActive(m_currentSrc)) {
+ NS_LOG_ERROR ("Seclected source was detached before the end of the"
+ "transmission");
+ retVal = false;
+ }
+
+ NS_LOG_LOGIC ("Schedule event in " << m_delay.GetSeconds () << " sec");
+
+ Simulator::Schedule (m_delay,
+ &CsmaChannel::PropagationCompleteEvent,
+ this);
+ return retVal;
+}
+
+void
+CsmaChannel::PropagationCompleteEvent()
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &m_currentPkt << ")");
+ NS_LOG_INFO ("UID is " << m_currentPkt.GetUid () << ")");
+
+ NS_ASSERT(m_state == PROPAGATING);
+
+ NS_LOG_LOGIC ("Receive");
+
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->IsActive())
+ {
+ it->devicePtr->Receive (m_currentPkt);
+ }
+ }
+ m_state = IDLE;
+}
+
+
+uint32_t
+CsmaChannel::GetNumActDevices (void)
+{
+ int numActDevices = 0;
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->active)
+ {
+ numActDevices++;
+ }
+ }
+ return numActDevices;
+}
+
+// This is not the number of active devices. This is the total number
+// of devices even if some were detached after.
+uint32_t
+CsmaChannel::GetNDevices (void) const
+{
+ return (m_deviceList.size());
+}
+
+Ptr<NetDevice>
+CsmaChannel::GetDevice (uint32_t i) const
+{
+ Ptr< CsmaNetDevice > netDevice;
+
+ netDevice = m_deviceList[i].devicePtr;
+ return netDevice;
+}
+
+int32_t
+CsmaChannel::GetDeviceNum (Ptr<CsmaNetDevice> device)
+{
+ std::vector<CsmaDeviceRec>::iterator it;
+ int i = 0;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->devicePtr == device)
+ {
+ if (it->active)
+ {
+ return i;
+ }
+ else
+ {
+ return -2;
+ }
+ }
+ i++;
+ }
+ return -1;
+}
+
+bool
+CsmaChannel::IsBusy (void)
+{
+ if (m_state == IDLE)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+DataRate
+CsmaChannel::GetDataRate (void)
+{
+ return m_bps;
+}
+
+Time
+CsmaChannel::GetDelay (void)
+{
+ return m_delay;
+}
+
+WireState
+CsmaChannel::GetState(void)
+{
+ return m_state;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,307 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise<emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef CSMA_CHANNEL_H
+#define CSMA_CHANNEL_H
+
+#include "ns3/channel.h"
+#include "ns3/ptr.h"
+#include "ns3/packet.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class CsmaNetDevice;
+
+ /**
+ * \brief CsmaNetDevice Record
+ *
+ * Stores the information related to each net device that is
+ * connected to the channel.
+ */
+ class CsmaDeviceRec {
+ public:
+ Ptr< CsmaNetDevice > devicePtr; /// Pointer to the net device
+ bool active; /// Is net device enabled to TX/RX
+
+ CsmaDeviceRec();
+ CsmaDeviceRec(Ptr< CsmaNetDevice > device);
+ /*
+ * \return If the net device pointed to by the devicePtr is active
+ * and ready to RX/TX.
+ */
+ bool IsActive();
+ };
+
+ /**
+ * Current state of the channel
+ */
+ enum WireState
+ {
+ IDLE, /**< Channel is IDLE, no packet is being
+ transmitted */
+ TRANSMITTING, /**< Channel is BUSY, a packet is being written
+ by a net device */
+ PROPAGATING /**< Channel is BUSY, packet is propagating to
+ all attached net devices */
+ };
+
+/**
+ * \brief Csma Channel.
+ *
+ * This class represents a simple Csma channel that can be used
+ * when many nodes are connected to one wire. It uses a single busy
+ * flag to indicate if the channel is currently in use. It does not
+ * take into account the distances between stations or the speed of
+ * light to determine collisions.
+ *
+ * Each net device must query the state of the channel and make sure
+ * that it is IDLE before writing a packet to the channel.
+ *
+ * When the channel is instaniated, the constructor takes parameters
+ * for a single speed, in bits per second, and a speed-of-light delay
+ * time as a Time object. When a net device is attached to a channel,
+ * it is assigned a device ID, this is in order to facilitate the
+ * check that makes sure that a net device that is trying to send a
+ * packet to the channel is really connected to this channel
+ *
+ */
+class CsmaChannel : public Channel {
+public:
+ /**
+ * \brief Create a CsmaChannel
+ *
+ * By default, you get a channel with the name "Csma Channel" that
+ * has an "infitely" fast transmission speed and zero delay.
+ */
+ CsmaChannel ();
+
+ /**
+ * \brief Create a CsmaChannel
+ *
+ * \param bps The bitrate of the channel
+ * \param delay Transmission delay through the channel
+ */
+ CsmaChannel (const DataRate& bps, const Time& delay);
+
+ /**
+ * \brief Create a CsmaChannel
+ *
+ * \param name the name of the channel for identification purposes
+ * \param bps The bitrate of the channel
+ * \param delay Transmission delay through the channel
+ */
+ CsmaChannel (const std::string& name,
+ const DataRate& bps, const Time& delay);
+
+ /**
+ * \brief Attach a given netdevice to this channel
+ *
+ * \param device Device pointer to the netdevice to attach to the channel
+ * \return The assigned device number
+ */
+ int32_t Attach (Ptr<CsmaNetDevice> device);
+ /**
+ * \brief Detach a given netdevice from this channel
+ *
+ * The net device is marked as inactive and it is not allowed to
+ * receive or transmit packets
+ *
+ * \param device Device pointer to the netdevice to detach from the channel
+ * \return True if the device is found and attached to the channel,
+ * false if the device is not currently connected to the channel or
+ * can't be found.
+ */
+ bool Detach (Ptr<CsmaNetDevice> device);
+ /**
+ * \brief Detach a given netdevice from this channel
+ *
+ * The net device is marked as inactive and it is not allowed to
+ * receive or transmit packets
+ *
+ * \param deviceId The deviceID assigned to the net device when it
+ * was connected to the channel
+ * \return True if the device is found and attached to the channel,
+ * false if the device is not currently connected to the channel or
+ * can't be found.
+ */
+ bool Detach (uint32_t deviceId);
+ /**
+ * \brief Reattach a previously detached net device to the channel
+ *
+ * The net device is marked as active. It is now allowed to receive
+ * or transmit packets. The net device must have been previously
+ * attached to the channel using the attach function.
+ *
+ * \param deviceId The device ID assigned to the net device when it
+ * was connected to the channel
+ * \return True if the device is found and is not attached to the
+ * channel, false if the device is currently connected to the
+ * channel or can't be found.
+ */
+ bool Reattach(uint32_t deviceId);
+ /**
+ * \brief Reattach a previously detached net device to the channel
+ *
+ * The net device is marked as active. It is now allowed to receive
+ * or transmit packets. The net device must have been previously
+ * attached to the channel using the attach function.
+ *
+ * \param device Device pointer to the netdevice to detach from the channel
+ * \return True if the device is found and is not attached to the
+ * channel, false if the device is currently connected to the
+ * channel or can't be found.
+ */
+ bool Reattach(Ptr<CsmaNetDevice> device);
+ /**
+ * \brief Start transmitting a packet over the channel
+ *
+ * If the srcId belongs to a net device that is connected to the
+ * channel, packet transmission begins, and the channel becomes busy
+ * until the packet has completely reached all destinations.
+ *
+ * \param p A reference to the packet that will be transmitted over
+ * the channel
+ * \param srcId The device Id of the net device that wants to
+ * transmit on the channel.
+ * \return True if the channel is not busy and the transmitting net
+ * device is currently active.
+ */
+ bool TransmitStart (Packet& p, uint32_t srcId);
+ /**
+ * \brief Indicates that the net device has finished transmitting
+ * the packet over the channel
+ *
+ * The channel will stay busy until the packet has completely
+ * propagated to all net devices attached to the channel. The
+ * TransmitEnd function schedules the PropagationCompleteEvent which
+ * will free the channel for further transmissions. Stores the
+ * packet p as the m_currentPkt, the packet being currently
+ * transmitting.
+ *
+ * \return Returns true unless the source was detached before it
+ * completed its transmission.
+ */
+ bool TransmitEnd ();
+ /**
+ * \brief Indicates that the channel has finished propagating the
+ * current packet. The channel is released and becomes free.
+ *
+ * Calls the receive function of every active net device that is
+ * attached to the channel.
+ */
+ void PropagationCompleteEvent();
+ /**
+ * \return Returns the device number assigned to a net device by the
+ * channel
+ *
+ * \param device Device pointer to the netdevice for which the device
+ * number is needed
+ */
+ int32_t GetDeviceNum (Ptr<CsmaNetDevice> device);
+ /**
+ * \return Returns the state of the channel (IDLE -- free,
+ * TRANSMITTING -- busy, PROPAGATING - busy )
+ */
+ WireState GetState();
+
+ /**
+ * \brief Indicates if the channel is busy. The channel will only
+ * accept new packets for transmission if it is not busy.
+ *
+ * \return Returns true if the channel is busy and false if it is
+ * free.
+ */
+ bool IsBusy();
+
+ /**
+ * \brief Indicates if a net device is currently attached or
+ * detached from the channel.
+ *
+ * \param deviceId The ID that was assigned to the net device when
+ * it was attached to the channel.
+ * \return Returns true if the net device is attached to the
+ * channel, false otherwise.
+ */
+ bool IsActive(uint32_t deviceId);
+ /**
+ * \return Returns the number of net devices that are currently
+ * attached to the channel.
+ */
+ uint32_t GetNumActDevices (void);
+ /**
+ * \return Returns the total number of devices including devices
+ * that have been detached from the channel.
+ */
+ virtual uint32_t GetNDevices (void) const;
+ /**
+ * \param i The deviceId of the net device for which we want the
+ * pointer.
+ * \return Returns the pointer to the net device that is associated
+ * with deviceId i.
+ */
+ virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
+ virtual DataRate GetDataRate (void);
+ virtual Time GetDelay (void);
+
+private:
+ DataRate m_bps; /// Data rate of the channel
+ Time m_delay; /// Delay of the channel.
+
+ /**
+ * List of the net devices that have been or are currently connected
+ * to the channel.
+ *
+ * Devices are nor removed from this list, they are marked as
+ * inactive. Otherwise the assigned device IDs will not refer to the
+ * correct NetDevice. The DeviceIds are used so that it is possible
+ * to have a number to refer to an entry in the list so that the
+ * whole list does not have to be searched when making sure that a
+ * source is attached to a channel when it is transmitting data.
+ */
+ std::vector< CsmaDeviceRec > m_deviceList;
+ /**
+ * Packet that is currently being transmitted on the channel (or last
+ * packet to have been transmitted on the channel if the channel is
+ * free.)
+ */
+ Packet m_currentPkt;
+ /**
+ * Device Id of the source that is currently transmitting on the
+ * channel. Or last source to have transmitted a packet on the
+ * channel, if the channel is currently not busy.
+ */
+ uint32_t m_currentSrc;
+ /**
+ * Current state of the channel
+ */
+ WireState m_state;
+ /**
+ * Initializes the channel when it is constructed. Resets the
+ * deviceList and sets the channel state to IDLE.
+ */
+ void Init (void);
+};
+
+} // namespace ns3
+
+#endif /* CSMA_CHANNEL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,151 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#include <algorithm>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/nstime.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-ipv4-topology.h"
+
+namespace ns3 {
+
+uint32_t
+CsmaIpv4Topology::AddIpv4CsmaNetDevice(
+ Ptr<Node> node,
+ Ptr<CsmaChannel> channel,
+ Mac48Address addr)
+{
+ Ptr<Queue> q = Queue::CreateDefault ();
+
+ // assume full-duplex
+ Ptr<CsmaNetDevice> nd = Create<CsmaNetDevice> (node, addr,
+ ns3::CsmaNetDevice::IP_ARP, true, true);
+
+ nd->AddQueue(q);
+ nd->Attach (channel);
+ return nd->GetIfIndex ();
+}
+
+
+void
+CsmaIpv4Topology::AddIpv4LlcCsmaNode(Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Mac48Address addr)
+{
+ Ptr<Queue> q = Queue::CreateDefault ();
+
+ Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::LLC,
+ true, false);
+ nd0->AddQueue(q);
+ nd0->Attach (ch);
+
+ Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::LLC,
+ false, true);
+ nd1->AddQueue(q);
+ nd1->Attach (ch);
+}
+
+void
+CsmaIpv4Topology::AddIpv4RawCsmaNode(Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Mac48Address addr)
+{
+ Ptr<Queue> q = Queue::CreateDefault ();
+
+ Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::RAW,
+ true, false);
+ nd0->AddQueue(q);
+ nd0->Attach (ch);
+
+ Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::RAW,
+ false, true);
+ nd1->AddQueue(q);
+ nd1->Attach (ch);
+}
+
+uint32_t
+CsmaIpv4Topology::AddIpv4Address(
+ Ptr<Node> node,
+ uint32_t netDeviceNumber,
+ const Ipv4Address address,
+ const Ipv4Mask mask)
+{
+ Ptr<NetDevice> nd = node->GetDevice(netDeviceNumber);
+
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t ifIndex = ipv4->AddInterface (nd);
+
+ ipv4->SetAddress (ifIndex, address);
+ ipv4->SetNetworkMask (ifIndex, mask);
+ ipv4->SetUp (ifIndex);
+ return ifIndex;
+}
+
+void
+CsmaIpv4Topology::AddIpv4Routes (
+ Ptr<NetDevice> nd1, Ptr<NetDevice> nd2)
+{
+ // Assert that both are Ipv4 nodes
+ Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+ Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT(ip1 != 0 && ip2 != 0);
+
+ // Get interface indexes for both nodes corresponding to the right channel
+ uint32_t index1 = 0;
+ bool found = false;
+ for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
+ {
+ if (ip1 ->GetNetDevice (i) == nd1)
+ {
+ index1 = i;
+ found = true;
+ }
+ }
+ NS_ASSERT (found);
+
+ uint32_t index2 = 0;
+ found = false;
+ for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
+ {
+ if (ip2 ->GetNetDevice (i) == nd2)
+ {
+ index2 = i;
+ found = true;
+ }
+ }
+ NS_ASSERT (found);
+
+ ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
+ ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2);
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#ifndef __CSMA_IPV4_TOPOLOGY_H__
+#define __CSMA_IPV4_TOPOLOGY_H__
+
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-net-device.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaIpv4Channel;
+class Node;
+class IPAddr;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Topologies based on the
+ * InternetNodes and CsmaChannels. Either the
+ * SimpleCsmaNetDevice or the LLCCsmaNetDevice can be used
+ * when constructing these topologies.
+ */
+class CsmaIpv4Topology {
+public:
+
+ /**
+ * \param n1 Node to be attached to the Csma channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr Mac address of the node
+ *
+ * Add a Csma node to a Csma channel. This function adds
+ * a EthernetCsmaNetDevice to the nodes so that they can
+ * connect to a CsmaChannel. This means that Ethernet headers
+ * and trailers will be added to the packet before sending out on
+ * the net device.
+ *
+ * \return ifIndex of the device
+ */
+ static uint32_t AddIpv4CsmaNetDevice(Ptr<Node> node,
+ Ptr<CsmaChannel> channel,
+ Mac48Address addr);
+
+ /**
+ * \param n1 Node to be attached to the Csma channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr Mac address of the node
+ *
+ * Add a Csma node to a Csma channel. This function adds
+ * a RawCsmaNetDevice to the nodes so that they can connect
+ * to a CsmaChannel.
+ */
+ static void AddIpv4RawCsmaNode( Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Mac48Address addr);
+
+ /**
+ * \param n1 Node to be attached to the Csma channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr Mac address of the node
+ *
+ * Add a Csma node to a Csma channel. This function adds
+ * a LlcCsmaNetDevice to the nodes so that they can connect
+ * to a CsmaChannel.
+ */
+ static void AddIpv4LlcCsmaNode( Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Mac48Address addr);
+
+
+
+ /**
+ * \brief Create an Ipv4 interface for a net device and assign an
+ * Ipv4Address to that interface.
+ *
+ * \param node The node to which to add the new address and corresponding
+ * interface.
+ * \param netDeviceNumber The NetDevice index number with which to associate
+ * the address.
+ * \param address The Ipv4 Address for the interface.
+ * \param network The network mask for the interface
+ *
+ * Add an Ipv4Address to the Ipv4 interface associated with the
+ * ndNum CsmaIpv4NetDevices on the provided CsmaIpv4Channel
+ */
+ static uint32_t AddIpv4Address(Ptr<Node> node,
+ uint32_t netDeviceNumber,
+ const Ipv4Address address,
+ const Ipv4Mask mask);
+
+ /**
+ * \param nd1 Node
+ * \param nd2 Node
+ *
+ * Add an IPV4 host route between the two specified net devices
+ */
+ static void AddIpv4Routes (Ptr<NetDevice> nd1, Ptr<NetDevice> nd2);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,690 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "ns3/log.h"
+#include "ns3/queue.h"
+#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "csma-net-device.h"
+#include "csma-channel.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/ethernet-trailer.h"
+#include "ns3/llc-snap-header.h"
+
+NS_LOG_COMPONENT_DEFINE ("CsmaNetDevice");
+
+namespace ns3 {
+
+CsmaTraceType::CsmaTraceType (enum Type type)
+ : m_type (type)
+{
+ NS_LOG_FUNCTION;
+}
+
+CsmaTraceType::CsmaTraceType ()
+ : m_type (RX)
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+CsmaTraceType::Print (std::ostream &os) const
+{
+ switch (m_type) {
+ case RX:
+ os << "dev-rx";
+ break;
+ case DROP:
+ os << "dev-drop";
+ break;
+ }
+}
+
+uint16_t
+CsmaTraceType::GetUid (void)
+{
+ NS_LOG_FUNCTION;
+ static uint16_t uid = AllocateUid<CsmaTraceType> ("CsmaTraceType");
+ return uid;
+}
+
+std::string
+CsmaTraceType::GetTypeName (void) const
+{
+ NS_LOG_FUNCTION;
+ return "ns3::CsmaTraceType";
+}
+
+enum CsmaTraceType::Type
+CsmaTraceType::Get (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_type;
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node)
+ : NetDevice (node, Mac48Address::Allocate ()),
+ m_bps (DataRate (0xffffffff))
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << node << ")");
+ m_encapMode = IP_ARP;
+ Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Mac48Address addr,
+ CsmaEncapsulationMode encapMode)
+ : NetDevice(node, addr),
+ m_bps (DataRate (0xffffffff))
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << node << ")");
+ m_encapMode = encapMode;
+
+ Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Mac48Address addr,
+ CsmaEncapsulationMode encapMode,
+ bool sendEnable, bool receiveEnable)
+ : NetDevice(node, addr),
+ m_bps (DataRate (0xffffffff))
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << node << ")");
+ m_encapMode = encapMode;
+
+ Init(sendEnable, receiveEnable);
+}
+
+CsmaNetDevice::~CsmaNetDevice()
+{
+ NS_LOG_FUNCTION;
+ m_queue = 0;
+}
+
+void
+CsmaNetDevice::DoDispose ()
+{
+ NS_LOG_FUNCTION;
+ m_channel = 0;
+ NetDevice::DoDispose ();
+}
+
+//
+// Assignment operator for CsmaNetDevice.
+//
+// This uses the non-obvious trick of taking the source net device passed by
+// value instead of by reference. This causes the copy constructor to be
+// invoked (where the real work is done -- see above). All we have to do
+// here is to return the newly constructed net device.
+//
+/*
+CsmaNetDevice&
+CsmaNetDevice::operator= (const CsmaNetDevice nd)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &nd << ")");
+ return *this;
+}
+*/
+
+void
+CsmaNetDevice::Init(bool sendEnable, bool receiveEnable)
+{
+ NS_LOG_FUNCTION;
+ m_txMachineState = READY;
+ m_tInterframeGap = Seconds(0);
+ m_channel = 0;
+ m_queue = 0;
+
+ EnableBroadcast (Mac48Address ("ff:ff:ff:ff:ff:ff"));
+ EnableMulticast (Mac48Address ("01:00:5e:00:00:00"));
+
+ SetSendEnable (sendEnable);
+ SetReceiveEnable (receiveEnable);
+}
+
+void
+CsmaNetDevice::SetSendEnable (bool sendEnable)
+{
+ NS_LOG_FUNCTION;
+ m_sendEnable = sendEnable;
+}
+
+void
+CsmaNetDevice::SetReceiveEnable (bool receiveEnable)
+{
+ NS_LOG_FUNCTION;
+ m_receiveEnable = receiveEnable;
+}
+
+bool
+CsmaNetDevice::IsSendEnabled (void)
+{
+ NS_LOG_FUNCTION;
+ return (m_sendEnable);
+}
+
+bool
+CsmaNetDevice::IsReceiveEnabled (void)
+{
+ NS_LOG_FUNCTION;
+ return (m_receiveEnable);
+}
+
+void
+CsmaNetDevice::SetDataRate (DataRate bps)
+{
+ NS_LOG_FUNCTION;
+ m_bps = bps;
+}
+
+void
+CsmaNetDevice::SetInterframeGap (Time t)
+{
+ NS_LOG_FUNCTION;
+ m_tInterframeGap = t;
+}
+
+void
+CsmaNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots,
+ uint32_t maxSlots, uint32_t ceiling,
+ uint32_t maxRetries)
+{
+ NS_LOG_FUNCTION;
+ m_backoff.m_slotTime = slotTime;
+ m_backoff.m_minSlots = minSlots;
+ m_backoff.m_maxSlots = maxSlots;
+ m_backoff.m_ceiling = ceiling;
+ m_backoff.m_maxRetries = maxRetries;
+}
+
+void
+CsmaNetDevice::AddHeader (Packet& p, Mac48Address dest,
+ uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION;
+ if (m_encapMode == RAW)
+ {
+ return;
+ }
+ EthernetHeader header (false);
+ EthernetTrailer trailer;
+ Mac48Address source = Mac48Address::ConvertFrom (GetAddress ());
+ header.SetSource(source);
+ header.SetDestination(dest);
+
+ uint16_t lengthType = 0;
+ switch (m_encapMode)
+ {
+ case ETHERNET_V1:
+ lengthType = p.GetSize() + header.GetSerializedSize() + trailer.GetSerializedSize();
+ break;
+ case IP_ARP:
+ lengthType = protocolNumber;
+ break;
+ case LLC: {
+ LlcSnapHeader llc;
+ llc.SetType (protocolNumber);
+ p.AddHeader (llc);
+ } break;
+ case RAW:
+ NS_ASSERT (false);
+ break;
+ }
+ header.SetLengthType (lengthType);
+ p.AddHeader(header);
+ trailer.CalcFcs(p);
+ p.AddTrailer(trailer);
+}
+
+bool
+CsmaNetDevice::ProcessHeader (Packet& p, uint16_t & param)
+{
+ NS_LOG_FUNCTION;
+ if (m_encapMode == RAW)
+ {
+ return true;
+ }
+ EthernetHeader header (false);
+ EthernetTrailer trailer;
+
+ p.RemoveTrailer(trailer);
+ trailer.CheckFcs(p);
+ p.RemoveHeader(header);
+
+ if ((header.GetDestination() != GetBroadcast ()) &&
+ (header.GetDestination() != GetAddress ()))
+ {
+ return false;
+ }
+
+ switch (m_encapMode)
+ {
+ case ETHERNET_V1:
+ case IP_ARP:
+ param = header.GetLengthType();
+ break;
+ case LLC: {
+ LlcSnapHeader llc;
+ p.RemoveHeader (llc);
+ param = llc.GetType ();
+ } break;
+ case RAW:
+ NS_ASSERT (false);
+ break;
+ }
+ return true;
+}
+
+bool
+CsmaNetDevice::DoNeedsArp (void) const
+{
+ NS_LOG_FUNCTION;
+ if ((m_encapMode == IP_ARP) || (m_encapMode == LLC))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+CsmaNetDevice::SendTo (
+ const Packet& packet,
+ const Address& dest,
+ uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION;
+ Packet p = packet;
+ NS_LOG_LOGIC ("p=" << &p);
+ NS_LOG_LOGIC ("UID is " << p.GetUid () << ")");
+
+ NS_ASSERT (IsLinkUp ());
+
+ // Only transmit if send side of net device is enabled
+ if (!IsSendEnabled())
+ return false;
+
+ Mac48Address destination = Mac48Address::ConvertFrom (dest);
+ AddHeader(p, destination, protocolNumber);
+
+ // Place the packet to be sent on the send queue
+ if (m_queue->Enqueue(p) == false )
+ {
+ return false;
+ }
+ // If the device is idle, we need to start a transmission. Otherwise,
+ // the transmission will be started when the current packet finished
+ // transmission (see TransmitCompleteEvent)
+ if (m_txMachineState == READY)
+ {
+ // Store the next packet to be transmitted
+ if (m_queue->Dequeue (m_currentPkt))
+ {
+ TransmitStart();
+ }
+ }
+ return true;
+}
+
+void
+CsmaNetDevice::TransmitStart ()
+{
+ NS_LOG_FUNCTION;
+ 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.
+//
+ NS_ASSERT_MSG((m_txMachineState == READY) || (m_txMachineState == BACKOFF),
+ "Must be READY to transmit. Tx state is: "
+ << m_txMachineState);
+
+ // Only transmit if send side of net device is enabled
+ if (!IsSendEnabled())
+ return;
+
+ if (m_channel->GetState() != IDLE)
+ { // Channel busy, backoff and rechedule TransmitStart()
+ m_txMachineState = BACKOFF;
+ if (m_backoff.MaxRetriesReached())
+ { // Too many retries reached, abort transmission of packet
+ TransmitAbort();
+ }
+ else
+ {
+ m_backoff.IncrNumRetries();
+ Time backoffTime = m_backoff.GetBackoffTime();
+
+ NS_LOG_LOGIC ("Channel busy, backing off for " <<
+ backoffTime.GetSeconds () << " sec");
+
+ Simulator::Schedule (backoffTime,
+ &CsmaNetDevice::TransmitStart,
+ this);
+ }
+ }
+ else
+ {
+ // Channel is free, transmit packet
+ m_txMachineState = BUSY;
+ Time tEvent = Seconds (m_bps.CalculateTxTime(m_currentPkt.GetSize()));
+
+ NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " <<
+ tEvent.GetSeconds () << "sec");
+
+ Simulator::Schedule (tEvent,
+ &CsmaNetDevice::TransmitCompleteEvent,
+ this);
+ if (!m_channel->TransmitStart (m_currentPkt, m_deviceId))
+ {
+ NS_LOG_WARN ("Channel transmit start did not work at " <<
+ tEvent.GetSeconds () << "sec");
+ m_txMachineState = READY;
+ }
+ else
+ {
+ // Transmission success, reset backoff time parameters.
+ m_backoff.ResetBackoffTime();
+ }
+ }
+}
+
+
+void
+CsmaNetDevice::TransmitAbort (void)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt.GetUid () << ")");
+
+ // Try to transmit a new packet
+ bool found;
+ found = m_queue->Dequeue (m_currentPkt);
+ NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+ m_backoff.ResetBackoffTime();
+ m_txMachineState = READY;
+ TransmitStart ();
+}
+
+void
+CsmaNetDevice::TransmitCompleteEvent (void)
+{
+ NS_LOG_FUNCTION;
+//
+// This function is called to finish the process of transmitting a packet.
+// We need to tell the channel that we've stopped wiggling the wire and
+// schedule an event that will be executed when it's time to re-enable
+// the transmitter after the interframe gap.
+//
+ NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
+ // Channel should be transmitting
+ NS_ASSERT(m_channel->GetState() == TRANSMITTING);
+ m_txMachineState = GAP;
+
+ NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt.GetUid () << ")");
+ m_channel->TransmitEnd ();
+
+ NS_LOG_LOGIC ("Schedule TransmitReadyEvent in "
+ << m_tInterframeGap.GetSeconds () << "sec");
+
+ Simulator::Schedule (m_tInterframeGap,
+ &CsmaNetDevice::TransmitReadyEvent,
+ this);
+}
+
+void
+CsmaNetDevice::TransmitReadyEvent (void)
+{
+ NS_LOG_FUNCTION;
+//
+// This function is called to enable the transmitter after the interframe
+// gap has passed. If there are pending transmissions, we use this opportunity
+// to start the next transmit.
+//
+ NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
+ m_txMachineState = READY;
+
+ // Get the next packet from the queue for transmitting
+ if (m_queue->IsEmpty())
+ {
+ return;
+ }
+ else
+ {
+ bool found;
+ found = m_queue->Dequeue (m_currentPkt);
+ NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+ TransmitStart ();
+ }
+}
+
+Ptr<TraceResolver>
+CsmaNetDevice::GetTraceResolver (void) const
+{
+ NS_LOG_FUNCTION;
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ resolver->AddComposite ("queue", m_queue);
+ resolver->AddSource ("rx",
+ TraceDoc ("receive MAC packet",
+ "const Packet &", "packet received"),
+ m_rxTrace,
+ CsmaTraceType (CsmaTraceType::RX));
+ resolver->AddSource ("drop",
+ TraceDoc ("drop MAC packet",
+ "const Packet &", "packet dropped"),
+ m_dropTrace,
+ CsmaTraceType (CsmaTraceType::DROP));
+ resolver->SetParentResolver (NetDevice::GetTraceResolver ());
+ return resolver;
+}
+
+bool
+CsmaNetDevice::Attach (Ptr<CsmaChannel> ch)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &ch << ")");
+
+ m_channel = ch;
+
+ m_deviceId = m_channel->Attach(this);
+ m_bps = m_channel->GetDataRate ();
+ m_tInterframeGap = m_channel->GetDelay ();
+
+ /*
+ * For now, this device is up whenever a channel is attached to it.
+ */
+ NotifyLinkUp ();
+ return true;
+}
+
+void
+CsmaNetDevice::AddQueue (Ptr<Queue> q)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << q << ")");
+
+ m_queue = q;
+}
+
+void
+CsmaNetDevice::Receive (const Packet& packet)
+{
+ NS_LOG_FUNCTION;
+
+ EthernetHeader header (false);
+ EthernetTrailer trailer;
+ Mac48Address broadcast;
+ Mac48Address multicast;
+ Mac48Address destination;
+ Packet p = packet;
+
+ NS_LOG_LOGIC ("UID is " << p.GetUid());
+
+ // Only receive if send side of net device is enabled
+ if (!IsReceiveEnabled())
+ {
+ m_dropTrace (p);
+ return;
+ }
+
+ if (m_encapMode == RAW)
+ {
+ ForwardUp (packet, 0, GetBroadcast ());
+ m_dropTrace (p);
+ return;
+ }
+ p.RemoveTrailer(trailer);
+ trailer.CheckFcs(p);
+ p.RemoveHeader(header);
+
+ NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
+//
+// 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);
+
+ multicast = Mac48Address::ConvertFrom (GetMulticast ());
+ broadcast = Mac48Address::ConvertFrom (GetBroadcast ());
+ destination = Mac48Address::ConvertFrom (GetAddress ());
+
+ if ((header.GetDestination () != broadcast) &&
+ (mcDest != multicast) &&
+ (header.GetDestination () != destination))
+ {
+ NS_LOG_LOGIC ("Dropping pkt ");
+ m_dropTrace (p);
+ return;
+ }
+
+ m_rxTrace (p);
+//
+// protocol must be initialized to avoid a compiler warning in the RAW
+// case that breaks the optimized build.
+//
+ uint16_t protocol = 0;
+
+ switch (m_encapMode)
+ {
+ case ETHERNET_V1:
+ case IP_ARP:
+ protocol = header.GetLengthType();
+ break;
+ case LLC: {
+ LlcSnapHeader llc;
+ p.RemoveHeader (llc);
+ protocol = llc.GetType ();
+ } break;
+ case RAW:
+ NS_ASSERT (false);
+ break;
+ }
+
+ ForwardUp (p, protocol, header.GetSource ());
+ return;
+}
+
+Address
+CsmaNetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << multicastGroup << ")");
+//
+// First, get the generic multicast address.
+//
+ Address hardwareDestination = GetMulticast ();
+
+ 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);
+
+ return etherAddr;
+}
+
+Ptr<Queue>
+CsmaNetDevice::GetQueue(void) const
+{
+ NS_LOG_FUNCTION;
+ return m_queue;
+}
+
+Ptr<Channel>
+CsmaNetDevice::DoGetChannel(void) const
+{
+ NS_LOG_FUNCTION;
+ return m_channel;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,472 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+ */
+
+#ifndef CSMA_NET_DEVICE_H
+#define CSMA_NET_DEVICE_H
+
+#include <string.h>
+#include "ns3/node.h"
+#include "ns3/backoff.h"
+#include "ns3/address.h"
+#include "ns3/net-device.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/callback-trace-source.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/mac48-address.h"
+
+namespace ns3 {
+
+class Queue;
+class CsmaChannel;
+
+/**
+ * \brief hold in a TraceContext the type of trace source from a CsmaNetDevice
+ */
+class CsmaTraceType : public TraceContextElement
+{
+public:
+ enum Type {
+ RX,
+ DROP
+ };
+ CsmaTraceType (enum Type type);
+ CsmaTraceType ();
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+ std::string GetTypeName (void) const;
+ /**
+ * \returns the type of the trace source which generated an event.
+ */
+ enum Type Get (void) const;
+private:
+ enum Type m_type;
+};
+
+/**
+ * \class CsmaNetDevice
+ * \brief A Device for a Csma Network Link.
+ *
+ * The Csma net device class is analogous to layer 1 and 2 of the
+ * TCP stack. The NetDevice takes a raw packet of bytes and creates a
+ * protocol specific packet from them. The Csma net device class
+ * takes this packet and adds and processes the headers/trailers that
+ * are associated with EthernetV1, EthernetV2, RAW or LLC
+ * protocols. The EthernetV1 packet type adds and removes Ethernet
+ * destination and source addresses. The LLC packet type adds and
+ * removes LLC snap headers. The raw packet type does not add or
+ * remove any headers. Each Csma net device will receive all
+ * packets written to the Csma link. The ProcessHeader function can
+ * be used to filter out the packets such that higher level layers
+ * only receive packets that are addressed to their associated net
+ * devices
+ *
+ */
+class CsmaNetDevice : public NetDevice {
+public:
+
+ /**
+ * Enumeration of the types of packets supported in the class.
+ *
+ */
+enum CsmaEncapsulationMode {
+ ETHERNET_V1, /**< Version one ethernet packet, length field */
+ IP_ARP, /**< Ethernet packet encapsulates IP/ARP packet */
+ RAW, /**< Packet that contains no headers */
+ LLC, /**< LLC packet encapsulation */
+};
+
+ CsmaNetDevice (Ptr<Node> node);
+ /**
+ * Construct a CsmaNetDevice
+ *
+ * This is the constructor for the CsmaNetDevice. It takes as a
+ * parameter the Node to which this device is connected. Ownership of the
+ * Node pointer is not implied and the node must not be deleted.
+ *
+ * \param node the Node to which this device is connected.
+ * \param addr The source MAC address of the net device.
+ * \param pktType the type of encapsulation
+ */
+ CsmaNetDevice (Ptr<Node> node, Mac48Address addr, CsmaEncapsulationMode pktType);
+
+ /**
+ * Construct a CsmaNetDevice
+ *
+ * This is the constructor for the CsmaNetDevice. It takes as a
+ * parameter the Node to which this device is connected. Ownership of the
+ * Node pointer is not implied and the node must not be deleted.
+ *
+ * \param node the Node to which this device is connected.
+ * \param addr The source MAC address of the net device.
+ * \param pktType the type of encapsulation
+ * \param sendEnable whether this device is able to send
+ * \param receiveEnable whether this device is able to receive
+ */
+ CsmaNetDevice (Ptr<Node> node, Mac48Address addr,
+ CsmaEncapsulationMode pktType,
+ bool sendEnable, bool receiveEnable);
+ /**
+ * Destroy a CsmaNetDevice
+ *
+ * This is the destructor for the CsmaNetDevice.
+ */
+ virtual ~CsmaNetDevice();
+ /**
+ * Set the Data Rate used for transmission of packets. The data rate is
+ * set in the Attach () method from the corresponding field in the channel
+ * to which the device is attached. It can be overridden using this method.
+ *
+ * @see Attach ()
+ * \param bps the data rate at which this object operates
+ */
+ void SetDataRate (DataRate bps);
+ /**
+ * Set the inteframe gap used to separate packets. The interframe gap
+ * defines the minimum space required between packets sent by this device.
+ * It is usually set in the Attach () method based on the speed of light
+ * delay of the channel to which the device is attached. It can be
+ * overridden using this method if desired.
+ *
+ * @see Attach ()
+ * \param t the interframe gap time
+ */
+ void SetInterframeGap (Time t);
+ /**
+ * Set the backoff parameters used to determine the wait to retry
+ * transmitting a packet when the channel is busy.
+ *
+ * @see Attach ()
+ * \param slotTime Length of a packet slot (or average packet time)
+ * \param minSlots Minimum number of slots to wait
+ * \param maxSlots Maximum number of slots to wait
+ * \param maxRetries Maximum number of retries before packet is discard
+ * \param ceiling Cap on the exponential function when calculating max slots
+ */
+ void SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+ uint32_t maxRetries, uint32_t ceiling);
+ /**
+ * Attach the device to a channel.
+ *
+ * The function Attach is used to add a CsmaNetDevice to a
+ * CsmaChannel.
+ *
+ * @see SetDataRate ()
+ * @see SetInterframeGap ()
+ * \param ch a pointer to the channel to which this object is being attached.
+ */
+ bool Attach (Ptr<CsmaChannel> ch);
+ /**
+ * Attach a queue to the CsmaNetDevice.
+ *
+ * The CsmaNetDevice "owns" a queue. This queue is created by the
+ * CsmaTopology object and implements a queueing method such as
+ * DropTail or RED. The CsmaNetDevice assumes ownership of this
+ * queue and must delete it when the device is destroyed.
+ *
+ * @see CsmaTopology::AddCsmaLink ()
+ * @see Queue
+ * @see DropTailQueue
+ * \param queue a pointer to the queue for which object is assuming
+ * ownership.
+ */
+ void AddQueue (Ptr<Queue> queue);
+ /**
+ * Receive a packet from a connected CsmaChannel.
+ *
+ * The CsmaNetDevice receives packets from its connected channel
+ * and forwards them up the protocol stack. This is the public method
+ * used by the channel to indicate that the last bit of a packet has
+ * arrived at the device.
+ *
+ * @see CsmaChannel
+ * \param p a reference to the received packet
+ */
+ void Receive (const Packet& p);
+
+ /**
+ * @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
+ * 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).
+ *
+ * This method performs the multicast address creation function appropriate
+ * to an EUI-48-based CSMA device. This MAC address is encapsulated in an
+ * abstract Address to avoid dependencies on the exact address format.
+ *
+ * A default imlementation of MakeMulticastAddress is provided, but this
+ * method simply NS_ASSERTS. In the case of net devices that do not support
+ * multicast, clients are expected to test NetDevice::IsMulticast and avoid
+ * attempting to map multicast packets. Subclasses of NetDevice that do
+ * support multicasting are expected to override this method and provide an
+ * implementation appropriate to the particular device.
+ *
+ * @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
+ * multicast group.
+ *
+ * @see Ipv4Address
+ * @see Mac48Address
+ * @see Address
+ */
+ Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
+ bool IsSendEnabled (void);
+ bool IsReceiveEnabled (void);
+
+ void SetSendEnable (bool);
+ void SetReceiveEnable (bool);
+
+protected:
+ virtual bool DoNeedsArp (void) const;
+ virtual void DoDispose (void);
+ /**
+ * Create a Trace Resolver for events in the net device.
+ * (NOT TESTED)
+ * @see class TraceResolver
+ */
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+
+ /**
+ * Get a copy of the attached Queue.
+ *
+ * This method is provided for any derived class that may need to get
+ * direct access to the underlying queue.
+ *
+ * \return a pointer to the queue.
+ */
+ Ptr<Queue> GetQueue (void) const;
+ /**
+ * Get a copy of the attached Channel
+ *
+ * This method is provided for any derived class that may need to get
+ * direct access to the connected channel
+ *
+ * \return a pointer to the channel
+ */
+ virtual Ptr<Channel> DoGetChannel (void) const;
+ /**
+ * Adds the necessary headers and trailers to a packet of data in order to
+ * respect the packet type
+ *
+ * \param p Packet to which header should be added
+ * \param dest MAC destination address to which packet should be sent
+ * \param protocolNumber In some protocols, identifies the type of
+ * payload contained in this packet.
+ */
+ void AddHeader (Packet& p, Mac48Address dest,
+ uint16_t protocolNumber);
+ /**
+ * Removes, from a packet of data, all headers and trailers that
+ * relate to the packet type
+ *
+ * \param p Packet whose headers need to be processed
+ * \param param An integer parameter that can be set by the function
+ * to return information gathered in the header
+ * \return Returns true if the packet should be forwarded up the
+ * protocol stack.
+ */
+ bool ProcessHeader (Packet& p, uint16_t & param);
+
+private:
+ // disable copy constructor and operator =
+ CsmaNetDevice &operator = (const CsmaNetDevice &o);
+ CsmaNetDevice (const CsmaNetDevice &o);
+ /**
+ * Initializes variablea when construction object.
+ */
+ void Init (bool sendEnable, bool receiveEnable);
+ /**
+ * Send a Packet on the Csma network
+ *
+ * This method does not use a destination address since all packets
+ * are broadcast to all NetDevices attached to the channel. Packet
+ * should contain all needed headers at this time.
+ *
+ * If the device is ready to transmit, the next packet is read off
+ * of the queue and stored locally until it has been transmitted.
+ *
+ * \param p a reference to the packet to send
+ * \param dest destination address
+ * \param protocolNumber -- this parameter is not used here
+ * \return true if success, false on failure
+ */
+ virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber);
+
+ /**
+ * Start Sending a Packet Down the Wire.
+ *
+ * The TransmitStart method is the method that is used internally in
+ * the CsmaNetDevice to begin the process of sending a packet
+ * out on the channel. The corresponding method is called on the
+ * channel to let it know that the physical device this class
+ * represents has virually started sending signals, this causes the
+ * channel to become busy. An event is scheduled for the time at
+ * which the bits have been completely transmitted. If the channel
+ * is busy, the method reschedules itself for a later time (within
+ * the backoff period)
+ *
+ * @see CsmaChannel::TransmitStart ()
+ * @see TransmitCompleteEvent ()
+ */
+ void TransmitStart ();
+ /**
+ * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
+ *
+ * The TransmitCompleteEvent method is used internally to finish the process
+ * of sending a packet out on the channel. During execution of this method
+ * the TransmitEnd method is called on the channel to let it know that the
+ * physical device this class represents has virually finished sending
+ * signals. The channel uses this event to begin its speed of light delay
+ * timer after which it notifies the Net Device at the other end of the
+ * link that the bits have arrived. During this method, the net device
+ * also schedules the TransmitReadyEvent at which time the transmitter
+ * becomes ready to send the next packet.
+ *
+ * @see CsmaChannel::TransmitEnd ()
+ * @see TransmitReadyEvent ()
+ */
+ void TransmitCompleteEvent (void);
+ /**
+ * Cause the Transmitter to Become Ready to Send Another Packet.
+ *
+ * The TransmitReadyEvent method is used internally to re-enable the
+ * transmit machine of the net device. It is scheduled after a suitable
+ * interframe gap after the completion of the previous transmission.
+ * The queue is checked at this time, and if there is a packet waiting on
+ * the queue, the transmission process is begun.
+ *
+ * If a packet is in the queue, it is extracted for the queue as the
+ * next packet to be transmitted by the net device.
+ *
+ * @see TransmitStart ()
+ */
+ void TransmitReadyEvent (void);
+
+ /**
+ * Aborts the transmission of the current packet
+ *
+ * If the net device has tried to transmit a packet for more times
+ * than the maximum allowed number of retries (channel always busy)
+ * then the packet is dropped.
+ *
+ */
+ void TransmitAbort (void);
+
+ /**
+ * Device ID returned by the attached functions. It is used by the
+ * mp-channel to identify each net device to make sure that only
+ * active net devices are writing to the channel
+ */
+ uint32_t m_deviceId;
+
+ /**
+ * Enable net device to send packets. True by default
+ */
+ bool m_sendEnable;
+ /**
+ * Enable net device to receive packets. True by default
+ */
+ bool m_receiveEnable;
+ /**
+ * Enumeration of the states of the transmit machine of the net device.
+ */
+ enum TxMachineState
+ {
+ READY, /**< The transmitter is ready to begin transmission of a packet */
+ BUSY, /**< The transmitter is busy transmitting a packet */
+ GAP, /**< The transmitter is in the interframe gap time */
+ BACKOFF /**< The transmitter is waiting for the channel to be free */
+ };
+ /**
+ * The state of the Net Device transmit state machine.
+ * @see TxMachineState
+ */
+ TxMachineState m_txMachineState;
+
+ /**
+ * The type of packet that should be created by the AddHeader
+ * function and that should be processed by the ProcessHeader
+ * function.
+ */
+ CsmaEncapsulationMode m_encapMode;
+ /**
+ * The data rate that the Net Device uses to simulate packet transmission
+ * timing.
+ * @see class DataRate
+ */
+ DataRate m_bps;
+ /**
+ * The interframe gap that the Net Device uses to throttle packet
+ * transmission
+ * @see class Time
+ */
+ Time m_tInterframeGap;
+ /**
+ * Holds the backoff parameters and is used to calculate the next
+ * backoff time to use when the channel is busy and the net device
+ * is ready to transmit
+ */
+ Backoff m_backoff;
+ /**
+ * Next packet that will be transmitted (if transmitter is not
+ * currently transmitting) or packet that is currently being
+ * transmitted.
+ */
+ Packet m_currentPkt;
+ /**
+ * The CsmaChannel to which this CsmaNetDevice has been
+ * attached.
+ * @see class CsmaChannel
+ */
+ Ptr<CsmaChannel> m_channel;
+ /**
+ * The Queue which this CsmaNetDevice uses as a packet source.
+ * Management of this Queue has been delegated to the CsmaNetDevice
+ * and it has the responsibility for deletion.
+ * @see class Queue
+ * @see class DropTailQueue
+ */
+ Ptr<Queue> m_queue;
+ /**
+ * NOT TESTED
+ * The trace source for the packet reception events that the device can
+ * fire.
+ *
+ * @see class CallBackTraceSource
+ * @see class TraceResolver
+ */
+ CallbackTraceSource<const Packet &> m_rxTrace;
+ CallbackTraceSource<const Packet &> m_dropTrace;
+
+};
+
+}; // namespace ns3
+
+#endif // CSMA_NET_DEVICE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,102 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+//
+// Topology helper for Csma channels in ns3.
+
+#include "ns3/assert.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-topology.h"
+#include "ns3/socket-factory.h"
+
+namespace ns3 {
+
+Ptr<CsmaChannel>
+CsmaTopology::CreateCsmaChannel(
+ const DataRate& bps,
+ const Time& delay)
+{
+ Ptr<CsmaChannel> channel = Create<CsmaChannel> (bps, delay);
+
+ return channel;
+}
+
+#if 0
+Ptr<CsmaNetDevice>
+CsmaTopology::AddCsmaEthernetNode(
+ Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ MacAddress addr)
+{
+ Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::ETHERNET_V1);
+
+ Ptr<Queue> q = Queue::CreateDefault ();
+ nd1->AddQueue(q);
+ nd1->Attach (ch);
+
+ return nd1;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ Ptr<CsmaNetDevice> ndDest)
+{
+ Ptr<PacketSocket> socket = Create<PacketSocket> ();
+ socket->Bind(ndSrc);
+ socket->Connect(ndDest->GetAddress());
+ app->Connect(socket);
+
+ return socket;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ MacAddress macAddr)
+{
+ Ptr<PacketSocket> socket = Create<PacketSocket> ();
+ socket->Bind(ndSrc);
+ socket->Connect(macAddr);
+ app->Connect(socket);
+
+ return socket;
+}
+
+Ptr<Socket>
+CsmaTopology::CreatePacketSocket(Ptr<Node> n1, std::string iid_name)
+{
+ InterfaceId iid = InterfaceId::LookupByName (iid_name);
+
+ Ptr<SocketFactory> socketFactory =
+ n1->QueryInterface<SocketFactory> (iid);
+
+ Ptr<Socket> socket = socketFactory->CreateSocket ();
+
+ return socket;
+}
+#endif
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,123 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+// Topology helper for multipoint channels in ns3.
+//
+#ifndef CSMA_TOPOLOGY_H
+#define CSMA_TOPOLOGY_H
+
+#include "ns3/ptr.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/node.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaChannel;
+class Node;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Csma Topologies
+ *
+ * Csma topologies are created based on the
+ * ns3::CsmaNetDevice subclasses and ns3::CsmaChannel
+ * objects. This class uses the EthernetNetDevice and
+ * PacketSocket classes in order to create logical connections between
+ * net devices. The PacketSocket class generates the data and the
+ * EthernetNetDevice class creates ethernet packets from the
+ * data, filling in source and destination addresses. The
+ * EthernetNetDevice class filters received data packets
+ * according to its destination Mac addresses.
+ */
+class CsmaTopology {
+public:
+ /**
+ * \param dataRate Maximum transmission link rate
+ * \param delay propagation delay between any two nodes
+ * \return Pointer to the created CsmaChannel
+ *
+ * Create a CsmaChannel. All nodes connected to a multipoint
+ * channels will receive all packets written to that channel
+ */
+ static Ptr<CsmaChannel> CreateCsmaChannel(
+ const DataRate& dataRate, const Time& delay);
+
+#if 0
+ /**
+ * \param n1 Node to be attached to the multipoint channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr MacAddress that should be assigned to the
+ * EthernetNetDevice that will be added to the node.
+ *
+ * Add a multipoint node to a multipoint channel
+ */
+ static Ptr<CsmaNetDevice> AddCsmaEthernetNode(Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ MacAddress addr);
+
+ /**
+ * \param app Application that will be sending data to the agent
+ * \param ndSrc Net Device that will be sending the packets onto the
+ * network
+ * \param ndDest Net Device to which ndSrc will be sending the packets
+ * \return A pointer to the PacketSocket
+ *
+ * Creates an PacketSocket and configure it to send packets between
+ * two net devices
+ */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ Ptr<CsmaNetDevice> ndDest);
+
+ /**
+ * \param app Application that will be sending data to the agent
+ * \param ndSrc Net Device that will be sending the packets onto the
+ * network
+ * \param macAddr Mac destination address for the packets send by
+ * the ndSrc net device \return a Pointer to the created
+ * PacketSocket
+ *
+ * Creates an PacketSocket and configure it to send packets from a
+ * net device to a destination MacAddress
+ */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ MacAddress macAddr);
+
+ /**
+ * \param n1 Node from which socketfactory should be tested.
+ * \param iid_name Interface identifier ("Packet", in this case)
+ *
+ * This is a test function to make sure that a socket can be created
+ * by using the socketfactory interface provided in the
+ * netdevicenode.
+ */
+static Ptr<Socket> CreatePacketSocket(Ptr<Node> n1,
+ std::string iid_name);
+#endif
+
+};
+} // namespace ns3
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,19 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_module('csma', ['node'])
+ obj.source = [
+ 'backoff.cc',
+ 'csma-net-device.cc',
+ 'csma-channel.cc',
+ 'csma-topology.cc',
+ 'csma-ipv4-topology.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'backoff.h',
+ 'csma-net-device.h',
+ 'csma-channel.h',
+ 'csma-topology.h',
+ 'csma-ipv4-topology.h',
+ ]
--- a/src/devices/p2p/p2p-channel.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 University of Washington
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Craig Dowell <craigdo@ee.washington.edu>
- */
-
-#include "p2p-channel.h"
-#include "p2p-net-device.h"
-#include "ns3/packet.h"
-#include "ns3/simulator.h"
-#include "ns3/debug.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("PointToPointChannel");
-
-namespace ns3 {
-
-//
-// By default, you get a channel with the name "PointToPoint Channel" that
-// has an "infitely" fast transmission speed and zero delay.
-PointToPointChannel::PointToPointChannel()
-:
- Channel ("PointToPoint Channel"),
- m_bps (DataRate(0xffffffff)),
- m_delay (Seconds(0)),
- m_nDevices(0)
-{
- NS_DEBUG("PointToPointChannel::PointToPointChannel ()");
-}
-
-PointToPointChannel::PointToPointChannel(
- const DataRate& bps,
- const Time& delay)
-:
- Channel ("PointToPoint Channel"),
- m_bps (bps),
- m_delay (delay),
- m_nDevices(0)
-{
- NS_DEBUG("PointToPointChannel::PointToPointChannel (" << Channel::GetName()
- << ", " << bps.GetBitRate() << ", " << delay << ")");
-}
-
-PointToPointChannel::PointToPointChannel(
- const std::string& name,
- const DataRate& bps,
- const Time& delay)
-:
- Channel (name),
- m_bps (bps),
- m_delay (delay),
- m_nDevices(0)
-{
- NS_DEBUG("PointToPointChannel::PointToPointChannel (" << name << ", " <<
- bps.GetBitRate() << ", " << delay << ")");
-}
-
- void
-PointToPointChannel::Attach(Ptr<PointToPointNetDevice> device)
-{
- NS_DEBUG("PointToPointChannel::Attach (" << device << ")");
- NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted");
- NS_ASSERT(device != 0);
-
- m_link[m_nDevices].m_src = device;
- ++m_nDevices;
-//
-// If we have both devices connected to the channel, then finish introducing
-// the two halves and set the links to IDLE.
-//
- if (m_nDevices == N_DEVICES)
- {
- m_link[0].m_dst = m_link[1].m_src;
- m_link[1].m_dst = m_link[0].m_src;
- m_link[0].m_state = IDLE;
- m_link[1].m_state = IDLE;
- }
-}
-
-bool
-PointToPointChannel::TransmitStart(Packet& p, Ptr<PointToPointNetDevice> src)
-{
- NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src <<
- ")");
- NS_DEBUG ("PointToPointChannel::TransmitStart (): UID is " <<
- p.GetUid () << ")");
-
- NS_ASSERT(m_link[0].m_state != INITIALIZING);
- NS_ASSERT(m_link[1].m_state != INITIALIZING);
-
- uint32_t wire = src == m_link[0].m_src ? 0 : 1;
-
- if (m_link[wire].m_state == TRANSMITTING)
- {
- NS_DEBUG("PointToPointChannel::TransmitStart (): **** ERROR ****");
- NS_DEBUG("PointToPointChannel::TransmitStart (): state TRANSMITTING");
- return false;
- }
-
- NS_DEBUG("PointToPointChannel::TransmitStart (): switch to TRANSMITTING");
- m_link[wire].m_state = TRANSMITTING;
- return true;
-}
-
-bool
-PointToPointChannel::TransmitEnd(Packet& p, Ptr<PointToPointNetDevice> src)
-{
- NS_DEBUG("PointToPointChannel::TransmitEnd (" << &p << ", " << src << ")");
- NS_DEBUG ("PointToPointChannel::TransmitEnd (): UID is " <<
- p.GetUid () << ")");
-
- NS_ASSERT(m_link[0].m_state != INITIALIZING);
- NS_ASSERT(m_link[1].m_state != INITIALIZING);
-
- uint32_t wire = src == m_link[0].m_src ? 0 : 1;
-
- NS_ASSERT(m_link[wire].m_state == TRANSMITTING);
-
- m_link[wire].m_state = PROPAGATING;
-//
-// The sender is going to free the packet as soon as it has been transmitted.
-// We need to copy it to get a reference so it won't e deleted.
-//
- Packet packet = p;
- NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " <<
- m_delay.GetSeconds () << "sec");
- Simulator::Schedule (m_delay,
- &PointToPointChannel::PropagationCompleteEvent,
- this, packet, src);
- return true;
-}
-
-void
-PointToPointChannel::PropagationCompleteEvent(
- Packet p,
- Ptr<PointToPointNetDevice> src)
-{
- NS_DEBUG("PointToPointChannel::PropagationCompleteEvent (" << &p << ", " <<
- src << ")");
- NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): UID is " <<
- p.GetUid () << ")");
-
- uint32_t wire = src == m_link[0].m_src ? 0 : 1;
- NS_ASSERT(m_link[wire].m_state == PROPAGATING);
- m_link[wire].m_state = IDLE;
-
- NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): Receive");
- m_link[wire].m_dst->Receive (p);
-}
-
-
-uint32_t
-PointToPointChannel::GetNDevices (void) const
-{
- return m_nDevices;
-}
-
-Ptr<NetDevice>
-PointToPointChannel::GetDevice (uint32_t i) const
-{
- NS_ASSERT(i < 2);
- return m_link[i].m_src;
-}
-
- DataRate
-PointToPointChannel::GetDataRate (void)
-{
- return m_bps;
-}
-
- Time
-PointToPointChannel::GetDelay (void)
-{
- return m_delay;
-}
-
-
-} // namespace ns3
--- a/src/devices/p2p/p2p-channel.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/* -*- 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
- */
-
-#ifndef POINT_TO_POINT_CHANNEL_H
-#define POINT_TO_POINT_CHANNEL_H
-
-#include <list>
-#include "ns3/channel.h"
-#include "ns3/ptr.h"
-#include "ns3/packet.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-
-namespace ns3 {
-
-class PointToPointNetDevice;
-
-/**
- * \brief Simple Point To Point Channel.
- *
- * This class represents a very simple point to point channel. Think full
- * duplex RS-232 or RS-422 with null modem and no handshaking. There is no
- * multi-drop capability on this channel -- there can be a maximum of two
- * point-to-point net devices connected. Once we start talking about multi-
- * drop, or CSMA, or some other sharing mechanism, things begin getting
- * complicated quickly. Rather than invent some ad-hoc mechanism, we just
- * Keep It Simple everywhere.
- *
- * When the channel is instaniated, the constructor takes parameters for
- * a single speed, in bits per second, and a speed-of-light delay time as a
- * Time object. Both directions use the same speed and delay time.
- *
- * There are two "wires" in the channel. The first device connected gets the
- * [0] wire to transmit on. The second device gets the [1] wire. There is a
- * state (IDLE, TRANSMITTING) associated with each wire.
- */
-class PointToPointChannel : public Channel {
-public:
-//
-// This is really kidding myself, since just setting N_DEVICES to 3 isn't
-// going to come close to magically creating a multi-drop link, but I can't
-// bring myself to just type 2 in the code (even though I type 0 and 1 :-).
-//
- static const int N_DEVICES = 2;
- /**
- * \brief Create a PointToPointChannel
- *
- * By default, you get a channel with the name "PointToPoint Channel" that
- * has an "infitely" fast transmission speed and zero delay.
- */
- PointToPointChannel ();
-
- /**
- * \brief Create a PointToPointChannel
- *
- * \param bps The bitrate of the channel
- * \param delay Transmission delay through the channel
- */
- PointToPointChannel (const DataRate& bps, const Time& delay);
-
- /**
- * \brief Create a PointToPointChannel
- *
- * \param name the name of the channel for identification purposes
- * \param bps The bitrate of the channel
- * \param delay Transmission delay through the channel
- */
- PointToPointChannel (const std::string& name,
- const DataRate& bps, const Time& delay);
-
- /**
- * \brief Attach a given netdevice to this channel
- * \param device pointer to the netdevice to attach to the channel
- */
- void Attach (Ptr<PointToPointNetDevice> device);
- bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src);
- bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
- void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
-
-
- virtual uint32_t GetNDevices (void) const;
- virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
-
- virtual DataRate GetDataRate (void);
- virtual Time GetDelay (void);
-
-private:
- DataRate m_bps;
- Time m_delay;
-
- int32_t m_nDevices;
-
- enum WireState
- {
- INITIALIZING,
- IDLE,
- TRANSMITTING,
- PROPAGATING
- };
-
- class Link
- {
- public:
- Link() : m_state (INITIALIZING), m_src (0), m_dst (0) {}
- WireState m_state;
- Ptr<PointToPointNetDevice> m_src;
- Ptr<PointToPointNetDevice> m_dst;
- };
-
- Link m_link[N_DEVICES];
-};
-
-} // namespace ns3
-
-#endif /* POINT_TO_POINT_CHANNEL_H */
--- a/src/devices/p2p/p2p-net-device.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005,2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include <iostream>
-#include <cassert>
-#include "ns3/debug.h"
-#include "ns3/queue.h"
-#include "ns3/simulator.h"
-#include "ns3/composite-trace-resolver.h"
-#include "p2p-net-device.h"
-#include "p2p-channel.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice");
-
-namespace ns3 {
-
-PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node)
-:
- NetDevice(node, MacAddress ("00:00:00:00:00:00")),
- m_txMachineState (READY),
- m_bps (DataRate (0xffffffff)),
- m_tInterframeGap (Seconds(0)),
- m_channel (0),
- m_queue (0),
- m_rxTrace ()
-{
- NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << node << ")");
-
- // BUGBUG FIXME
- //
- // You _must_ support broadcast to get any sort of packet from the ARP layer.
- EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff"));
- EnableMulticast();
- EnablePointToPoint();
-}
-
-PointToPointNetDevice::~PointToPointNetDevice()
-{
- NS_DEBUG ("PointToPointNetDevice::~PointToPointNetDevice ()");
- m_queue = 0;
-}
-
-//
-// Copy constructor for PointToPointNetDevice.
-//
-// We use the underlying NetDevice copy constructor to get the base class
-// copied. These just remain as is (e.g. you get the same name, the same
-// MAC address). If you need to fix them up, YOU, the copier need to do
-// that.
-//
-// The things we need to be careful of are the channel, the queue and the
-// trace callback. If the channel pointer is non-zero, we copy the pointer
-// and add a reference. If the queue is non-zero, we copy it using the queue
-// assignment operator. We don't mess with the trace -- we just reset it.
-// We're assuming that the tracing will be set up after the topology creation
-// phase and this won't actually matter.
-//
-PointToPointNetDevice::PointToPointNetDevice (const PointToPointNetDevice& nd)
-:
- NetDevice(nd),
- m_txMachineState(READY),
- m_bps (nd.m_bps),
- m_tInterframeGap (nd.m_tInterframeGap),
- m_channel(nd.m_channel),
- m_queue(0),
- m_rxTrace ()
-{
- NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << &nd << ")");
-
- if (nd.m_queue)
- {
- m_queue = nd.m_queue;
- }
-
-}
-
-void PointToPointNetDevice::DoDispose()
-{
- m_channel = 0;
- NetDevice::DoDispose ();
-}
-
-//
-// Assignment operator for PointToPointNetDevice.
-//
-// This uses the non-obvious trick of taking the source net device passed by
-// value instead of by reference. This causes the copy constructor to be
-// invoked (where the real work is done -- see above). All we have to do
-// here is to return the newly constructed net device.
-//
- PointToPointNetDevice&
-PointToPointNetDevice::operator= (const PointToPointNetDevice nd)
-{
- NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")");
- return *this;
-}
-
- void
-PointToPointNetDevice::SetDataRate(DataRate bps)
-{
- m_bps = bps;
-}
-
- void
-PointToPointNetDevice::SetInterframeGap(Time t)
-{
- m_tInterframeGap = t;
-}
-
- bool
-PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest)
-{
- NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")");
- NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")");
-
- NS_ASSERT (IsLinkUp ());
-
-#ifdef NOTYET
- struct NetDevicePacketDestAddress tag;
- tag.address = address;
- p.AddTag (tag);
-#endif
-
-//
-// This class simulates a point to point device. In the case of a serial
-// link, this means that we're simulating something like a UART. This is
-// not a requirement for a point-to-point link, but it's a typical model for
-// the device.
-//
-// Generally, a real device will have a list of pending packets to transmit.
-// An on-device CPU frees the main CPU(s) of the details of what is happening
-// in the device and feeds the USART. The main CPU basically just sees the
-// list of packets -- it puts packets into the list, and the device frees the
-// packets when they are transmitted.
-//
-// In the case of our virtual device here, the queue pointed to by m_queue
-// corresponds to this list. The main CPU adds packets to the list by
-// calling this method and when the device completes a send, the packets are
-// freed in an "interrupt" service routine.
-//
-// We're going to do the same thing here. So first of all, the incoming packet
-// goes onto our queue if possible. If the queue can't handle it, there's
-// nothing to be done.
-//
- if (m_queue->Enqueue(p) == false )
- {
- return false;
- }
-//
-// If there's a transmission in progress, the "interrupt" will keep the
-// transmission process going. If the device is idle, we need to start a
-// transmission.
-//
-// In the real world, the USART runs until it finishes sending bits, and then
-// pulls on the device's transmit complete interrupt wire. At the same time,
-// the electrons from the last wiggle of the wire are busy propagating down
-// the wire. In the case of a long speed-of-light delay in the wire, we could
-// conceivably start transmitting the next packet before the end of the
-// previously sent data has even reached the end of the wire. This situation
-// is usually avoided (like the plague) and an "interframe gap" is introduced.
-// This is usually the round-trip delay on the channel plus some hard-to-
-// quantify receiver turn-around time (the time required for the receiver
-// to process the last frame and prepare for reception of the next).
-//
-// So, if the transmit machine is ready, we need to schedule a transmit
-// complete event (at which time we tell the channel we're no longer sending
-// bits). A separate transmit ready event (at which time the transmitter
-// becomes ready to start sending bits again is scheduled there). Finally,
-// we tell the channel (via TransmitStart ()) that we've started wiggling the
-// wire and bits are coming out.
-//
-// If the transmit machine is not ready, we just leave and the transmit ready
-// event we know is coming will kick-start the transmit process.
-//
- if (m_txMachineState == READY)
- {
- return TransmitStart (p);
- }
- return true;
-}
-
- bool
-PointToPointNetDevice::TransmitStart (Packet &p)
-{
- NS_DEBUG ("PointToPointNetDevice::TransmitStart (" << &p << ")");
- NS_DEBUG (
- "PointToPointNetDevice::TransmitStart (): UID is " << p.GetUid () << ")");
-//
-// This function is called to start the process of transmitting a packet.
-// We need to tell the channel that we've started wiggling the wire and
-// schedule an event that will be executed when it's time to tell the
-// channel that we're done wiggling the wire.
-//
- NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
- m_txMachineState = BUSY;
- Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize()));
-
- NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " <<
- "Schedule TransmitCompleteEvent in " <<
- tEvent.GetSeconds () << "sec");
-
- Simulator::Schedule (tEvent,
- &PointToPointNetDevice::TransmitCompleteEvent,
- this);
- return m_channel->TransmitStart (p, this);
-}
-
- void
-PointToPointNetDevice::TransmitCompleteEvent (void)
-{
- NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()");
-//
-// This function is called to finish the process of transmitting a packet.
-// We need to tell the channel that we've stopped wiggling the wire and
-// schedule an event that will be executed when it's time to re-enable
-// the transmitter after the interframe gap.
-//
- NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
- m_txMachineState = GAP;
- Packet p;
- bool found;
- found = m_queue->Dequeue (p);
- NS_ASSERT_MSG(found, "Packet must be on queue if transmitted");
- NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " <<
- p.GetUid () << ")");
- m_channel->TransmitEnd (p, this);
-
- NS_DEBUG (
- "PointToPointNetDevice::TransmitCompleteEvent (): " <<
- "Schedule TransmitReadyEvent in "
- << m_tInterframeGap.GetSeconds () << "sec");
-
- Simulator::Schedule (m_tInterframeGap,
- &PointToPointNetDevice::TransmitReadyEvent,
- this);
-}
-
- void
-PointToPointNetDevice::TransmitReadyEvent (void)
-{
- NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()");
-//
-// This function is called to enable the transmitter after the interframe
-// gap has passed. If there are pending transmissions, we use this opportunity
-// to start the next transmit.
-//
- NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
- m_txMachineState = READY;
-
- if (m_queue->IsEmpty())
- {
- return;
- }
- else
- {
- Packet p;
- bool found;
- found = m_queue->Peek (p);
- NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
- TransmitStart (p);
- }
-}
-
-TraceResolver *
-PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context)
-{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- resolver->Add ("queue",
- MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)),
- PointToPointNetDevice::QUEUE);
- resolver->Add ("rx",
- m_rxTrace,
- PointToPointNetDevice::RX);
- return resolver;
-}
-
-bool
-PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
-{
- NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")");
-
- m_channel = ch;
-
- m_channel->Attach(this);
- m_bps = m_channel->GetDataRate ();
- m_tInterframeGap = m_channel->GetDelay ();
-
- /*
- * For now, this device is up whenever a channel is attached to it.
- * In fact, it should become up only when the second device
- * is attached to the channel. So, there should be a way for
- * a PointToPointChannel to notify both of its attached devices
- * that the channel is 'complete', hence that the devices are
- * up, hence that they can call NotifyLinkUp.
- */
- NotifyLinkUp ();
- return true;
-}
-
-void
-PointToPointNetDevice::AddQueue (Ptr<Queue> q)
-{
- NS_DEBUG ("PointToPointNetDevice::AddQueue (" << q << ")");
-
- m_queue = q;
-}
-
-void
-PointToPointNetDevice::Receive (Packet& p)
-{
- // ignore return value for now.
- NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")");
-
- m_rxTrace (p);
- ForwardUp (p);
-}
-
-Ptr<Queue>
-PointToPointNetDevice::GetQueue(void) const
-{
- return m_queue;
-}
-
-Ptr<Channel>
-PointToPointNetDevice::DoGetChannel(void) const
-{
- return m_channel;
-}
-
-bool
-PointToPointNetDevice::DoNeedsArp (void) const
-{
- return false;
-}
-
-} // namespace ns3
--- a/src/devices/p2p/p2p-net-device.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/* -*- 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
- *
- * Author: Craig Dowell <craigdo@ee.washington.edu>
- */
-
-#ifndef POINT_TO_POINT_NET_DEVICE_H
-#define POINT_TO_POINT_NET_DEVICE_H
-
-#include <string.h>
-#include "ns3/mac-address.h"
-#include "ns3/node.h"
-#include "ns3/net-device.h"
-#include "ns3/callback.h"
-#include "ns3/packet.h"
-#include "ns3/callback-trace-source.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Queue;
-class PointToPointChannel;
-
-/**
- * \class PointToPointNetDevice
- * \brief A Device for a Point to Point Network Link.
- *
- * Ns-3 takes a four-layer view of a protocol stack. This is the same model
- * that TCP uses. In this view, layers 5-7 of the OSI reference model are
- * grouped together into an application layer; layer four (transport / TCP) is
- * broken out; layer three (network / IP) is broken out; and layers 1-2 are
- * grouped together. We call this grouping of layers one and two a NetDevice
- * and represent it as a class in the system.
- *
- * The NetDevice class is specialized according to the needs of the specific
- * kind of network link. In this case, the link is a PointToPoint link. The
- * PointToPoint link is a family of classes that includes this class, the
- * PointToPointNetDevice, a PointToPointChannel class that represents the
- * actual medium across which bits are sent, a PointToPointIpv4Interface class
- * that provides the hook to tie a general purpose node to this specific
- * link, and finally, a PointToPointTopology object that is responsible for
- * putting all of the pieces together.
- *
- * This is the PointToPointNetDevice class that represents, essentially, the
- * PC card that is used to connect to the PointToPoint network.
- */
-class PointToPointNetDevice : public NetDevice {
-public:
- /**
- * Enumeration of the types of traces supported in the class.
- *
- */
- enum TraceType {
- QUEUE, /**< Trace queue events on the attached queue */
- RX, /**< Trace packet reception events (from the channel) */
- };
- /**
- * Construct a PointToPointNetDevice
- *
- * This is the constructor for the PointToPointNetDevice. It takes as a
- * parameter the Node to which this device is connected. Ownership of the
- * Node pointer is not implied and the node must not be deleded.
- *
- * @see PointToPointTopology::AddPointToPointLink ()
- * @param node the Node to which this device is connected.
- */
- PointToPointNetDevice (Ptr<Node> node);
- /**
- * Copy Construct a PointToPointNetDevice
- *
- * This is the copy constructor for the PointToPointNetDevice. This is
- * primarily used in topology creation.
- *
- * @see PointToPointTopology::AddPointToPointLink ()
- * @param nd the object to be copied
- */
- PointToPointNetDevice (const PointToPointNetDevice& nd);
- /**
- * Destroy a PointToPointNetDevice
- *
- * This is the destructor for the PointToPointNetDevice.
- */
- virtual ~PointToPointNetDevice();
- /**
- * Assignment Operator for a PointToPointNetDevice
- *
- * This is the assignment operator for the PointToPointNetDevice. This is
- * to allow
- *
- * @param nd the object to be copied
- */
- PointToPointNetDevice& operator= (PointToPointNetDevice nd);
- /**
- * Set the Data Rate used for transmission of packets. The data rate is
- * set in the Attach () method from the corresponding field in the channel
- * to which the device is attached. It can be overridden using this method.
- *
- * @see Attach ()
- * @param bps the data rate at which this object operates
- */
- void SetDataRate(DataRate bps);
- /**
- * Set the inteframe gap used to separate packets. The interframe gap
- * defines the minimum space required between packets sent by this device.
- * It is usually set in the Attach () method based on the speed of light
- * delay of the channel to which the device is attached. It can be
- * overridden using this method if desired.
- *
- * @see Attach ()
- * @param t the interframe gap time
- */
- void SetInterframeGap(Time t);
- /**
- * Attach the device to a channel.
- *
- * The PointToPointTopology object creates a PointToPointChannel and two
- * PointtoPointNetDevices. In order to introduce these components to each
- * other, the topology object calls Attach () on each PointToPointNetDevice.
- * Inside this method, the Net Device calls out to the PointToPointChannel
- * to introduce itself.
- *
- * @see PointToPointTopology::AddPointToPointLink ()
- * @see SetDataRate ()
- * @see SetInterframeGap ()
- * @param ch a pointer to the channel to which this object is being attached.
- */
- bool Attach(Ptr<PointToPointChannel> ch);
- /**
- * Attach a queue to the PointToPointNetDevice.
- *
- * The PointToPointNetDevice "owns" a queue. This queue is created by the
- * PointToPointTopology object and implements a queueing method such as
- * DropTail or RED. The PointToPointNetDevice assumes ownership of this
- * queue and must delete it when the device is destroyed.
- *
- * @see PointToPointTopology::AddPointToPointLink ()
- * @see Queue
- * @see DropTailQueue
- * @param queue a pointer to the queue for which object is assuming
- * ownership.
- */
- void AddQueue(Ptr<Queue> queue);
- /**
- * Receive a packet from a connected PointToPointChannel.
- *
- * The PointToPointNetDevice receives packets from its connected channel
- * and forwards them up the protocol stack. This is the public method
- * used by the channel to indicate that the last bit of a packet has
- * arrived at the device.
- *
- * @see PointToPointChannel
- * @param p a reference to the received packet
- */
- void Receive (Packet& p);
-protected:
- virtual void DoDispose (void);
- /**
- * Get a copy of the attached Queue.
- *
- * This method is provided for any derived class that may need to get
- * direct access to the underlying queue.
- *
- * @see PointToPointTopology
- * @returns a pointer to the queue.
- */
- Ptr<Queue> GetQueue(void) const;
- /**
- * Get a copy of the attached Channel
- *
- * This method is provided for any derived class that may need to get
- * direct access to the connected channel
- *
- * @see PointToPointChannel
- * @returns a pointer to the channel
- */
- virtual Ptr<Channel> DoGetChannel(void) const;
-private:
- /**
- * Send a Packet Down the Wire.
- *
- * The SendTo method is defined as the standard way that the level three
- * protocol uses to tell a NetDevice to send a packet. SendTo is declared
- * as abstract in the NetDevice class and we declare it here.
- *
- * @see NetDevice
- * @param p a reference to the packet to send
- * @param dest a reference to the MacAddress of the destination device
- * @returns true if success, false on failure
- */
- virtual bool SendTo (Packet& p, const MacAddress& dest);
- /**
- * Start Sending a Packet Down the Wire.
- *
- * The TransmitStart method is the method that is used internally in the
- * PointToPointNetDevice to begin the process of sending a packet out on
- * the channel. The corresponding method is called on the channel to let
- * it know that the physical device this class represents has virually
- * started sending signals. An event is scheduled for the time at which
- * the bits have been completely transmitted.
- *
- * @see PointToPointChannel::TransmitStart ()
- * @see TransmitCompleteEvent ()
- * @param p a reference to the packet to send
- * @returns true if success, false on failure
- */
- bool TransmitStart (Packet &p);
- /**
- * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
- *
- * The TransmitCompleteEvent method is used internally to finish the process
- * of sending a packet out on the channel. During execution of this method
- * the TransmitEnd method is called on the channel to let it know that the
- * physical device this class represents has virually finished sending
- * signals. The channel uses this event to begin its speed of light delay
- * timer after which it notifies the Net Device at the other end of the
- * link that the bits have arrived. During this method, the net device
- * also schedules the TransmitReadyEvent at which time the transmitter
- * becomes ready to send the next packet.
- *
- * @see PointToPointChannel::TransmitEnd ()
- * @see TransmitReadyEvent ()
- * @returns true if success, false on failure
- */
- void TransmitCompleteEvent (void);
- /**
- * Cause the Transmitter to Become Ready to Send Another Packet.
- *
- * The TransmitReadyEvent method is used internally to re-enable the
- * transmit machine of the net device. It is scheduled after a suitable
- * interframe gap after the completion of the previous transmission.
- * The queue is checked at this time, and if there is a packet waiting on
- * the queue, the transmission process is begun.
- *
- * @see TransmitStart ()
- */
- void TransmitReadyEvent (void);
- /**
- * Create a Trace Resolver for events in the net device.
- *
- * @see class TraceResolver
- */
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
- virtual bool DoNeedsArp (void) const;
- /**
- * Enumeration of the states of the transmit machine of the net device.
- */
- enum TxMachineState
- {
- READY, /**< The transmitter is ready to begin transmission of a packet */
- BUSY, /**< The transmitter is busy transmitting a packet */
- GAP /**< The transmitter is in the interframe gap time */
- };
- /**
- * The state of the Net Device transmit state machine.
- * @see TxMachineState
- */
- TxMachineState m_txMachineState;
- /**
- * The data rate that the Net Device uses to simulate packet transmission
- * timing.
- * @see class DataRate
- */
- DataRate m_bps;
- /**
- * The interframe gap that the Net Device uses to throttle packet
- * transmission
- * @see class Time
- */
- Time m_tInterframeGap;
- /**
- * The PointToPointChannel to which this PointToPointNetDevice has been
- * attached.
- * @see class PointToPointChannel
- */
- Ptr<PointToPointChannel> m_channel;
- /**
- * The Queue which this PointToPointNetDevice uses as a packet source.
- * Management of this Queue has been delegated to the PointToPointNetDevice
- * and it has the responsibility for deletion.
- * @see class Queue
- * @see class DropTailQueue
- */
- Ptr<Queue> m_queue;
- /**
- * The trace source for the packet reception events that the device can
- * fire.
- *
- * @see class CallBackTraceSource
- * @see class TraceResolver
- */
- CallbackTraceSource<Packet &> m_rxTrace;
-};
-
-}; // namespace ns3
-
-#endif // POINT_TO_POINT_NET_DEVICE_H
-
--- a/src/devices/p2p/p2p-topology.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +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<riley@ece.gatech.edu>
-//
-
-//
-// Topology helper for ns3.
-// George F. Riley, Georgia Tech, Spring 2007
-
-#include <algorithm>
-#include "ns3/assert.h"
-#include "ns3/debug.h"
-#include "ns3/fatal-error.h"
-#include "ns3/nstime.h"
-#include "ns3/internet-node.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/queue.h"
-
-#include "p2p-channel.h"
-#include "p2p-net-device.h"
-#include "p2p-topology.h"
-
-namespace ns3 {
-
-Ptr<PointToPointChannel>
-PointToPointTopology::AddPointToPointLink(
- Ptr<Node> n1,
- Ptr<Node> n2,
- const DataRate& bps,
- const Time& delay)
-{
- Ptr<PointToPointChannel> channel = Create<PointToPointChannel> (bps, delay);
-
- Ptr<PointToPointNetDevice> net1 = Create<PointToPointNetDevice> (n1);
-
- Ptr<Queue> q = Queue::CreateDefault ();
- net1->AddQueue(q);
- net1->Attach (channel);
-
- Ptr<PointToPointNetDevice> net2 = Create<PointToPointNetDevice> (n2);
-
- q = Queue::CreateDefault ();
- net2->AddQueue(q);
- net2->Attach (channel);
-
- return channel;
-}
-
-void
-PointToPointTopology::AddIpv4Addresses(
- Ptr<const PointToPointChannel> chan,
- Ptr<Node> n1, const Ipv4Address& addr1,
- Ptr<Node> n2, const Ipv4Address& addr2)
-{
-
- // Duplex link is assumed to be subnetted as a /30
- // May run this unnumbered in the future?
- Ipv4Mask netmask("255.255.255.252");
- NS_ASSERT (netmask.IsMatch(addr1,addr2));
-
- // The PointToPoint channel is used to find the relevant NetDevices
- NS_ASSERT (chan->GetNDevices () == 2);
- Ptr<NetDevice> nd1 = chan->GetDevice (0);
- Ptr<NetDevice> nd2 = chan->GetDevice (1);
- // Make sure that nd1 belongs to n1 and nd2 to n2
- if ( (nd1->GetNode ()->GetId () == n2->GetId () ) &&
- (nd2->GetNode ()->GetId () == n1->GetId () ) )
- {
- std::swap(nd1, nd2);
- }
- NS_ASSERT (nd1->GetNode ()->GetId () == n1->GetId ());
- NS_ASSERT (nd2->GetNode ()->GetId () == n2->GetId ());
-
- Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
- uint32_t index1 = ip1->AddInterface (nd1);
-
- ip1->SetAddress (index1, addr1);
- ip1->SetNetworkMask (index1, netmask);
- ip1->SetUp (index1);
-
- Ptr<Ipv4> ip2 = n2->QueryInterface<Ipv4> (Ipv4::iid);
- uint32_t index2 = ip2->AddInterface (nd2);
-
- ip2->SetAddress (index2, addr2);
- ip2->SetNetworkMask (index2, netmask);
- ip2->SetUp (index2);
-
-}
-
-void
-PointToPointTopology::AddIpv4Routes (
- Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> chan)
-{
- // The PointToPoint channel is used to find the relevant NetDevices
- NS_ASSERT (chan->GetNDevices () == 2);
- Ptr<NetDevice> nd1 = chan->GetDevice (0);
- Ptr<NetDevice> nd2 = chan->GetDevice (1);
-
- // Assert that n1 is the Node owning one of the two NetDevices
- // and make sure that nd1 corresponds to it
- if (nd1->GetNode ()->GetId () == n1->GetId ())
- {
- ; // Do nothing
- }
- else if (nd2->GetNode ()->GetId () == n1->GetId ())
- {
- std::swap(nd1, nd2);
- }
- else
- {
- NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
- }
-
- // Assert that n2 is the Node owning one of the two NetDevices
- // and make sure that nd2 corresponds to it
- if (nd2->GetNode ()->GetId () != n2->GetId ())
- {
- NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
- }
-
- // Assert that both are Ipv4 nodes
- Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
- Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
- NS_ASSERT(ip1 != 0 && ip2 != 0);
-
- // Get interface indexes for both nodes corresponding to the right channel
- uint32_t index1 = 0;
- bool found = false;
- for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
- {
- if (ip1 ->GetNetDevice (i) == nd1)
- {
- index1 = i;
- found = true;
- }
- }
- NS_ASSERT(found);
-
- uint32_t index2 = 0;
- found = false;
- for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
- {
- if (ip2 ->GetNetDevice (i) == nd2)
- {
- index2 = i;
- found = true;
- }
- }
- NS_ASSERT(found);
-
- ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
- ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2);
-}
-
-} // namespace ns3
-
--- a/src/devices/p2p/p2p-topology.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-// Topology helper for ns3.
-// George F. Riley, Georgia Tech, Spring 2007
-#ifndef __POINT_TO_POINT_TOPOLOGY_H__
-#define __POINT_TO_POINT_TOPOLOGY_H__
-
-#include "ns3/ptr.h"
-
-// The topology class consists of only static methods thar are used to
-// create the topology and data flows for an ns3 simulation
-
-namespace ns3 {
-
-class PointToPointChannel;
-class Node;
-class IPAddr;
-class DataRate;
-class Queue;
-
-/**
- * \brief A helper class to create Topologies based on the
- * ns3::PointToPointNetDevice and ns3::PointToPointChannel objects.
- */
-class PointToPointTopology {
-public:
- /**
- * \param n1 Node
- * \param n2 Node
- * \param dataRate Maximum transmission link rate
- * \param delay one-way propagation delay
- * \return Pointer to the underlying PointToPointChannel
- *
- * Add a full-duplex point-to-point link between two nodes
- * and attach PointToPointNetDevices to the resulting
- * PointToPointChannel.
- */
- static Ptr<PointToPointChannel> AddPointToPointLink(
- Ptr<Node> n1, Ptr<Node> n2, const DataRate& dataRate, const Time& delay);
-
- /**
- * \param chan PointToPointChannel to use
- * \param n1 Node
- * \param addr1 Ipv4 Address for n1
- * \param n2 Node
- * \param addr2 Ipv4 Address for n2
- *
- * Add Ipv4Addresses to the Ipv4 interfaces associated with the
- * two PointToPointNetDevices on the provided PointToPointChannel
- */
- static void AddIpv4Addresses(
- Ptr<const PointToPointChannel> chan,
- Ptr<Node> n1, const Ipv4Address& addr1,
- Ptr<Node> n2, const Ipv4Address& addr2);
-
- /**
- * \param channel PointToPointChannel to use
- * \param n1 Node
- * \param n2 Node
- *
- * For the given PointToPointChannel, for each Node, add an
- * IPv4 host route to the IPv4 address of the peer node.
- */
- static void AddIpv4Routes (Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> channel);
-};
-
-} // namespace ns3
-
-#endif
-
--- a/src/devices/p2p/wscript Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-
-def configure(conf):
- conf.env.append_value('NS3_MODULES', 'ns3-p2p')
-
-
-def build(bld):
- p2p = bld.create_obj('cpp', 'shlib')
- p2p.name = 'ns3-p2p'
- p2p.target = p2p.name
- p2p.uselib_local = ['ns3-node']
- p2p.source = [
- 'p2p-net-device.cc',
- 'p2p-channel.cc',
- 'p2p-topology.cc',
- ]
- headers = bld.create_obj('ns3header')
- headers.source = [
- 'p2p-net-device.h',
- 'p2p-channel.h',
- 'p2p-topology.h',
- ]
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-channel.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 University of Washington
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Craig Dowell <craigdo@ee.washington.edu>
+ */
+
+#include "point-to-point-channel.h"
+#include "point-to-point-net-device.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("PointToPointChannel");
+
+namespace ns3 {
+
+//
+// By default, you get a channel with the name "PointToPoint Channel" that
+// has an "infitely" fast transmission speed and zero delay.
+PointToPointChannel::PointToPointChannel()
+:
+ Channel ("PointToPoint Channel"),
+ m_bps (DataRate(0xffffffff)),
+ m_delay (Seconds(0)),
+ m_nDevices(0)
+{
+ NS_LOG_FUNCTION;
+}
+
+PointToPointChannel::PointToPointChannel(
+ const DataRate& bps,
+ const Time& delay)
+:
+ Channel ("PointToPoint Channel"),
+ m_bps (bps),
+ m_delay (delay),
+ m_nDevices(0)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << Channel::GetName() << ", " << bps.GetBitRate() <<
+ ", " << delay << ")");
+}
+
+PointToPointChannel::PointToPointChannel(
+ const std::string& name,
+ const DataRate& bps,
+ const Time& delay)
+:
+ Channel (name),
+ m_bps (bps),
+ m_delay (delay),
+ m_nDevices(0)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << name << ", " << bps.GetBitRate() << ", " <<
+ delay << ")");
+}
+
+void
+PointToPointChannel::Attach(Ptr<PointToPointNetDevice> device)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << device << ")");
+ NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted");
+ NS_ASSERT(device != 0);
+
+ m_link[m_nDevices++].m_src = device;
+//
+// If we have both devices connected to the channel, then finish introducing
+// the two halves and set the links to IDLE.
+//
+ if (m_nDevices == N_DEVICES)
+ {
+ m_link[0].m_dst = m_link[1].m_src;
+ m_link[1].m_dst = m_link[0].m_src;
+ m_link[0].m_state = IDLE;
+ m_link[1].m_state = IDLE;
+ }
+}
+
+bool
+PointToPointChannel::TransmitStart(Packet& p,
+ Ptr<PointToPointNetDevice> src,
+ const Time& txTime)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ", " << src << ")");
+ NS_LOG_LOGIC ("UID is " << p.GetUid () << ")");
+
+ NS_ASSERT(m_link[0].m_state != INITIALIZING);
+ NS_ASSERT(m_link[1].m_state != INITIALIZING);
+
+ uint32_t wire = src == m_link[0].m_src ? 0 : 1;
+
+ // Here we schedule the packet receive event at the receiver,
+ // which simplifies this model quite a bit. The channel just
+ // adds the propagation delay time
+ Simulator::Schedule (txTime + m_delay,
+ &PointToPointNetDevice::Receive,
+ m_link[wire].m_dst, p);
+ return true;
+}
+
+uint32_t
+PointToPointChannel::GetNDevices (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_nDevices;
+}
+
+Ptr<NetDevice>
+PointToPointChannel::GetDevice (uint32_t i) const
+{
+ NS_LOG_FUNCTION;
+ NS_ASSERT(i < 2);
+ return m_link[i].m_src;
+}
+
+const DataRate&
+PointToPointChannel::GetDataRate (void)
+{
+ NS_LOG_FUNCTION;
+ return m_bps;
+}
+
+const Time&
+PointToPointChannel::GetDelay (void)
+{
+ NS_LOG_FUNCTION;
+ return m_delay;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-channel.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,127 @@
+/* -*- 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
+ */
+
+#ifndef POINT_TO_POINT_CHANNEL_H
+#define POINT_TO_POINT_CHANNEL_H
+
+#include <list>
+#include "ns3/channel.h"
+#include "ns3/ptr.h"
+#include "ns3/packet.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class PointToPointNetDevice;
+
+/**
+ * \brief Simple Point To Point Channel.
+ *
+ * This class represents a very simple point to point channel. Think full
+ * duplex RS-232 or RS-422 with null modem and no handshaking. There is no
+ * multi-drop capability on this channel -- there can be a maximum of two
+ * point-to-point net devices connected. Once we start talking about multi-
+ * drop, or CSMA, or some other sharing mechanism, things begin getting
+ * complicated quickly. Rather than invent some ad-hoc mechanism, we just
+ * Keep It Simple everywhere.
+ *
+ * When the channel is instaniated, the constructor takes parameters for
+ * a single speed, in bits per second, and a speed-of-light delay time as a
+ * Time object. Both directions use the same speed and delay time.
+ *
+ * There are two "wires" in the channel. The first device connected gets the
+ * [0] wire to transmit on. The second device gets the [1] wire. There is a
+ * state (IDLE, TRANSMITTING) associated with each wire.
+ */
+class PointToPointChannel : public Channel {
+public:
+// Each point to point link has exactly two net devices
+ static const int N_DEVICES = 2;
+ /**
+ * \brief Create a PointToPointChannel
+ *
+ * By default, you get a channel with the name "PointToPoint Channel" that
+ * has an "infitely" fast transmission speed and zero delay.
+ */
+ PointToPointChannel ();
+
+ /**
+ * \brief Create a PointToPointChannel
+ *
+ * \param bps The maximum bitrate of the channel
+ * \param delay Transmission delay through the channel
+ */
+ PointToPointChannel (const DataRate& bps, const Time& delay);
+
+ /**
+ * \brief Create a PointToPointChannel
+ *
+ * \param name the name of the channel for identification purposes
+ * \param bps The maximum bitrate of the channel
+ * \param delay Transmission delay through the channel
+ */
+ PointToPointChannel (const std::string& name,
+ const DataRate& bps, const Time& delay);
+
+ /**
+ * \brief Attach a given netdevice to this channel
+ * \param device pointer to the netdevice to attach to the channel
+ */
+ void Attach (Ptr<PointToPointNetDevice> device);
+ bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src,
+ const Time& txTime);
+ // Below two not needed
+ //bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
+ //void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
+
+
+ virtual uint32_t GetNDevices (void) const;
+ virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
+ virtual const DataRate& GetDataRate (void);
+ virtual const Time& GetDelay (void);
+
+private:
+ DataRate m_bps;
+ Time m_delay;
+ int32_t m_nDevices;
+
+ enum WireState
+ {
+ INITIALIZING,
+ IDLE,
+ TRANSMITTING,
+ PROPAGATING
+ };
+
+ class Link
+ {
+ public:
+ Link() : m_state (INITIALIZING), m_src (0), m_dst (0) {}
+ WireState m_state;
+ Ptr<PointToPointNetDevice> m_src;
+ Ptr<PointToPointNetDevice> m_dst;
+ };
+
+ Link m_link[N_DEVICES];
+};
+
+} // namespace ns3
+
+#endif /* POINT_TO_POINT_CHANNEL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-net-device.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,295 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Craig Dowell <craigdo@ee.washington.edu>
+ * Revised: George Riley <riley@ece.gatech.edu>
+ */
+
+#include "ns3/log.h"
+#include "ns3/queue.h"
+#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "ns3/mac48-address.h"
+#include "ns3/llc-snap-header.h"
+#include "point-to-point-net-device.h"
+#include "point-to-point-channel.h"
+
+NS_LOG_COMPONENT_DEFINE ("PointToPointNetDevice");
+
+namespace ns3 {
+
+DataRateDefaultValue PointToPointNetDevice::g_defaultRate(
+ "PointToPointLinkDataRate",
+ "The default data rate for point to point links",
+ DataRate ("10Mb/s"));
+
+PointToPointTraceType::PointToPointTraceType ()
+{
+ NS_LOG_FUNCTION;
+}
+void
+PointToPointTraceType::Print (std::ostream &os) const
+{
+ os << "dev-rx";
+}
+
+uint16_t
+PointToPointTraceType::GetUid (void)
+{
+ NS_LOG_FUNCTION;
+ static uint16_t uid = AllocateUid<PointToPointTraceType> ("PointToPointTraceType");
+ return uid;
+}
+
+std::string
+PointToPointTraceType::GetTypeName (void) const
+{
+ NS_LOG_FUNCTION;
+ return "ns3::PointToPointTraceType";
+}
+
+
+PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
+ const DataRate& rate)
+:
+ NetDevice(node, Mac48Address::Allocate ()),
+ m_txMachineState (READY),
+ m_bps (rate),
+ m_tInterframeGap (Seconds(0)),
+ m_channel (0),
+ m_queue (0),
+ m_rxTrace ()
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << node << ")");
+//
+// XXX BUGBUG
+//
+// You _must_ support broadcast to get any sort of packet from the ARP layer.
+//
+ EnableBroadcast (Mac48Address ("ff:ff:ff:ff:ff:ff"));
+//
+// We want to allow multicast packets to flow across this link
+//
+ EnableMulticast (Mac48Address ("01:00:5e:00:00:00"));
+ EnablePointToPoint();
+}
+
+PointToPointNetDevice::~PointToPointNetDevice()
+{
+ NS_LOG_FUNCTION;
+ m_queue = 0;
+}
+
+void
+PointToPointNetDevice::AddHeader(Packet& p, uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION;
+ LlcSnapHeader llc;
+ llc.SetType (protocolNumber);
+ p.AddHeader (llc);
+}
+
+bool
+PointToPointNetDevice::ProcessHeader(Packet& p, uint16_t& param)
+{
+ NS_LOG_FUNCTION;
+ LlcSnapHeader llc;
+ p.RemoveHeader (llc);
+
+ param = llc.GetType ();
+
+ return true;
+}
+
+void PointToPointNetDevice::DoDispose()
+{
+ NS_LOG_FUNCTION;
+ m_channel = 0;
+ NetDevice::DoDispose ();
+}
+
+void PointToPointNetDevice::SetDataRate(const DataRate& bps)
+{
+ NS_LOG_FUNCTION;
+ m_bps = bps;
+}
+
+void PointToPointNetDevice::SetInterframeGap(const Time& t)
+{
+ NS_LOG_FUNCTION;
+ m_tInterframeGap = t;
+}
+
+bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest,
+ uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION;
+ Packet p = packet;
+ NS_LOG_LOGIC ("p=" << &p << ", dest=" << &dest);
+ NS_LOG_LOGIC ("UID is " << p.GetUid ());
+
+ // GFR Comment. Why is this an assertion? Can't a link legitimately
+ // "go down" during the simulation? Shouldn't we just wait for it
+ // to come back up?
+ NS_ASSERT (IsLinkUp ());
+ AddHeader(p, protocolNumber);
+
+//
+// This class simulates a point to point device. In the case of a serial
+// link, this means that we're simulating something like a UART.
+//
+//
+// If there's a transmission in progress, we enque the packet for later
+// transmission; otherwise we send it now.
+ if (m_txMachineState == READY)
+ {
+// We still enqueue and dequeue it to hit the tracing hooks
+ m_queue->Enqueue (p);
+ m_queue->Dequeue (p);
+ return TransmitStart (p);
+ }
+ else
+ {
+ return m_queue->Enqueue(p);
+ }
+}
+
+ bool
+PointToPointNetDevice::TransmitStart (Packet &p)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
+ NS_LOG_LOGIC ("UID is " << p.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 the transmission is complete.
+//
+ NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
+ m_txMachineState = BUSY;
+ Time txTime = Seconds (m_bps.CalculateTxTime(p.GetSize()));
+ Time txCompleteTime = txTime + m_tInterframeGap;
+
+ NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " <<
+ txCompleteTime.GetSeconds () << "sec");
+ // Schedule the tx complete event
+ Simulator::Schedule (txCompleteTime,
+ &PointToPointNetDevice::TransmitComplete,
+ this);
+ return m_channel->TransmitStart(p, this, txTime);
+}
+
+void PointToPointNetDevice::TransmitComplete (void)
+{
+ NS_LOG_FUNCTION;
+//
+// 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
+// get the next packet from the queue. If the queue is empty, we are
+// done, otherwise transmit the next packet.
+//
+ NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
+ m_txMachineState = READY;
+ Packet p;
+ if (!m_queue->Dequeue(p)) return; // Nothing to do at this point
+ TransmitStart(p);
+}
+
+Ptr<TraceResolver>
+PointToPointNetDevice::GetTraceResolver (void) const
+{
+ NS_LOG_FUNCTION;
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ resolver->AddComposite ("queue", m_queue);
+ resolver->AddSource ("rx",
+ TraceDoc ("receive MAC packet",
+ "const Packet &", "packet received"),
+ m_rxTrace,
+ PointToPointTraceType ());
+ resolver->SetParentResolver (NetDevice::GetTraceResolver ());
+ return resolver;
+}
+
+bool
+PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &ch << ")");
+
+ m_channel = ch;
+
+ m_channel->Attach(this);
+ m_bps = m_channel->GetDataRate ();
+ // GFR Comment. Below is definitely wrong. Interframe gap
+ // is unrelated to channel delay.
+ // -- unlesss you want to introduce a default gap which is there to avoid
+ // parts of multiple packets flowing on the "wire" at the same time.
+ //m_tInterframeGap = m_channel->GetDelay ();
+
+ /*
+ * For now, this device is up whenever a channel is attached to it.
+ * In fact, it should become up only when the second device
+ * is attached to the channel. So, there should be a way for
+ * a PointToPointChannel to notify both of its attached devices
+ * that the channel is 'complete', hence that the devices are
+ * up, hence that they can call NotifyLinkUp.
+ */
+ NotifyLinkUp ();
+ return true;
+}
+
+void PointToPointNetDevice::AddQueue (Ptr<Queue> q)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << q << ")");
+
+ m_queue = q;
+}
+
+void PointToPointNetDevice::Receive (Packet& p)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
+ uint16_t protocol = 0;
+ Packet packet = p;
+
+ m_rxTrace (packet);
+ ProcessHeader(packet, protocol);
+ ForwardUp (packet, protocol, GetBroadcast ());
+}
+
+Ptr<Queue> PointToPointNetDevice::GetQueue(void) const
+{
+ NS_LOG_FUNCTION;
+ return m_queue;
+}
+
+Ptr<Channel> PointToPointNetDevice::DoGetChannel(void) const
+{
+ NS_LOG_FUNCTION;
+ return m_channel;
+}
+
+bool PointToPointNetDevice::DoNeedsArp (void) const
+{
+ NS_LOG_FUNCTION;
+ return false;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-net-device.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,308 @@
+/* -*- 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
+ *
+ * Author: Craig Dowell <craigdo@ee.washington.edu>
+ */
+
+#ifndef POINT_TO_POINT_NET_DEVICE_H
+#define POINT_TO_POINT_NET_DEVICE_H
+
+#include <string.h>
+#include "ns3/address.h"
+#include "ns3/node.h"
+#include "ns3/net-device.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/callback-trace-source.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Queue;
+class PointToPointChannel;
+
+/**
+ * \brief hold in a TraceContext the type of trace source from a PointToPointNetDevice
+ */
+class PointToPointTraceType : public TraceContextElement
+{
+public:
+ PointToPointTraceType ();
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+ std::string GetTypeName (void) const;
+};
+
+/**
+ * \class PointToPointNetDevice
+ * \brief A Device for a Point to Point Network Link.
+ *
+ * Ns-3 takes a four-layer view of a protocol stack. This is the same model
+ * that TCP uses. In this view, layers 5-7 of the OSI reference model are
+ * grouped together into an application layer; layer four (transport / TCP) is
+ * broken out; layer three (network / IP) is broken out; and layers 1-2 are
+ * grouped together. We call this grouping of layers one and two a NetDevice
+ * and represent it as a class in the system.
+ *
+ * The NetDevice class is specialized according to the needs of the specific
+ * kind of network link. In this case, the link is a PointToPoint link. The
+ * PointToPoint link is a family of classes that includes this class, the
+ * PointToPointNetDevice, a PointToPointChannel class that represents the
+ * actual medium across which bits are sent, a PointToPointIpv4Interface class
+ * that provides the hook to tie a general purpose node to this specific
+ * link, and finally, a PointToPointTopology object that is responsible for
+ * putting all of the pieces together.
+ *
+ * This is the PointToPointNetDevice class that represents, essentially, the
+ * PC card that is used to connect to the PointToPoint network.
+ */
+class PointToPointNetDevice : public NetDevice {
+public:
+ /**
+ * Construct a PointToPointNetDevice
+ *
+ * This is the constructor for the PointToPointNetDevice. It takes as a
+ * parameter the Node to which this device is connected. Ownership of the
+ * Node pointer is not implied and the node must not be deleded.
+ *
+ * @see PointToPointTopology::AddPointToPointLink ()
+ * @param node the Node to which this device is connected.
+ */
+ PointToPointNetDevice (Ptr<Node> node,
+ const DataRate& = g_defaultRate.GetValue());
+ /**
+ * Destroy a PointToPointNetDevice
+ *
+ * This is the destructor for the PointToPointNetDevice.
+ */
+ virtual ~PointToPointNetDevice();
+ /**
+ * Set the Data Rate used for transmission of packets. The data rate is
+ * set in the Attach () method from the corresponding field in the channel
+ * to which the device is attached. It can be overridden using this method.
+ *
+ * @see Attach ()
+ * @param bps the data rate at which this object operates
+ */
+ void SetDataRate(const DataRate& bps);
+ /**
+ * Set the inteframe gap used to separate packets. The interframe gap
+ * defines the minimum space required between packets sent by this device.
+ * It is usually set in the Attach () method based on the speed of light
+ * delay of the channel to which the device is attached. It can be
+ * overridden using this method if desired.
+ *
+ * @see Attach ()
+ * @param t the interframe gap time
+ */
+ void SetInterframeGap(const Time& t);
+ /**
+ * Attach the device to a channel.
+ *
+ * The PointToPointTopology object creates a PointToPointChannel and two
+ * PointtoPointNetDevices. In order to introduce these components to each
+ * other, the topology object calls Attach () on each PointToPointNetDevice.
+ * Inside this method, the Net Device calls out to the PointToPointChannel
+ * to introduce itself.
+ *
+ * @see PointToPointTopology::AddPointToPointLink ()
+ * @see SetDataRate ()
+ * @see SetInterframeGap ()
+ * @param ch a pointer to the channel to which this object is being attached.
+ */
+ bool Attach(Ptr<PointToPointChannel> ch);
+ /**
+ * Attach a queue to the PointToPointNetDevice.
+ *
+ * The PointToPointNetDevice "owns" a queue. This queue is created by the
+ * PointToPointTopology object and implements a queueing method such as
+ * DropTail or RED. The PointToPointNetDevice assumes ownership of this
+ * queue and must delete it when the device is destroyed.
+ *
+ * @see PointToPointTopology::AddPointToPointLink ()
+ * @see Queue
+ * @see DropTailQueue
+ * @param queue a pointer to the queue for which object is assuming
+ * ownership.
+ */
+ void AddQueue(Ptr<Queue> queue);
+ /**
+ * Receive a packet from a connected PointToPointChannel.
+ *
+ * The PointToPointNetDevice receives packets from its connected channel
+ * and forwards them up the protocol stack. This is the public method
+ * used by the channel to indicate that the last bit of a packet has
+ * arrived at the device.
+ *
+ * @see PointToPointChannel
+ * @param p a reference to the received packet
+ */
+ void Receive (Packet& p);
+protected:
+ /**
+ * Create a Trace Resolver for events in the net device.
+ *
+ * @see class TraceResolver
+ */
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+ virtual void DoDispose (void);
+ /**
+ * Get a copy of the attached Queue.
+ *
+ * This method is provided for any derived class that may need to get
+ * direct access to the underlying queue.
+ *
+ * @see PointToPointTopology
+ * @returns a pointer to the queue.
+ */
+ Ptr<Queue> GetQueue(void) const;
+ /**
+ * Get a copy of the attached Channel
+ *
+ * This method is provided for any derived class that may need to get
+ * direct access to the connected channel
+ *
+ * @see PointToPointChannel
+ * @returns a pointer to the channel
+ */
+ virtual Ptr<Channel> DoGetChannel(void) const;
+ /**
+ * Set a new default data rate
+ */
+ static void SetDefaultRate(const DataRate&);
+
+ /**
+ * Get the current default rate.
+ * @returns a const reference to current default
+ */
+
+ static const DataRate& GetDefaultRate();
+
+private:
+ /**
+ * Adds the necessary headers and trailers to a packet of data in order to
+ * respect the protocol implemented by the agent.
+ */
+ void AddHeader(Packet& p, uint16_t protocolNumber);
+ /**
+ * Removes, from a packet of data, all headers and trailers that
+ * relate to the protocol implemented by the agent
+ * \return Returns true if the packet should be forwarded up the
+ * protocol stack.
+ */
+ bool ProcessHeader(Packet& p, uint16_t& param);
+ /**
+ * Send a Packet Down the Wire.
+ *
+ * The SendTo method is defined as the standard way that the level three
+ * protocol uses to tell a NetDevice to send a packet. SendTo is declared
+ * as abstract in the NetDevice class and we declare it here.
+ *
+ * @see NetDevice
+ * @param p a reference to the packet to send
+ * @param dest a reference to the Address of the destination device
+ * @param protocolNumber Protocol Number used to find protocol touse
+ * @returns true if success, false on failure
+ */
+ virtual bool SendTo (const Packet& p, const Address& dest,
+ uint16_t protocolNumber);
+ /**
+ * Start Sending a Packet Down the Wire.
+ *
+ * The TransmitStart method is the method that is used internally in the
+ * PointToPointNetDevice to begin the process of sending a packet out on
+ * the channel. The corresponding method is called on the channel to let
+ * it know that the physical device this class represents has virually
+ * started sending signals. An event is scheduled for the time at which
+ * the bits have been completely transmitted.
+ *
+ * @see PointToPointChannel::TransmitStart ()
+ * @see TransmitCompleteEvent ()
+ * @param p a reference to the packet to send
+ * @returns true if success, false on failure
+ */
+ bool TransmitStart (Packet &p);
+ /**
+ * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
+ *
+ * The TransmitComplete method is used internally to finish the process
+ * of sending a packet out on the channel.
+ *
+ */
+ void TransmitComplete(void);
+ virtual bool DoNeedsArp (void) const;
+ /**
+ * Enumeration of the states of the transmit machine of the net device.
+ */
+ enum TxMachineState
+ {
+ READY, /**< The transmitter is ready to begin transmission of a packet */
+ BUSY /**< The transmitter is busy transmitting a packet */
+ };
+ /**
+ * The state of the Net Device transmit state machine.
+ * @see TxMachineState
+ */
+ TxMachineState m_txMachineState;
+ /**
+ * The data rate that the Net Device uses to simulate packet transmission
+ * timing.
+ * @see class DataRate
+ */
+ DataRate m_bps;
+ /**
+ * The interframe gap that the Net Device uses to throttle packet
+ * transmission
+ * @see class Time
+ */
+ Time m_tInterframeGap;
+ /**
+ * The PointToPointChannel to which this PointToPointNetDevice has been
+ * attached.
+ * @see class PointToPointChannel
+ */
+ Ptr<PointToPointChannel> m_channel;
+ /**
+ * The Queue which this PointToPointNetDevice uses as a packet source.
+ * Management of this Queue has been delegated to the PointToPointNetDevice
+ * and it has the responsibility for deletion.
+ * @see class Queue
+ * @see class DropTailQueue
+ */
+ Ptr<Queue> m_queue;
+ /**
+ * The trace source for the packet reception events that the device can
+ * fire.
+ *
+ * @see class CallBackTraceSource
+ * @see class TraceResolver
+ */
+ CallbackTraceSource<const Packet &> m_rxTrace;
+ /**
+ * Default data rate. Used for all newly created p2p net devices
+ */
+ static DataRateDefaultValue g_defaultRate;
+
+};
+
+}; // namespace ns3
+
+#endif // POINT_TO_POINT_NET_DEVICE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-topology.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,172 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+
+//
+// Topology helper for ns3.
+// George F. Riley, Georgia Tech, Spring 2007
+
+#include <algorithm>
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/fatal-error.h"
+#include "ns3/nstime.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/queue.h"
+
+#include "point-to-point-channel.h"
+#include "point-to-point-net-device.h"
+#include "point-to-point-topology.h"
+
+namespace ns3 {
+
+Ptr<PointToPointChannel>
+PointToPointTopology::AddPointToPointLink(
+ Ptr<Node> n1,
+ Ptr<Node> n2,
+ const DataRate& bps,
+ const Time& delay)
+{
+ Ptr<PointToPointChannel> channel = Create<PointToPointChannel> (bps, delay);
+
+ Ptr<PointToPointNetDevice> net1 = Create<PointToPointNetDevice> (n1);
+
+ Ptr<Queue> q = Queue::CreateDefault ();
+ net1->AddQueue(q);
+ net1->Attach (channel);
+
+ Ptr<PointToPointNetDevice> net2 = Create<PointToPointNetDevice> (n2);
+
+ q = Queue::CreateDefault ();
+ net2->AddQueue(q);
+ net2->Attach (channel);
+
+ return channel;
+}
+
+void
+PointToPointTopology::AddIpv4Addresses(
+ Ptr<const PointToPointChannel> chan,
+ Ptr<Node> n1, const Ipv4Address& addr1,
+ Ptr<Node> n2, const Ipv4Address& addr2)
+{
+
+ // Duplex link is assumed to be subnetted as a /30
+ // May run this unnumbered in the future?
+ Ipv4Mask netmask("255.255.255.252");
+ NS_ASSERT (netmask.IsMatch(addr1,addr2));
+
+ // The PointToPoint channel is used to find the relevant NetDevices
+ NS_ASSERT (chan->GetNDevices () == 2);
+ Ptr<NetDevice> nd1 = chan->GetDevice (0);
+ Ptr<NetDevice> nd2 = chan->GetDevice (1);
+ // Make sure that nd1 belongs to n1 and nd2 to n2
+ if ( (nd1->GetNode ()->GetId () == n2->GetId () ) &&
+ (nd2->GetNode ()->GetId () == n1->GetId () ) )
+ {
+ std::swap(nd1, nd2);
+ }
+ NS_ASSERT (nd1->GetNode ()->GetId () == n1->GetId ());
+ NS_ASSERT (nd2->GetNode ()->GetId () == n2->GetId ());
+
+ Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t index1 = ip1->AddInterface (nd1);
+
+ ip1->SetAddress (index1, addr1);
+ ip1->SetNetworkMask (index1, netmask);
+ ip1->SetUp (index1);
+
+ Ptr<Ipv4> ip2 = n2->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t index2 = ip2->AddInterface (nd2);
+
+ ip2->SetAddress (index2, addr2);
+ ip2->SetNetworkMask (index2, netmask);
+ ip2->SetUp (index2);
+
+}
+
+void
+PointToPointTopology::AddIpv4Routes (
+ Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> chan)
+{
+ // The PointToPoint channel is used to find the relevant NetDevices
+ NS_ASSERT (chan->GetNDevices () == 2);
+ Ptr<NetDevice> nd1 = chan->GetDevice (0);
+ Ptr<NetDevice> nd2 = chan->GetDevice (1);
+
+ // Assert that n1 is the Node owning one of the two NetDevices
+ // and make sure that nd1 corresponds to it
+ if (nd1->GetNode ()->GetId () == n1->GetId ())
+ {
+ ; // Do nothing
+ }
+ else if (nd2->GetNode ()->GetId () == n1->GetId ())
+ {
+ std::swap(nd1, nd2);
+ }
+ else
+ {
+ NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
+ }
+
+ // Assert that n2 is the Node owning one of the two NetDevices
+ // and make sure that nd2 corresponds to it
+ if (nd2->GetNode ()->GetId () != n2->GetId ())
+ {
+ NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
+ }
+
+ // Assert that both are Ipv4 nodes
+ Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+ Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT(ip1 != 0 && ip2 != 0);
+
+ // Get interface indexes for both nodes corresponding to the right channel
+ uint32_t index1 = 0;
+ bool found = false;
+ for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
+ {
+ if (ip1 ->GetNetDevice (i) == nd1)
+ {
+ index1 = i;
+ found = true;
+ }
+ }
+ NS_ASSERT(found);
+
+ uint32_t index2 = 0;
+ found = false;
+ for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
+ {
+ if (ip2 ->GetNetDevice (i) == nd2)
+ {
+ index2 = i;
+ found = true;
+ }
+ }
+ NS_ASSERT(found);
+
+ ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
+ ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2);
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-topology.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+// Topology helper for ns3.
+// George F. Riley, Georgia Tech, Spring 2007
+#ifndef __POINT_TO_POINT_TOPOLOGY_H__
+#define __POINT_TO_POINT_TOPOLOGY_H__
+
+#include "ns3/ptr.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class PointToPointChannel;
+class Node;
+class IPAddr;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Topologies based on the
+ * ns3::PointToPointNetDevice and ns3::PointToPointChannel objects.
+ */
+class PointToPointTopology {
+public:
+ /**
+ * \param n1 Node
+ * \param n2 Node
+ * \param dataRate Maximum transmission link rate
+ * \param delay one-way propagation delay
+ * \return Pointer to the underlying PointToPointChannel
+ *
+ * Add a full-duplex point-to-point link between two nodes
+ * and attach PointToPointNetDevices to the resulting
+ * PointToPointChannel.
+ */
+ static Ptr<PointToPointChannel> AddPointToPointLink(
+ Ptr<Node> n1, Ptr<Node> n2, const DataRate& dataRate, const Time& delay);
+
+ /**
+ * \param chan PointToPointChannel to use
+ * \param n1 Node
+ * \param addr1 Ipv4 Address for n1
+ * \param n2 Node
+ * \param addr2 Ipv4 Address for n2
+ *
+ * Add Ipv4Addresses to the Ipv4 interfaces associated with the
+ * two PointToPointNetDevices on the provided PointToPointChannel
+ */
+ static void AddIpv4Addresses(
+ Ptr<const PointToPointChannel> chan,
+ Ptr<Node> n1, const Ipv4Address& addr1,
+ Ptr<Node> n2, const Ipv4Address& addr2);
+
+ /**
+ * \param channel PointToPointChannel to use
+ * \param n1 Node
+ * \param n2 Node
+ *
+ * For the given PointToPointChannel, for each Node, add an
+ * IPv4 host route to the IPv4 address of the peer node.
+ */
+ static void AddIpv4Routes (Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> channel);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,17 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+
+def build(bld):
+ module = bld.create_ns3_module('point-to-point', ['node'])
+ module.source = [
+ 'point-to-point-net-device.cc',
+ 'point-to-point-channel.cc',
+ 'point-to-point-topology.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'point-to-point-net-device.h',
+ 'point-to-point-channel.h',
+ 'point-to-point-topology.h',
+ ]
+
--- a/src/internet-node/arp-cache.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-cache.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,16 +19,16 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "ns3/assert.h"
-
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "arp-cache.h"
#include "arp-header.h"
+#include "ipv4-interface.h"
namespace ns3 {
-ArpCache::ArpCache (Ptr<NetDevice> device, Ipv4Interface *interface)
+ArpCache::ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
: m_device (device),
m_interface (interface),
m_aliveTimeout (Seconds (120)),
@@ -47,7 +47,7 @@
return m_device;
}
-Ipv4Interface *
+Ptr<Ipv4Interface>
ArpCache::GetInterface (void) const
{
return m_interface;
@@ -109,6 +109,8 @@
ArpCache::Entry *
ArpCache::Add (Ipv4Address to)
{
+ NS_ASSERT (m_arpCache.find (to) == m_arpCache.end ());
+
ArpCache::Entry *entry = new ArpCache::Entry (this);
m_arpCache[to] = entry;
return entry;
@@ -146,7 +148,7 @@
UpdateSeen ();
}
Packet
-ArpCache::Entry::MarkAlive (MacAddress macAddress)
+ArpCache::Entry::MarkAlive (Address macAddress)
{
NS_ASSERT (m_state == WAIT_REPLY);
//NS_ASSERT (m_waiting != 0);
@@ -180,7 +182,7 @@
UpdateSeen ();
}
-MacAddress
+Address
ArpCache::Entry::GetMacAddress (void)
{
NS_ASSERT (m_state == ALIVE);
--- a/src/internet-node/arp-cache.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-cache.h Fri Sep 28 11:59:46 2007 +0100
@@ -26,7 +26,7 @@
#include "ns3/nstime.h"
#include "ns3/net-device.h"
#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
#include "ns3/ptr.h"
#include "sgi-hashmap.h"
@@ -48,7 +48,7 @@
* \param device The hardware NetDevice associated with this ARP chache
* \param interface the Ipv4Interface associated with this ARP chache
*/
- ArpCache (Ptr<NetDevice> device, Ipv4Interface *interface);
+ ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface);
~ArpCache ();
/**
* \return The NetDevice that this ARP cache is associated with
@@ -57,7 +57,7 @@
/**
* \return the Ipv4Interface that this ARP cache is associated with
*/
- Ipv4Interface *GetInterface (void) const;
+ Ptr<Ipv4Interface> GetInterface (void) const;
void SetAliveTimeout (Time aliveTimeout);
void SetDeadTimeout (Time deadTimeout);
@@ -101,7 +101,7 @@
* \param macAddress
* \return
*/
- Packet MarkAlive (MacAddress macAddress);
+ Packet MarkAlive (Address macAddress);
/**
* \param waiting
*/
@@ -127,7 +127,7 @@
/**
* \return The MacAddress of this entry
*/
- MacAddress GetMacAddress (void);
+ Address GetMacAddress (void);
/**
* \return True if this entry has timedout; false otherwise.
*/
@@ -143,7 +143,7 @@
ArpCache *m_arp;
ArpCacheEntryState_e m_state;
Time m_lastSeen;
- MacAddress m_macAddress;
+ Address m_macAddress;
Packet m_waiting;
};
@@ -152,7 +152,7 @@
typedef sgi::hash_map<Ipv4Address, ArpCache::Entry *, Ipv4AddressHash>::iterator CacheI;
Ptr<NetDevice> m_device;
- Ipv4Interface *m_interface;
+ Ptr<Ipv4Interface> m_interface;
Time m_aliveTimeout;
Time m_deadTimeout;
Time m_waitReplyTimeout;
--- a/src/internet-node/arp-header.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-header.cc Fri Sep 28 11:59:46 2007 +0100
@@ -20,18 +20,24 @@
*/
#include "ns3/assert.h"
+#include "ns3/address-utils.h"
#include "arp-header.h"
-#include "header-utils.h"
namespace ns3 {
-ArpHeader::~ArpHeader ()
-{}
+NS_HEADER_ENSURE_REGISTERED (ArpHeader);
+
+uint32_t
+ArpHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<ArpHeader> ("ArpHeader.ns3");
+ return uid;
+}
void
-ArpHeader::SetRequest (MacAddress sourceHardwareAddress,
+ArpHeader::SetRequest (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress)
{
m_type = ARP_TYPE_REQUEST;
@@ -41,9 +47,9 @@
m_ipv4Dest = destinationProtocolAddress;
}
void
-ArpHeader::SetReply (MacAddress sourceHardwareAddress,
+ArpHeader::SetReply (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress)
{
m_type = ARP_TYPE_REPLY;
@@ -62,12 +68,12 @@
{
return (m_type == ARP_TYPE_REPLY)?true:false;
}
-MacAddress
+Address
ArpHeader::GetSourceHardwareAddress (void)
{
return m_macSource;
}
-MacAddress
+Address
ArpHeader::GetDestinationHardwareAddress (void)
{
return m_macDest;
@@ -83,24 +89,36 @@
return m_ipv4Dest;
}
+std::string
+ArpHeader::GetName (void) const
+{
+ return "ARP";
+}
void
-ArpHeader::PrintTo (std::ostream &os) const
+ArpHeader::Print (std::ostream &os) const
{
- os << "(arp)";
if (IsRequest ())
{
- os << " source mac: " << m_macSource
- << " source ipv4: " << m_ipv4Source
- << " dest ipv4: " << m_ipv4Dest;
+ os << "("
+ << "request "
+ << "source mac: " << m_macSource << " "
+ << "source ipv4: " << m_ipv4Source << " "
+ << "dest ipv4: " << m_ipv4Dest
+ << ")"
+ ;
}
else
{
NS_ASSERT (IsReply ());
- os << " source mac: " << m_macSource
- << " source ipv4: " << m_ipv4Source
- << " dest mac: " << m_macDest
- << " dest ipv4: " <<m_ipv4Dest;
+ os << "("
+ << "reply "
+ << "source mac: " << m_macSource << " "
+ << "source ipv4: " << m_ipv4Source << " "
+ << "dest mac: " << m_macDest << " "
+ << "dest ipv4: " <<m_ipv4Dest
+ << ")"
+ ;
}
}
uint32_t
@@ -111,7 +129,7 @@
}
void
-ArpHeader::SerializeTo (Buffer::Iterator start) const
+ArpHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
NS_ASSERT (m_macSource.GetLength () == m_macDest.GetLength ());
@@ -129,7 +147,7 @@
WriteTo (i, m_ipv4Dest);
}
uint32_t
-ArpHeader::DeserializeFrom (Buffer::Iterator start)
+ArpHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
i.Next (2+2);
--- a/src/internet-node/arp-header.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-header.h Fri Sep 28 11:59:46 2007 +0100
@@ -23,58 +23,47 @@
#define ARP_HEADER_H
#include "ns3/header.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
#include "ns3/ipv4-address.h"
+#include <string>
namespace ns3 {
/**
* \brief The packet header for an ARP packet
*/
-class ArpHeader : public Header {
- public:
- virtual ~ArpHeader ();
+class ArpHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
- void SetRequest (MacAddress sourceHardwareAddress,
+ void SetRequest (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress);
- void SetReply (MacAddress sourceHardwareAddress,
+ void SetReply (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress);
bool IsRequest (void) const;
bool IsReply (void) const;
- MacAddress GetSourceHardwareAddress (void);
- MacAddress GetDestinationHardwareAddress (void);
+ Address GetSourceHardwareAddress (void);
+ Address GetDestinationHardwareAddress (void);
Ipv4Address GetSourceIpv4Address (void);
Ipv4Address GetDestinationIpv4Address (void);
-private:
- /**
- * \param os
- */
- virtual void PrintTo (std::ostream &os) const;
- /**
- * \return
- */
- virtual uint32_t GetSerializedSize (void) const;
- /**
- * \param start
- */
- virtual void SerializeTo (Buffer::Iterator start) const;
- /**
- * \param start
- * \return
- */
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
enum ArpType_e {
ARP_TYPE_REQUEST = 1,
ARP_TYPE_REPLY = 2
};
uint16_t m_type;
- MacAddress m_macSource;
- MacAddress m_macDest;
+ Address m_macSource;
+ Address m_macDest;
Ipv4Address m_ipv4Source;
Ipv4Address m_ipv4Dest;
};
--- a/src/internet-node/arp-ipv4-interface.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-ipv4-interface.cc Fri Sep 28 11:59:46 2007 +0100
@@ -21,54 +21,95 @@
*/
#include "ns3/packet.h"
+#include "ns3/log.h"
#include "ns3/composite-trace-resolver.h"
#include "ns3/node.h"
#include "ns3/net-device.h"
+#include "ns3/address.h"
#include "arp-ipv4-interface.h"
-#include "arp-private.h"
#include "ipv4-l3-protocol.h"
+#include "arp-l3-protocol.h"
+
+NS_LOG_COMPONENT_DEFINE ("ArpIpv4Interface");
namespace ns3 {
ArpIpv4Interface::ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device)
: Ipv4Interface (device),
m_node (node)
-{}
-ArpIpv4Interface::~ArpIpv4Interface ()
-{}
+{
+ NS_LOG_FUNCTION;
+}
-TraceResolver *
-ArpIpv4Interface::DoCreateTraceResolver (TraceContext const &context)
+ArpIpv4Interface::~ArpIpv4Interface ()
{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+ NS_LOG_FUNCTION;
+}
+
+Ptr<TraceResolver>
+ArpIpv4Interface::GetTraceResolver (void) const
+{
+ NS_LOG_FUNCTION;
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
if (GetDevice () != 0)
{
- resolver->Add ("netdevice",
- MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())),
- ArpIpv4Interface::NETDEVICE);
+ resolver->AddComposite ("netdevice", GetDevice ());
}
-
+ resolver->SetParentResolver (Ipv4Interface::GetTraceResolver ());
return resolver;
}
void
ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ", " << dest << ")");
+
NS_ASSERT (GetDevice () != 0);
if (GetDevice ()->NeedsArp ())
{
- Ptr<ArpPrivate> arp = m_node->QueryInterface<ArpPrivate> (ArpPrivate::iid);
- MacAddress hardwareDestination;
- bool found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
+ NS_LOG_LOGIC ("Needs ARP");
+ Ptr<ArpL3Protocol> arp =
+ m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
+ Address hardwareDestination;
+ bool found;
+
+ if (dest.IsBroadcast () ||
+ dest.IsSubnetDirectedBroadcast (GetNetworkMask ()) )
+ {
+ NS_LOG_LOGIC ("IsBroadcast");
+ hardwareDestination = GetDevice ()->GetBroadcast ();
+ found = true;
+ }
+ else if (dest.IsMulticast ())
+ {
+ NS_LOG_LOGIC ("IsMulticast");
+ NS_ASSERT_MSG(GetDevice ()->IsMulticast (),
+ "ArpIpv4Interface::SendTo (): Sending multicast packet over "
+ "non-multicast device");
+
+ hardwareDestination = GetDevice ()->MakeMulticastAddress(dest);
+ found = true;
+ }
+ else
+ {
+ NS_LOG_LOGIC ("ARP Lookup");
+ found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
+ }
+
if (found)
{
- GetDevice ()->Send (p, hardwareDestination, Ipv4L3Protocol::PROT_NUMBER);
+ NS_LOG_LOGIC ("Address Resolved. Send.");
+ GetDevice ()->Send (p, hardwareDestination,
+ Ipv4L3Protocol::PROT_NUMBER);
}
}
else
{
- GetDevice ()->Send (p, GetDevice ()->GetBroadcast (), Ipv4L3Protocol::PROT_NUMBER);
+ NS_LOG_LOGIC ("Doesn't need ARP");
+ GetDevice ()->Send (p, GetDevice ()->GetBroadcast (),
+ Ipv4L3Protocol::PROT_NUMBER);
}
}
--- a/src/internet-node/arp-ipv4-interface.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-ipv4-interface.h Fri Sep 28 11:59:46 2007 +0100
@@ -39,16 +39,13 @@
class ArpIpv4Interface : public Ipv4Interface
{
public:
- enum TraceType {
- NETDEVICE,
- ARP,
- };
ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device);
virtual ~ArpIpv4Interface ();
- private:
+protected:
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+private:
virtual void SendTo (Packet p, Ipv4Address dest);
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
Ptr<Node> m_node;
};
--- a/src/internet-node/arp-l3-protocol.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-l3-protocol.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,52 +19,52 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "ns3/packet.h"
-#include "ns3/debug.h"
-#include "ns3/empty-trace-resolver.h"
+#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/net-device.h"
+#include "ipv4-l3-protocol.h"
#include "arp-l3-protocol.h"
#include "arp-header.h"
#include "arp-cache.h"
#include "ipv4-interface.h"
-#include "ipv4-private.h"
-NS_DEBUG_COMPONENT_DEFINE ("ArpL3Protocol");
+NS_LOG_COMPONENT_DEFINE ("ArpL3Protocol");
namespace ns3 {
+const InterfaceId ArpL3Protocol::iid = MakeInterfaceId ("ArpL3Protocol", Object::iid);
const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
ArpL3Protocol::ArpL3Protocol (Ptr<Node> node)
- : L3Protocol (PROT_NUMBER, 0/* XXX: correct version number ? */ ),
- m_node (node)
-{}
+ : m_node (node)
+{
+ NS_LOG_FUNCTION;
+ SetInterfaceId (ArpL3Protocol::iid);
+}
ArpL3Protocol::~ArpL3Protocol ()
-{}
+{
+ NS_LOG_FUNCTION;
+}
void
ArpL3Protocol::DoDispose (void)
{
+ NS_LOG_FUNCTION;
for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
{
delete *i;
}
m_cacheList.clear ();
m_node = 0;
- L3Protocol::DoDispose ();
-}
-
-TraceResolver *
-ArpL3Protocol::CreateTraceResolver (TraceContext const &context)
-{
- return new EmptyTraceResolver (context);
+ Object::DoDispose ();
}
ArpCache *
ArpL3Protocol::FindCache (Ptr<NetDevice> device)
{
+ NS_LOG_FUNCTION;
for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
{
if ((*i)->GetDevice () == device)
@@ -72,8 +72,8 @@
return *i;
}
}
- Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
- Ipv4Interface *interface = ipv4->FindInterfaceForDevice (device);
+ Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+ Ptr<Ipv4Interface> interface = ipv4->FindInterfaceForDevice (device);
ArpCache * cache = new ArpCache (device, interface);
NS_ASSERT (device->IsBroadcast ());
device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
@@ -82,22 +82,31 @@
}
void
-ArpL3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+ArpL3Protocol::Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
{
+ NS_LOG_FUNCTION;
ArpCache *cache = FindCache (device);
ArpHeader arp;
+ Packet packet = p;
packet.RemoveHeader (arp);
+
+ NS_LOG_LOGIC ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") <<
+ " node="<<m_node->GetId ()<<", got request from " <<
+ arp.GetSourceIpv4Address () << " for address " <<
+ arp.GetDestinationIpv4Address () << "; we have address " <<
+ cache->GetInterface ()->GetAddress ());
+
if (arp.IsRequest () &&
arp.GetDestinationIpv4Address () == cache->GetInterface ()->GetAddress ())
{
- NS_DEBUG ("node="<<m_node->GetId () <<", got request from " <<
+ NS_LOG_LOGIC ("node="<<m_node->GetId () <<", got request from " <<
arp.GetSourceIpv4Address () << " -- send reply");
SendArpReply (cache, arp.GetSourceIpv4Address (),
arp.GetSourceHardwareAddress ());
}
else if (arp.IsReply () &&
arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress ()) &&
- arp.GetDestinationHardwareAddress ().IsEqual (device->GetAddress ()))
+ arp.GetDestinationHardwareAddress () == device->GetAddress ())
{
Ipv4Address from = arp.GetSourceIpv4Address ();
ArpCache::Entry *entry = cache->Lookup (from);
@@ -105,10 +114,10 @@
{
if (entry->IsWaitReply ())
{
- NS_DEBUG ("node="<<m_node->GetId ()<<", got reply from " <<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply from " <<
arp.GetSourceIpv4Address ()
<< " for waiting entry -- flush");
- MacAddress from_mac = arp.GetSourceHardwareAddress ();
+ Address from_mac = arp.GetSourceHardwareAddress ();
Packet waiting = entry->MarkAlive (from_mac);
cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ());
}
@@ -116,7 +125,7 @@
{
// ignore this reply which might well be an attempt
// at poisening my arp cache.
- NS_DEBUG ("node="<<m_node->GetId ()<<", got reply from " <<
+ NS_LOG_LOGIC("node="<<m_node->GetId ()<<", got reply from " <<
arp.GetSourceIpv4Address () <<
" for non-waiting entry -- drop");
// XXX report packet as dropped.
@@ -124,16 +133,23 @@
}
else
{
- NS_DEBUG ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
// XXX report packet as dropped.
}
}
+ else
+ {
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got request from " <<
+ arp.GetSourceIpv4Address () << " for unknown address " <<
+ arp.GetDestinationIpv4Address () << " -- drop");
+ }
}
bool
ArpL3Protocol::Lookup (Packet &packet, Ipv4Address destination,
- Ptr<NetDevice> device,
- MacAddress *hardwareDestination)
+ Ptr<NetDevice> device,
+ Address *hardwareDestination)
{
+ NS_LOG_FUNCTION;
ArpCache *cache = FindCache (device);
ArpCache::Entry *entry = cache->Lookup (destination);
if (entry != 0)
@@ -142,21 +158,21 @@
{
if (entry->IsDead ())
{
- NS_DEBUG ("node="<<m_node->GetId ()<<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", dead entry for " << destination << " expired -- send arp request");
entry->MarkWaitReply (packet);
SendArpRequest (cache, destination);
}
else if (entry->IsAlive ())
{
- NS_DEBUG ("node="<<m_node->GetId ()<<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", alive entry for " << destination << " expired -- send arp request");
entry->MarkWaitReply (packet);
SendArpRequest (cache, destination);
}
else if (entry->IsWaitReply ())
{
- NS_DEBUG ("node="<<m_node->GetId ()<<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", wait reply for " << destination << " expired -- drop");
entry->MarkDead ();
// XXX report packet as 'dropped'
@@ -166,20 +182,20 @@
{
if (entry->IsDead ())
{
- NS_DEBUG ("node="<<m_node->GetId ()<<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", dead entry for " << destination << " valid -- drop");
// XXX report packet as 'dropped'
}
else if (entry->IsAlive ())
{
- NS_DEBUG ("node="<<m_node->GetId ()<<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", alive entry for " << destination << " valid -- send");
*hardwareDestination = entry->GetMacAddress ();
return true;
}
else if (entry->IsWaitReply ())
{
- NS_DEBUG ("node="<<m_node->GetId ()<<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", wait reply for " << destination << " valid -- drop previous");
Packet old = entry->UpdateWaitReply (packet);
// XXX report 'old' packet as 'dropped'
@@ -190,7 +206,7 @@
else
{
// This is our first attempt to transmit data to this destination.
- NS_DEBUG ("node="<<m_node->GetId ()<<
+ NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", no entry for " << destination << " -- send arp request");
entry = cache->Add (destination);
entry->MarkWaitReply (packet);
@@ -202,7 +218,13 @@
void
ArpL3Protocol::SendArpRequest (ArpCache const *cache, Ipv4Address to)
{
+ NS_LOG_FUNCTION;
ArpHeader arp;
+ NS_LOG_LOGIC ("ARP: sending request from node "<<m_node->GetId ()<<
+ " || src: " << cache->GetDevice ()->GetAddress () <<
+ " / " << cache->GetInterface ()->GetAddress () <<
+ " || dst: " << cache->GetDevice ()->GetBroadcast () <<
+ " / " << to);
arp.SetRequest (cache->GetDevice ()->GetAddress (),
cache->GetInterface ()->GetAddress (),
cache->GetDevice ()->GetBroadcast (),
@@ -213,9 +235,14 @@
}
void
-ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac)
+ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac)
{
+ NS_LOG_FUNCTION;
ArpHeader arp;
+ NS_LOG_LOGIC ("ARP: sending reply from node "<<m_node->GetId ()<<
+ "|| src: " << cache->GetDevice ()->GetAddress () <<
+ " / " << cache->GetInterface ()->GetAddress () <<
+ " || dst: " << toMac << " / " << toIp);
arp.SetReply (cache->GetDevice ()->GetAddress (),
cache->GetInterface ()->GetAddress (),
toMac, toIp);
--- a/src/internet-node/arp-l3-protocol.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-l3-protocol.h Fri Sep 28 11:59:46 2007 +0100
@@ -23,9 +23,8 @@
#include <list>
#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
#include "ns3/ptr.h"
-#include "l3-protocol.h"
namespace ns3 {
@@ -38,22 +37,21 @@
/**
* \brief An implementation of the ARP protocol
*/
-class ArpL3Protocol : public L3Protocol
+class ArpL3Protocol : public Object
{
public:
+ static const InterfaceId iid;
static const uint16_t PROT_NUMBER;
/**
* \brief Constructor
* \param node The node which this ARP object is associated with
*/
ArpL3Protocol (Ptr<Node> node);
- ~ArpL3Protocol ();
-
- virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
+ virtual ~ArpL3Protocol ();
/**
* \brief Recieve a packet
*/
- virtual void Receive(Packet& p, Ptr<NetDevice> device);
+ void Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
/**
* \brief Perform an ARP lookup
* \param p
@@ -64,14 +62,14 @@
*/
bool Lookup (Packet &p, Ipv4Address destination,
Ptr<NetDevice> device,
- MacAddress *hardwareDestination);
+ Address *hardwareDestination);
protected:
virtual void DoDispose (void);
private:
typedef std::list<ArpCache *> CacheList;
ArpCache *FindCache (Ptr<NetDevice> device);
void SendArpRequest (ArpCache const *cache, Ipv4Address to);
- void SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac);
+ void SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac);
CacheList m_cacheList;
Ptr<Node> m_node;
};
--- a/src/internet-node/arp-private.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "arp-private.h"
-#include "arp-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId ArpPrivate::iid = MakeInterfaceId ("ArpPrivate", Object::iid);
-
-ArpPrivate::ArpPrivate (Ptr<ArpL3Protocol> arp)
- : m_arp (arp)
-{
- SetInterfaceId (ArpPrivate::iid);
-}
-ArpPrivate::~ArpPrivate ()
-{
- NS_ASSERT (m_arp == 0);
-}
-
-bool
-ArpPrivate::Lookup (Packet &p, Ipv4Address destination,
- Ptr<NetDevice> device,
- MacAddress *hardwareDestination)
-{
- return m_arp->Lookup (p, destination, device, hardwareDestination);
-}
-
-void
-ArpPrivate::DoDispose (void)
-{
- m_arp = 0;
- Object::DoDispose ();
-}
-
-
-} // namespace ns3
--- a/src/internet-node/arp-private.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef ARP_PRIVATE_H
-#define ARP_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-
-namespace ns3 {
-
-class NetDevice;
-class MacAddress;
-class Packet;
-class ArpL3Protocol;
-
-class ArpPrivate : public Object
-{
-public:
- static const InterfaceId iid;
- ArpPrivate (Ptr<ArpL3Protocol> arp);
- virtual ~ArpPrivate ();
- bool Lookup (Packet &p, Ipv4Address destination,
- Ptr<NetDevice> device,
- MacAddress *hardwareDestination);
-protected:
- virtual void DoDispose (void);
-private:
- Ptr<ArpL3Protocol> m_arp;
-};
-
-} // namespace ns3
-
-#endif /* ARP_PRIVATE_H */
--- a/src/internet-node/ascii-trace.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ascii-trace.cc Fri Sep 28 11:59:46 2007 +0100
@@ -21,17 +21,11 @@
#include "ascii-trace.h"
#include "ns3/trace-context.h"
-#include "ns3/trace-root.h"
#include "ns3/simulator.h"
#include "ns3/node.h"
+#include "ns3/node-list.h"
+#include "ns3/packet.h"
#include "ns3/queue.h"
-#include "ns3/node-list.h"
-#include "ns3/llc-snap-header.h"
-
-#include "ipv4-l3-protocol.h"
-#include "arp-header.h"
-#include "udp-header.h"
-#include "ipv4-header.h"
namespace ns3 {
@@ -46,90 +40,64 @@
void
AsciiTrace::TraceAllQueues (void)
{
- TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*",
- MakeCallback (&AsciiTrace::LogDevQueue, this));
+ Packet::EnableMetadata ();
+ NodeList::Connect ("/nodes/*/devices/*/queue/enqueue",
+ MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this));
+ NodeList::Connect ("/nodes/*/devices/*/queue/dequeue",
+ MakeCallback (&AsciiTrace::LogDevQueueDequeue, this));
+ NodeList::Connect ("/nodes/*/devices/*/queue/drop",
+ MakeCallback (&AsciiTrace::LogDevQueueDrop, this));
}
void
AsciiTrace::TraceAllNetDeviceRx (void)
{
- TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx",
- MakeCallback (&AsciiTrace::LogDevRx, this));
+ Packet::EnableMetadata ();
+ NodeList::Connect ("/nodes/*/devices/*/rx",
+ MakeCallback (&AsciiTrace::LogDevRx, this));
+}
+
+void
+AsciiTrace::LogDevQueueEnqueue (TraceContext const &context,
+ Packet const &packet)
+{
+ m_os << "+ ";
+ m_os << Simulator::Now ().GetSeconds () << " ";
+ context.Print (m_os);
+ m_os << " pkt-uid=" << packet.GetUid () << " ";
+ packet.Print (m_os);
+ m_os << std::endl;
}
-void
-AsciiTrace::PrintType (Packet const &packet)
+void
+AsciiTrace::LogDevQueueDequeue (TraceContext const &context,
+ Packet const &packet)
{
- Packet p = packet;
- LlcSnapHeader llc;
- p.RemoveHeader (llc);
- switch (llc.GetType ())
- {
- case 0x0800: {
- Ipv4Header ipv4;
- p.RemoveHeader (ipv4);
- if (ipv4.GetProtocol () == 17)
- {
- UdpHeader udp;
- p.RemoveHeader (udp);
- m_os << "udp size=" << p.GetSize ();
- }
- } break;
- case 0x0806: {
- ArpHeader arp;
- p.RemoveHeader (arp);
- m_os << "arp ";
- if (arp.IsRequest ())
- {
- m_os << "request";
- }
- else
- {
- m_os << "reply ";
- }
- } break;
- }
-}
+ m_os << "- ";
+ m_os << Simulator::Now ().GetSeconds () << " ";
+ context.Print (m_os);
+ m_os << " pkt-uid=" << packet.GetUid () << " ";
+ packet.Print (m_os);
+ m_os << std::endl;
+}
void
-AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet)
+AsciiTrace::LogDevQueueDrop (TraceContext const &context,
+ Packet const &packet)
{
- enum Queue::TraceType type;
- context.Get (type);
- switch (type)
- {
- case Queue::ENQUEUE:
- m_os << "+ ";
- break;
- case Queue::DEQUEUE:
- m_os << "- ";
- break;
- case Queue::DROP:
- m_os << "d ";
- break;
- }
+ m_os << "d ";
m_os << Simulator::Now ().GetSeconds () << " ";
- NodeList::NodeIndex nodeIndex;
- context.Get (nodeIndex);
- m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
- Ipv4L3Protocol::InterfaceIndex interfaceIndex;
- context.Get (interfaceIndex);
- m_os << "interface=" << interfaceIndex << " ";
- m_os << "pkt-uid=" << packet.GetUid () << " ";
- PrintType (packet);
+ context.Print (m_os);
+ m_os << " pkt-uid=" << packet.GetUid () << " ";
+ packet.Print (m_os);
m_os << std::endl;
}
void
-AsciiTrace::LogDevRx (TraceContext const &context, Packet &p)
+AsciiTrace::LogDevRx (TraceContext const &context, const Packet &p)
{
m_os << "r " << Simulator::Now ().GetSeconds () << " ";
- NodeList::NodeIndex nodeIndex;
- context.Get (nodeIndex);
- m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
- Ipv4L3Protocol::InterfaceIndex interfaceIndex;
- context.Get (interfaceIndex);
- m_os << "interface=" << interfaceIndex << " ";
- m_os << "pkt-uid=" << p.GetUid () << " ";
- PrintType (p);
+ context.Print (m_os);
+ m_os << " pkt-uid=" << p.GetUid () << " ";
+ p.Print (m_os);
m_os << std::endl;
}
--- a/src/internet-node/ascii-trace.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ascii-trace.h Fri Sep 28 11:59:46 2007 +0100
@@ -37,9 +37,10 @@
void TraceAllQueues (void);
void TraceAllNetDeviceRx (void);
private:
- void PrintType (Packet const &p);
- void LogDevQueue (TraceContext const &context, const Packet &p);
- void LogDevRx (TraceContext const &context, Packet &p);
+ void LogDevQueueEnqueue (TraceContext const &context, const Packet &p);
+ void LogDevQueueDequeue (TraceContext const &context, const Packet &p);
+ void LogDevQueueDrop (TraceContext const &context, const Packet &p);
+ void LogDevRx (TraceContext const &context, const Packet &p);
std::ofstream m_os;
};
--- a/src/internet-node/header-utils.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "header-utils.h"
-
-namespace ns3 {
-
-void WriteTo (Buffer::Iterator &i, Ipv4Address ad)
-{
- i.WriteHtonU32 (ad.GetHostOrder ());
-}
-void WriteTo (Buffer::Iterator &i, MacAddress ad)
-{
- uint8_t mac[MacAddress::MAX_LEN];
- ad.Peek (mac);
- i.Write (mac, ad.GetLength ());
-}
-
-void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad)
-{
- ad.SetHostOrder (i.ReadNtohU32 ());
-}
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len)
-{
- uint8_t mac[MacAddress::MAX_LEN];
- i.Read (mac, len);
- ad.Set (mac, len);
-}
-
-
-
-}; // namespace ns3
--- a/src/internet-node/header-utils.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef HEADER_UTILS_H
-#define HEADER_UTILS_H
-
-#include "ns3/buffer.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
-
-namespace ns3 {
-
-void WriteTo (Buffer::Iterator &i, Ipv4Address ad);
-void WriteTo (Buffer::Iterator &i, MacAddress ad);
-
-void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad);
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len);
-
-};
-
-#endif /* HEADER_UTILS_H */
--- a/src/internet-node/internet-node.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/internet-node.cc Fri Sep 28 11:59:46 2007 +0100
@@ -23,21 +23,18 @@
#include "ns3/composite-trace-resolver.h"
#include "ns3/net-device.h"
+#include "ns3/callback.h"
-#include "l3-demux.h"
#include "ipv4-l4-demux.h"
#include "internet-node.h"
#include "udp-l4-protocol.h"
#include "ipv4-l3-protocol.h"
#include "arp-l3-protocol.h"
#include "udp-impl.h"
-#include "arp-private.h"
#include "ipv4-impl.h"
-#include "ipv4-private.h"
namespace ns3 {
-
InternetNode::InternetNode()
{
Construct ();
@@ -56,38 +53,34 @@
{
Ptr<Ipv4L3Protocol> ipv4 = Create<Ipv4L3Protocol> (this);
Ptr<ArpL3Protocol> arp = Create<ArpL3Protocol> (this);
- Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
+ // XXX remove the PeekPointer below.
+ RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, PeekPointer (ipv4)),
+ Ipv4L3Protocol::PROT_NUMBER, 0);
+ RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (arp)),
+ ArpL3Protocol::PROT_NUMBER, 0);
- Ptr<L3Demux> l3Demux = Create<L3Demux> (this);
+
Ptr<Ipv4L4Demux> ipv4L4Demux = Create<Ipv4L4Demux> (this);
-
- l3Demux->Insert (ipv4);
- l3Demux->Insert (arp);
+ Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
ipv4L4Demux->Insert (udp);
Ptr<UdpImpl> udpImpl = Create<UdpImpl> (udp);
- Ptr<ArpPrivate> arpPrivate = Create<ArpPrivate> (arp);
Ptr<Ipv4Impl> ipv4Impl = Create<Ipv4Impl> (ipv4);
- Ptr<Ipv4Private> ipv4Private = Create<Ipv4Private> (ipv4);
- Object::AddInterface (ipv4Private);
+ Object::AddInterface (ipv4);
+ Object::AddInterface (arp);
Object::AddInterface (ipv4Impl);
- Object::AddInterface (arpPrivate);
Object::AddInterface (udpImpl);
- Object::AddInterface (l3Demux);
Object::AddInterface (ipv4L4Demux);
}
-
-TraceResolver *
-InternetNode::DoCreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+InternetNode::GetTraceResolver () const
{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- Ptr<Ipv4Private> ipv4 = QueryInterface<Ipv4Private> (Ipv4Private::iid);
- resolver->Add ("ipv4",
- MakeCallback (&Ipv4Private::CreateTraceResolver, PeekPointer (ipv4)),
- InternetNode::IPV4);
-
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ Ptr<Ipv4L3Protocol> ipv4 = QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+ resolver->AddComposite ("ipv4", ipv4);
+ resolver->SetParentResolver (Node::GetTraceResolver ());
return resolver;
}
@@ -97,25 +90,4 @@
Node::DoDispose ();
}
-void
-InternetNode::DoAddDevice (Ptr<NetDevice> device) const
-{
- device->SetReceiveCallback (MakeCallback (&InternetNode::ReceiveFromDevice, this));
-}
-
-bool
-InternetNode::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const
-{
- Ptr<L3Demux> demux = QueryInterface<L3Demux> (L3Demux::iid);
- Ptr<L3Protocol> target = demux->GetProtocol (protocolNumber);
- if (target != 0)
- {
- Packet packet = p;
- target->Receive(packet, device);
- return true;
- }
- return false;
-}
-
-
}//namespace ns3
--- a/src/internet-node/internet-node.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/internet-node.h Fri Sep 28 11:59:46 2007 +0100
@@ -36,18 +36,14 @@
class InternetNode : public Node
{
public:
- enum TraceType {
- IPV4,
- };
InternetNode();
InternetNode(uint32_t systemId);
virtual ~InternetNode ();
protected:
virtual void DoDispose(void);
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
- virtual void DoAddDevice (Ptr<NetDevice> device) const;
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const;
void Construct (void);
};
--- a/src/internet-node/ipv4-end-point-demux.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point-demux.cc Fri Sep 28 11:59:46 2007 +0100
@@ -21,15 +21,21 @@
#include "ipv4-end-point-demux.h"
#include "ipv4-end-point.h"
+#include "ns3/log.h"
namespace ns3{
+NS_LOG_COMPONENT_DEFINE ("Ipv4EndPointDemux");
+
Ipv4EndPointDemux::Ipv4EndPointDemux ()
- : m_ephemeral (1025)
-{}
+ : m_ephemeral (49152)
+{
+ NS_LOG_FUNCTION;
+}
Ipv4EndPointDemux::~Ipv4EndPointDemux ()
{
+ NS_LOG_FUNCTION;
for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
{
Ipv4EndPoint *endPoint = *i;
@@ -41,6 +47,7 @@
bool
Ipv4EndPointDemux::LookupPortLocal (uint16_t port)
{
+ NS_LOG_FUNCTION;
for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
{
if ((*i)->GetLocalPort () == port)
@@ -54,6 +61,7 @@
bool
Ipv4EndPointDemux::LookupLocal (Ipv4Address addr, uint16_t port)
{
+ NS_LOG_FUNCTION;
for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
{
if ((*i)->GetLocalPort () == port &&
@@ -68,41 +76,56 @@
Ipv4EndPoint *
Ipv4EndPointDemux::Allocate (void)
{
+ NS_LOG_FUNCTION;
uint16_t port = AllocateEphemeralPort ();
if (port == 0)
{
+ NS_LOG_WARN ("Ephemeral port allocation failed.");
return 0;
}
Ipv4EndPoint *endPoint = new Ipv4EndPoint (Ipv4Address::GetAny (), port);
m_endPoints.push_back (endPoint);
+ NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
return endPoint;
}
+
Ipv4EndPoint *
Ipv4EndPointDemux::Allocate (Ipv4Address address)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << this << ", " << address << ")");
uint16_t port = AllocateEphemeralPort ();
if (port == 0)
{
+ NS_LOG_WARN ("Ephemeral port allocation failed.");
return 0;
}
Ipv4EndPoint *endPoint = new Ipv4EndPoint (address, port);
m_endPoints.push_back (endPoint);
+ NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
return endPoint;
}
+
Ipv4EndPoint *
Ipv4EndPointDemux::Allocate (uint16_t port)
{
+ NS_LOG_FUNCTION;
return Allocate (Ipv4Address::GetAny (), port);
}
+
Ipv4EndPoint *
Ipv4EndPointDemux::Allocate (Ipv4Address address, uint16_t port)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << this << ", " << address << ", " << port << ")");
if (LookupLocal (address, port))
{
+ NS_LOG_WARN ("Duplicate address/port; failing.");
return 0;
}
Ipv4EndPoint *endPoint = new Ipv4EndPoint (address, port);
m_endPoints.push_back (endPoint);
+ NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
return endPoint;
}
@@ -110,6 +133,11 @@
Ipv4EndPointDemux::Allocate (Ipv4Address localAddress, uint16_t localPort,
Ipv4Address peerAddress, uint16_t peerPort)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(localAddress=" << localAddress
+ << ", localPort=" << localPort
+ << ", peerAddress=" << peerAddress
+ << ", peerPort=" << peerPort << ")");
for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
{
if ((*i)->GetLocalPort () == localPort &&
@@ -117,6 +145,7 @@
(*i)->GetPeerPort () == peerPort &&
(*i)->GetPeerAddress () == peerAddress)
{
+ NS_LOG_WARN ("No way we can allocate this end-point.");
/* no way we can allocate this end-point. */
return 0;
}
@@ -124,12 +153,16 @@
Ipv4EndPoint *endPoint = new Ipv4EndPoint (localAddress, localPort);
endPoint->SetPeer (peerAddress, peerPort);
m_endPoints.push_back (endPoint);
+
+ NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
+
return endPoint;
}
void
Ipv4EndPointDemux::DeAllocate (Ipv4EndPoint *endPoint)
{
+ NS_LOG_FUNCTION;
for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
{
if (*i == endPoint)
@@ -141,41 +174,58 @@
}
}
-
/*
* If we have an exact match, we return it.
* Otherwise, if we find a generic match, we return it.
* Otherwise, we return 0.
*/
-Ipv4EndPoint *
+Ipv4EndPointDemux::EndPoints
Ipv4EndPointDemux::Lookup (Ipv4Address daddr, uint16_t dport,
- Ipv4Address saddr, uint16_t sport)
+ Ipv4Address saddr, uint16_t sport,
+ Ptr<Ipv4Interface> incomingInterface)
{
+ NS_LOG_FUNCTION;
uint32_t genericity = 3;
Ipv4EndPoint *generic = 0;
- //TRACE ("lookup " << daddr << ":" << dport << " " << saddr << ":" << sport);
+ EndPoints retval;
+
+ NS_LOG_PARAM ("(daddr=" << daddr << ", dport=" << dport
+ << ", saddr=" << saddr << ", sport=" << sport << ")");
+
for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
{
-#if 0
- TRACE ("against " <<
- (*i)->GetLocalAddress ()
- << ":" <<
- (*i)->GetLocalPort ()
- << " " <<
- (*i)->GetPeerAddress ()
- << ":"
- << (*i)->GetPeerPort ());
-#endif
+ NS_LOG_DEBUG ("Looking at endpoint dport=" << (*i)->GetLocalPort ()
+ << " daddr=" << (*i)->GetLocalAddress ()
+ << " sport=" << (*i)->GetPeerPort ()
+ << " saddr=" << (*i)->GetPeerAddress ());
if ((*i)->GetLocalPort () != dport)
{
+ NS_LOG_LOGIC ("Skipping endpoint " << &(*i)
+ << " because endpoint dport "
+ << (*i)->GetLocalPort ()
+ << " does not match packet dport " << dport);
continue;
}
- if ((*i)->GetLocalAddress () == daddr &&
- (*i)->GetPeerPort () == sport &&
- (*i)->GetPeerAddress () == saddr)
+ bool isBroadcast =
+ (daddr.IsBroadcast () ||
+ daddr.IsSubnetDirectedBroadcast (incomingInterface->GetNetworkMask ()));
+ NS_LOG_DEBUG ("dest addr " << daddr << " broadcast? " << isBroadcast);
+
+ NS_LOG_LOGIC ("Local address matches: " <<
+ bool ((*i)->GetLocalAddress () == daddr || isBroadcast));
+ NS_LOG_LOGIC ("Peer port matches: " <<
+ bool ((*i)->GetPeerPort () == sport || (*i)->GetPeerPort () == 0));
+ NS_LOG_LOGIC ("Peer address matches: " <<
+ bool ((*i)->GetPeerAddress () == saddr ||
+ (*i)->GetPeerAddress () == Ipv4Address::GetAny ()));
+
+ if ( ((*i)->GetLocalAddress () == daddr || isBroadcast)
+ && ((*i)->GetPeerPort () == sport || (*i)->GetPeerPort () == 0)
+ && ((*i)->GetPeerAddress () == saddr || (*i)->GetPeerAddress () == Ipv4Address::GetAny ()))
{
+ NS_LOG_LOGIC ("MATCH");
/* this is an exact match. */
- return *i;
+ retval.push_back (*i);
}
uint32_t tmp = 0;
if ((*i)->GetLocalAddress () == Ipv4Address::GetAny ())
@@ -192,19 +242,24 @@
genericity = tmp;
}
}
- return generic;
+ if (retval.size () == 0 && generic != 0)
+ {
+ retval.push_back (generic);
+ }
+ return retval;
}
uint16_t
Ipv4EndPointDemux::AllocateEphemeralPort (void)
{
+ NS_LOG_FUNCTION;
uint16_t port = m_ephemeral;
do
{
port++;
- if (port > 5000)
+ if (port == 65535)
{
- port = 1024;
+ port = 49152;
}
if (!LookupPortLocal (port))
{
--- a/src/internet-node/ipv4-end-point-demux.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point-demux.h Fri Sep 28 11:59:46 2007 +0100
@@ -25,6 +25,7 @@
#include <stdint.h>
#include <list>
#include "ns3/ipv4-address.h"
+#include "ipv4-interface.h"
namespace ns3 {
@@ -32,15 +33,19 @@
class Ipv4EndPointDemux {
public:
+ typedef std::list<Ipv4EndPoint *> EndPoints;
+ typedef std::list<Ipv4EndPoint *>::iterator EndPointsI;
+
Ipv4EndPointDemux ();
~Ipv4EndPointDemux ();
bool LookupPortLocal (uint16_t port);
bool LookupLocal (Ipv4Address addr, uint16_t port);
- Ipv4EndPoint *Lookup (Ipv4Address daddr,
- uint16_t dport,
- Ipv4Address saddr,
- uint16_t sport);
+ EndPoints Lookup (Ipv4Address daddr,
+ uint16_t dport,
+ Ipv4Address saddr,
+ uint16_t sport,
+ Ptr<Ipv4Interface> incomingInterface);
Ipv4EndPoint *Allocate (void);
Ipv4EndPoint *Allocate (Ipv4Address address);
@@ -55,8 +60,6 @@
private:
uint16_t AllocateEphemeralPort (void);
- typedef std::list<Ipv4EndPoint *> EndPoints;
- typedef std::list<Ipv4EndPoint *>::iterator EndPointsI;
uint16_t m_ephemeral;
EndPoints m_endPoints;
--- a/src/internet-node/ipv4-end-point.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point.cc Fri Sep 28 11:59:46 2007 +0100
@@ -42,6 +42,13 @@
{
return m_localAddr;
}
+
+void
+Ipv4EndPoint::SetLocalAddress (Ipv4Address address)
+{
+ m_localAddr = address;
+}
+
uint16_t
Ipv4EndPoint::GetLocalPort (void)
{
--- a/src/internet-node/ipv4-end-point.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point.h Fri Sep 28 11:59:46 2007 +0100
@@ -37,6 +37,7 @@
~Ipv4EndPoint ();
Ipv4Address GetLocalAddress (void);
+ void SetLocalAddress (Ipv4Address address);
uint16_t GetLocalPort (void);
Ipv4Address GetPeerAddress (void);
uint16_t GetPeerPort (void);
--- a/src/internet-node/ipv4-header.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-header.cc Fri Sep 28 11:59:46 2007 +0100
@@ -20,27 +20,25 @@
*/
#include "ns3/assert.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "ns3/header.h"
#include "ipv4-header.h"
-NS_DEBUG_COMPONENT_DEFINE ("Ipv4Header");
+NS_LOG_COMPONENT_DEFINE ("Ipv4Header");
namespace ns3 {
-static uint16_t
-UtilsNtoh16 (uint16_t v)
-{
- uint16_t val;
- uint8_t *array;
- array = (uint8_t *)&v;
- val = (array[0] << 8) | (array[1] << 0);
- return val;
-}
-
+NS_HEADER_ENSURE_REGISTERED (Ipv4Header);
bool Ipv4Header::m_calcChecksum = false;
+uint32_t
+Ipv4Header::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<Ipv4Header> ("Ipv4Header.ns3");
+ return uid;
+}
+
Ipv4Header::Ipv4Header ()
: m_payloadSize (0),
m_identification (0),
@@ -51,8 +49,6 @@
m_fragmentOffset (0),
m_goodChecksum (true)
{}
-Ipv4Header::~Ipv4Header ()
-{}
void
Ipv4Header::EnableChecksums (void)
@@ -190,21 +186,48 @@
return m_goodChecksum;
}
+std::string
+Ipv4Header::GetName (void) const
+{
+ return "IPV4";
+}
+
void
-Ipv4Header::PrintTo (std::ostream &os) const
+Ipv4Header::Print (std::ostream &os) const
{
// ipv4, right ?
- os << "(ipv4)"
- << " tos=" << (uint32_t)m_tos
- << ", payload length=" << UtilsNtoh16 (m_payloadSize)
- << ", id=" << m_identification
- << ", " << (IsLastFragment ()?"last":"more")
- << ", " << (IsDontFragment ()?"dont":"may")
- << ", frag offset=" << m_fragmentOffset
- << ", ttl=" << m_ttl
- << ", protocol=" << m_protocol
- << ", source=" << m_source
- << ", destination=" << m_destination;
+ std::string flags;
+ if (m_flags == 0)
+ {
+ flags = "none";
+ }
+ else if (m_flags & MORE_FRAGMENTS &&
+ m_flags & DONT_FRAGMENT)
+ {
+ flags = "MF|DF";
+ }
+ else if (m_flags & DONT_FRAGMENT)
+ {
+ flags = "DF";
+ }
+ else if (m_flags & MORE_FRAGMENTS)
+ {
+ flags = "MF";
+ }
+ else
+ {
+ flags = "XX";
+ }
+ os << "("
+ << "tos 0x" << std::hex << m_tos << std::dec << " "
+ << "ttl " << m_ttl << " "
+ << "id " << m_identification << " "
+ << "offset " << m_fragmentOffset << " "
+ << "flags [" << flags << "] "
+ << "length: " << (m_payloadSize + 5 * 4)
+ << ") "
+ << m_source << " > " << m_destination
+ ;
}
uint32_t
Ipv4Header::GetSerializedSize (void) const
@@ -213,7 +236,7 @@
}
void
-Ipv4Header::SerializeTo (Buffer::Iterator start) const
+Ipv4Header::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
@@ -248,7 +271,7 @@
uint8_t *data = start.PeekData ();
uint16_t checksum = UtilsChecksumCalculate (0, data, GetSize ());
checksum = UtilsChecksumComplete (checksum);
- NS_DEBUG ("checksum=" <<checksum);
+ NS_LOG_LOGIC ("checksum=" <<checksum);
i = start;
i.Next (10);
i.WriteU16 (checksum);
@@ -256,7 +279,7 @@
}
}
uint32_t
-Ipv4Header::DeserializeFrom (Buffer::Iterator start)
+Ipv4Header::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
uint8_t verIhl = i.ReadU8 ();
--- a/src/internet-node/ipv4-header.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-header.h Fri Sep 28 11:59:46 2007 +0100
@@ -29,13 +29,14 @@
/**
* \brief Packet header for IPv4
*/
-class Ipv4Header : public Header {
+class Ipv4Header : public Header
+{
public:
+ static uint32_t GetUid (void);
/**
* \brief Construct a null IPv4 header
*/
Ipv4Header ();
- virtual ~Ipv4Header ();
/**
* \brief Enable checksum calculation for IP (XXX currently has no effect)
*/
@@ -139,11 +140,12 @@
*/
bool IsChecksumOk (void) const;
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
private:
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
enum FlagsE {
DONT_FRAGMENT = (1<<0),
@@ -164,7 +166,7 @@
bool m_goodChecksum;
};
-}; // namespace ns3
+} // namespace ns3
#endif /* IPV4_HEADER_H */
--- a/src/internet-node/ipv4-impl.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-impl.cc Fri Sep 28 11:59:46 2007 +0100
@@ -39,6 +39,13 @@
m_ipv4 = 0;
}
+void
+Ipv4Impl::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+ int16_t priority)
+{
+ m_ipv4->AddRoutingProtocol (routingProtocol, priority);
+}
+
void
Ipv4Impl::AddHostRouteTo (Ipv4Address dest,
Ipv4Address nextHop,
@@ -88,16 +95,72 @@
{
return m_ipv4->RemoveRoute (i);
}
+
+void
+Ipv4Impl::AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ m_ipv4->AddMulticastRoute (origin, group, inputInterface, outputInterfaces);
+}
+
+void
+Ipv4Impl::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+ m_ipv4->SetDefaultMulticastRoute (outputInterface);
+}
+
+uint32_t
+Ipv4Impl::GetNMulticastRoutes (void) const
+{
+ return m_ipv4->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute
+Ipv4Impl::GetMulticastRoute (uint32_t i) const
+{
+ return *m_ipv4->GetMulticastRoute (i);
+}
+
+void
+Ipv4Impl::RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface)
+{
+ m_ipv4->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void
+Ipv4Impl::RemoveMulticastRoute (uint32_t i)
+{
+ return m_ipv4->RemoveMulticastRoute (i);
+}
+
uint32_t
Ipv4Impl::AddInterface (Ptr<NetDevice> device)
{
return m_ipv4->AddInterface (device);
}
+
uint32_t
Ipv4Impl::GetNInterfaces (void)
{
return m_ipv4->GetNInterfaces ();
}
+
+uint32_t
+Ipv4Impl::FindInterfaceForAddr (Ipv4Address addr) const
+{
+ return m_ipv4->FindInterfaceForAddr (addr);
+}
+
+uint32_t
+Ipv4Impl::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
+{
+ return m_ipv4->FindInterfaceForAddr (addr, mask);
+}
+
Ptr<NetDevice>
Ipv4Impl::GetNetDevice (uint32_t i)
{
@@ -105,6 +168,18 @@
}
void
+Ipv4Impl::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+ m_ipv4->JoinMulticastGroup(origin, group);
+}
+
+void
+Ipv4Impl::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+ m_ipv4->LeaveMulticastGroup(origin, group);
+}
+
+void
Ipv4Impl::SetAddress (uint32_t i, Ipv4Address address)
{
m_ipv4->SetAddress (i, address);
@@ -119,11 +194,39 @@
{
return m_ipv4->GetNetworkMask (i);
}
+
Ipv4Address
Ipv4Impl::GetAddress (uint32_t i) const
{
return m_ipv4->GetAddress (i);
}
+
+bool
+Ipv4Impl::GetIfIndexForDestination (Ipv4Address dest, uint32_t &ifIndex) const
+{
+ return m_ipv4->GetIfIndexForDestination (dest, ifIndex);
+}
+
+Ipv4Address
+Ipv4Impl::GetSourceAddress (Ipv4Address destination) const
+{
+ uint32_t ifIndex = 0xffffffff;
+
+ bool result = m_ipv4->GetIfIndexForDestination (destination, ifIndex);
+
+ if (result)
+ {
+ return m_ipv4->GetAddress (ifIndex);
+ }
+ else
+ {
+//
+// If we can't find any address, just leave it 0.0.0.0
+//
+ return Ipv4Address::GetAny ();
+ }
+}
+
uint16_t
Ipv4Impl::GetMtu (uint32_t i) const
{
--- a/src/internet-node/ipv4-impl.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-impl.h Fri Sep 28 11:59:46 2007 +0100
@@ -35,6 +35,9 @@
virtual ~Ipv4Impl ();
+ virtual void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+ int16_t priority);
+
virtual void AddHostRouteTo (Ipv4Address dest,
Ipv4Address nextHop,
uint32_t interface);
@@ -52,14 +55,43 @@
virtual uint32_t GetNRoutes (void);
virtual Ipv4Route GetRoute (uint32_t i);
virtual void RemoveRoute (uint32_t i);
+
+
+ virtual void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+ virtual void SetDefaultMulticastRoute (uint32_t outputInterface);
+
+ virtual uint32_t GetNMulticastRoutes (void) const;
+ virtual Ipv4MulticastRoute GetMulticastRoute (uint32_t i) const;
+
+ virtual void RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface);
+ virtual void RemoveMulticastRoute (uint32_t i);
+
virtual uint32_t AddInterface (Ptr<NetDevice> device);
virtual uint32_t GetNInterfaces (void);
+
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr) const;
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr,
+ Ipv4Mask mask) const;
+
virtual Ptr<NetDevice> GetNetDevice(uint32_t i);
+ virtual void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+ virtual void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
virtual void SetAddress (uint32_t i, Ipv4Address address);
virtual void SetNetworkMask (uint32_t i, Ipv4Mask mask);
virtual Ipv4Mask GetNetworkMask (uint32_t t) const;
virtual Ipv4Address GetAddress (uint32_t i) const;
+ virtual Ipv4Address GetSourceAddress (Ipv4Address destination) const;
+ virtual bool GetIfIndexForDestination (Ipv4Address dest,
+ uint32_t &ifIndex) const;
+
virtual uint16_t GetMtu (uint32_t i) const;
virtual bool IsUp (uint32_t i) const;
virtual void SetUp (uint32_t i);
--- a/src/internet-node/ipv4-interface.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-interface.cc Fri Sep 28 11:59:46 2007 +0100
@@ -22,6 +22,10 @@
#include "ipv4-interface.h"
#include "ns3/ipv4-address.h"
#include "ns3/net-device.h"
+#include "ns3/trace-resolver.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4Interface");
namespace ns3 {
@@ -34,56 +38,75 @@
Ipv4Interface::Ipv4Interface (Ptr<NetDevice> nd)
: m_netdevice (nd),
m_ifup(false)
-{}
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &nd << ")");
+}
Ipv4Interface::~Ipv4Interface ()
-{}
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+Ipv4Interface::DoDispose (void)
+{
+ NS_LOG_FUNCTION;
+ m_netdevice = 0;
+ Object::DoDispose ();
+}
Ptr<NetDevice>
Ipv4Interface::GetDevice (void) const
{
+ NS_LOG_FUNCTION;
return m_netdevice;
}
-TraceResolver *
-Ipv4Interface::CreateTraceResolver (TraceContext const &context)
-{
- return DoCreateTraceResolver (context);
-}
-
void
Ipv4Interface::SetAddress (Ipv4Address a)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << a << ")");
m_address = a;
}
+
void
Ipv4Interface::SetNetworkMask (Ipv4Mask mask)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << mask << ")");
m_netmask = mask;
}
Ipv4Address
Ipv4Interface::GetBroadcast (void) const
{
+ NS_LOG_FUNCTION;
uint32_t mask = m_netmask.GetHostOrder ();
uint32_t address = m_address.GetHostOrder ();
Ipv4Address broadcast = Ipv4Address (address | (~mask));
return broadcast;
}
+
Ipv4Mask
Ipv4Interface::GetNetworkMask (void) const
{
+ NS_LOG_FUNCTION;
return m_netmask;
}
+
Ipv4Address
Ipv4Interface::GetAddress (void) const
{
+ NS_LOG_FUNCTION;
return m_address;
}
uint16_t
Ipv4Interface::GetMtu (void) const
{
+ NS_LOG_FUNCTION;
if (m_netdevice == 0)
{
uint32_t mtu = (1<<16) - 1;
@@ -92,32 +115,36 @@
return m_netdevice->GetMtu ();
}
- /**
- * These are IP interface states and may be distinct from
- * NetDevice states, such as found in real implementations
- * (where the device may be down but IP interface state is still up).
- */
+/**
+ * These are IP interface states and may be distinct from
+ * NetDevice states, such as found in real implementations
+ * (where the device may be down but IP interface state is still up).
+ */
bool
Ipv4Interface::IsUp (void) const
{
+ NS_LOG_FUNCTION;
return m_ifup;
}
bool
Ipv4Interface::IsDown (void) const
{
+ NS_LOG_FUNCTION;
return !m_ifup;
}
void
Ipv4Interface::SetUp (void)
{
+ NS_LOG_FUNCTION;
m_ifup = true;
}
void
Ipv4Interface::SetDown (void)
{
+ NS_LOG_FUNCTION;
m_ifup = false;
}
@@ -125,7 +152,9 @@
void
Ipv4Interface::Send(Packet p, Ipv4Address dest)
{
+ NS_LOG_FUNCTION;
if (IsUp()) {
+ NS_LOG_LOGIC ("SendTo");
SendTo(p, dest);
}
}
--- a/src/internet-node/ipv4-interface.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-interface.h Fri Sep 28 11:59:46 2007 +0100
@@ -26,6 +26,7 @@
#include <list>
#include "ns3/ipv4-address.h"
#include "ns3/ptr.h"
+#include "ns3/object.h"
namespace ns3 {
@@ -60,9 +61,8 @@
*
* Subclasses must implement the two methods:
* - Ipv4Interface::SendTo
- * - Ipv4Interface::DoCreateTraceResolver
*/
-class Ipv4Interface
+class Ipv4Interface : public Object
{
public:
/**
@@ -74,17 +74,6 @@
virtual ~Ipv4Interface();
/**
- * \param context the trace context to use to construct the
- * TraceResolver to return
- * \returns a TraceResolver which can resolve all traces
- * performed in this object. The caller must
- * delete the returned object.
- *
- * This method will delegate the work to the private DoCreateTraceResolver
- * method which is supposed to be implemented by subclasses.
- */
- TraceResolver *CreateTraceResolver (TraceContext const &context);
- /**
* \returns the underlying NetDevice. This method can return
* zero if this interface has no associated NetDevice.
*/
@@ -150,10 +139,10 @@
*/
void Send(Packet p, Ipv4Address dest);
-
- private:
+protected:
+ virtual void DoDispose (void);
+private:
virtual void SendTo (Packet p, Ipv4Address dest) = 0;
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
Ptr<NetDevice> m_netdevice;
bool m_ifup;
Ipv4Address m_address;
--- a/src/internet-node/ipv4-l3-protocol.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l3-protocol.cc Fri Sep 28 11:59:46 2007 +0100
@@ -20,9 +20,8 @@
//
#include "ns3/packet.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "ns3/composite-trace-resolver.h"
-#include "ns3/array-trace-resolver.h"
#include "ns3/callback.h"
#include "ns3/ipv4-address.h"
#include "ns3/ipv4-route.h"
@@ -37,58 +36,156 @@
#include "arp-ipv4-interface.h"
#include "ipv4-l4-demux.h"
-NS_DEBUG_COMPONENT_DEFINE ("Ipv4L3Protocol");
+NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol");
namespace ns3 {
+const InterfaceId Ipv4L3Protocol::iid = MakeInterfaceId ("Ipv4L3Protocol", Object::iid);
const uint16_t Ipv4L3Protocol::PROT_NUMBER = 0x0800;
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement ()
+ : m_type (TX)
+{
+ NS_LOG_FUNCTION;
+}
+
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement (enum Type type)
+ : m_type (type)
+{
+ NS_LOG_FUNCTION;
+}
+
+bool
+Ipv4L3ProtocolTraceContextElement::IsTx (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_type == TX;
+}
+
+bool
+Ipv4L3ProtocolTraceContextElement::IsRx (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_type == RX;
+}
+
+bool
+Ipv4L3ProtocolTraceContextElement::IsDrop (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_type == DROP;
+}
+
+void
+Ipv4L3ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+ NS_LOG_FUNCTION;
+ os << "ipv4=";
+ switch (m_type)
+ {
+ case TX:
+ os << "tx";
+ break;
+ case RX:
+ os << "rx";
+ break;
+ case DROP:
+ os << "drop";
+ break;
+ }
+}
+
+uint16_t
+Ipv4L3ProtocolTraceContextElement::GetUid (void)
+{
+ NS_LOG_FUNCTION;
+ static uint16_t uid = AllocateUid<Ipv4L3ProtocolTraceContextElement> ("Ipv4L3ProtocolTraceContextElement");
+ return uid;
+}
+
+std::string
+Ipv4L3ProtocolTraceContextElement::GetTypeName (void) const
+{
+ NS_LOG_FUNCTION;
+ return "ns3::Ipv4L3ProtocolTraceContextElement";
+}
+
+Ipv4L3ProtocolInterfaceIndex::Ipv4L3ProtocolInterfaceIndex ()
+ : m_index (0)
+{
+ NS_LOG_FUNCTION;
+}
+
+Ipv4L3ProtocolInterfaceIndex::Ipv4L3ProtocolInterfaceIndex (uint32_t index)
+ : m_index (index)
+{
+ NS_LOG_FUNCTION;
+}
+
+uint32_t
+Ipv4L3ProtocolInterfaceIndex::Get (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_index;
+}
+
+void
+Ipv4L3ProtocolInterfaceIndex::Print (std::ostream &os) const
+{
+ os << "ipv4-interface=" << m_index;
+}
+
+uint16_t
+Ipv4L3ProtocolInterfaceIndex::GetUid (void)
+{
+ NS_LOG_FUNCTION;
+ static uint16_t uid = AllocateUid<Ipv4L3ProtocolInterfaceIndex> ("Ipv4L3ProtocolInterfaceIndex");
+ return uid;
+}
+
+std::string
+Ipv4L3ProtocolInterfaceIndex::GetTypeName (void) const
+{
+ NS_LOG_FUNCTION;
+ return "ns3::Ipv4L3ProtocolInterfaceIndex";
+}
+
+
Ipv4L3Protocol::Ipv4L3Protocol(Ptr<Node> node)
- : L3Protocol (PROT_NUMBER, 4),
- m_nInterfaces (0),
+ : m_nInterfaces (0),
m_defaultTtl (64),
m_identification (0),
- m_defaultRoute (0),
m_node (node)
{
+ NS_LOG_FUNCTION;
+ SetInterfaceId (Ipv4L3Protocol::iid);
+ m_staticRouting = Create<Ipv4StaticRouting> ();
+ AddRoutingProtocol (m_staticRouting, 0);
SetupLoopback ();
}
+
Ipv4L3Protocol::~Ipv4L3Protocol ()
-{}
+{
+ NS_LOG_FUNCTION;
+}
void
Ipv4L3Protocol::DoDispose (void)
{
- for (Ipv4InterfaceList::iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
- {
- delete (*i);
- }
+ NS_LOG_FUNCTION;
m_interfaces.clear ();
- for (HostRoutesI i = m_hostRoutes.begin ();
- i != m_hostRoutes.end ();
- i = m_hostRoutes.erase (i))
- {
- delete (*i);
- }
- for (NetworkRoutesI j = m_networkRoutes.begin ();
- j != m_networkRoutes.end ();
- j = m_networkRoutes.erase (j))
- {
- delete (*j);
- }
- if (m_defaultRoute != 0)
- {
- delete m_defaultRoute;
- m_defaultRoute = 0;
- }
m_node = 0;
- L3Protocol::DoDispose ();
+ m_staticRouting->Dispose ();
+ m_staticRouting = 0;
+ Object::DoDispose ();
}
void
Ipv4L3Protocol::SetupLoopback (void)
{
- Ipv4LoopbackInterface * interface = new Ipv4LoopbackInterface (m_node);
+ NS_LOG_FUNCTION;
+
+ Ptr<Ipv4LoopbackInterface> interface = Create<Ipv4LoopbackInterface> (m_node);
interface->SetAddress (Ipv4Address::GetLoopback ());
interface->SetNetworkMask (Ipv4Mask::GetLoopback ());
uint32_t index = AddIpv4Interface (interface);
@@ -96,33 +193,36 @@
interface->SetUp ();
}
-TraceResolver *
-Ipv4L3Protocol::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Ipv4L3Protocol::GetTraceResolver (void) const
{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- resolver->Add ("tx", m_txTrace, Ipv4L3Protocol::TX);
- resolver->Add ("rx", m_rxTrace, Ipv4L3Protocol::RX);
- resolver->Add ("drop", m_dropTrace, Ipv4L3Protocol::DROP);
- resolver->Add ("interfaces",
- MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this),
- Ipv4L3Protocol::INTERFACES);
- return resolver;
-}
+ NS_LOG_FUNCTION;
-TraceResolver *
-Ipv4L3Protocol::InterfacesCreateTraceResolver (TraceContext const &context) const
-{
- ArrayTraceResolver<Ipv4Interface> *resolver =
- new ArrayTraceResolver<Ipv4Interface>
- (context,
- MakeCallback (&Ipv4L3Protocol::GetNInterfaces, this),
- MakeCallback (&Ipv4L3Protocol::GetInterface, this));
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ resolver->AddSource ("tx",
+ TraceDoc ("send ipv4 packet to outgoing interface",
+ "const Packet &", "packet sent",
+ "uint32_t", "index of output ipv4 interface"),
+ m_txTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::TX));
+ resolver->AddSource ("rx",
+ TraceDoc ("receive ipv4 packet from incoming interface",
+ "const Packet &", "packet received",
+ "uint32_t", "index of input ipv4 interface"),
+ m_rxTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::RX));
+ resolver->AddSource ("drop",
+ TraceDoc ("drop ipv4 packet",
+ "const Packet &", "packet dropped"),
+ m_dropTrace, Ipv4L3ProtocolTraceContextElement (Ipv4L3ProtocolTraceContextElement::DROP));
+ resolver->AddArray ("interfaces",
+ m_interfaces.begin (), m_interfaces.end (),
+ Ipv4L3ProtocolInterfaceIndex ());
return resolver;
}
void
Ipv4L3Protocol::SetDefaultTtl (uint8_t ttl)
{
+ NS_LOG_FUNCTION;
m_defaultTtl = ttl;
}
@@ -132,201 +232,232 @@
Ipv4Address nextHop,
uint32_t interface)
{
- Ipv4Route *route = new Ipv4Route ();
- *route = Ipv4Route::CreateHostRouteTo (dest, nextHop, interface);
- m_hostRoutes.push_back (route);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << dest << ", " << nextHop << ", " << interface << ")");
+ m_staticRouting->AddHostRouteTo (dest, nextHop, interface);
}
+
void
Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest,
uint32_t interface)
{
- Ipv4Route *route = new Ipv4Route ();
- *route = Ipv4Route::CreateHostRouteTo (dest, interface);
- m_hostRoutes.push_back (route);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << dest << ", " << interface << ")");
+ m_staticRouting->AddHostRouteTo (dest, interface);
}
+
void
Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
Ipv4Address nextHop,
uint32_t interface)
{
- Ipv4Route *route = new Ipv4Route ();
- *route = Ipv4Route::CreateNetworkRouteTo (network,
- networkMask,
- nextHop,
- interface);
- m_networkRoutes.push_back (route);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << network << ", " << networkMask << ", " << nextHop <<
+ ", " << interface << ")");
+ m_staticRouting->AddNetworkRouteTo (network, networkMask, nextHop, interface);
}
+
void
Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
uint32_t interface)
{
- Ipv4Route *route = new Ipv4Route ();
- *route = Ipv4Route::CreateNetworkRouteTo (network,
- networkMask,
- interface);
- m_networkRoutes.push_back (route);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << network << ", " << networkMask << ", " << interface <<
+ ")");
+ m_staticRouting->AddNetworkRouteTo (network, networkMask, interface);
}
+
void
Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop,
uint32_t interface)
{
- Ipv4Route *route = new Ipv4Route ();
- *route = Ipv4Route::CreateDefaultRoute (nextHop, interface);
- delete m_defaultRoute;
- m_defaultRoute = route;
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << nextHop << ", " << interface << ")");
+ m_staticRouting->SetDefaultRoute (nextHop, interface);
+}
+
+void
+Ipv4L3Protocol::Lookup (
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &ipHeader << ", " << &packet << &routeReply << ")");
+
+ Lookup (Ipv4RoutingProtocol::IF_INDEX_ANY, ipHeader, packet, routeReply);
}
-Ipv4Route *
-Ipv4L3Protocol::Lookup (Ipv4Address dest)
+void
+Ipv4L3Protocol::Lookup (
+ uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ Ipv4RoutingProtocol::RouteReplyCallback routeReply)
{
- for (HostRoutesCI i = m_hostRoutes.begin ();
- i != m_hostRoutes.end ();
- i++)
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << ifIndex << ", " << &ipHeader << ", " << &packet <<
+ &routeReply << ")");
+
+ for (Ipv4RoutingProtocolList::const_iterator rprotoIter =
+ m_routingProtocols.begin ();
+ rprotoIter != m_routingProtocols.end ();
+ rprotoIter++)
+ {
+ NS_LOG_LOGIC ("Requesting route");
+ if ((*rprotoIter).second->RequestRoute (ifIndex, ipHeader, packet,
+ routeReply))
+ return;
+ }
+
+ if (ipHeader.GetDestination ().IsMulticast () &&
+ ifIndex == Ipv4RoutingProtocol::IF_INDEX_ANY)
{
- NS_ASSERT ((*i)->IsHost ());
- if ((*i)->GetDest ().IsEqual (dest))
+ NS_LOG_LOGIC ("Multicast destination with local source");
+//
+// We have a multicast packet originating from the current node and were not
+// able to send it using the usual RequestRoute process. Since the usual
+// process includes trying to use a default multicast route, this means that
+// there was no specific route out of the node found, and there was no default
+// multicast route set.
+//
+// The fallback position is to look for a default unicast route and use that
+// to get the packet off the node if we have one.
+//
+ Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+ if (route)
{
- return (*i);
+ NS_LOG_LOGIC ("Local source. Using unicast default route for "
+ "multicast packet");
+
+ routeReply (true, *route, packet, ipHeader);
+ return;
}
}
- for (NetworkRoutesI j = m_networkRoutes.begin ();
- j != m_networkRoutes.end ();
- j++)
- {
- NS_ASSERT ((*j)->IsNetwork ());
- Ipv4Mask mask = (*j)->GetDestNetworkMask ();
- Ipv4Address entry = (*j)->GetDestNetwork ();
- if (mask.IsMatch (dest, entry))
- {
- return (*j);
- }
- }
- if (m_defaultRoute != 0)
- {
- NS_ASSERT (m_defaultRoute->IsDefault ());
- return m_defaultRoute;
- }
- return 0;
+//
+// No route found
+//
+ routeReply (false, Ipv4Route (), packet, ipHeader);
+}
+
+void
+Ipv4L3Protocol::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+ int priority)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &routingProtocol << ", " << priority << ")");
+ m_routingProtocols.push_back
+ (std::pair<int, Ptr<Ipv4RoutingProtocol> > (-priority, routingProtocol));
+ m_routingProtocols.sort ();
}
uint32_t
Ipv4L3Protocol::GetNRoutes (void)
{
- uint32_t n = 0;
- if (m_defaultRoute != 0)
- {
- n++;
- }
- n += m_hostRoutes.size ();
- n += m_networkRoutes.size ();
- return n;
+ NS_LOG_FUNCTION;
+ return m_staticRouting->GetNRoutes ();
}
+
Ipv4Route *
Ipv4L3Protocol::GetRoute (uint32_t index)
{
- if (index == 0 && m_defaultRoute != 0)
- {
- return m_defaultRoute;
- }
- if (index > 0 && m_defaultRoute != 0)
- {
- index--;
- }
- if (index < m_hostRoutes.size ())
- {
- uint32_t tmp = 0;
- for (HostRoutesCI i = m_hostRoutes.begin ();
- i != m_hostRoutes.end ();
- i++)
- {
- if (tmp == index)
- {
- return *i;
- }
- tmp++;
- }
- }
- index -= m_hostRoutes.size ();
- uint32_t tmp = 0;
- for (NetworkRoutesI j = m_networkRoutes.begin ();
- j != m_networkRoutes.end ();
- j++)
- {
- if (tmp == index)
- {
- return *j;
- }
- tmp++;
- }
- NS_ASSERT (false);
- // quiet compiler.
- return 0;
+ NS_LOG_FUNCTION;
+ return m_staticRouting->GetRoute (index);
}
+
void
Ipv4L3Protocol::RemoveRoute (uint32_t index)
{
- if (index == 0 && m_defaultRoute != 0)
- {
- delete m_defaultRoute;
- m_defaultRoute = 0;
- }
- if (index > 0 && m_defaultRoute != 0)
- {
- index--;
- }
- if (index < m_hostRoutes.size ())
- {
- uint32_t tmp = 0;
- for (HostRoutesI i = m_hostRoutes.begin ();
- i != m_hostRoutes.end ();
- i++)
- {
- if (tmp == index)
- {
- delete *i;
- m_hostRoutes.erase (i);
- return;
- }
- tmp++;
- }
- }
- index -= m_hostRoutes.size ();
- uint32_t tmp = 0;
- for (NetworkRoutesI j = m_networkRoutes.begin ();
- j != m_networkRoutes.end ();
- j++)
- {
- if (tmp == index)
- {
- delete *j;
- m_networkRoutes.erase (j);
- return;
- }
- tmp++;
- }
- NS_ASSERT (false);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM("(" << index << ")");
+ m_staticRouting->RemoveRoute (index);
+}
+
+void
+Ipv4L3Protocol::AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << origin << ", " << group << ", " << inputInterface <<
+ ", " << &outputInterfaces << ")");
+
+ m_staticRouting->AddMulticastRoute (origin, group, inputInterface,
+ outputInterfaces);
+}
+
+void
+Ipv4L3Protocol::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << outputInterface << ")");
+
+ m_staticRouting->SetDefaultMulticastRoute (outputInterface);
}
+uint32_t
+Ipv4L3Protocol::GetNMulticastRoutes (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_staticRouting->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute *
+Ipv4L3Protocol::GetMulticastRoute (uint32_t index) const
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << index << ")");
+ return m_staticRouting->GetMulticastRoute (index);
+}
+
+void
+Ipv4L3Protocol::RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << origin << ", " << group << ", " << inputInterface <<
+ ")");
+ m_staticRouting->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void
+Ipv4L3Protocol::RemoveMulticastRoute (uint32_t index)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << index << ")");
+ m_staticRouting->RemoveMulticastRoute (index);
+}
uint32_t
Ipv4L3Protocol::AddInterface (Ptr<NetDevice> device)
{
- Ipv4Interface *interface = new ArpIpv4Interface (m_node, device);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &device << ")");
+ Ptr<Ipv4Interface> interface = Create<ArpIpv4Interface> (m_node, device);
return AddIpv4Interface (interface);
}
+
uint32_t
-Ipv4L3Protocol::AddIpv4Interface (Ipv4Interface *interface)
+Ipv4L3Protocol::AddIpv4Interface (Ptr<Ipv4Interface>interface)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << interface << ")");
uint32_t index = m_nInterfaces;
m_interfaces.push_back (interface);
m_nInterfaces++;
return index;
}
-Ipv4Interface *
+
+Ptr<Ipv4Interface>
Ipv4L3Protocol::GetInterface (uint32_t index) const
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << index << ")");
uint32_t tmp = 0;
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
{
@@ -338,15 +469,63 @@
}
return 0;
}
+
uint32_t
Ipv4L3Protocol::GetNInterfaces (void) const
{
+ NS_LOG_FUNCTION;
return m_nInterfaces;
}
-Ipv4Interface *
+uint32_t
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr) const
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << addr << ")");
+
+ uint32_t ifIndex = 0;
+ for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+ i != m_interfaces.end ();
+ i++, ifIndex++)
+ {
+ if ((*i)->GetAddress () == addr)
+ {
+ return ifIndex;
+ }
+ }
+
+ NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
+ "Interface not found for IP address");
+ return 0;
+}
+
+uint32_t
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << addr << ", " << mask << ")");
+
+ uint32_t ifIndex = 0;
+ for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+ i != m_interfaces.end ();
+ i++, ifIndex++)
+ {
+ if ((*i)->GetAddress ().CombineMask (mask) == addr.CombineMask (mask))
+ {
+ return ifIndex;
+ }
+ }
+
+ NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
+ "Interface not found for masked IP address");
+ return 0;
+}
+
+Ptr<Ipv4Interface>
Ipv4L3Protocol::FindInterfaceForDevice (Ptr<const NetDevice> device)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &device << ")");
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
{
if ((*i)->GetDevice () == device)
@@ -358,18 +537,29 @@
}
void
-Ipv4L3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+Ipv4L3Protocol::Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &device << ", " << &p << ", " << protocol << ", " <<
+ from << ")");
+
+ NS_LOG_LOGIC ("Packet from " << from);
+
uint32_t index = 0;
- for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
+ Ptr<Ipv4Interface> ipv4Interface;
+ for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+ i != m_interfaces.end ();
+ i++)
{
- if ((*i)->GetDevice () == device)
+ ipv4Interface = *i;
+ if (ipv4Interface->GetDevice () == device)
{
- m_rxTrace (packet, index);
+ m_rxTrace (p, index);
break;
}
index++;
}
+ Packet packet = p;
Ipv4Header ipHeader;
packet.RemoveHeader (ipHeader);
@@ -378,20 +568,26 @@
return;
}
- if (Forwarding (packet, ipHeader, device))
+ if (Forwarding (index, packet, ipHeader, device))
{
return;
}
- ForwardUp (packet, ipHeader);
+ NS_LOG_LOGIC ("Forward up");
+ ForwardUp (packet, ipHeader, ipv4Interface);
}
+
void
Ipv4L3Protocol::Send (Packet const &packet,
Ipv4Address source,
Ipv4Address destination,
uint8_t protocol)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &packet << ", " << source << ", " << ", " <<
+ destination << ", " << protocol << ")");
+
Ipv4Header ipHeader;
ipHeader.SetSource (source);
@@ -404,53 +600,88 @@
m_identification ++;
- // XXX Note here that in most ipv4 stacks in the world,
- // the route calculation for an outgoing packet is not
- // done in the ip layer. It is done within the application
- // socket when the first packet is sent to avoid this
- // costly lookup on a per-packet basis.
- // That would require us to get the route from the packet,
- // most likely with a packet tag. The higher layers do not
- // do this yet for us.
- Ipv4Route *route = Lookup (ipHeader.GetDestination ());
- if (route == 0)
+ if (destination.IsBroadcast ())
+ {
+ uint32_t ifaceIndex = 0;
+ for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
+ ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
+ {
+ Ptr<Ipv4Interface> outInterface = *ifaceIter;
+ Packet packetCopy = packet;
+
+ NS_ASSERT (packetCopy.GetSize () <= outInterface->GetMtu ());
+ packetCopy.AddHeader (ipHeader);
+ m_txTrace (packetCopy, ifaceIndex);
+ outInterface->Send (packetCopy, destination);
+ }
+ }
+ else
{
- NS_DEBUG ("not for me -- forwarding but no route to host. drop.");
+ // XXX Note here that in most ipv4 stacks in the world,
+ // the route calculation for an outgoing packet is not
+ // done in the ip layer. It is done within the application
+ // socket when the first packet is sent to avoid this
+ // costly lookup on a per-packet basis.
+ // That would require us to get the route from the packet,
+ // most likely with a packet tag. The higher layers do not
+ // do this yet for us.
+ Lookup (ipHeader, packet,
+ MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
+ }
+}
+
+void
+Ipv4L3Protocol::SendRealOut (bool found,
+ Ipv4Route const &route,
+ Packet packet,
+ Ipv4Header const &ipHeader)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << found << ", " << &route << ", " << &packet <<
+ &ipHeader << ")");
+
+ if (!found)
+ {
+ NS_LOG_WARN ("No route to host. Drop.");
m_dropTrace (packet);
return;
}
- SendRealOut (packet, ipHeader, *route);
-}
+ NS_LOG_LOGIC ("Send via interface " << route.GetInterface ());
-void
-Ipv4L3Protocol::SendRealOut (Packet const &p, Ipv4Header const &ip, Ipv4Route const &route)
-{
- Packet packet = p;
- packet.AddHeader (ip);
- Ipv4Interface *outInterface = GetInterface (route.GetInterface ());
+ packet.AddHeader (ipHeader);
+ Ptr<Ipv4Interface> outInterface = GetInterface (route.GetInterface ());
NS_ASSERT (packet.GetSize () <= outInterface->GetMtu ());
m_txTrace (packet, route.GetInterface ());
if (route.IsGateway ())
{
+ NS_LOG_LOGIC ("Send to gateway " << route.GetGateway ());
outInterface->Send (packet, route.GetGateway ());
}
else
{
- outInterface->Send (packet, ip.GetDestination ());
+ NS_LOG_LOGIC ("Send to destination " << ipHeader.GetDestination ());
+ outInterface->Send (packet, ipHeader.GetDestination ());
}
}
+bool
+Ipv4L3Protocol::Forwarding (
+ uint32_t ifIndex,
+ Packet const &packet,
+ Ipv4Header &ipHeader,
+ Ptr<NetDevice> device)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << ifIndex << ", " << &packet << ", " << &ipHeader <<
+ ", " << device << ")");
-bool
-Ipv4L3Protocol::Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device)
-{
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
i != m_interfaces.end (); i++)
{
if ((*i)->GetAddress ().IsEqual (ipHeader.GetDestination ()))
{
- NS_DEBUG ("for me 1");
+ NS_LOG_LOGIC ("For me (destination match)");
return false;
}
}
@@ -458,106 +689,267 @@
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
i != m_interfaces.end (); i++)
{
- Ipv4Interface *interface = *i;
+ Ptr<Ipv4Interface> interface = *i;
if (interface->GetDevice () == device)
{
if (ipHeader.GetDestination ().IsEqual (interface->GetBroadcast ()))
{
- NS_DEBUG ("for me 2");
+ NS_LOG_LOGIC ("For me (interface broadcast address)");
return false;
}
break;
}
}
- if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetBroadcast ()))
+ if (ipHeader.GetDestination ().IsBroadcast ())
{
- NS_DEBUG ("for me 3");
+ NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
return false;
}
+
if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetAny ()))
{
- NS_DEBUG ("for me 4");
+ NS_LOG_LOGIC ("For me (Ipv4Addr any address)");
return false;
}
+
if (ipHeader.GetTtl () == 1)
{
// Should send ttl expired here
// XXX
- NS_DEBUG ("not for me -- ttl expired. drop.");
+ NS_LOG_LOGIC ("Not for me (TTL expired). Drop");
m_dropTrace (packet);
return true;
}
ipHeader.SetTtl (ipHeader.GetTtl () - 1);
- Ipv4Route *route = Lookup (ipHeader.GetDestination ());
- if (route == 0)
+
+ NS_LOG_LOGIC ("Forwarding packet.");
+ Lookup (ifIndex, ipHeader, packet,
+ MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
+//
+// If this is a to a multicast address and this node is a member of the
+// indicated group we need to return false so the multicast is forwarded up.
+// Note that we may have just forwarded this packet too.
+//
+ for (Ipv4MulticastGroupList::const_iterator i = m_multicastGroups.begin ();
+ i != m_multicastGroups.end (); i++)
{
- NS_DEBUG ("not for me -- forwarding but no route to host. drop.");
- m_dropTrace (packet);
- return true;
+ if ((*i).first.IsEqual (ipHeader.GetSource ()) &&
+ (*i).second.IsEqual (ipHeader.GetDestination ()))
+ {
+ NS_LOG_LOGIC ("For me (Joined multicast group)");
+ return false;
+ }
}
- NS_DEBUG ("not for me -- forwarding.");
- SendRealOut (packet, ipHeader, *route);
+
+ NS_LOG_LOGIC("Not for me.");
return true;
}
+void
+Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip,
+ Ptr<Ipv4Interface> incomingInterface)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ", " << &ip << ")");
+
+ Ptr<Ipv4L4Demux> demux = m_node->QueryInterface<Ipv4L4Demux> (Ipv4L4Demux::iid);
+ Ptr<Ipv4L4Protocol> protocol = demux->GetProtocol (ip.GetProtocol ());
+ protocol->Receive (p, ip.GetSource (), ip.GetDestination (), incomingInterface);
+}
+
+void
+Ipv4L3Protocol::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << origin << ", " << group << ")");
+ m_multicastGroups.push_back(
+ std::pair<Ipv4Address, Ipv4Address> (origin, group));
+}
void
-Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip)
+Ipv4L3Protocol::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
{
- Ptr<Ipv4L4Demux> demux = m_node->QueryInterface<Ipv4L4Demux> (Ipv4L4Demux::iid);
- Ptr<Ipv4L4Protocol> protocol = demux->GetProtocol (ip.GetProtocol ());
- protocol->Receive (p, ip.GetSource (), ip.GetDestination ());
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << origin << ", " << group << ")");
+
+ for (Ipv4MulticastGroupList::iterator i = m_multicastGroups.begin ();
+ i != m_multicastGroups.end ();
+ i++)
+ {
+ if ((*i).first.IsEqual(origin) && (*i).second.IsEqual(group))
+ {
+ m_multicastGroups.erase (i);
+ return;
+ }
+ }
}
void
Ipv4L3Protocol::SetAddress (uint32_t i, Ipv4Address address)
{
- Ipv4Interface *interface = GetInterface (i);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << i << ", " << address << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetAddress (address);
}
+
void
Ipv4L3Protocol::SetNetworkMask (uint32_t i, Ipv4Mask mask)
{
- Ipv4Interface *interface = GetInterface (i);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << i << ", " << mask << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetNetworkMask (mask);
}
+
Ipv4Mask
Ipv4L3Protocol::GetNetworkMask (uint32_t i) const
{
- Ipv4Interface *interface = GetInterface (i);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << i << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetNetworkMask ();
}
+
Ipv4Address
Ipv4L3Protocol::GetAddress (uint32_t i) const
{
- Ipv4Interface *interface = GetInterface (i);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << i << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetAddress ();
}
+
+bool
+Ipv4L3Protocol::GetIfIndexForDestination (
+ Ipv4Address destination, uint32_t& ifIndex) const
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << destination << ", " << &ifIndex << ")");
+//
+// The first thing we do in trying to determine a source address is to
+// consult the routing protocols. These will also check for a default route
+// if one has been set.
+//
+ for (Ipv4RoutingProtocolList::const_iterator i = m_routingProtocols.begin ();
+ i != m_routingProtocols.end ();
+ i++)
+ {
+ NS_LOG_LOGIC ("Requesting Source Address");
+ uint32_t ifIndexTmp;
+
+ if ((*i).second->RequestIfIndex (destination, ifIndexTmp))
+ {
+ NS_LOG_LOGIC ("Found ifIndex " << ifIndexTmp);
+ ifIndex = ifIndexTmp;
+ return true;
+ }
+ }
+//
+// If there's no routing table entry telling us what *single* interface will
+// be used to send a packet to this destination, we'll have to just pick one.
+// If there's only one interface on this node, a good answer isn't very hard
+// to come up with. Before jumping to any conclusions, remember that the
+// zeroth interface is the loopback interface, so what we actually want is
+// a situation where there are exactly two interfaces on the node, in which
+// case interface one is the "single" interface connected to the outside world.
+//
+ if (GetNInterfaces () == 2)
+ {
+ NS_LOG_LOGIC ("One Interface. Using interface 1.");
+ ifIndex = 1;
+ return true;
+ }
+//
+// If we fall through to here, we have a node with multiple interfaces and
+// no routes to guide us in determining what interface to choose. Either
+// no default route was found (for unicast or multicast), or in the case of a
+// multicast, the default route contained multiple outbound interfaces.
+//
+// The fallback position is to just get the unicast default route and use
+// the outgoing interface specified there. We don't want to leave the source
+// address unset, so we just assert here.
+//
+// N.B. that in the case of a multicast with a route containing multiple
+// outgoing interfaces, the source address of packets from that node will be
+// set to the IP address of the interface set in the default unicast route.
+// Also, in the case of a broadcast, the same will be true.
+//
+ NS_LOG_LOGIC ("Using default unicast route");
+ Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+ NS_ASSERT_MSG(route,
+ "Ipv4L3Protocol::GetIfIndexForDestination (): "
+ "Unable to determine outbound interface. No default route set");
+
+ ifIndex = route->GetInterface ();
+
+ NS_LOG_LOGIC ("Default route specifies interface " << ifIndex);
+ return true;
+}
+
uint16_t
Ipv4L3Protocol::GetMtu (uint32_t i) const
{
- Ipv4Interface *interface = GetInterface (i);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << i << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetMtu ();
}
+
bool
Ipv4L3Protocol::IsUp (uint32_t i) const
{
- Ipv4Interface *interface = GetInterface (i);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << i << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->IsUp ();
}
+
void
Ipv4L3Protocol::SetUp (uint32_t i)
{
- Ipv4Interface *interface = GetInterface (i);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << i << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetUp ();
-}
-void
-Ipv4L3Protocol::SetDown (uint32_t i)
-{
- Ipv4Interface *interface = GetInterface (i);
- interface->SetDown ();
+
+ // If interface address and network mask have been set, add a route
+ // to the network of the interface (like e.g. ifconfig does on a
+ // Linux box)
+ if ((interface->GetAddress ()) != (Ipv4Address ())
+ && (interface->GetNetworkMask ()) != (Ipv4Mask ()))
+ {
+ AddNetworkRouteTo (interface->GetAddress ().CombineMask (interface->GetNetworkMask ()),
+ interface->GetNetworkMask (), i);
+ }
}
+void
+Ipv4L3Protocol::SetDown (uint32_t ifaceIndex)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << ifaceIndex << ")");
+ Ptr<Ipv4Interface> interface = GetInterface (ifaceIndex);
+ interface->SetDown ();
+
+ // Remove all routes that are going through this interface
+ bool modified = true;
+ while (modified)
+ {
+ modified = false;
+ for (uint32_t i = 0; i < GetNRoutes (); i++)
+ {
+ Ipv4Route *route = GetRoute (i);
+ if (route->GetInterface () == ifaceIndex)
+ {
+ RemoveRoute (i);
+ modified = true;
+ break;
+ }
+ }
+ }
+}
}//namespace ns3
--- a/src/internet-node/ipv4-l3-protocol.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l3-protocol.h Fri Sep 28 11:59:46 2007 +0100
@@ -25,10 +25,12 @@
#include <list>
#include <stdint.h>
#include "ns3/callback-trace-source.h"
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
#include "ns3/ipv4-address.h"
#include "ns3/ptr.h"
-#include "l3-protocol.h"
+#include "ns3/ipv4.h"
+#include "ipv4-header.h"
+#include "ipv4-static-routing.h"
namespace ns3 {
@@ -42,33 +44,68 @@
class TraceResolver;
class TraceContext;
-
-class Ipv4L3Protocol : public L3Protocol
+/**
+ * \brief hold in a TraceContext the type of trace source used by this Ipv4L3Protocol
+ */
+class Ipv4L3ProtocolTraceContextElement : public TraceContextElement
{
public:
- static const uint16_t PROT_NUMBER;
-
- enum TraceType {
+ enum Type {
TX,
RX,
DROP,
- INTERFACES,
};
- typedef ArrayTraceResolver<Ipv4Interface>::Index InterfaceIndex;
+ Ipv4L3ProtocolTraceContextElement ();
+ Ipv4L3ProtocolTraceContextElement (enum Type type);
+ /**
+ * \returns true if this is a tx event, false otherwise.
+ */
+ bool IsTx (void) const;
+ /**
+ * \returns true if this is a rx event, false otherwise.
+ */
+ bool IsRx (void) const;
+ /**
+ * \returns true if this is a drop event, false otherwise.
+ */
+ bool IsDrop (void) const;
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+ std::string GetTypeName (void) const;
+private:
+ enum Type m_type;
+};
+
+/**
+ * \brief hold in a TraceContext the index of an Ipv4Interface within the ipv4 stack of a Node
+ */
+class Ipv4L3ProtocolInterfaceIndex : public TraceContextElement
+{
+public:
+ Ipv4L3ProtocolInterfaceIndex ();
+ Ipv4L3ProtocolInterfaceIndex (uint32_t index);
+ /**
+ * \returns the index of the Ipv4Interface within a Node.
+ */
+ uint32_t Get (void) const;
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+ std::string GetTypeName (void) const;
+private:
+ uint32_t m_index;
+};
+
+
+class Ipv4L3Protocol : public Object
+{
+public:
+ static const InterfaceId iid;
+ static const uint16_t PROT_NUMBER;
Ipv4L3Protocol(Ptr<Node> node);
virtual ~Ipv4L3Protocol ();
/**
- * \param context the trace context to use to construct the
- * TraceResolver to return
- * \returns a TraceResolver which can resolve all traces
- * performed in this object. The caller must
- * delete the returned object.
- */
- virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
-
- /**
* \param ttl default ttl to use
*
* When we need to send an ipv4 packet, we use this default
@@ -83,7 +120,7 @@
* Try to find an Ipv4Interface whose NetDevice is equal to
* the input NetDevice.
*/
- Ipv4Interface *FindInterfaceForDevice (Ptr<const NetDevice> device);
+ Ptr<Ipv4Interface> FindInterfaceForDevice (Ptr<const NetDevice> device);
/**
* Lower layer calls this method after calling L3Demux::Lookup
@@ -92,7 +129,7 @@
* - implement a per-NetDevice ARP cache
* - send back arp replies on the right device
*/
- virtual void Receive(Packet& p, Ptr<NetDevice> device);
+ void Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
/**
* \param packet packet to send
@@ -124,57 +161,96 @@
void SetDefaultRoute (Ipv4Address nextHop,
uint32_t interface);
- Ipv4Route *Lookup (Ipv4Address dest);
+ void Lookup (Ipv4Header const &ipHeader,
+ Packet packet,
+ Ipv4RoutingProtocol::RouteReplyCallback routeReply);
+
uint32_t GetNRoutes (void);
Ipv4Route *GetRoute (uint32_t i);
void RemoveRoute (uint32_t i);
+ void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+ void SetDefaultMulticastRoute (uint32_t onputInterface);
+
+ uint32_t GetNMulticastRoutes (void) const;
+ Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
+
+ void RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface);
+ void RemoveMulticastRoute (uint32_t i);
+
uint32_t AddInterface (Ptr<NetDevice> device);
- Ipv4Interface * GetInterface (uint32_t i) const;
+ Ptr<Ipv4Interface> GetInterface (uint32_t i) const;
uint32_t GetNInterfaces (void) const;
+ uint32_t FindInterfaceForAddr (Ipv4Address addr) const;
+ uint32_t FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const;
+ void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+ void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
void SetAddress (uint32_t i, Ipv4Address address);
void SetNetworkMask (uint32_t i, Ipv4Mask mask);
Ipv4Mask GetNetworkMask (uint32_t t) const;
Ipv4Address GetAddress (uint32_t i) const;
+ bool GetIfIndexForDestination (Ipv4Address destination,
+ uint32_t& ifIndex) const;
uint16_t GetMtu (uint32_t i) const;
bool IsUp (uint32_t i) const;
void SetUp (uint32_t i);
void SetDown (uint32_t i);
+ void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+ int priority);
protected:
+
virtual void DoDispose (void);
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+
private:
- void SendRealOut (Packet const &packet, Ipv4Header const &ip, Ipv4Route const &route);
- bool Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device);
- void ForwardUp (Packet p, Ipv4Header const&ip);
- uint32_t AddIpv4Interface (Ipv4Interface *interface);
+ void Lookup (uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ Ipv4RoutingProtocol::RouteReplyCallback routeReply);
+
+ void SendRealOut (bool found,
+ Ipv4Route const &route,
+ Packet packet,
+ Ipv4Header const &ipHeader);
+ bool Forwarding (uint32_t ifIndex,
+ Packet const &packet,
+ Ipv4Header &ipHeader,
+ Ptr<NetDevice> device);
+ void ForwardUp (Packet p, Ipv4Header const&ip, Ptr<Ipv4Interface> incomingInterface);
+ uint32_t AddIpv4Interface (Ptr<Ipv4Interface> interface);
void SetupLoopback (void);
- TraceResolver *InterfacesCreateTraceResolver (TraceContext const &context) const;
- typedef std::list<Ipv4Interface*> Ipv4InterfaceList;
- typedef std::list<Ipv4Route *> HostRoutes;
- typedef std::list<Ipv4Route *>::const_iterator HostRoutesCI;
- typedef std::list<Ipv4Route *>::iterator HostRoutesI;
- typedef std::list<Ipv4Route *> NetworkRoutes;
- typedef std::list<Ipv4Route *>::const_iterator NetworkRoutesCI;
- typedef std::list<Ipv4Route *>::iterator NetworkRoutesI;
+ typedef std::list<Ptr<Ipv4Interface> > Ipv4InterfaceList;
+ typedef std::list<std::pair<Ipv4Address, Ipv4Address> >
+ Ipv4MulticastGroupList;
+ typedef std::list< std::pair< int, Ptr<Ipv4RoutingProtocol> > > Ipv4RoutingProtocolList;
Ipv4InterfaceList m_interfaces;
uint32_t m_nInterfaces;
uint8_t m_defaultTtl;
uint16_t m_identification;
- HostRoutes m_hostRoutes;
- NetworkRoutes m_networkRoutes;
- Ipv4Route *m_defaultRoute;
Ptr<Node> m_node;
CallbackTraceSource<Packet const &, uint32_t> m_txTrace;
CallbackTraceSource<Packet const &, uint32_t> m_rxTrace;
CallbackTraceSource<Packet const &> m_dropTrace;
+
+ Ipv4RoutingProtocolList m_routingProtocols;
+
+ Ptr<Ipv4StaticRouting> m_staticRouting;
+ Ipv4MulticastGroupList m_multicastGroups;
};
} // Namespace ns3
-#endif /* IPV$_L3_PROTOCOL_H */
+#endif /* IPV4_L3_PROTOCOL_H */
--- a/src/internet-node/ipv4-l4-demux.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l4-demux.cc Fri Sep 28 11:59:46 2007 +0100
@@ -32,6 +32,35 @@
const InterfaceId Ipv4L4Demux::iid = MakeInterfaceId ("Ipv4L4Demux", Object::iid);
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement ()
+ : m_protocolNumber (0)
+{}
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement (int protocolNumber)
+ : m_protocolNumber (protocolNumber)
+{}
+int
+Ipv4L4ProtocolTraceContextElement::Get (void) const
+{
+ return m_protocolNumber;
+}
+void
+Ipv4L4ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+ os << "ipv4-protocol=0x" << std::hex << m_protocolNumber << std::dec;
+}
+uint16_t
+Ipv4L4ProtocolTraceContextElement::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<Ipv4L4ProtocolTraceContextElement> ("Ipv4L4ProtocolTraceContextElement");
+ return uid;
+}
+std::string
+Ipv4L4ProtocolTraceContextElement::GetTypeName (void) const
+{
+ return "ns3::Ipv4L4ProtocolTraceContextElement";
+}
+
+
Ipv4L4Demux::Ipv4L4Demux (Ptr<Node> node)
: m_node (node)
{
@@ -54,21 +83,19 @@
Object::DoDispose ();
}
-TraceResolver *
-Ipv4L4Demux::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Ipv4L4Demux::GetTraceResolver (void) const
{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
for (L4List_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
{
Ptr<Ipv4L4Protocol> protocol = *i;
- std::string protValue;
- std::ostringstream oss (protValue);
- oss << (*i)->GetProtocolNumber ();
- Ipv4L4ProtocolTraceType protocolNumber = (*i)->GetProtocolNumber ();
- resolver->Add (protValue,
- MakeCallback (&Ipv4L4Protocol::CreateTraceResolver, PeekPointer (protocol)),
- protocolNumber);
+ std::ostringstream oss;
+ oss << (unsigned int) (*i)->GetProtocolNumber ();
+ Ipv4L4ProtocolTraceContextElement protocolNumber = (*i)->GetProtocolNumber ();
+ resolver->AddComposite (oss.str (), protocol, protocolNumber);
}
+ resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}
void
--- a/src/internet-node/ipv4-l4-demux.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l4-demux.h Fri Sep 28 11:59:46 2007 +0100
@@ -28,6 +28,7 @@
#include <list>
#include "ns3/object.h"
#include "ns3/ptr.h"
+#include "ns3/trace-context-element.h"
namespace ns3 {
@@ -37,25 +38,35 @@
class TraceContext;
/**
+ * \brief hold in a TraceContext the protocol number of a L4 Protocol
+ */
+class Ipv4L4ProtocolTraceContextElement : public TraceContextElement
+{
+public:
+ Ipv4L4ProtocolTraceContextElement ();
+ Ipv4L4ProtocolTraceContextElement (int protocolNumber);
+ /**
+ * \returns the protocol number as registered in the Ipv4L4Demux.
+ */
+ int Get (void) const;
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+ std::string GetTypeName (void) const;
+private:
+ int m_protocolNumber;
+};
+
+/**
* \brief L4 Ipv4 Demux
*/
class Ipv4L4Demux : public Object
{
public:
static const InterfaceId iid;
- typedef int Ipv4L4ProtocolTraceType;
Ipv4L4Demux (Ptr<Node> node);
virtual ~Ipv4L4Demux();
/**
- * \param context the trace context to use to construct the
- * TraceResolver to return
- * \returns a TraceResolver which can resolve all traces
- * performed in this object. The caller must
- * delete the returned object.
- */
- TraceResolver *CreateTraceResolver (TraceContext const &context);
- /**
* \param protocol a template for the protocol to add to this L4 Demux.
* \returns the L4Protocol effectively added.
*
@@ -83,8 +94,10 @@
* returned from the Ipv4L4Protocol::Insert method.
*/
void Remove (Ptr<Ipv4L4Protocol> protocol);
+protected:
+ Ptr<TraceResolver> GetTraceResolver (void) const;
+ virtual void DoDispose (void);
private:
- virtual void DoDispose (void);
typedef std::list<Ptr<Ipv4L4Protocol> > L4List_t;
L4List_t m_protocols;
Ptr<Node> m_node;
--- a/src/internet-node/ipv4-l4-protocol.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l4-protocol.h Fri Sep 28 11:59:46 2007 +0100
@@ -26,6 +26,7 @@
#define IPV4_L4_PROTOCOL_H
#include "ns3/object.h"
+#include "ipv4-interface.h"
namespace ns3 {
@@ -37,10 +38,6 @@
/**
* \brief L4 Protocol base class
*
- * All subclasses must implement:
- * - Ipv4L4Protocol::Copy
- * - Ipv4L4Protocol::CreateTraceResolver
- *
* 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.
*/
@@ -59,19 +56,19 @@
*/
int GetVersion() const;
- virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0;
-
/**
* \param p packet to forward up
* \param source source address of packet received
* \param destination address of packet received
+ * \param incomingInterface the Ipv4Interface on which the packet arrived
*
* Called from lower-level layers to send the packet up
* in the stack.
*/
virtual void Receive(Packet& p,
Ipv4Address const &source,
- Ipv4Address const &destination) = 0;
+ Ipv4Address const &destination,
+ Ptr<Ipv4Interface> incomingInterface) = 0;
protected:
virtual void DoDispose (void);
private:
--- a/src/internet-node/ipv4-loopback-interface.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-loopback-interface.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,32 +19,41 @@
* Authors:
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
*/
-#include "ns3/empty-trace-resolver.h"
+
+#include "ns3/log.h"
#include "ns3/net-device.h"
#include "ns3/node.h"
+#include "ns3/mac48-address.h"
#include "ipv4-loopback-interface.h"
-#include "ipv4-private.h"
+#include "ipv4-l3-protocol.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4LoopbackInterface");
namespace ns3 {
Ipv4LoopbackInterface::Ipv4LoopbackInterface (Ptr<Node> node)
: Ipv4Interface (0),
m_node (node)
-{}
-Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
-{}
+{
+ NS_LOG_FUNCTION;
+}
-TraceResolver *
-Ipv4LoopbackInterface::DoCreateTraceResolver (TraceContext const &context)
+Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
{
- return new EmptyTraceResolver (context);
+ NS_LOG_FUNCTION;
}
void
Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest)
{
- Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
- ipv4->Receive (packet, GetDevice ());
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &packet << ", " << dest << ")");
+
+ Ptr<Ipv4L3Protocol> ipv4 =
+ m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+
+ ipv4->Receive (0, packet, Ipv4L3Protocol::PROT_NUMBER,
+ Mac48Address ("ff:ff:ff:ff:ff:ff"));
}
}//namespace ns3
--- a/src/internet-node/ipv4-loopback-interface.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-loopback-interface.h Fri Sep 28 11:59:46 2007 +0100
@@ -43,7 +43,6 @@
private:
virtual void SendTo (Packet p, Ipv4Address dest);
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
Ptr<Node> m_node;
};
--- a/src/internet-node/ipv4-private.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "ipv4-private.h"
-#include "ipv4-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId Ipv4Private::iid = MakeInterfaceId ("Ipv4Private", Object::iid);
-
-Ipv4Private::Ipv4Private (Ptr<Ipv4L3Protocol> ipv4)
- : m_ipv4 (ipv4)
-{
- SetInterfaceId (Ipv4Private::iid);
-}
-Ipv4Private::~Ipv4Private ()
-{
- NS_ASSERT (m_ipv4 == 0);
-}
-TraceResolver *
-Ipv4Private::CreateTraceResolver (TraceContext const &context)
-{
- return m_ipv4->CreateTraceResolver (context);
-}
-void
-Ipv4Private::Send (Packet const &packet, Ipv4Address source,
- Ipv4Address destination, uint8_t protocol)
-{
- m_ipv4->Send (packet, source, destination, protocol);
-}
-Ipv4Interface *
-Ipv4Private::FindInterfaceForDevice (Ptr<const NetDevice>device)
-{
- return m_ipv4->FindInterfaceForDevice (device);
-}
-void
-Ipv4Private::Receive(Packet& p, Ptr<NetDevice> device)
-{
- m_ipv4->Receive (p, device);
-}
-void
-Ipv4Private::DoDispose (void)
-{
- m_ipv4 = 0;
- Object::DoDispose ();
-}
-
-} // namespace ns3
--- a/src/internet-node/ipv4-private.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef IPV4_PRIVATE_H
-#define IPV4_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ptr.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class Packet;
-class Ipv4L3Protocol;
-class TraceContext;
-class TraceResolver;
-class Ipv4Interface;
-class NetDevice;
-
-class Ipv4Private : public Object
-{
-public:
- static const InterfaceId iid;
- Ipv4Private (Ptr<Ipv4L3Protocol> ipv4);
- virtual ~Ipv4Private ();
-
- TraceResolver *CreateTraceResolver (TraceContext const &context);
- void Send (Packet const &packet, Ipv4Address source,
- Ipv4Address destination, uint8_t protocol);
- Ipv4Interface *FindInterfaceForDevice (Ptr<const NetDevice>device);
- void Receive(Packet& p, Ptr<NetDevice> device);
-protected:
- virtual void DoDispose (void);
-private:
- Ptr<Ipv4L3Protocol> m_ipv4;
-};
-
-} // namespace ns3
-
-#endif /* IPV4_PRIVATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/ipv4-static-routing.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,658 @@
+// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+// All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+// Gustavo Carneiro <gjc@inescporto.pt>
+
+#include "ns3/log.h"
+#include "ipv4-static-routing.h"
+#include "ns3/packet.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4StaticRouting");
+
+namespace ns3 {
+
+Ipv4StaticRouting::Ipv4StaticRouting ()
+: m_defaultRoute (0), m_defaultMulticastRoute (0)
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest,
+ Ipv4Address nextHop,
+ uint32_t interface)
+{
+ NS_LOG_FUNCTION;
+ Ipv4Route *route = new Ipv4Route ();
+ *route = Ipv4Route::CreateHostRouteTo (dest, nextHop, interface);
+ m_hostRoutes.push_back (route);
+}
+
+void
+Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest,
+ uint32_t interface)
+{
+ NS_LOG_FUNCTION;
+ Ipv4Route *route = new Ipv4Route ();
+ *route = Ipv4Route::CreateHostRouteTo (dest, interface);
+ m_hostRoutes.push_back (route);
+}
+
+void
+Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network,
+ Ipv4Mask networkMask,
+ Ipv4Address nextHop,
+ uint32_t interface)
+{
+ NS_LOG_FUNCTION;
+ Ipv4Route *route = new Ipv4Route ();
+ *route = Ipv4Route::CreateNetworkRouteTo (network,
+ networkMask,
+ nextHop,
+ interface);
+ m_networkRoutes.push_back (route);
+}
+
+void
+Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network,
+ Ipv4Mask networkMask,
+ uint32_t interface)
+{
+ NS_LOG_FUNCTION;
+ Ipv4Route *route = new Ipv4Route ();
+ *route = Ipv4Route::CreateNetworkRouteTo (network,
+ networkMask,
+ interface);
+ m_networkRoutes.push_back (route);
+}
+
+void
+Ipv4StaticRouting::SetDefaultRoute (Ipv4Address nextHop,
+ uint32_t interface)
+{
+ NS_LOG_FUNCTION;
+ Ipv4Route *route = new Ipv4Route ();
+ *route = Ipv4Route::CreateDefaultRoute (nextHop, interface);
+ delete m_defaultRoute;
+ m_defaultRoute = route;
+}
+
+void
+Ipv4StaticRouting::AddMulticastRoute(Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ NS_LOG_FUNCTION;
+ Ipv4MulticastRoute *route = new Ipv4MulticastRoute ();
+ *route = Ipv4MulticastRoute::CreateMulticastRoute (origin, group,
+ inputInterface, outputInterfaces);
+ m_multicastRoutes.push_back (route);
+}
+
+void
+Ipv4StaticRouting::SetDefaultMulticastRoute(uint32_t outputInterface)
+{
+ NS_LOG_FUNCTION;
+ Ipv4Address origin = Ipv4Address::GetAny ();
+ Ipv4Address group = Ipv4Address::GetAny ();
+ uint32_t inputInterface = Ipv4RoutingProtocol::IF_INDEX_ANY;
+
+ std::vector<uint32_t> outputInterfaces (1);
+ outputInterfaces[0] = outputInterface;
+
+ Ipv4MulticastRoute *route = new Ipv4MulticastRoute ();
+ *route = Ipv4MulticastRoute::CreateMulticastRoute (origin, group,
+ inputInterface, outputInterfaces);
+
+ delete m_defaultMulticastRoute;
+ m_defaultMulticastRoute = route;
+}
+
+uint32_t
+Ipv4StaticRouting::GetNMulticastRoutes (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_multicastRoutes.size () + m_defaultMulticastRoute ? 1 : 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::GetMulticastRoute (uint32_t index) const
+{
+ NS_LOG_FUNCTION;
+ NS_ASSERT_MSG(index < m_multicastRoutes.size (),
+ "Ipv4StaticRouting::GetMulticastRoute (): Index out of range");
+//
+// From an external point of view the default route appears to be in slot 0
+// of the routing table. The implementation, however, puts it in a separate
+// place. So, if a client asks for index 0 and we have a default multicast
+// route, we have to return it from that different place
+// (m_defaultMulticastRoute).
+//
+ if (index == 0 && m_defaultMulticastRoute != 0)
+ {
+ return m_defaultMulticastRoute;
+ }
+//
+// If there is a default multicast route present, a client will just assume
+// that it is in slot zero and there is one "extra" zeroth route in the table.
+// To return the correct indexed entry in our list, we have to decrement the
+// index to take into account the default route not being in the actual list.
+// Since we fell through to here, we've taken care of the case where the
+// index was zero.
+//
+ if (m_defaultMulticastRoute != 0)
+ {
+ NS_ASSERT(index > 0);
+ index--;
+ }
+
+ if (index < m_multicastRoutes.size ())
+ {
+ uint32_t tmp = 0;
+ for (MulticastRoutesCI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ if (tmp == index)
+ {
+ return *i;
+ }
+ tmp++;
+ }
+ }
+ return 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::GetDefaultMulticastRoute () const
+{
+ NS_LOG_FUNCTION;
+ if (m_defaultMulticastRoute != 0)
+ {
+ return m_defaultMulticastRoute;
+ }
+ return 0;
+}
+
+bool
+Ipv4StaticRouting::RemoveMulticastRoute(Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface)
+{
+ NS_LOG_FUNCTION;
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+ if (origin == route->GetOrigin () &&
+ group == route->GetGroup () &&
+ inputInterface == route->GetInputInterface ())
+ {
+ delete *i;
+ m_multicastRoutes.erase (i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Ipv4StaticRouting::RemoveMulticastRoute(uint32_t index)
+{
+ NS_LOG_FUNCTION;
+//
+// From an external point of view the default route appears to be in slot 0
+// of the routing table. The implementation, however, puts it in a separate
+// place. So, if a client asks to delete index 0 and we have a default
+// multicast route set, we have to delete it from that different place
+// (m_defaultMulticastRoute).
+//
+ if (index == 0 && m_defaultMulticastRoute != 0)
+ {
+ delete m_defaultMulticastRoute;
+ m_defaultMulticastRoute = 0;
+ }
+//
+// If there is a default multicast route present, a client will just assume
+// that it is in slot zero and there is one "extra" zeroth route in the table.
+// To return the correct indexed entry in our list, we have to decrement the
+// index to take into account the default route not being in the actual list.
+// Since we fell through to here, we've taken care of the case where the
+// index was zero.
+//
+ if (m_defaultMulticastRoute != 0)
+ {
+ NS_ASSERT(index > 0);
+ index--;
+ }
+
+ uint32_t tmp = 0;
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ if (tmp == index)
+ {
+ delete *i;
+ m_multicastRoutes.erase (i);
+ return;
+ }
+ tmp++;
+ }
+}
+
+Ipv4Route *
+Ipv4StaticRouting::LookupStatic (Ipv4Address dest)
+{
+ NS_LOG_FUNCTION;
+ for (HostRoutesCI i = m_hostRoutes.begin ();
+ i != m_hostRoutes.end ();
+ i++)
+ {
+ NS_ASSERT ((*i)->IsHost ());
+ if ((*i)->GetDest ().IsEqual (dest))
+ {
+ return (*i);
+ }
+ }
+ for (NetworkRoutesI j = m_networkRoutes.begin ();
+ j != m_networkRoutes.end ();
+ j++)
+ {
+ NS_ASSERT ((*j)->IsNetwork ());
+ Ipv4Mask mask = (*j)->GetDestNetworkMask ();
+ Ipv4Address entry = (*j)->GetDestNetwork ();
+ if (mask.IsMatch (dest, entry))
+ {
+ return (*j);
+ }
+ }
+ if (m_defaultRoute != 0)
+ {
+ NS_ASSERT (m_defaultRoute->IsDefault ());
+ return m_defaultRoute;
+ }
+ return 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::LookupStatic (
+ Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t ifIndex)
+{
+ NS_LOG_FUNCTION;
+//
+// We treat the "any" address (typically 0.0.0.0) as a wildcard in our matching
+// scheme.
+//
+ Ipv4Address wildcard = Ipv4Address::GetAny ();
+
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+//
+// We've been passed an origin address, a multicast group address and an
+// interface index. We have to decide if the current route in the list is
+// a match.
+//
+// The first case is the restrictive case where the origin, group and index
+// matches. This picks up exact routes during forwarded and exact routes from
+// the local node (in which case the ifIndex is a wildcard).
+//
+ if (origin == route->GetOrigin () && group == route->GetGroup ())
+ {
+ if (ifIndex == Ipv4RoutingProtocol::IF_INDEX_ANY ||
+ ifIndex == route->GetInputInterface ())
+ {
+ return *i;
+ }
+ }
+ }
+//
+// If the input interface index is not a wildcard (that means that the packet
+// did not originally come from this node), we're done. We don't
+// just happily forward packets we don't really know what to do with.
+// Multicast storms are not generally considered a good thing.
+//
+ if (ifIndex != Ipv4RoutingProtocol::IF_INDEX_ANY)
+ {
+ return 0;
+ }
+//
+// Now, we're going to get a litle less restricive. This only applies in the
+// case where the packet in question is coming from the local node. In order
+// to avoid dependencies on the order in which routes were added, we will
+// actually walk the list two more times, the first time looking for routes
+// with a single wildcard, and the last time looking for the first route
+// with two wildcards.
+//
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+//
+// Here we will ignore the origin. We know that a single source address must
+// be picked for a packet, but we may want to send multicast packets out
+// multiple interfaces. To support this case, a user would need to add
+// a Multicast route with the route's origin set to wildcard. N.B As a
+// result, packets sourced from a node with multiple interface may have a
+// source IP address different from that of the interface actually used to
+// send the packet.
+//
+ if (route->GetOrigin () == wildcard && group == route->GetGroup ())
+ {
+ return *i;
+ }
+ }
+//
+// Finally we want to allow users to specify a default route that specifies
+// sending all multicast packets out multiple interfaces. The standard
+// default multicast route is patterned after other systems and limits the
+// number of outputs to one. If, however a client manually adds a multicast
+// route with the origin, the multicast group and the input interface index
+// all set to wildcard, she has created a default route with multiple output
+// interfaces.
+//
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+
+ if (route->GetOrigin () == wildcard && route->GetGroup () == wildcard)
+ {
+ return *i;
+ }
+ }
+//
+// We also allow users to specify a typical default multicast route. This
+// default route is limited to specifying a single output interface.
+//
+ if (m_defaultMulticastRoute != 0)
+ {
+ return m_defaultMulticastRoute;
+ }
+
+ return 0;
+}
+
+uint32_t
+Ipv4StaticRouting::GetNRoutes (void)
+{
+ NS_LOG_FUNCTION;
+ uint32_t n = 0;
+ if (m_defaultRoute != 0)
+ {
+ n++;
+ }
+ n += m_hostRoutes.size ();
+ n += m_networkRoutes.size ();
+ return n;
+}
+
+Ipv4Route *
+Ipv4StaticRouting::GetDefaultRoute ()
+{
+ NS_LOG_FUNCTION;
+ if (m_defaultRoute != 0)
+ {
+ return m_defaultRoute;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+Ipv4Route *
+Ipv4StaticRouting::GetRoute (uint32_t index)
+{
+ NS_LOG_FUNCTION;
+ if (index == 0 && m_defaultRoute != 0)
+ {
+ return m_defaultRoute;
+ }
+ if (index > 0 && m_defaultRoute != 0)
+ {
+ index--;
+ }
+ if (index < m_hostRoutes.size ())
+ {
+ uint32_t tmp = 0;
+ for (HostRoutesCI i = m_hostRoutes.begin ();
+ i != m_hostRoutes.end ();
+ i++)
+ {
+ if (tmp == index)
+ {
+ return *i;
+ }
+ tmp++;
+ }
+ }
+ index -= m_hostRoutes.size ();
+ uint32_t tmp = 0;
+ for (NetworkRoutesI j = m_networkRoutes.begin ();
+ j != m_networkRoutes.end ();
+ j++)
+ {
+ if (tmp == index)
+ {
+ return *j;
+ }
+ tmp++;
+ }
+ NS_ASSERT (false);
+ // quiet compiler.
+ return 0;
+}
+void
+Ipv4StaticRouting::RemoveRoute (uint32_t index)
+{
+ NS_LOG_FUNCTION;
+ if (index == 0 && m_defaultRoute != 0)
+ {
+ delete m_defaultRoute;
+ m_defaultRoute = 0;
+ }
+ if (index > 0 && m_defaultRoute != 0)
+ {
+ index--;
+ }
+ if (index < m_hostRoutes.size ())
+ {
+ uint32_t tmp = 0;
+ for (HostRoutesI i = m_hostRoutes.begin ();
+ i != m_hostRoutes.end ();
+ i++)
+ {
+ if (tmp == index)
+ {
+ delete *i;
+ m_hostRoutes.erase (i);
+ return;
+ }
+ tmp++;
+ }
+ }
+ index -= m_hostRoutes.size ();
+ uint32_t tmp = 0;
+ for (NetworkRoutesI j = m_networkRoutes.begin ();
+ j != m_networkRoutes.end ();
+ j++)
+ {
+ if (tmp == index)
+ {
+ delete *j;
+ m_networkRoutes.erase (j);
+ return;
+ }
+ tmp++;
+ }
+ NS_ASSERT (false);
+}
+
+bool
+Ipv4StaticRouting::RequestRoute (
+ uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ RouteReplyCallback routeReply)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << ifIndex << &ipHeader << ", " << &packet << ", " <<
+ &routeReply << ")");
+
+ NS_LOG_LOGIC ("source = " << ipHeader.GetSource ());
+
+ NS_LOG_LOGIC ("destination = " << ipHeader.GetDestination ());
+
+ if (ipHeader.GetDestination ().IsMulticast ())
+ {
+ NS_LOG_LOGIC ("Multicast destination");
+
+ Ipv4MulticastRoute *mRoute = LookupStatic(ipHeader.GetSource (),
+ ipHeader.GetDestination (), ifIndex);
+
+ if (mRoute)
+ {
+ NS_LOG_LOGIC ("Multicast route found");
+
+ for (uint32_t i = 0; i < mRoute->GetNOutputInterfaces (); ++i)
+ {
+ Packet p = packet;
+ Ipv4Header h = ipHeader;
+ Ipv4Route route =
+ Ipv4Route::CreateHostRouteTo(h.GetDestination (),
+ mRoute->GetOutputInterface(i));
+ NS_LOG_LOGIC ( "Send via interface " <<
+ mRoute->GetOutputInterface(i));
+ routeReply (true, route, p, h);
+ }
+ return true;
+ }
+ return false; // Let other routing protocols try to handle this
+ }
+//
+// This is a unicast packet. Check to see if we have a route for it.
+//
+ NS_LOG_LOGIC ("Unicast destination");
+ Ipv4Route *route = LookupStatic (ipHeader.GetDestination ());
+ if (route != 0)
+ {
+ routeReply (true, *route, packet, ipHeader);
+ return true;
+ }
+ else
+ {
+ return false; // Let other routing protocols try to handle this
+ // route request.
+ }
+}
+
+bool
+Ipv4StaticRouting::RequestIfIndex (Ipv4Address destination, uint32_t& ifIndex)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << destination << ", " << &ifIndex << ")");
+//
+// First, see if this is a multicast packet we have a route for. If we
+// have a route, then send the packet down each of the specified interfaces.
+//
+ if (destination.IsMulticast ())
+ {
+ NS_LOG_LOGIC ("Multicast destination");
+
+ Ipv4MulticastRoute *mRoute = LookupStatic(Ipv4Address::GetAny (),
+ destination, Ipv4RoutingProtocol::IF_INDEX_ANY);
+
+ if (mRoute)
+ {
+ NS_LOG_LOGIC ("Multicast route found");
+
+ if (mRoute->GetNOutputInterfaces () != 1)
+ {
+ NS_LOG_LOGIC ("Route is to multiple interfaces. Ignoring.");
+ return false;
+ }
+
+ ifIndex = mRoute->GetOutputInterface(0);
+ NS_LOG_LOGIC ("Found ifIndex " << ifIndex);
+ return true;
+ }
+ return false; // Let other routing protocols try to handle this
+ }
+//
+// See if this is a unicast packet we have a route for.
+//
+ NS_LOG_LOGIC ("Unicast destination");
+ Ipv4Route *route = LookupStatic (destination);
+ if (route)
+ {
+ ifIndex = route->GetInterface ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void
+Ipv4StaticRouting::DoDispose (void)
+{
+ NS_LOG_FUNCTION;
+ for (HostRoutesI i = m_hostRoutes.begin ();
+ i != m_hostRoutes.end ();
+ i = m_hostRoutes.erase (i))
+ {
+ delete (*i);
+ }
+ for (NetworkRoutesI j = m_networkRoutes.begin ();
+ j != m_networkRoutes.end ();
+ j = m_networkRoutes.erase (j))
+ {
+ delete (*j);
+ }
+ if (m_defaultRoute != 0)
+ {
+ delete m_defaultRoute;
+ m_defaultRoute = 0;
+ }
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i = m_multicastRoutes.erase (i))
+ {
+ delete (*i);
+ }
+ if (m_defaultMulticastRoute != 0)
+ {
+ delete m_defaultMulticastRoute;
+ m_defaultMulticastRoute = 0;
+ }
+ Ipv4RoutingProtocol::DoDispose ();
+}
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/ipv4-static-routing.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,511 @@
+// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+// All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+// Gustavo Carneiro <gjc@inescporto.pt>
+//
+
+#ifndef IPV4_STATIC_ROUTING_H
+#define IPV4_STATIC_ROUTING_H
+
+#include <list>
+#include <stdint.h>
+#include "ns3/callback-trace-source.h"
+#include "ns3/array-trace-resolver.h"
+#include "ns3/ipv4-address.h"
+#include "ipv4-header.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4.h"
+
+namespace ns3 {
+
+class Packet;
+class NetDevice;
+class Ipv4Interface;
+class Ipv4Address;
+class Ipv4Header;
+class Ipv4Route;
+class Node;
+class TraceResolver;
+class TraceContext;
+
+
+/**
+ * @brief Static routing protocol for IP version 4 stacks.
+ *
+ * In ns-3 we have the concept of a pluggable routing protocol. Routing
+ * protocols are added to a list maintained by the Ipv4L3Protocol. Every
+ * stack gets one routing protocol for free -- the Ipv4StaticRouting routing
+ * protocol is added in the constructor of the Ipv4L3Protocol (this is the
+ * piece of code that implements the functionality of the IP layer).
+ *
+ * The Ipv4StaticRouting class inherits from the abstract base class
+ * Ipv4RoutingProtocol that defines the interface methods that a routing
+ * protocol must support.
+ *
+ * When a packet arrives in the Ipv4L3Protocol for transmission, it comes
+ * either from a local source via Ipv4L3Protocol::Send or from a remote
+ * source via Ipv4L3Protocol::Forwarding. In both cases, a function is called
+ * (Ipv4L3Protocol::Lookup) to look up the routing information for the packet.
+ *
+ * The lookup function iterates through the list of routing protocols asking
+ * each to see if it can find a route and send the packet. A callback is
+ * provided during each of these calls that should be considered a pre-
+ * packaged send call. This is done to allow asynchronous calls into
+ * routing subsystems in order to support on-demand routing, for example. The
+ * method for requesting this operation is Ipv4StaticRouting::RequestRoute for
+ * the static routing protocol.
+ *
+ * Each routing protocol is also free to implement its own methods for managing
+ * routes which you will find below. This class manages a set of "static" or
+ * manually configured routes for host, network and multicast routes.
+ *
+ * @see Ipv4RoutingProtocol
+ * @see Ipv4L3Protocol::AddRoutingProtocol
+ * @see Ipv4L3Protocol::Ipv4L3Protocol
+ */
+class Ipv4StaticRouting : public Ipv4RoutingProtocol
+{
+public:
+/**
+ * @brief Construct an empty Ipv4StaticRouting routing protocol,
+ * @internal
+ *
+ * The Ipv4StaticRouting class supports host, network and multicast routes.
+ * This method initializes the lists containing these routes to empty.
+ *
+ * @see Ipv4StaticRouting
+ */
+ Ipv4StaticRouting ();
+
+/**
+ * @brief Request that a check for a route bw performed and if a route is found
+ * that the packet be sent on its way using the pre-packaged send callback.
+ *
+ * The source and destination IP addresses for the packet in question are found
+ * in the provided Ipv4Header. There are two major processing forks depending
+ * on the type of destination address.
+ *
+ * If the destination address is unicast then the routing table is consulted
+ * for a route to the destination and if it is found, the routeReply callback
+ * is executed to send the packet (with the found route).
+ *
+ * If the destination address is a multicast, then the exact processing steps
+ * depend on whether or not the packet has been sourced locally. This is
+ * determined by the parameter ifIndex. This is the interface index over which
+ * this packet was received. If the packet has not been received over a
+ * network interface, this index will be set to
+ * Ipv4RoutingProtocol::IF_INDEX_ANY (a very large number). In that case,
+ * we want to avoid the requirement that an explicit route out of each node
+ * must be set, so we don't do anything here.
+ *
+ * If the packet is a multicast destination and has been received over a
+ * network interface, a call to this method implies that the packet is being
+ * forwarded. In that case, there must be an explicit route out of the node.
+ * A multicast route references the source address, the destination address
+ * (the multicast group) and the input interface in order to find a route.
+ * We consult the multicast routing table and, if a route is found, send the
+ * packet out of as many interfaces as required using the provided callback
+ * (think of it as a pre-packaged send call).
+ *
+ * @param ifIndex The network interface index over which the packed was
+ * received. If the packet is from a local source, ifIndex will be set to
+ * Ipv4RoutingProtocol::IF_INDEX_ANY.
+ * @param ipHeader the Ipv4Header containing the source and destination IP
+ * addresses for the packet.
+ * @param packet The packet to be sent if a route is found.
+ * @param routeReply A callback that packaged up the call to actually send the
+ * packet.
+ * @return Returns true if a route is found and the packet has been sent,
+ * otherwise returns false indicating that the next routing protocol should
+ * be consulted. In practice, the static routing protocol is the last chance
+ * protocol.
+ *
+ * @see Ipv4StaticRouting
+ * @see Ipv4RoutingProtocol
+ */
+ virtual bool RequestRoute (uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ RouteReplyCallback routeReply);
+
+/**
+ * @brief Check to see if we can determine the interface index that will be
+ * used if a packet is sent to this destination.
+ *
+ * This method addresses a problem in the IP stack where a destination address
+ * must be present and checksummed into the IP header before the actual
+ * interface over which the packet is sent can be determined. The answer is
+ * to implement a known and intentional cross-layer violation. This is the
+ * endpoint of a call chain that started up quite high in the stack (sockets)
+ * and has found its way down to the Ipv4L3Protocol which is consulting the
+ * routing protocols for what they would do if presented with a packet of the
+ * given destination.
+ *
+ * Note that the a single interface index is returned. This means that if
+ * the destination address is a multicast, and an explicit route is present
+ * that includeds multiple output interfaces, that route cannot be used.
+ *
+ * If there are multiple paths out of the node, the resolution is performed
+ * by Ipv4L3Protocol::GetIfIndexforDestination which has access to more
+ * contextual information that is useful for making a determination.
+ *
+ * @param destination The Ipv4Address if the destination of a hypothetical
+ * packet. This may be a multicast group address.
+ * @param ifIndex A reference to the interface index over which a packet
+ * sent to this destination would be sent.
+ * @return Returns true if a route is found to the destination that involves
+ * a single output interface index, otherwise returns false indicating that
+ * the next routing protocol should be consulted. In practice, the static
+ * routing protocol is the last chance protocol.
+ *
+ * @see Ipv4StaticRouting
+ * @see Ipv4RoutingProtocol
+ * @see Ipv4L3Protocol
+ */
+ virtual bool RequestIfIndex (Ipv4Address destination, uint32_t& ifIndex);
+
+/**
+ * @brief Add a host route to the static routing table.
+ *
+ * @param dest The Ipv4Address destination for this route.
+ * @param nextHop The Ipv4Address of the next hop in the route.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
+ void AddHostRouteTo (Ipv4Address dest,
+ Ipv4Address nextHop,
+ uint32_t interface);
+/**
+ * @brief Add a host route to the static routing table.
+ *
+ * @param dest The Ipv4Address destination for this route.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
+ void AddHostRouteTo (Ipv4Address dest,
+ uint32_t interface);
+
+/**
+ * @brief Add a network route to the static routing table.
+ *
+ * @param network The Ipv4Address network for this route.
+ * @param networkmask The Ipv4Mask to extract the network.
+ * @param nextHop The next hop in the route to the destination network.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
+ void AddNetworkRouteTo (Ipv4Address network,
+ Ipv4Mask networkMask,
+ Ipv4Address nextHop,
+ uint32_t interface);
+
+/**
+ * @brief Add a network route to the static routing table.
+ *
+ * @param network The Ipv4Address network for this route.
+ * @param networkmask The Ipv4Mask to extract the network.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
+ void AddNetworkRouteTo (Ipv4Address network,
+ Ipv4Mask networkMask,
+ uint32_t interface);
+
+/**
+ * @brief Add a default route to the static routing table.
+ *
+ * This method tells the routing system what to do in the case where a specific
+ * route to a destination is not found. The system forwards packets to the
+ * specified node in the hope that it knows better how to route the packet.
+ *
+ * If the default route is set, it is returned as the selected route from
+ * LookupStatic irrespective of destination address if no specific route is
+ * found.
+ *
+ * @param nextHop The Ipv4Address to send packets to in the hope that they
+ * will be forwarded correctly.
+ * @param interface The network interface index used to send packets.
+ *
+ * @see Ipv4Address
+ * @see Ipv4StaticRouting::Lookup
+ */
+ void SetDefaultRoute (Ipv4Address nextHop,
+ uint32_t interface);
+
+/**
+ * @brief Get the number of individual unicast routes that have been added
+ * to the routing table.
+ *
+ * @warning The default route counts as one of the routes.
+ */
+ uint32_t GetNRoutes (void);
+
+/**
+ * @brief Get the default route from the static routing table.
+ *
+ * @return If the default route is set, a pointer to that Ipv4Route is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ */
+ Ipv4Route *GetDefaultRoute (void);
+
+/**
+ * @brief Get a route from the static unicast routing table.
+ *
+ * Externally, the unicast static routing table appears simply as a table with
+ * n entries. The one sublety of note is that if a default route has been set
+ * it will appear as the zeroth entry in the table. This means that if you
+ * add only a default route, the table will have one entry that can be accessed
+ * either by explicity calling GetDefaultRoute () or by calling GetRoute (0).
+ *
+ * Similarly, if the default route has been set, calling RemoveRoute (0) will
+ * remove the default route.
+ *
+ * @param i The index (into the routing table) of the route to retrieve. If
+ * the default route has been set, it will occupy index zero.
+ * @return If route is set, a pointer to that Ipv4Route is returned, otherwise
+ * a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::RemoveRoute
+ */
+ Ipv4Route *GetRoute (uint32_t i);
+
+/**
+ * @brief Remove a route from the static unicast routing table.
+ *
+ * Externally, the unicast static routing table appears simply as a table with
+ * n entries. The one sublety of note is that if a default route has been set
+ * it will appear as the zeroth entry in the table. This means that if the
+ * default route has been set, calling RemoveRoute (0) will remove the
+ * default route.
+ *
+ * @param i The index (into the routing table) of the route to remove. If
+ * the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
+ void RemoveRoute (uint32_t i);
+
+/**
+ * @brief Add a multicast route to the static routing table.
+ *
+ * A multicast route must specify an origin IP address, a multicast group and
+ * an input network interface index as conditions and provide a vector of
+ * output network interface indices over which packets matching the conditions
+ * are sent.
+ *
+ * Typically there are two main types of multicast routes: routes of the
+ * first kind are used during forwarding. All of the conditions must be
+ * exlicitly provided. The second kind of routes are used to get packets off
+ * of a local node. The difference is in the input interface. Routes for
+ * forwarding will always have an explicit input interface specified. Routes
+ * off of a node will always set the input interface to a wildcard specified
+ * by the index Ipv4RoutingProtocol::IF_INDEX_ANY.
+ *
+ * For routes off of a local node wildcards may be used in the origin and
+ * multicast group addresses. The wildcard used for Ipv4Adresses is that
+ * address returned by Ipv4Address::GetAny () -- typically "0.0.0.0". Usage
+ * of a wildcard allows one to specify default behavior to varying degrees.
+ *
+ * For example, making the origin address a wildcard, but leaving the
+ * multicast group specific allows one (in the case of a node with multiple
+ * interfaces) to create different routes using different output interfaces
+ * for each multicast group.
+ *
+ * If the origin and multicast addresses are made wildcards, you have created
+ * essentially a default multicast address that can forward to multiple
+ * interfaces. Compare this to the actual default multicast address that is
+ * limited to specifying a single output interface for compatibility with
+ * existing functionality in other systems.
+ *
+ * @param origin The Ipv4Address of the origin of packets for this route. May
+ * be Ipv4Address:GetAny for open groups.
+ * @param group The Ipv4Address of the multicast group or this route.
+ * @param inputInterface The input network interface index over which to
+ * expect packets destined for this route. May be
+ * Ipv4RoutingProtocol::IF_INDEX_ANY for packets of local origin.
+ * @param outputInterface A vector of network interface indices used to specify
+ * how to send packets to the destination(s).
+ *
+ * @see Ipv4Address
+ */
+ void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+/**
+ * @brief Add a default multicast route to the static routing table.
+ *
+ * This is the multicast equivalent of the unicast version SetDefaultRoute.
+ * We tell the routing system what to do in the case where a specific route
+ * to a destination multicast group is not found. The system forwards
+ * packets out the specified interface in the hope that "something out there"
+ * knows better how to route the packet. This method is only used in
+ * initially sending packets off of a host. The default multicast route is
+ * not consulted during forwarding -- exact routes must be specified using
+ * AddMulticastRoute for that case.
+ *
+ * Since we're basically sending packets to some entity we think may know
+ * better what to do, we don't pay attention to "subtleties" like origin
+ * address, nor do we worry about forwarding out multiple interfaces. If the
+ * default multicast route is set, it is returned as the selected route from
+ * LookupStatic irrespective of origin or multicast group if another specific
+ * route is not found.
+ *
+ * @param outputInterface The network interface index used to specify where
+ * to send packets in the case of unknown routes.
+ *
+ * @see Ipv4Address
+ */
+ void SetDefaultMulticastRoute (uint32_t outputInterface);
+
+/**
+ * @brief Get the number of individual multicast routes that have been added
+ * to the routing table.
+ *
+ * @warning The default multicast route counts as one of the routes.
+ */
+ uint32_t GetNMulticastRoutes (void) const;
+
+/**
+ * @brief Get a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default route has
+ * been set it will appear as the zeroth entry in the table. This means that
+ * if you add only a default route, the table will have one entry that can be
+ * accessed either by explicity calling GetDefaultMulticastRoute () or by
+ * calling GetMulticastRoute (0).
+ *
+ * Similarly, if the default route has been set, calling
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param i The index (into the routing table) of the multicast route to
+ * retrieve. If the default route has been set, it will occupy index zero.
+ * @return If route <i> is set, a pointer to that Ipv4MulticastRoute is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::RemoveRoute
+ */
+ Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
+
+/**
+ * @brief Get the default multicast route from the static routing table.
+ *
+ * @return If the default route is set, a pointer to that Ipv4MulticastRoute is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ */
+ Ipv4MulticastRoute *GetDefaultMulticastRoute (void) const;
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table. This
+ * means that the default route may be removed by calling this method with
+ * appropriate wildcard parameters.
+ *
+ * This method causes the multicast routing table to be searched for the first
+ * route that matches the parameters and removes it.
+ *
+ * Wildcards may be provided to this function, but the wildcards are used to
+ * exacly match wildcards in the routes (see AddMulticastRoute). That is,
+ * calling RemoveMulticastRoute with the origin set to "0.0.0.0" will not
+ * remove routes with any address in the origin, but will only remove routes
+ * with "0.0.0.0" set as the the origin.
+ *
+ * @param origin The IP address specified as the origin of packets for the
+ * route.
+ * @param origin The IP address specified as the multicast group addres of
+ * the route.
+ * @param inputInterfade The network interface index specified as the expected
+ * input interface for the route.
+ * @returns True if a route was found and removed, false otherwise.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::AddMulticastRoute
+ */
+ bool RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface);
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table. This
+ * means that if the default route has been set, calling
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param index The index (into the multicast routing table) of the route to
+ * remove. If the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
+ void RemoveMulticastRoute (uint32_t index);
+
+protected:
+ void DoDispose (void);
+
+private:
+ typedef std::list<Ipv4Route *> HostRoutes;
+ typedef std::list<Ipv4Route *>::const_iterator HostRoutesCI;
+ typedef std::list<Ipv4Route *>::iterator HostRoutesI;
+ typedef std::list<Ipv4Route *> NetworkRoutes;
+ typedef std::list<Ipv4Route *>::const_iterator NetworkRoutesCI;
+ typedef std::list<Ipv4Route *>::iterator NetworkRoutesI;
+
+ typedef std::list<Ipv4MulticastRoute *> MulticastRoutes;
+ typedef std::list<Ipv4MulticastRoute *>::const_iterator MulticastRoutesCI;
+ typedef std::list<Ipv4MulticastRoute *>::iterator MulticastRoutesI;
+
+ Ipv4Route *LookupStatic (Ipv4Address dest);
+ Ipv4MulticastRoute *LookupStatic (Ipv4Address origin, Ipv4Address group,
+ uint32_t ifIndex);
+
+ HostRoutes m_hostRoutes;
+ NetworkRoutes m_networkRoutes;
+ Ipv4Route *m_defaultRoute;
+ Ipv4MulticastRoute *m_defaultMulticastRoute;
+ MulticastRoutes m_multicastRoutes;
+};
+
+} // Namespace ns3
+
+#endif /* IPV4_STATIC_ROUTING_H */
--- a/src/internet-node/l3-demux.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-// Implement the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-#include <sstream>
-#include <string>
-#include "ns3/composite-trace-resolver.h"
-#include "ns3/node.h"
-#include "l3-demux.h"
-#include "l3-protocol.h"
-
-namespace ns3 {
-
-const InterfaceId L3Demux::iid = MakeInterfaceId ("L3Demux", Object::iid);
-
-L3Demux::L3Demux (Ptr<Node> node)
- : m_node (node)
-{
- SetInterfaceId (L3Demux::iid);
-}
-
-L3Demux::~L3Demux()
-{}
-
-void
-L3Demux::DoDispose (void)
-{
- for (L3Map_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
- {
- i->second->Dispose ();
- i->second = 0;
- }
- m_protocols.clear ();
- m_node = 0;
- Object::DoDispose ();
-}
-
-TraceResolver *
-L3Demux::CreateTraceResolver (TraceContext const &context) const
-{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- for (L3Map_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
- {
- std::string protValue;
- std::ostringstream oss (protValue);
- oss << i->second->GetProtocolNumber ();
- ProtocolTraceType context = i->second->GetProtocolNumber ();
- resolver->Add (protValue,
- MakeCallback (&L3Protocol::CreateTraceResolver, PeekPointer (i->second)),
- context);
- }
- return resolver;
-}
-
-void L3Demux::Insert(Ptr<L3Protocol> p)
-{
- m_protocols.insert(L3Map_t::value_type(p->GetProtocolNumber (), p));
-}
-
-Ptr<L3Protocol>
-L3Demux::GetProtocol (int p)
-{ // Look up a protocol by protocol number
- L3Map_t::iterator i = m_protocols.find(p);
- if (i == m_protocols.end())
- {
- return 0;
- }
- return i->second; // Return the protocol
-}
-
-} //namespace ns3
-
--- a/src/internet-node/l3-demux.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-// Define the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-// This object manages the different layer 3 protocols for any ns3
-// node that has this capability.
-
-#ifndef L3_DEMUX_H
-#define L3_DEMUX_H
-
-#include <map>
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class L3Protocol;
-class Node;
-class TraceResolver;
-class TraceContext;
-
-/**
- * \brief L3 Demux
- */
-class L3Demux : public Object
-{
-public:
- static const InterfaceId iid;
- typedef int ProtocolTraceType;
- L3Demux(Ptr<Node> node);
- virtual ~L3Demux();
-
- /**
- * \param context the trace context to use to construct the
- * TraceResolver to return
- * \returns a TraceResolver which can resolve all traces
- * performed in this object. The caller must
- * delete the returned object.
- */
- TraceResolver *CreateTraceResolver (TraceContext const &context) const;
-
-
- /**
- * \param protocol a template for the protocol to add to this L3 Demux.
- *
- * Invoke Copy on the input template to get a copy of the input
- * protocol which can be used on the Node on which this L3 Demux
- * is running. The new L3Protocol is registered internally as
- * a working L3 Protocol and returned from this method.
- * The caller does not get ownership of the returned pointer.
- */
- void Insert(Ptr<L3Protocol> protocol);
- /**
- * \param protocolNumber number of protocol to lookup
- * in this L4 Demux
- * \returns a matching L3 Protocol
- *
- * This method is typically called by lower layers
- * to forward packets up the stack to the right protocol.
- * It is also called from NodeImpl::GetIpv4 for example.
- */
- Ptr<L3Protocol> GetProtocol (int protocolNumber);
-protected:
- virtual void DoDispose (void);
-private:
- typedef std::map<int, Ptr<ns3::L3Protocol> > L3Map_t;
-
- Ptr<Node> m_node;
- L3Map_t m_protocols;
-};
-
-} //namespace ns3
-#endif
-
--- a/src/internet-node/l3-protocol.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#include "l3-protocol.h"
-
-
-namespace ns3 {
-
-L3Protocol::L3Protocol(int protocolNumber, int version)
- : m_protocolNumber (protocolNumber),
- m_version (version)
-{}
-L3Protocol::~L3Protocol ()
-{}
-
-int
-L3Protocol::GetProtocolNumber (void) const
-{
- return m_protocolNumber;
-}
-int
-L3Protocol::GetVersion() const
-{
- return m_version;
-}
-
-void
-L3Protocol::DoDispose (void)
-{
- Object::DoDispose ();
-}
-
-}//namespace ns3
--- a/src/internet-node/l3-protocol.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#ifndef L3_PROTOCOL_H
-#define L3_PROTOCOL_H
-
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class NetDevice;
-class TraceResolver;
-class TraceContext;
-
-/**
- * ::Send is always defined in subclasses.
- */
-class L3Protocol : public Object {
-public:
- L3Protocol(int protocolNumber, int version);
- virtual ~L3Protocol ();
- /**
- * \return The protocol number of this Layer 3 protocol
- */
- int GetProtocolNumber (void) const;
- /**
- * \return The version number of this protocol
- */
- int GetVersion() const;
-
- virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0;
- /**
- * Lower layer calls this method after calling L3Demux::Lookup
- * The ARP subclass needs to know from which NetDevice this
- * packet is coming to:
- * - implement a per-NetDevice ARP cache
- * - send back arp replies on the right device
- */
- virtual void Receive(Packet& p, Ptr<NetDevice> device) = 0;
-
-protected:
- virtual void DoDispose (void);
-private:
- int m_protocolNumber;
- int m_version;
-};
-
-} // Namespace ns3
-
-#endif
--- a/src/internet-node/pcap-trace.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/pcap-trace.cc Fri Sep 28 11:59:46 2007 +0100
@@ -22,7 +22,7 @@
#include <sstream>
-#include "ns3/trace-root.h"
+#include "ns3/node-list.h"
#include "ns3/trace-context.h"
#include "ns3/callback.h"
#include "ns3/pcap-writer.h"
@@ -50,8 +50,8 @@
void
PcapTrace::TraceAllIp (void)
{
- TraceRoot::Connect ("/nodes/*/ipv4/(tx|rx)",
- MakeCallback (&PcapTrace::LogIp, this));
+ NodeList::Connect ("/nodes/*/ipv4/(tx|rx)",
+ MakeCallback (&PcapTrace::LogIp, this));
}
PcapWriter *
@@ -82,10 +82,9 @@
void
PcapTrace::LogIp (TraceContext const &context, Packet const &p, uint32_t interfaceIndex)
{
- NodeList::NodeIndex nodeIndex;
- context.Get (nodeIndex);
- uint32_t nodeId = NodeList::GetNode (nodeIndex)->GetId ();
- PcapWriter *writer = GetStream (nodeId, interfaceIndex);
+ NodeListIndex nodeIndex;
+ context.GetElement (nodeIndex);
+ PcapWriter *writer = GetStream (nodeIndex.Get (), interfaceIndex);
writer->WritePacket (p);
}
--- a/src/internet-node/udp-header.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-header.cc Fri Sep 28 11:59:46 2007 +0100
@@ -24,8 +24,17 @@
namespace ns3 {
+NS_HEADER_ENSURE_REGISTERED (UdpHeader);
+
bool UdpHeader::m_calcChecksum = false;
+uint32_t
+UdpHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<UdpHeader> ("UdpHeader.ns3");
+ return uid;
+}
+
/* The magic values below are used only for debugging.
* They can be used to easily detect memory corruption
* problems so you can see the patterns in memory.
@@ -84,22 +93,27 @@
destination.Serialize (buf+4);
buf[8] = 0;
buf[9] = protocol;
- uint16_t udpLength = m_payloadSize + GetSize ();
+ uint16_t udpLength = m_payloadSize + GetSerializedSize ();
buf[10] = udpLength >> 8;
buf[11] = udpLength & 0xff;
m_initialChecksum = Ipv4ChecksumCalculate (0, buf, 12);
}
-
+std::string
+UdpHeader::GetName (void) const
+{
+ return "UDP";
+}
void
-UdpHeader::PrintTo (std::ostream &os) const
+UdpHeader::Print (std::ostream &os) const
{
- os << "(udp)"
- << ", port source=" << m_sourcePort
- << ", port destination=" << m_destinationPort
- << ", length=" << m_payloadSize;
+ os << "("
+ << "length: " << m_payloadSize + GetSerializedSize ()
+ << ") "
+ << m_sourcePort << " > " << m_destinationPort
+ ;
}
uint32_t
@@ -109,12 +123,12 @@
}
void
-UdpHeader::SerializeTo (Buffer::Iterator start) const
+UdpHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
i.WriteHtonU16 (m_sourcePort);
i.WriteHtonU16 (m_destinationPort);
- i.WriteHtonU16 (m_payloadSize + GetSize ());
+ i.WriteHtonU16 (m_payloadSize + GetSerializedSize ());
i.WriteU16 (0);
if (m_calcChecksum)
@@ -123,7 +137,7 @@
//XXXX
uint16_t checksum = Ipv4ChecksumCalculate (m_initialChecksum,
buffer->PeekData (),
- GetSize () + m_payloadSize);
+ GetSerializedSize () + m_payloadSize);
checksum = Ipv4ChecksumComplete (checksum);
i = buffer->Begin ();
i.Next (6);
@@ -132,12 +146,12 @@
}
}
uint32_t
-UdpHeader::DeserializeFrom (Buffer::Iterator start)
+UdpHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
m_sourcePort = i.ReadNtohU16 ();
m_destinationPort = i.ReadNtohU16 ();
- m_payloadSize = i.ReadNtohU16 () - GetSize ();
+ m_payloadSize = i.ReadNtohU16 () - GetSerializedSize ();
if (m_calcChecksum)
{
// XXX verify checksum.
--- a/src/internet-node/udp-header.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-header.h Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,7 @@
#define UDP_HEADER_H
#include <stdint.h>
+#include <string>
#include "ns3/header.h"
#include "ns3/ipv4-address.h"
@@ -30,15 +31,18 @@
/**
* \brief Packet header for UDP packets
*/
-class UdpHeader : public Header {
+class UdpHeader : public Header
+{
public:
+ static uint32_t GetUid (void);
+
/**
* \brief Constructor
*
* Creates a null header
*/
UdpHeader ();
- virtual ~UdpHeader ();
+ ~UdpHeader ();
/**
* \brief Enable checksum calculation for UDP (XXX currently has no effect)
@@ -80,12 +84,13 @@
Ipv4Address destination,
uint8_t protocol);
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
+
private:
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-
uint16_t m_sourcePort;
uint16_t m_destinationPort;
uint16_t m_payloadSize;
@@ -94,6 +99,6 @@
static bool m_calcChecksum;
};
-}; // namespace ns3
+} // namespace ns3
#endif /* UDP_HEADER */
--- a/src/internet-node/udp-l4-protocol.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-l4-protocol.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,9 +19,9 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+#include "ns3/log.h"
#include "ns3/assert.h"
#include "ns3/packet.h"
-#include "ns3/empty-trace-resolver.h"
#include "ns3/node.h"
#include "udp-l4-protocol.h"
@@ -29,10 +29,10 @@
#include "ipv4-end-point-demux.h"
#include "ipv4-end-point.h"
#include "ipv4-l3-protocol.h"
-#include "ipv4-private.h"
-#include "l3-demux.h"
#include "udp-socket.h"
+NS_LOG_COMPONENT_DEFINE ("UdpL4Protocol");
+
namespace ns3 {
/* see http://www.iana.org/assignments/protocol-numbers */
@@ -42,20 +42,19 @@
: Ipv4L4Protocol (PROT_NUMBER, 2),
m_node (node),
m_endPoints (new Ipv4EndPointDemux ())
-{}
+{
+ NS_LOG_FUNCTION;
+}
UdpL4Protocol::~UdpL4Protocol ()
-{}
-
-TraceResolver *
-UdpL4Protocol::CreateTraceResolver (TraceContext const &context)
{
- return new EmptyTraceResolver (context);
+ NS_LOG_FUNCTION;
}
void
UdpL4Protocol::DoDispose (void)
{
+ NS_LOG_FUNCTION;
if (m_endPoints != 0)
{
delete m_endPoints;
@@ -68,6 +67,7 @@
Ptr<Socket>
UdpL4Protocol::CreateSocket (void)
{
+ NS_LOG_FUNCTION;
Ptr<Socket> socket = Create<UdpSocket> (m_node, this);
return socket;
}
@@ -75,27 +75,40 @@
Ipv4EndPoint *
UdpL4Protocol::Allocate (void)
{
+ NS_LOG_FUNCTION;
return m_endPoints->Allocate ();
}
+
Ipv4EndPoint *
UdpL4Protocol::Allocate (Ipv4Address address)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << address << ")");
return m_endPoints->Allocate (address);
}
+
Ipv4EndPoint *
UdpL4Protocol::Allocate (uint16_t port)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << port << ")");
return m_endPoints->Allocate (port);
}
+
Ipv4EndPoint *
UdpL4Protocol::Allocate (Ipv4Address address, uint16_t port)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << address << ", " << port << ")");
return m_endPoints->Allocate (address, port);
}
Ipv4EndPoint *
UdpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort,
Ipv4Address peerAddress, uint16_t peerPort)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << localAddress << ", " << localPort << ", " <<
+ peerAddress << ", " << peerPort << ")");
return m_endPoints->Allocate (localAddress, localPort,
peerAddress, peerPort);
}
@@ -103,23 +116,31 @@
void
UdpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << endPoint << ")");
m_endPoints->DeAllocate (endPoint);
}
void
UdpL4Protocol::Receive(Packet& packet,
- Ipv4Address const &source,
- Ipv4Address const &destination)
+ Ipv4Address const &source,
+ Ipv4Address const &destination,
+ Ptr<Ipv4Interface> interface)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &packet << ", " << source << ", " << destination <<
+ ")");
+
UdpHeader udpHeader;
packet.RemoveHeader (udpHeader);
- Ipv4EndPoint *endPoint = m_endPoints->Lookup (destination, udpHeader.GetDestination (),
- source, udpHeader.GetSource ());
- if (endPoint == 0)
+ Ipv4EndPointDemux::EndPoints endPoints =
+ m_endPoints->Lookup (destination, udpHeader.GetDestination (),
+ source, udpHeader.GetSource (), interface);
+ for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
+ endPoint != endPoints.end (); endPoint++)
{
- return;
+ (*endPoint)->ForwardUp (packet, source, udpHeader.GetSource ());
}
- endPoint->ForwardUp (packet, source, udpHeader.GetSource ());
}
void
@@ -127,6 +148,10 @@
Ipv4Address saddr, Ipv4Address daddr,
uint16_t sport, uint16_t dport)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &packet << ", " << saddr << ", " << daddr << ", " <<
+ sport << ", " << dport << ")");
+
UdpHeader udpHeader;
udpHeader.SetDestination (dport);
udpHeader.SetSource (sport);
@@ -137,9 +162,10 @@
packet.AddHeader (udpHeader);
- Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
+ Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
if (ipv4 != 0)
{
+ NS_LOG_LOGIC ("Sending to IP");
ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
}
}
--- a/src/internet-node/udp-l4-protocol.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-l4-protocol.h Fri Sep 28 11:59:46 2007 +0100
@@ -49,7 +49,6 @@
UdpL4Protocol (Ptr<Node> node);
virtual ~UdpL4Protocol ();
- virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \return A smart Socket pointer to a UdpSocket, allocated by this instance
* of the UDP protocol
@@ -86,7 +85,8 @@
// inherited from Ipv4L4Protocol
virtual void Receive(Packet& p,
Ipv4Address const &source,
- Ipv4Address const &destination);
+ Ipv4Address const &destination,
+ Ptr<Ipv4Interface> interface);
protected:
virtual void DoDispose (void);
private:
--- a/src/internet-node/udp-socket.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-socket.cc Fri Sep 28 11:59:46 2007 +0100
@@ -18,11 +18,19 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+
+#include "ns3/log.h"
#include "ns3/node.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/ipv4.h"
#include "udp-socket.h"
#include "udp-l4-protocol.h"
#include "ipv4-end-point.h"
#include "ipv4-l4-demux.h"
+#include "ns3/ipv4.h"
+
+NS_LOG_COMPONENT_DEFINE ("UdpSocket");
namespace ns3 {
@@ -34,9 +42,14 @@
m_shutdownSend (false),
m_shutdownRecv (false),
m_connected (false)
-{}
+{
+ NS_LOG_FUNCTION;
+}
+
UdpSocket::~UdpSocket ()
{
+ NS_LOG_FUNCTION;
+
m_node = 0;
if (m_endPoint != 0)
{
@@ -56,132 +69,189 @@
m_udp = 0;
}
+enum Socket::SocketErrno
+UdpSocket::GetErrno (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_errno;
+}
+
Ptr<Node>
UdpSocket::GetNode (void) const
{
+ NS_LOG_FUNCTION;
return m_node;
}
void
UdpSocket::Destroy (void)
{
+ NS_LOG_FUNCTION;
m_node = 0;
m_endPoint = 0;
m_udp = 0;
}
+
int
UdpSocket::FinishBind (void)
{
- m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
- m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
+ NS_LOG_FUNCTION;
if (m_endPoint == 0)
{
return -1;
}
+ m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
+ m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
return 0;
}
int
UdpSocket::Bind (void)
{
+ NS_LOG_FUNCTION;
m_endPoint = m_udp->Allocate ();
return FinishBind ();
}
-int
-UdpSocket::Bind (Ipv4Address address)
-{
- m_endPoint = m_udp->Allocate (address);
- return FinishBind ();
-}
+
int
-UdpSocket::Bind (uint16_t port)
+UdpSocket::Bind (const Address &address)
{
- m_endPoint = m_udp->Allocate (port);
- return FinishBind ();
-}
-int
-UdpSocket::Bind (Ipv4Address address, uint16_t port)
-{
- m_endPoint = m_udp->Allocate (address, port);
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM("(" << address << ")");
+
+ if (!InetSocketAddress::IsMatchingType (address))
+ {
+ NS_LOG_ERROR ("Not IsMatchingType");
+ return ERROR_INVAL;
+ }
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ if (ipv4 == Ipv4Address::GetAny () && port == 0)
+ {
+ m_endPoint = m_udp->Allocate ();
+ }
+ else if (ipv4 == Ipv4Address::GetAny () && port != 0)
+ {
+ m_endPoint = m_udp->Allocate (port);
+ }
+ else if (ipv4 != Ipv4Address::GetAny () && port == 0)
+ {
+ m_endPoint = m_udp->Allocate (ipv4);
+ }
+ else if (ipv4 != Ipv4Address::GetAny () && port != 0)
+ {
+ m_endPoint = m_udp->Allocate (ipv4, port);
+ }
+
return FinishBind ();
}
-enum Socket::SocketErrno
-UdpSocket::GetErrno (void) const
-{
- return m_errno;
-}
int
UdpSocket::ShutdownSend (void)
{
+ NS_LOG_FUNCTION;
m_shutdownSend = true;
return 0;
}
+
int
UdpSocket::ShutdownRecv (void)
{
+ NS_LOG_FUNCTION;
m_shutdownRecv = false;
return 0;
}
-void
-UdpSocket::DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted)
+int
+UdpSocket::Close(void)
{
- // XXX: we should set the close state and check it in all API methods.
- if (!closeCompleted.IsNull ())
- {
- closeCompleted (this);
- }
+ NS_LOG_FUNCTION;
+ NotifyCloseCompleted ();
+ return 0;
}
-void
-UdpSocket::DoConnect(const Ipv4Address & address,
- uint16_t portNumber,
- ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
- ns3::Callback<void, Ptr<Socket> > connectionFailed,
- ns3::Callback<void, Ptr<Socket> > halfClose)
+
+int
+UdpSocket::Connect(const Address & address)
{
- m_defaultAddress = address;
- m_defaultPort = portNumber;
- if (!connectionSucceeded.IsNull ())
- {
- connectionSucceeded (this);
- }
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << address << ")");
+ Ipv4Route routeToDest;
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ m_defaultAddress = transport.GetIpv4 ();
+ m_defaultPort = transport.GetPort ();
+ NotifyConnectionSucceeded ();
m_connected = true;
+
+ return 0;
}
-int
-UdpSocket::DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- ns3::Callback<void, Ptr<Socket> > closeRequested)
+
+int
+UdpSocket::Send (const Packet &p)
{
- // calling accept on a udp socket is a programming error.
- m_errno = ERROR_OPNOTSUPP;
- return -1;
-}
-int
-UdpSocket::DoSend (const uint8_t* buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
-{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
+
if (!m_connected)
{
m_errno = ERROR_NOTCONN;
return -1;
}
- Packet p;
- if (buffer == 0)
+ return DoSend (p);
+}
+
+int
+UdpSocket::DoSend (const Packet &p)
+{
+ NS_LOG_FUNCTION;
+ if (m_endPoint == 0)
+ {
+ if (Bind () == -1)
+ {
+ NS_ASSERT (m_endPoint == 0);
+ return -1;
+ }
+ NS_ASSERT (m_endPoint != 0);
+ }
+ if (m_shutdownSend)
{
- p = Packet (size);
+ m_errno = ERROR_SHUTDOWN;
+ return -1;
+ }
+
+ return DoSendTo (p, m_defaultAddress, m_defaultPort);
+}
+
+int
+UdpSocket::DoSendTo (const Packet &p, const Address &address)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ", " << address << ")");
+
+ if (!m_connected)
+ {
+ NS_LOG_LOGIC ("Not connected");
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ return DoSendTo (p, ipv4, port);
}
else
{
- p = Packet (buffer, size);
+ // connected UDP socket must use default addresses
+ NS_LOG_LOGIC ("Connected");
+ return DoSendTo (p, m_defaultAddress, m_defaultPort);
}
- return DoSendPacketTo (p, m_defaultAddress, m_defaultPort, dataSent);
}
+
int
-UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ", " << dest << ", " << port << ")");
+
+ Ipv4Route routeToDest;
+
if (m_endPoint == 0)
{
if (Bind () == -1)
@@ -196,64 +266,198 @@
m_errno = ERROR_SHUTDOWN;
return -1;
}
- m_udp->Send (p, m_endPoint->GetLocalAddress (), daddr,
- m_endPoint->GetLocalPort (), dport);
- if (!dataSent.IsNull ())
+
+ uint32_t localIfIndex;
+ Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+
+ //
+ // If dest is sent to the limited broadcast address (all ones),
+ // convert it to send a copy of the packet out of every interface
+ //
+ if (dest.IsBroadcast ())
{
- dataSent (this, p.GetSize ());
+ NS_LOG_LOGIC ("Limited broadcast");
+ for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
+ {
+ Ipv4Address addri = ipv4->GetAddress (i);
+ Ipv4Mask maski = ipv4->GetNetworkMask (i);
+ m_udp->Send (p, addri, addri.GetSubnetDirectedBroadcast (maski),
+ m_endPoint->GetLocalPort (), port);
+ NotifyDataSent (p.GetSize ());
+ }
}
+ else if (ipv4->GetIfIndexForDestination(dest, localIfIndex))
+ {
+ NS_LOG_LOGIC ("Route exists");
+ m_udp->Send (p, ipv4->GetAddress (localIfIndex), dest,
+ m_endPoint->GetLocalPort (), port);
+ NotifyDataSent (p.GetSize ());
+ return 0;
+ }
+ else
+ {
+ NS_LOG_ERROR ("ERROR_NOROUTETOHOST");
+ m_errno = ERROR_NOROUTETOHOST;
+ return -1;
+ }
+
return 0;
}
+
int
-UdpSocket::DoSendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::SendTo(const Address &address, const Packet &p)
{
- if (m_connected)
- {
- m_errno = ERROR_ISCONN;
- return -1;
- }
- Packet p;
- if (buffer == 0)
- {
- p = Packet (size);
- }
- else
- {
- p = Packet (buffer, size);
- }
- return DoSendPacketTo (p, address, port, dataSent);
-}
-void
-UdpSocket::DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
- m_rxCallback = callback;
-}
-void
-UdpSocket::DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
- m_dummyRxCallback = callback;
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << address << ", " << &p << ")");
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ return DoSendTo (p, ipv4, port);
}
void
-UdpSocket::ForwardUp (const Packet &packet, Ipv4Address saddr, uint16_t sport)
+UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &packet << ", " << ipv4 << ", " << port << ")");
+
if (m_shutdownRecv)
{
return;
}
+
+ Address address = InetSocketAddress (ipv4, port);
Packet p = packet;
- if (!m_dummyRxCallback.IsNull ())
- {
- m_dummyRxCallback (this, p.GetSize (), saddr, sport);
- }
- if (!m_rxCallback.IsNull ())
- {
- m_rxCallback (this, p.PeekData (), p.GetSize (), saddr, sport);
- }
+ NotifyDataReceived (p, address);
+}
+
+} //namespace ns3
+
+
+#ifdef RUN_SELF_TESTS
+
+#include "ns3/test.h"
+#include "ns3/internet-node.h"
+#include "ns3/socket-factory.h"
+#include "ns3/udp.h"
+#include "ns3/simulator.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/drop-tail-queue.h"
+#include <string>
+
+namespace ns3 {
+
+class UdpSocketTest: public Test
+{
+ Packet m_receivedPacket;
+ Packet m_receivedPacket2;
+
+public:
+ virtual bool RunTests (void);
+ UdpSocketTest ();
+
+ void ReceivePacket (Ptr<Socket> socket, const Packet &packet, const Address &from);
+ void ReceivePacket2 (Ptr<Socket> socket, const Packet &packet, const Address &from);
+};
+
+
+UdpSocketTest::UdpSocketTest ()
+ : Test ("UdpSocket") {}
+
+
+void UdpSocketTest::ReceivePacket (Ptr<Socket> socket, const Packet &packet, const Address &from)
+{
+ m_receivedPacket = packet;
+}
+
+void UdpSocketTest::ReceivePacket2 (Ptr<Socket> socket, const Packet &packet, const Address &from)
+{
+ m_receivedPacket2 = packet;
}
-}//namespace ns3
+bool
+UdpSocketTest::RunTests (void)
+{
+ bool result = true;
+
+ // Create topology
+
+ // Receiver Node
+ Ptr<Node> rxNode = Create<InternetNode> ();
+ Ptr<PointToPointNetDevice> rxDev = Create<PointToPointNetDevice> (rxNode);
+ rxDev->AddQueue(Create<DropTailQueue> ());
+ Ptr<Ipv4> ipv4 = rxNode->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t netdev_idx = ipv4->AddInterface (rxDev);
+ ipv4->SetAddress (netdev_idx, Ipv4Address ("10.0.0.1"));
+ ipv4->SetNetworkMask (netdev_idx, Ipv4Mask (0xffff0000U));
+ ipv4->SetUp (netdev_idx);
+
+ // Sender Node
+ Ptr<Node> txNode = Create<InternetNode> ();
+ Ptr<PointToPointNetDevice> txDev = Create<PointToPointNetDevice> (txNode);
+ txDev->AddQueue(Create<DropTailQueue> ());
+ ipv4 = txNode->QueryInterface<Ipv4> (Ipv4::iid);
+ netdev_idx = ipv4->AddInterface (txDev);
+ ipv4->SetAddress (netdev_idx, Ipv4Address ("10.0.0.2"));
+ ipv4->SetNetworkMask (netdev_idx, Ipv4Mask (0xffff0000U));
+ ipv4->SetUp (netdev_idx);
+
+ // link the two nodes
+ Ptr<PointToPointChannel> channel = Create<PointToPointChannel> ();
+ rxDev->Attach (channel);
+ txDev->Attach (channel);
+
+
+ // Create the UDP sockets
+ Ptr<SocketFactory> rxSocketFactory = rxNode->QueryInterface<SocketFactory> (Udp::iid);
+ Ptr<Socket> rxSocket = rxSocketFactory->CreateSocket ();
+ NS_TEST_ASSERT_EQUAL (rxSocket->Bind (InetSocketAddress (Ipv4Address ("10.0.0.2"), 1234)), 0);
+ rxSocket->SetRecvCallback (MakeCallback (&UdpSocketTest::ReceivePacket, this));
+
+ Ptr<SocketFactory> txSocketFactory = txNode->QueryInterface<SocketFactory> (Udp::iid);
+ Ptr<Socket> txSocket = txSocketFactory->CreateSocket ();
+
+ // ------ Now the tests ------------
+
+ // Unicast test
+ m_receivedPacket = Packet ();
+ NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("10.0.0.1"), 1234),
+ Packet (123)), 0);
+ Simulator::Run ();
+ NS_TEST_ASSERT_EQUAL (m_receivedPacket.GetSize (), 123);
+
+
+ // Simple broadcast test
+
+ m_receivedPacket = Packet ();
+ NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("255.255.255.255"), 1234),
+ Packet (123)), 0);
+ Simulator::Run ();
+ NS_TEST_ASSERT_EQUAL (m_receivedPacket.GetSize (), 123);
+
+ // Broadcast test with multiple receiving sockets
+
+ // When receiving broadcast packets, all sockets sockets bound to
+ // the address/port should receive a copy of the same packet.
+ Ptr<Socket> rxSocket2 = rxSocketFactory->CreateSocket ();
+ rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketTest::ReceivePacket2, this));
+ NS_TEST_ASSERT_EQUAL (rxSocket2->Bind (InetSocketAddress (Ipv4Address ("0.0.0.0"), 1234)), 0);
+
+ m_receivedPacket = Packet ();
+ m_receivedPacket2 = Packet ();
+ NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("255.255.255.255"), 1234),
+ Packet (123)), 0);
+ Simulator::Run ();
+ NS_TEST_ASSERT_EQUAL (m_receivedPacket.GetSize (), 123);
+ NS_TEST_ASSERT_EQUAL (m_receivedPacket2.GetSize (), 123);
+
+ return result;
+}
+
+
+static UdpSocketTest gUdpSocketTest;
+
+}; // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- a/src/internet-node/udp-socket.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-socket.h Fri Sep 28 11:59:46 2007 +0100
@@ -25,6 +25,7 @@
#include "ns3/callback.h"
#include "ns3/socket.h"
#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
namespace ns3 {
@@ -45,49 +46,33 @@
virtual enum SocketErrno GetErrno (void) const;
virtual Ptr<Node> GetNode (void) const;
virtual int Bind (void);
- virtual int Bind (Ipv4Address address);
- virtual int Bind (uint16_t port);
- virtual int Bind (Ipv4Address address, uint16_t port);
+ virtual int Bind (const Address &address);
+ virtual int Close (void);
virtual int ShutdownSend (void);
virtual int ShutdownRecv (void);
+ virtual int Connect(const Address &address);
+ virtual int Send (const Packet &p);
+ virtual int SendTo(const Address &address,const Packet &p);
private:
- virtual void DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted);
- virtual void DoConnect(const Ipv4Address & address,
- uint16_t portNumber,
- ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
- ns3::Callback<void, Ptr<Socket> > connectionFailed,
- ns3::Callback<void, Ptr<Socket> > halfClose);
- virtual int DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- ns3::Callback<void, Ptr<Socket> > closeRequested);
- virtual int DoSend (const uint8_t* buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
- virtual int DoSendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
- virtual void DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t>);
- virtual void DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>);
private:
friend class Udp;
// invoked by Udp class
int FinishBind (void);
- void ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport);
+ void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port);
void Destroy (void);
- int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
+ int DoSend (const Packet &p);
+ int DoSendTo (const Packet &p, const Address &daddr);
+ int DoSendTo (const Packet &p, Ipv4Address daddr, uint16_t dport);
Ipv4EndPoint *m_endPoint;
Ptr<Node> m_node;
Ptr<UdpL4Protocol> m_udp;
Ipv4Address m_defaultAddress;
uint16_t m_defaultPort;
- Callback<void,Ptr<Socket>,uint32_t,const Ipv4Address &,uint16_t> m_dummyRxCallback;
- Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Ipv4Address &,uint16_t> m_rxCallback;
+ Callback<void,Ptr<Socket>,uint32_t,const Address &> m_dummyRxCallback;
+ Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Address &> m_rxCallback;
enum SocketErrno m_errno;
bool m_shutdownSend;
bool m_shutdownRecv;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/internet-node/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -1,19 +1,10 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-def configure(conf):
- conf.env.append_value('NS3_MODULES', 'ns3-internet-node')
-
-
def build(bld):
- obj = bld.create_obj('cpp', 'shlib')
- obj.name = 'ns3-internet-node'
- obj.target = obj.name
- obj.uselib_local = ['ns3-node', 'ns3-applications']
+ obj = bld.create_ns3_module('internet-node', ['node'])
obj.source = [
'internet-node.cc',
- 'l3-demux.cc',
- 'l3-protocol.cc',
'ipv4-l4-demux.cc',
'ipv4-l4-protocol.cc',
'ipv4-header.cc',
@@ -21,6 +12,7 @@
'ipv4-checksum.cc',
'ipv4-interface.cc',
'ipv4-l3-protocol.cc',
+ 'ipv4-static-routing.cc',
'ipv4-end-point.cc',
'udp-l4-protocol.cc',
'arp-header.cc',
@@ -28,12 +20,9 @@
'arp-ipv4-interface.cc',
'arp-l3-protocol.cc',
'ipv4-loopback-interface.cc',
- 'header-utils.cc',
'udp-socket.cc',
'ipv4-end-point-demux.cc',
- 'arp-private.cc',
'ipv4-impl.cc',
- 'ipv4-private.cc',
'ascii-trace.cc',
'pcap-trace.cc',
'udp-impl.cc',
@@ -44,4 +33,6 @@
'internet-node.h',
'ascii-trace.h',
'pcap-trace.h',
+ 'ipv4-header.h',
+ 'udp-header.h',
]
--- a/src/mobility/grid-topology.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/grid-topology.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -44,7 +43,10 @@
double x, y;
x = m_xMin + m_deltaX * (i % m_n);
y = m_yMin + m_deltaY * (i / m_n);
- object->AddInterface (ComponentManager::Create (m_positionClassId, x, y));
+ Ptr<MobilityModel> mobility = ComponentManager::Create<MobilityModel> (m_positionClassId,
+ MobilityModel::iid);
+ object->AddInterface (mobility);
+ mobility->Set (Position (x, y, 0.0));
}
void
@@ -53,7 +55,10 @@
double x, y;
x = m_xMin + m_deltaX * (i / m_n);
y = m_yMin + m_deltaY * (i % m_n);
- object->AddInterface (ComponentManager::Create (m_positionClassId, x, y));
+ Ptr<MobilityModel> mobility = ComponentManager::Create<MobilityModel> (m_positionClassId,
+ MobilityModel::iid);
+ object->AddInterface (mobility);
+ mobility->Set (Position (x, y, 0.0));
}
--- a/src/mobility/grid-topology.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/grid-topology.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/hierarchical-mobility-model.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/hierarchical-mobility-model.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -41,8 +40,8 @@
parentNotifier = Create<MobilityModelNotifier> ();
parent->AddInterface (parentNotifier);
}
- childNotifier->RegisterListener (MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
- parentNotifier->RegisterListener (MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
+ childNotifier->TraceConnect ("/course-changed", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
+ parentNotifier->TraceConnect ("/course-changed", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
}
Ptr<MobilityModel>
@@ -89,13 +88,13 @@
}
void
-HierarchicalMobilityModel::ParentChanged (Ptr<const MobilityModel> model)
+HierarchicalMobilityModel::ParentChanged (const TraceContext &context, Ptr<const MobilityModel> model)
{
MobilityModel::NotifyCourseChange ();
}
void
-HierarchicalMobilityModel::ChildChanged (Ptr<const MobilityModel> model)
+HierarchicalMobilityModel::ChildChanged (const TraceContext &context, Ptr<const MobilityModel> model)
{
MobilityModel::NotifyCourseChange ();
}
--- a/src/mobility/hierarchical-mobility-model.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/hierarchical-mobility-model.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -63,8 +62,8 @@
virtual void DoSet (const Position &position);
virtual Speed DoGetSpeed (void) const;
- void ParentChanged (Ptr<const MobilityModel> model);
- void ChildChanged (Ptr<const MobilityModel> model);
+ void ParentChanged (const TraceContext &context, Ptr<const MobilityModel> model);
+ void ChildChanged (const TraceContext &context, Ptr<const MobilityModel> model);
Ptr<MobilityModel> m_child;
Ptr<MobilityModel> m_parent;
--- a/src/mobility/mobility-model-notifier.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model-notifier.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,6 +18,8 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "mobility-model-notifier.h"
+#include "ns3/composite-trace-resolver.h"
+#include "ns3/trace-doc.h"
namespace ns3 {
@@ -33,36 +34,23 @@
}
void
-MobilityModelNotifier::RegisterListener (Listener listener)
-{
- m_listeners.push_back (listener);
-}
-void
-MobilityModelNotifier::UnregisterListener (Listener callback)
-{
- for (std::list<Listener>::iterator i = m_listeners.begin ();
- i != m_listeners.end ();)
- {
- Listener listener = *i;
- if (listener.IsEqual (callback))
- {
- i = m_listeners.erase (i);
- }
- else
- {
- i++;
- }
- }
-}
-void
MobilityModelNotifier::Notify (Ptr<const MobilityModel> position) const
{
- for (std::list<Listener>::const_iterator i = m_listeners.begin ();
- i != m_listeners.end (); i++)
- {
- Listener listener = *i;
- listener (position);
- }
+ m_trace (position);
+}
+
+Ptr<TraceResolver>
+MobilityModelNotifier::GetTraceResolver (void) const
+{
+ Ptr<CompositeTraceResolver> resolver =
+ Create<CompositeTraceResolver> ();
+ resolver->AddSource ("course-change",
+ TraceDoc ("The value of the speed vector changed",
+ "Ptr<const MobilityModel>",
+ "the mobility model whose course changed"),
+ m_trace);
+ resolver->SetParentResolver (Object::GetTraceResolver ());
+ return resolver;
}
} // namespace ns3
--- a/src/mobility/mobility-model-notifier.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model-notifier.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +23,7 @@
#include "ns3/object.h"
#include "ns3/component-manager.h"
#include "ns3/callback.h"
+#include "ns3/callback-trace-source.h"
#include "mobility-model.h"
namespace ns3 {
@@ -37,8 +37,6 @@
static const InterfaceId iid;
static const ClassId cid;
- typedef Callback<void,Ptr<const MobilityModel> > Listener;
-
/**
* Create a new position notifier
*/
@@ -48,23 +46,10 @@
* \param position the position which just changed.
*/
void Notify (Ptr<const MobilityModel> position) const;
-
- /**
- * \param listener listener to add
- *
- * The listener will be notified upon every position change.
- */
- void RegisterListener (Listener listener);
- /**
- * \param listener listener to remove
- *
- * The listener will not be notified anymore upon every
- * position change. It is not an error to try to unregister
- * a non-registered liste
- */
- void UnregisterListener (Listener listener);
+protected:
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
- std::list<Listener> m_listeners;
+ CallbackTraceSource<Ptr<const MobilityModel> > m_trace;
};
} // namespace ns3
--- a/src/mobility/mobility-model.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006,2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -52,9 +51,9 @@
}
double
-MobilityModel::GetDistanceFrom (const MobilityModel &other) const
+MobilityModel::GetDistanceFrom (Ptr<const MobilityModel> other) const
{
- Position oPosition = other.DoGet ();
+ Position oPosition = other->DoGet ();
Position position = DoGet ();
return CalculateDistance (position, oPosition);
}
--- a/src/mobility/mobility-model.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006,2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -57,7 +56,7 @@
* \param position a reference to another mobility model
* \returns the distance between the two objects. Unit is meters.
*/
- double GetDistanceFrom (const MobilityModel &position) const;
+ double GetDistanceFrom (Ptr<const MobilityModel> position) const;
protected:
/**
* Must be invoked by subclasses when the course of the
--- a/src/mobility/position.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/position.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "position.h"
#include <cmath>
--- a/src/mobility/position.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/position.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef POSITION_H
#define POSITION_H
--- a/src/mobility/random-position.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/random-position.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,11 +1,30 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "random-position.h"
#include "ns3/random-variable.h"
#include "ns3/default-value.h"
#include "ns3/random-variable-default-value.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include <cmath>
-NS_DEBUG_COMPONENT_DEFINE ("RandomPosition");
+NS_LOG_COMPONENT_DEFINE ("RandomPosition");
namespace ns3 {
@@ -22,19 +41,19 @@
static RandomVariableDefaultValue
g_discTheta ("RandomDiscPositionTheta",
"A random variable which represents the angle (gradients) of a position in a random disc.",
- "Uniform:0:3.1415");
+ "Uniform:0:6.2830");
static RandomVariableDefaultValue
g_discRho ("RandomDiscPositionRho",
"A random variable which represents the radius of a position in a random disc.",
"Uniform:0:200");
-static IntegerDefaultValue<double>
+static NumericDefaultValue<double>
g_discX ("RandomDiscPositionX",
"The x coordinate of the center of the random position disc.",
0.0);
-static IntegerDefaultValue<double>
+static NumericDefaultValue<double>
g_discY ("RandomDiscPositionY",
"The y coordinate of the center of the random position disc.",
0.0);
@@ -108,7 +127,7 @@
double rho = m_rho->GetValue ();
double x = m_x + std::cos (theta) * rho;
double y = m_y + std::sin (theta) * rho;
- NS_DEBUG ("Disc position x=" << x << ", y=" << y);
+ NS_LOG_DEBUG ("Disc position x=" << x << ", y=" << y);
return Position (x, y, 0.0);
}
--- a/src/mobility/random-position.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/random-position.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef RANDOM_POSITION_H
#define RANDOM_POSITION_H
--- a/src/mobility/random-topology.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/random-topology.cc Fri Sep 28 11:59:46 2007 +0100
@@ -69,9 +69,9 @@
{
Ptr<MobilityModel> mobility = ComponentManager::Create<MobilityModel> (m_mobilityModel,
MobilityModel::iid);
+ object->AddInterface (mobility);
Position position = m_positionModel->Get ();
mobility->Set (position);
- object->AddInterface (mobility);
}
--- a/src/mobility/rectangle-default-value.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle-default-value.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/rectangle-default-value.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle-default-value.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/rectangle.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/rectangle.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/speed.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/speed.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "speed.h"
namespace ns3 {
--- a/src/mobility/speed.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/speed.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef SPEED_H
#define SPEED_H
--- a/src/mobility/static-mobility-model.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-mobility-model.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2006,2007 INRIA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/static-mobility-model.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-mobility-model.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006,2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/static-speed-helper.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-helper.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "ns3/simulator.h"
#include "ns3/rectangle.h"
#include "static-speed-helper.h"
--- a/src/mobility/static-speed-helper.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-helper.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef STATIC_SPEED_HELPER_H
#define STATIC_SPEED_HELPER_H
--- a/src/mobility/static-speed-mobility-model.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-mobility-model.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006, 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- a/src/mobility/static-speed-mobility-model.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-mobility-model.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006, 2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,38 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ mobility = bld.create_ns3_module('mobility', ['core', 'simulator'])
+ mobility.source = [
+ 'grid-topology.cc',
+ 'hierarchical-mobility-model.cc',
+ 'mobility-model.cc',
+ 'mobility-model-notifier.cc',
+ 'position.cc',
+ 'random-position.cc',
+ 'random-topology.cc',
+ 'rectangle.cc',
+ 'rectangle-default-value.cc',
+ 'speed.cc',
+ 'static-mobility-model.cc',
+ 'static-speed-helper.cc',
+ 'static-speed-mobility-model.cc',
+ 'random-waypoint-mobility-model.cc',
+ ]
+
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'grid-topology.h',
+ 'hierarchical-mobility-model.h',
+ 'mobility-model.h',
+ 'mobility-model-notifier.h',
+ 'position.h',
+ 'random-position.h',
+ 'random-topology.h',
+ 'rectangle.h',
+ 'rectangle-default-value.h',
+ 'speed.h',
+ 'static-mobility-model.h',
+ 'static-speed-helper.h',
+ 'static-speed-mobility-model.h',
+ 'random-waypoint-mobility-model.h',
+ ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address-utils.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "address-utils.h"
+
+namespace ns3 {
+
+void WriteTo (Buffer::Iterator &i, Ipv4Address ad)
+{
+ i.WriteHtonU32 (ad.GetHostOrder ());
+}
+void WriteTo (Buffer::Iterator &i, const Address &ad)
+{
+ uint8_t mac[Address::MAX_SIZE];
+ ad.CopyTo (mac);
+ i.Write (mac, ad.GetLength ());
+}
+void WriteTo (Buffer::Iterator &i, Mac48Address ad)
+{
+ uint8_t mac[6];
+ ad.CopyTo (mac);
+ i.Write (mac, 6);
+}
+
+void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad)
+{
+ ad.SetHostOrder (i.ReadNtohU32 ());
+}
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len)
+{
+ uint8_t mac[Address::MAX_SIZE];
+ i.Read (mac, len);
+ ad.CopyFrom (mac, len);
+}
+void ReadFrom (Buffer::Iterator &i, Mac48Address &ad)
+{
+ uint8_t mac[6];
+ i.Read (mac, 6);
+ ad.CopyFrom (mac);
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address-utils.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef ADDRESS_UTILS_H
+#define ADDRESS_UTILS_H
+
+#include "ns3/buffer.h"
+#include "ipv4-address.h"
+#include "address.h"
+#include "mac48-address.h"
+
+namespace ns3 {
+
+void WriteTo (Buffer::Iterator &i, Ipv4Address ad);
+void WriteTo (Buffer::Iterator &i, const Address &ad);
+void WriteTo (Buffer::Iterator &i, Mac48Address ad);
+
+void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad);
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len);
+void ReadFrom (Buffer::Iterator &i, Mac48Address &ad);
+
+};
+
+#endif /* ADDRESS_UTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,164 @@
+#include "ns3/assert.h"
+#include "address.h"
+#include <iostream>
+#include <iomanip>
+
+namespace ns3 {
+
+Address::Address ()
+ : m_type (0),
+ m_len (0)
+{
+ memset (m_data, 0, m_len);
+}
+
+Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len)
+ : m_type (type),
+ m_len (len)
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memset (m_data, 0, m_len);
+ memcpy (m_data, buffer, m_len);
+}
+Address::Address (const Address & address)
+ : m_type (address.m_type),
+ m_len (address.m_len)
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memset (m_data, 0, m_len);
+ memcpy (m_data, address.m_data, m_len);
+}
+Address &
+Address::operator = (const Address &address)
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ m_type = address.m_type;
+ m_len = address.m_len;
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memset (m_data, 0, m_len);
+ memcpy (m_data, address.m_data, m_len);
+ return *this;
+}
+
+bool
+Address::IsInvalid (void) const
+{
+ return m_len == 0 && m_type == 0;
+}
+
+uint8_t
+Address::GetLength (void) const
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ return m_len;
+}
+uint32_t
+Address::CopyTo (uint8_t buffer[MAX_SIZE]) const
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memcpy (buffer, m_data, m_len);
+ return m_len;
+}
+uint32_t
+Address::CopyAllTo (uint8_t *buffer, uint8_t len) const
+{
+ NS_ASSERT (len >= m_len + 2);
+ buffer[0] = m_type;
+ buffer[1] = m_len;
+ memcpy (buffer + 2, m_data, m_len);
+ return m_len + 2;
+}
+
+uint32_t
+Address::CopyFrom (const uint8_t *buffer, uint8_t len)
+{
+ NS_ASSERT (len <= MAX_SIZE);
+ memcpy (m_data, buffer, len);
+ m_len = len;
+ return m_len;
+}
+uint32_t
+Address::CopyAllFrom (const uint8_t *buffer, uint8_t len)
+{
+ NS_ASSERT (len >= 2);
+ m_type = buffer[0];
+ m_len = buffer[1];
+ NS_ASSERT (len >= m_len + 2);
+ memcpy (m_data, buffer + 2, m_len);
+ return m_len + 2;
+}
+bool
+Address::CheckCompatible (uint8_t type, uint8_t len) const
+{
+ NS_ASSERT (len <= MAX_SIZE);
+ return m_len == len && (m_type == type || m_type == 0);
+}
+bool
+Address::IsMatchingType (uint8_t type) const
+{
+ return m_type == type;
+}
+
+uint8_t
+Address::Register (void)
+{
+ static uint8_t type = 1;
+ type++;
+ return type;
+}
+
+bool operator == (const Address &a, const Address &b)
+{
+ NS_ASSERT (a.m_type == b.m_type ||
+ a.m_type == 0 ||
+ b.m_type == 0);
+ NS_ASSERT (a.GetLength() == b.GetLength());
+ return memcmp (a.m_data, b.m_data, a.m_len) == 0;
+}
+bool operator != (const Address &a, const Address &b)
+{
+ return !(a == b);
+}
+bool operator < (const Address &a, const Address &b)
+{
+ NS_ASSERT (a.m_type == b.m_type ||
+ a.m_type == 0 ||
+ b.m_type == 0);
+ NS_ASSERT (a.GetLength() == b.GetLength());
+ for (uint8_t i = 0; i < a.GetLength(); i++)
+ {
+ if (a.m_data[i] < b.m_data[i])
+ {
+ return true;
+ }
+ else if (a.m_data[i] > b.m_data[i])
+ {
+ return false;
+ }
+ }
+ return false;
+}
+
+std::ostream& operator<< (std::ostream& os, const Address & address)
+{
+ if (address.m_len == 0)
+ {
+ os << "NULL-ADDRESS";
+ return os;
+ }
+ os.setf (std::ios::hex, std::ios::basefield);
+ os.fill('0');
+ for (uint8_t i=0; i < (address.m_len-1); i++)
+ {
+ os << std::setw(2) << (uint32_t)address.m_data[i] << ":";
+ }
+ // Final byte not suffixed by ":"
+ os << std::setw(2) << (uint32_t)address.m_data[address.m_len-1];
+ os.setf (std::ios::dec, std::ios::basefield);
+ os.fill(' ');
+ return os;
+}
+
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,172 @@
+#ifndef ADDRESS_H
+#define ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+/**
+ * \brief a polymophic address class
+ *
+ * This class is very similar in design and spirit to the BSD sockaddr
+ * structure: they are both used to hold multiple types of addresses
+ * together with the type of the address.
+ *
+ * A new address class defined by a user needs to:
+ * - allocate a type id with Address::Register
+ * - provide a method to convert his new address to an Address
+ * instance. This method is typically a member method named ConvertTo:
+ * Address MyAddress::ConvertTo (void) const;
+ * - provide a method to convert an Address instance back to
+ * an instance of his new address type. This method is typically
+ * a static member method of his address class named ConvertFrom:
+ * static MyAddress MyAddress::ConvertFrom (const Address &address);
+ * - the ConvertFrom method is expected to check that the type of the
+ * input Address instance is compatible with its own type.
+ *
+ * Typical code to create a new class type looks like:
+ * \code
+ * // this class represents addresses which are 2 bytes long.
+ * class MyAddress
+ * {
+ * public:
+ * Address ConvertTo (void) const;
+ * static MyAddress ConvertFrom (void);
+ * private:
+ * static uint8_t GetType (void);
+ * };
+ *
+ * Address MyAddress::ConvertTo (void) const
+ * {
+ * return Address (GetType (), m_buffer, 2);
+ * }
+ * MyAddress MyAddress::ConvertFrom (const Address &address)
+ * {
+ * MyAddress ad;
+ * NS_ASSERT (address.CheckCompatible (GetType (), 2));
+ * address.CopyTo (ad.m_buffer, 2);
+ * return ad;
+ * }
+ * uint8_t MyAddress::GetType (void)
+ * {
+ * static uint8_t type = Address::Register ();
+ * return type;
+ * }
+ * \endcode
+ */
+class Address
+{
+public:
+ enum {
+ /**
+ * The maximum size of a byte buffer which
+ * can be stored in an Address instance.
+ */
+ MAX_SIZE = 30
+ };
+
+ /**
+ * Create an invalid address
+ */
+ Address ();
+ /**
+ * \param type the type of the Address to create
+ * \param buffer a pointer to a buffer of bytes which hold
+ * a serialized representation of the address in network
+ * byte order.
+ * \param len the length of the buffer.
+ *
+ * Create an address from a type and a buffer. This constructor
+ * is typically invoked from the conversion functions of various
+ * address types when they have to convert themselves to an
+ * Address instance.
+ */
+ Address (uint8_t type, const uint8_t *buffer, uint8_t len);
+ Address (const Address & address);
+ Address &operator = (const Address &address);
+
+ /**
+ * \returns true if this address is invalid, false otherwise.
+ *
+ * An address is invalid if and only if it was created
+ * through the default constructor and it was never
+ * re-initialized.
+ */
+ bool IsInvalid (void) const;
+ /**
+ * \returns the length of the underlying address.
+ */
+ uint8_t GetLength (void) const;
+ /**
+ * \param buffer buffer to copy the address bytes to.
+ * \returns the number of bytes copied.
+ */
+ uint32_t CopyTo (uint8_t buffer[MAX_SIZE]) const;
+ /**
+ * \param buffer buffer to copy the whole address data structure to
+ * \param len the size of the buffer
+ * \returns the number of bytes copied.
+ */
+ uint32_t CopyAllTo (uint8_t *buffer, uint8_t len) const;
+ /**
+ * \param buffer pointer to a buffer of bytes which contain
+ * a serialized representation of the address in network
+ * byte order.
+ * \param len length of buffer
+ * \returns the number of bytes copied.
+ *
+ * Copy the input buffer to the internal buffer of this address
+ * instance.
+ */
+ uint32_t CopyFrom (const uint8_t *buffer, uint8_t len);
+ /**
+ * \param buffer pointer to a buffer of bytes which contain
+ * a copy of all the members of this Address class.
+ * \param len the length of the buffer
+ * \returns the number of bytes copied.
+ */
+ uint32_t CopyAllFrom (const uint8_t *buffer, uint8_t len);
+ /**
+ * \param type a type id as returned by Address::Register
+ * \param len the length associated to this type id.
+ *
+ * \returns true if the type of the address stored internally
+ * is compatible with the requested type, false otherwise.
+ */
+ bool CheckCompatible (uint8_t type, uint8_t len) const;
+ /**
+ * \param type a type id as returned by Address::Register
+ * \returns true if the type of the address stored internally
+ * is compatible with the requested type, false otherwise.
+ *
+ * This method checks that the types are _exactly_ equal.
+ * This method is really used only by the PacketSocketAddress
+ * and there is little point in using it otherwise so,
+ * you have been warned: DO NOT USE THIS METHOD.
+ */
+ bool IsMatchingType (uint8_t type) const;
+ /**
+ * Allocate a new type id for a new type of address.
+ * \returns a new type id.
+ */
+ static uint8_t Register (void);
+private:
+ friend bool operator == (const Address &a, const Address &b);
+ friend bool operator < (const Address &a, const Address &b);
+ friend std::ostream& operator<< (std::ostream& os, const Address & address);
+
+ uint8_t m_type;
+ uint8_t m_len;
+ uint8_t m_data[MAX_SIZE];
+};
+
+bool operator == (const Address &a, const Address &b);
+bool operator != (const Address &a, const Address &b);
+bool operator < (const Address &a, const Address &b);
+std::ostream& operator<< (std::ostream& os, const Address & address);
+
+} // namespace ns3
+
+
+#endif /* ADDRESS_H */
--- a/src/node/channel.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/channel.cc Fri Sep 28 11:59:46 2007 +0100
@@ -14,16 +14,12 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Craig Dowell <craigdo@ee.washingon.edu>
- *
- * Thu Feb 15 14:50:46 PST 2007 craigdo: Created.
*/
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "channel.h"
-NS_DEBUG_COMPONENT_DEFINE ("Channel");
+NS_LOG_COMPONENT_DEFINE ("Channel");
namespace ns3 {
@@ -32,31 +28,35 @@
Channel::Channel ()
: m_name("Channel")
{
+ NS_LOG_FUNCTION;
SetInterfaceId (Channel::iid);
- NS_DEBUG("Channel::Channel ()");
}
Channel::Channel (std::string name)
: m_name(name)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << name << ")");
SetInterfaceId (Channel::iid);
- NS_DEBUG("Channel::Channel (" << name << ")");
}
Channel::~Channel ()
{
- NS_DEBUG("Channel::~Channel ()");
+ NS_LOG_FUNCTION;
}
void
Channel::SetName(std::string name)
{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << name << ")");
m_name = name;
}
std::string
Channel::GetName(void)
{
+ NS_LOG_FUNCTION;
return m_name;
}
--- a/src/node/channel.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/channel.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,5 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2007 University of Washington
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
@@ -14,11 +12,8 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Craig Dowell <craigdo@ee.washingon.edu>
- *
- * Wed Feb 14 16:05:46 PST 2007 craigdo: Created
*/
+
#ifndef CHANNEL_H
#define CHANNEL_H
@@ -41,6 +36,7 @@
{
public:
static const InterfaceId iid;
+
Channel ();
Channel (std::string name);
@@ -62,8 +58,8 @@
virtual Ptr<NetDevice> GetDevice (uint32_t i) const = 0;
protected:
- virtual ~Channel ();
- std::string m_name;
+ virtual ~Channel ();
+ std::string m_name;
private:
};
--- a/src/node/drop-tail-queue.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/drop-tail-queue.cc Fri Sep 28 11:59:46 2007 +0100
@@ -17,10 +17,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "drop-tail-queue.h"
-NS_DEBUG_COMPONENT_DEFINE ("DropTailQueue");
+NS_LOG_COMPONENT_DEFINE ("DropTailQueue");
namespace ns3 {
@@ -33,38 +33,39 @@
m_packets (),
m_maxPackets(DTQ_NPACKETS_MAX_DEFAULT)
{
- NS_DEBUG("DropTailQueue::DropTailQueue ()");
+ NS_LOG_FUNCTION;
}
DropTailQueue::~DropTailQueue ()
{
- NS_DEBUG("DropTailQueue::~DropTailQueue ()");
+ NS_LOG_FUNCTION;
}
void
DropTailQueue::SetMaxPackets (uint32_t npackets)
{
- NS_DEBUG("DropTailQueue::SetMaxPackets (" << npackets << ")");
-
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << npackets << ")");
m_maxPackets = npackets;
}
uint32_t
DropTailQueue::GetMaxPackets (void)
{
- NS_DEBUG("DropTailQueue::GetMaxPackets () <= " << m_maxPackets);
-
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC ("returns " << m_maxPackets);
return m_maxPackets;
}
bool
DropTailQueue::DoEnqueue (const Packet& p)
{
- NS_DEBUG("DropTailQueue::DoEnqueue (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
if (m_packets.size () >= m_maxPackets)
{
- NS_DEBUG("DropTailQueue::DoEnqueue (): Queue full -- droppping pkt");
+ NS_LOG_LOGIC ("Queue full -- droppping pkt");
Drop (p);
return false;
}
@@ -76,18 +77,19 @@
bool
DropTailQueue::DoDequeue (Packet& p)
{
- NS_DEBUG("DropTailQueue::DoDequeue (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
if (m_packets.empty())
{
- NS_DEBUG("DropTailQueue::DoDequeue (): Queue empty");
+ NS_LOG_LOGIC ("Queue empty");
return false;
}
p = m_packets.front ();
m_packets.pop ();
- NS_DEBUG("DropTailQueue::DoDequeue (): Popped " << &p << " <= true");
+ NS_LOG_LOGIC ("Popped " << &p);
return true;
}
@@ -95,11 +97,12 @@
bool
DropTailQueue::DoPeek (Packet& p)
{
- NS_DEBUG("DropTailQueue::DoPeek (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
if (m_packets.empty())
{
- NS_DEBUG("DropTailQueue::DoPeek (): Queue empty");
+ NS_LOG_LOGIC ("Queue empty");
return false;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-header.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include <iomanip>
+#include <iostream>
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/header.h"
+#include "ethernet-header.h"
+#include "address-utils.h"
+
+NS_LOG_COMPONENT_DEFINE ("EthernetHeader");
+
+namespace ns3 {
+
+NS_HEADER_ENSURE_REGISTERED (EthernetHeader);
+
+uint32_t
+EthernetHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<EthernetHeader> ("EthernetHeader.ns3");
+ return uid;
+}
+
+EthernetHeader::EthernetHeader (bool hasPreamble)
+ : m_enPreambleSfd (hasPreamble),
+ m_lengthType (0)
+{}
+
+EthernetHeader::EthernetHeader ()
+ : m_enPreambleSfd (false),
+ m_lengthType (0)
+{}
+
+void
+EthernetHeader::SetLengthType (uint16_t lengthType)
+{
+ m_lengthType = lengthType;
+}
+uint16_t
+EthernetHeader::GetLengthType (void) const
+{
+ return m_lengthType;
+}
+
+void
+EthernetHeader::SetPreambleSfd (uint64_t preambleSfd)
+{
+ m_preambleSfd = preambleSfd;
+}
+uint64_t
+EthernetHeader::GetPreambleSfd (void) const
+{
+ return m_preambleSfd;
+}
+
+void
+EthernetHeader::SetSource (Mac48Address source)
+{
+ m_source = source;
+}
+Mac48Address
+EthernetHeader::GetSource (void) const
+{
+ return m_source;
+}
+
+void
+EthernetHeader::SetDestination (Mac48Address dst)
+{
+ m_destination = dst;
+}
+Mac48Address
+EthernetHeader::GetDestination (void) const
+{
+ return m_destination;
+}
+
+ethernet_header_t
+EthernetHeader::GetPacketType (void) const
+{
+ return LENGTH;
+}
+
+uint32_t
+EthernetHeader::GetHeaderSize (void) const
+{
+ return GetSerializedSize();
+}
+
+std::string
+EthernetHeader::GetName (void) const
+{
+ return "ETHERNET";
+}
+
+void
+EthernetHeader::Print (std::ostream &os) const
+{
+ // ethernet, right ?
+ if (m_enPreambleSfd)
+ {
+ os << " preamble/sfd=" << m_preambleSfd << ",";
+ }
+
+ os << " length/type=0x" << std::hex << m_lengthType << std::dec
+ << ", source=" << m_source
+ << ", destination=" << m_destination;
+}
+uint32_t
+EthernetHeader::GetSerializedSize (void) const
+{
+ if (m_enPreambleSfd)
+ {
+ return PREAMBLE_SIZE + LENGTH_SIZE + 2*MAC_ADDR_SIZE;
+ }
+ else
+ {
+ return LENGTH_SIZE + 2*MAC_ADDR_SIZE;
+ }
+}
+
+void
+EthernetHeader::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ if (m_enPreambleSfd)
+ {
+ i.WriteU64(m_preambleSfd);
+ }
+ WriteTo (i, m_destination);
+ WriteTo (i, m_source);
+ i.WriteU16 (m_lengthType);
+}
+uint32_t
+EthernetHeader::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+
+ if (m_enPreambleSfd)
+ {
+ m_enPreambleSfd = i.ReadU64 ();
+ }
+
+ ReadFrom (i, m_destination);
+ ReadFrom (i, m_source);
+ m_lengthType = i.ReadU16 ();
+
+ return GetSerializedSize ();
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-header.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef ETHERNET_HEADER_H
+#define ETHERNET_HEADER_H
+
+#include "ns3/header.h"
+#include <string>
+#include "ns3/mac48-address.h"
+
+namespace ns3 {
+
+ /**
+ * Types of ethernet packets. Indicates the type of the current
+ * header.
+ */
+ enum ethernet_header_t {
+ LENGTH, /**< Basic ethernet packet, no tags, type/length field
+ indicates packet length or IP/ARP packet */
+ VLAN, /**< Single tagged packet. Header includes VLAN tag */
+ QINQ /**< Double tagged packet. Header includes two VLAN tags */
+ };
+/**
+ * \brief Packet header for Ethernet
+ *
+ * This class can be used to add a header to an ethernet packet that
+ * will specify the source and destination addresses and the length of
+ * the packet. Eventually the class will be improved to also support
+ * VLAN tags in packet headers.
+ */
+class EthernetHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
+
+ /**
+ * \brief Construct a null ethernet header
+ * \param hasPreamble if true, insert and remove an ethernet preamble from the
+ * packet, if false, does not insert and remove it.
+ */
+ EthernetHeader (bool hasPreamble);
+ /**
+ * \brief Construct a null ethernet header
+ * By default, does not add or remove an ethernet preamble
+ */
+ EthernetHeader ();
+ /**
+ * \param size The size of the payload in bytes
+ */
+ void SetLengthType (uint16_t size);
+ /**
+ * \param source The source address of this packet
+ */
+ void SetSource (Mac48Address source);
+ /**
+ * \param destination The destination address of this packet.
+ */
+ void SetDestination (Mac48Address destination);
+ /**
+ * \param preambleSfd The value that the preambleSfd field should take
+ */
+ void SetPreambleSfd (uint64_t preambleSfd);
+ /**
+ * \return The size of the payload in bytes
+ */
+ uint16_t GetLengthType (void) const;
+ /**
+ * \return The type of packet (only basic Ethernet is currently supported)
+ */
+ ethernet_header_t GetPacketType (void) const;
+ /**
+ * \return The source address of this packet
+ */
+ Mac48Address GetSource (void) const;
+ /**
+ * \return The destination address of this packet
+ */
+ Mac48Address GetDestination (void) const;
+ /**
+ * \return The value of the PreambleSfd field
+ */
+ uint64_t GetPreambleSfd () const;
+ /**
+ * \return The size of the header
+ */
+ uint32_t GetHeaderSize() const;
+
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
+private:
+ static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field
+ static const int LENGTH_SIZE = 2; /// size of the length_type header field
+ static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields
+
+ /**
+ * If false, the preamble/sfd are not serialised/deserialised.
+ */
+ bool m_enPreambleSfd;
+ uint64_t m_preambleSfd; /// Value of the Preamble/SFD fields
+ uint16_t m_lengthType; /// Length or type of the packet
+ Mac48Address m_source; /// Source address
+ Mac48Address m_destination; /// Destination address
+};
+
+}; // namespace ns3
+
+
+#endif /* ETHERNET_HEADER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-trailer.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/trailer.h"
+#include "ethernet-trailer.h"
+
+NS_LOG_COMPONENT_DEFINE ("EthernetTrailer");
+
+namespace ns3 {
+
+NS_TRAILER_ENSURE_REGISTERED (EthernetTrailer);
+
+bool EthernetTrailer::m_calcFcs = false;
+
+uint32_t
+EthernetTrailer::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<EthernetTrailer> ("EthernetTrailer.ns3");
+ return uid;
+}
+
+EthernetTrailer::EthernetTrailer ()
+{
+ Init();
+}
+
+void EthernetTrailer::Init()
+{
+ m_fcs = 0;
+}
+
+void
+EthernetTrailer::EnableFcs (bool enable)
+{
+ m_calcFcs = enable;
+}
+
+bool
+EthernetTrailer::CheckFcs (const Packet& p) const
+{
+ if (!m_calcFcs)
+ {
+ return true;
+ } else {
+ NS_LOG_WARN ("FCS calculation is not yet enabled");
+ return false;
+ }
+}
+
+void
+EthernetTrailer::CalcFcs (const Packet& p)
+{
+ NS_LOG_WARN ("FCS calculation is not yet enabled");
+}
+
+void
+EthernetTrailer::SetFcs (uint32_t fcs)
+{
+ m_fcs = fcs;
+}
+
+uint32_t
+EthernetTrailer::GetFcs (void)
+{
+ return m_fcs;
+}
+
+uint32_t
+EthernetTrailer::GetTrailerSize (void) const
+{
+ return GetSerializedSize();
+}
+std::string
+EthernetTrailer::GetName (void) const
+{
+ return "ETHERNET";
+}
+
+void
+EthernetTrailer::Print (std::ostream &os) const
+{
+ os << " fcs=" << m_fcs;
+}
+uint32_t
+EthernetTrailer::GetSerializedSize (void) const
+{
+ return 4;
+}
+
+void
+EthernetTrailer::Serialize (Buffer::Iterator end) const
+{
+ Buffer::Iterator i = end;
+ i.Prev(GetSerializedSize());
+
+ i.WriteU32 (m_fcs);
+}
+uint32_t
+EthernetTrailer::Deserialize (Buffer::Iterator end)
+{
+ Buffer::Iterator i = end;
+ uint32_t size = GetSerializedSize();
+ i.Prev(size);
+
+ m_fcs = i.ReadU32 ();
+
+ return size;
+}
+
+}; // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-trailer.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef ETHERNET_TRAILER_H
+#define ETHERNET_TRAILER_H
+
+#include "ns3/trailer.h"
+#include "ns3/packet.h"
+#include <string>
+
+namespace ns3 {
+/**
+ * \brief Packet trailer for Ethernet
+ *
+ * This class can be used to add and verify the FCS at the end of an
+ * ethernet packet. The actual FCS functionality is not yet coded and
+ * so this acts more as a placeholder.
+ */
+class EthernetTrailer : public Trailer
+{
+public:
+ static uint32_t GetUid (void);
+
+ /**
+ * \brief Construct a null ethernet trailer
+ */
+ EthernetTrailer ();
+
+ /**
+ * \brief Enable or disabled FCS checking and calculations
+ * \param enable If true, enables FCS calculations.
+ */
+ static void EnableFcs (bool enable);
+ /**
+ * \brief Updates the Fcs Field to the correct FCS
+ * \param p Reference to a packet on which the FCS should be
+ * calculated. The packet should not currently contain an FCS
+ * trailer.
+ */
+ void CalcFcs (const Packet& p);
+ /**
+ * \brief Sets the FCS to a new value
+ * \param fcs New FCS value
+ */
+ void SetFcs (uint32_t fcs);
+ /**
+ * \return the FCS contained in this trailer
+ */
+ uint32_t GetFcs ();
+
+ /**
+ * \param p Reference to the packet on which the FCS should be
+ * calculated. The packet should not contain an FCS trailer.
+ * \return Returns true if the packet fcs is correct, false otherwise.
+ *
+ * If FCS checking is disabled, this method will always
+ * return true.
+ */
+ bool CheckFcs (const Packet& p) const;
+
+ /**
+ *\return Returns the size of the trailer
+ */
+ uint32_t GetTrailerSize() const;
+
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator end) const;
+ uint32_t Deserialize (Buffer::Iterator end);
+private:
+
+ /**
+ * Initializes the trailer parameters during construction.
+ */
+ void Init (void);
+
+ /**
+ * Enabled FCS calculations. If false, fcs is set to 0 and checkFCS
+ * returns true.
+ */
+ static bool m_calcFcs;
+ uint32_t m_fcs; /// Value of the fcs contained in the trailer
+
+};
+
+} // namespace ns3
+
+
+#endif /* ETHERNET_TRAILER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "inet-socket-address.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4, uint16_t port)
+ : m_ipv4 (ipv4),
+ m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4)
+ : m_ipv4 (ipv4),
+ m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (const char *ipv4, uint16_t port)
+ : m_ipv4 (Ipv4Address (ipv4)),
+ m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (const char * ipv4)
+ : m_ipv4 (Ipv4Address (ipv4)),
+ m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (uint16_t port)
+ : m_ipv4 (Ipv4Address::GetAny ()),
+ m_port (port)
+{}
+uint16_t
+InetSocketAddress::GetPort (void) const
+{
+ return m_port;
+}
+Ipv4Address
+InetSocketAddress::GetIpv4 (void) const
+{
+ return m_ipv4;
+}
+
+void
+InetSocketAddress::SetPort (uint16_t port)
+{
+ m_port = port;
+}
+void
+InetSocketAddress::SetIpv4 (Ipv4Address address)
+{
+ m_ipv4 = address;
+}
+
+bool
+InetSocketAddress::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 6);
+}
+
+InetSocketAddress::operator Address () const
+{
+ return ConvertTo ();
+}
+
+Address
+InetSocketAddress::ConvertTo (void) const
+{
+ uint8_t buf[6];
+ m_ipv4.Serialize (buf);
+ buf[4] = m_port & 0xff;
+ buf[5] = (m_port >> 8) & 0xff;
+ return Address (GetType (), buf, 6);
+}
+InetSocketAddress
+InetSocketAddress::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 6));
+ uint8_t buf[6];
+ address.CopyTo (buf);
+ Ipv4Address ipv4 = Ipv4Address::Deserialize (buf);
+ uint16_t port = buf[4] | (buf[5] << 8);
+ return InetSocketAddress (ipv4, port);
+}
+uint8_t
+InetSocketAddress::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef INET_SOCKET_ADDRESS_H
+#define INET_SOCKET_ADDRESS_H
+
+#include "address.h"
+#include "ipv4-address.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+
+/**
+ * \brief an Inet address class
+ *
+ * This class is similar to inet_sockaddr in the BSD socket
+ * API. i.e., this class holds an Ipv4Address and a port number
+ * to form an ipv4 transport endpoint.
+ */
+class InetSocketAddress
+{
+public:
+ /**
+ * \param ipv4 the ipv4 address
+ * \param port the port number
+ */
+ InetSocketAddress (Ipv4Address ipv4, uint16_t port);
+ /**
+ * \param ipv4 the ipv4 address
+ *
+ * The port number is set to zero by default.
+ */
+ InetSocketAddress (Ipv4Address ipv4);
+ /**
+ * \param port the port number
+ *
+ * The ipv4 address is set to the "Any" address by default.
+ */
+ InetSocketAddress (uint16_t port);
+ /**
+ * \param ipv4 string which represents an ipv4 address
+ * \param port the port number
+ */
+ InetSocketAddress (const char *ipv4, uint16_t port);
+ /**
+ * \param ipv4 string which represents an ipv4 address
+ *
+ * The port number is set to zero.
+ */
+ InetSocketAddress (const char *ipv4);
+ /**
+ * \returns the port number
+ */
+ uint16_t GetPort (void) const;
+ /**
+ * \returns the ipv4 address
+ */
+ Ipv4Address GetIpv4 (void) const;
+
+ /**
+ * \param port the new port number.
+ */
+ void SetPort (uint16_t port);
+ /**
+ * \param address the new ipv4 address
+ */
+ void SetIpv4 (Ipv4Address address);
+
+ /**
+ * \returns true if the address matches, false otherwise.
+ */
+ static bool IsMatchingType (const Address &address);
+
+ /**
+ * \returns an Address instance which represents this
+ * InetSocketAddress instance.
+ */
+ operator Address () const;
+
+ /**
+ * \param address the Address instance to convert from.
+ *
+ * Returns an InetSocketAddress which corresponds to the input
+ * Address
+ */
+ static InetSocketAddress ConvertFrom (const Address &address);
+private:
+ Address ConvertTo (void) const;
+
+ static uint8_t GetType (void);
+ Ipv4Address m_ipv4;
+ uint16_t m_port;
+};
+
+} // namespace ns3
+
+
+#endif /* INET_SOCKET_ADDRESS_H */
--- a/src/node/ipv4-address.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-address.cc Fri Sep 28 11:59:46 2007 +0100
@@ -18,12 +18,12 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
-#include "ns3/debug.h"
-NS_DEBUG_COMPONENT_DEFINE("Ipv4Address");
+#include "ns3/log.h"
+#include "ipv4-address.h"
+#include "ns3/assert.h"
-#include "ipv4-address.h"
-
+NS_LOG_COMPONENT_DEFINE("Ipv4Address");
namespace ns3 {
@@ -99,6 +99,11 @@
{
m_mask = value;
}
+uint32_t
+Ipv4Mask::GetInverse (void) const
+{
+ return ~m_mask;
+}
void
Ipv4Mask::Print (std::ostream &os) const
@@ -135,6 +140,17 @@
m_address = AsciiToIpv4Host (address);
}
+void
+Ipv4Address::Set (uint32_t address)
+{
+ m_address = address;
+}
+void
+Ipv4Address::Set (char const *address)
+{
+ m_address = AsciiToIpv4Host (address);
+}
+
bool
Ipv4Address::IsEqual (Ipv4Address other) const
{
@@ -145,11 +161,38 @@
}
}
-bool
-Ipv4Address::IsMulticast (void)
+Ipv4Address
+Ipv4Address::CombineMask (Ipv4Mask const &mask) const
+{
+ return Ipv4Address (GetHostOrder () & mask.GetHostOrder ());
+}
+
+Ipv4Address
+Ipv4Address::GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const
+{
+ return Ipv4Address (GetHostOrder () | mask.GetInverse ());
+}
+
+bool
+Ipv4Address::IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const
{
- // XXX
- return false;
+ return ( (GetHostOrder () | mask.GetInverse ()) == GetHostOrder () );
+}
+
+bool
+Ipv4Address::IsBroadcast (void) const
+{
+ return (m_address == 0xffffffffU);
+}
+
+bool
+Ipv4Address::IsMulticast (void) const
+{
+//
+// Multicast addresses are defined as ranging from 224.0.0.0 through
+// 239.255.255.255 (which is E0000000 through EFFFFFFF in hex).
+//
+ return (m_address >= 0xe0000000 && m_address <= 0xefffffff);
}
uint32_t
@@ -170,6 +213,20 @@
buf[2] = (m_address >> 8) & 0xff;
buf[3] = (m_address >> 0) & 0xff;
}
+Ipv4Address
+Ipv4Address::Deserialize (const uint8_t buf[4])
+{
+ Ipv4Address ipv4;
+ ipv4.m_address = 0;
+ ipv4.m_address |= buf[0];
+ ipv4.m_address <<= 8;
+ ipv4.m_address |= buf[1];
+ ipv4.m_address <<= 8;
+ ipv4.m_address |= buf[2];
+ ipv4.m_address <<= 8;
+ ipv4.m_address |= buf[3];
+ return ipv4;
+}
void
Ipv4Address::Print (std::ostream &os) const
@@ -180,7 +237,39 @@
<< ((m_address >> 0) & 0xff);
}
+bool
+Ipv4Address::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 4);
+}
+Ipv4Address::operator Address ()
+{
+ return ConvertTo ();
+}
+Address
+Ipv4Address::ConvertTo (void) const
+{
+ uint8_t buf[4];
+ Serialize (buf);
+ return Address (GetType (), buf, 4);
+}
+
+Ipv4Address
+Ipv4Address::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 4));
+ uint8_t buf[4];
+ address.CopyTo (buf);
+ return Deserialize (buf);
+}
+
+uint8_t
+Ipv4Address::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
Ipv4Address
Ipv4Address::GetZero (void)
--- a/src/node/ipv4-address.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-address.h Fri Sep 28 11:59:46 2007 +0100
@@ -24,9 +24,12 @@
#include <stdint.h>
#include <ostream>
+#include "address.h"
namespace ns3 {
+class Ipv4Mask;
+
/** Ipv4 addresses are stored in host order in
* this class.
*/
@@ -50,6 +53,22 @@
Ipv4Address (char const *address);
/**
+ * input address is in host order.
+ * \param address The host order 32-bit address
+ */
+ void Set (uint32_t address);
+ /**
+ * \brief Sets an Ipv4Address by parsing a the input C-string
+ *
+ * Input address is in format:
+ * hhh.xxx.xxx.lll
+ * where h is the high byte and l the
+ * low byte
+ * \param address C-string containing the address as described above
+ */
+ void Set (char const *address);
+
+ /**
* \brief Comparison operation between two Ipv4Addresses
* \param other address to which to compare this address
* \return True if the addresses are equal. False otherwise.
@@ -68,11 +87,19 @@
void SetHostOrder (uint32_t ip);
/**
* Serialize this address to a 4-byte buffer
+ *
* \param buf output buffer to which this address gets overwritten with this
* Ipv4Address
*/
void Serialize (uint8_t buf[4]) const;
/**
+ * \param buf buffer to read address from
+ * \returns an Ipv4Address
+ *
+ * The input address is expected to be in network byte order format.
+ */
+ static Ipv4Address Deserialize (const uint8_t buf[4]);
+ /**
* \brief Print this address to the given output stream
*
* The print format is in the typical "192.168.1.1"
@@ -80,14 +107,40 @@
*/
void Print (std::ostream &os) const;
- bool IsBroadcast (void);
- bool IsMulticast (void);
+ bool IsBroadcast (void) const;
+ bool IsMulticast (void) const;
+ /**
+ * \brief Combine this address with a network mask
+ *
+ * This method returns an IPv4 address that is this address combined
+ * (bitwise and) with a network mask, yielding an IPv4 network
+ * address.
+ *
+ * \param mask a network mask
+ */
+ Ipv4Address CombineMask (Ipv4Mask const &mask) const;
+ /**
+ * \brief Generate subnet-directed broadcast address corresponding to mask
+ *
+ * The subnet-directed broadcast address has the host bits set to all
+ * ones.
+ *
+ * \param mask a network mask
+ */
+ Ipv4Address GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
+ bool IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
+
+ static bool IsMatchingType (const Address &address);
+ operator Address ();
+ static Ipv4Address ConvertFrom (const Address &address);
static Ipv4Address GetZero (void);
static Ipv4Address GetAny (void);
static Ipv4Address GetBroadcast (void);
static Ipv4Address GetLoopback (void);
private:
+ Address ConvertTo (void) const;
+ static uint8_t GetType (void);
uint32_t m_address;
};
@@ -108,6 +161,10 @@
*/
uint32_t GetHostOrder (void) const;
void SetHostOrder (uint32_t value);
+ /**
+ * \brief Return the inverse mask in host order.
+ */
+ uint32_t GetInverse (void) const;
void Print (std::ostream &os) const;
--- a/src/node/ipv4-route.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-route.cc Fri Sep 28 11:59:46 2007 +0100
@@ -30,6 +30,7 @@
Ipv4Route::Ipv4Route ()
{}
+
Ipv4Route::Ipv4Route (Ipv4Route const &route)
: m_dest (route.m_dest),
m_destNetworkMask (route.m_destNetworkMask),
@@ -37,6 +38,13 @@
m_interface (route.m_interface)
{}
+Ipv4Route::Ipv4Route (Ipv4Route const *route)
+ : m_dest (route->m_dest),
+ m_destNetworkMask (route->m_destNetworkMask),
+ m_gateway (route->m_gateway),
+ m_interface (route->m_interface)
+{}
+
Ipv4Route::Ipv4Route (Ipv4Address dest,
Ipv4Address gateway,
uint32_t interface)
@@ -137,7 +145,6 @@
return m_interface;
}
-
Ipv4Route
Ipv4Route::CreateHostRouteTo (Ipv4Address dest,
Ipv4Address nextHop,
@@ -220,4 +227,108 @@
return os;
}
+/*****************************************************
+ * Ipv4MulticastRoute
+ *****************************************************/
+
+Ipv4MulticastRoute::Ipv4MulticastRoute ()
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (Ipv4MulticastRoute const &route)
+:
+ m_origin (route.m_origin),
+ m_group (route.m_group),
+ m_inputInterface (route.m_inputInterface),
+ m_outputInterfaces (route.m_outputInterfaces)
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (Ipv4MulticastRoute const *route)
+:
+ m_origin (route->m_origin),
+ m_group (route->m_group),
+ m_inputInterface (route->m_inputInterface),
+ m_outputInterfaces (route->m_outputInterfaces)
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (
+ Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ m_origin = origin;
+ m_group = group;
+ m_inputInterface = inputInterface;
+ m_outputInterfaces = outputInterfaces;
+}
+
+Ipv4Address
+Ipv4MulticastRoute::GetOrigin (void) const
+{
+ return m_origin;
+}
+
+Ipv4Address
+Ipv4MulticastRoute::GetGroup (void) const
+{
+ return m_group;
+}
+
+uint32_t
+Ipv4MulticastRoute::GetInputInterface (void) const
+{
+ return m_inputInterface;
+}
+
+uint32_t
+Ipv4MulticastRoute::GetNOutputInterfaces (void) const
+{
+ return m_outputInterfaces.size ();
+}
+
+uint32_t
+Ipv4MulticastRoute::GetOutputInterface (uint32_t n) const
+{
+ NS_ASSERT_MSG(n < m_outputInterfaces.size (),
+ "Ipv4MulticastRoute::GetOutputInterface (): index out of bounds");
+
+ return m_outputInterfaces[n];
+}
+
+std::vector<uint32_t>
+Ipv4MulticastRoute::GetOutputInterfaces (void) const
+{
+ return m_outputInterfaces;
+}
+
+Ipv4MulticastRoute
+Ipv4MulticastRoute::CreateMulticastRoute (
+ Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ return Ipv4MulticastRoute (origin, group, inputInterface, outputInterfaces);
+}
+
+std::ostream&
+operator<< (std::ostream& os, Ipv4MulticastRoute const& route)
+{
+ os << "origin=" << route.GetOrigin () <<
+ ", group=" << route.GetGroup () <<
+ ", input interface=" << route.GetInputInterface () <<
+ ", output interfaces=";
+
+ for (uint32_t i = 0; i < route.GetNOutputInterfaces (); ++i)
+ {
+ os << route.GetOutputInterface (i) << " ";
+
+ }
+
+ return os;
+}
+
}//namespace ns3
--- a/src/node/ipv4-route.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-route.h Fri Sep 28 11:59:46 2007 +0100
@@ -22,6 +22,7 @@
#define IPV4_ROUTE_H
#include <list>
+#include <vector>
#include <ostream>
#include "ipv4-address.h"
@@ -36,12 +37,19 @@
* \brief This constructor does nothing
*/
Ipv4Route ();
+
/**
* \brief Copy Constructor
* \param route The route to copy
*/
Ipv4Route (Ipv4Route const &route);
+ /**
+ * \brief Copy Constructor
+ * \param route The route to copy
+ */
+ Ipv4Route (Ipv4Route const *route);
+
bool IsHost (void) const;
/**
* \return The IPv4 address of the destination of this route
@@ -98,6 +106,74 @@
std::ostream& operator<< (std::ostream& os, Ipv4Route const& route);
+/**
+ * \brief A record of an IPv4 multicast route
+ */
+class Ipv4MulticastRoute {
+public:
+ /**
+ * \brief This constructor does nothing
+ */
+ Ipv4MulticastRoute ();
+
+ /**
+ * \brief Copy Constructor
+ * \param route The route to copy
+ */
+ Ipv4MulticastRoute (Ipv4MulticastRoute const &route);
+
+ /**
+ * \brief Copy Constructor
+ * \param route The route to copy
+ */
+ Ipv4MulticastRoute (Ipv4MulticastRoute const *route);
+
+ /**
+ * \return The IPv4 address of the source of this route
+ */
+ Ipv4Address GetOrigin (void) const;
+
+ /**
+ * \return The IPv4 address of the multicast group of this route
+ */
+ Ipv4Address GetGroup (void) const;
+
+ /**
+ * \return The IPv4 address of the input interface of this route
+ */
+ uint32_t GetInputInterface (void) const;
+
+ /**
+ * \return The number of output interfaces of this route
+ */
+ uint32_t GetNOutputInterfaces (void) const;
+
+ /**
+ * \return A specified output interface.
+ */
+ uint32_t GetOutputInterface (uint32_t n) const;
+
+ /**
+ * \return A vector of all of the output interfaces of this route.
+ */
+ std::vector<uint32_t> GetOutputInterfaces (void) const;
+
+ static Ipv4MulticastRoute CreateMulticastRoute (Ipv4Address origin,
+ Ipv4Address group, uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+private:
+ Ipv4MulticastRoute (Ipv4Address origin, Ipv4Address group,
+ uint32_t inputInterface, std::vector<uint32_t> outputInterfaces);
+
+ Ipv4Address m_origin;
+ Ipv4Address m_group;
+ uint32_t m_inputInterface;
+ std::vector<uint32_t> m_outputInterfaces;
+};
+
+std::ostream& operator<< (std::ostream& os, Ipv4MulticastRoute const& route);
+
}//namespace ns3
#endif /* IPV4_ROUTE_H */
--- a/src/node/ipv4.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4.cc Fri Sep 28 11:59:46 2007 +0100
@@ -18,6 +18,9 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+
+#include "ns3/assert.h"
+#include "ns3/node.h"
#include "ipv4.h"
namespace ns3 {
@@ -32,4 +35,61 @@
Ipv4::~Ipv4 ()
{}
+uint32_t
+Ipv4::GetIfIndexByAddress (Ptr<Node> node, Ipv4Address a, Ipv4Mask amask)
+{
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4, "Ipv4::GetIfIndexByAddress: No Ipv4 interface");
+ for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
+ {
+ if (ipv4->GetAddress (i).CombineMask(amask) == a.CombineMask(amask) )
+ {
+ return i;
+ }
+ }
+ // Mapping not found
+ NS_ASSERT_MSG (false, "Ipv4::GetIfIndexByAddress failed");
+ return 0;
+}
+
+//
+// XXX BUGBUG I don't think this is really the right approach here. The call
+// to GetRoute () filters down into Ipv4L3Protocol where it translates into
+// a call into the Ipv4 static routing package. This bypasses any other
+// routing packages. At a minimum, the name is misleading.
+//
+bool
+Ipv4::GetRouteToDestination (
+ Ptr<Node> node,
+ Ipv4Route& route,
+ Ipv4Address a,
+ Ipv4Mask amask)
+{
+ Ipv4Route tempRoute;
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4, "Ipv4::GetRouteToDestination: No Ipv4 interface");
+ for (uint32_t i = 0; i < ipv4->GetNRoutes (); i++)
+ {
+ tempRoute = ipv4->GetRoute (i);
+ // Host route found
+ if ( tempRoute.IsNetwork () == false && tempRoute.GetDest () == a )
+ {
+ route = tempRoute;
+ return true;
+ }
+ else if ( tempRoute.IsNetwork () &&
+ tempRoute.GetDestNetwork () == a.CombineMask(amask) )
+ {
+ route = tempRoute;
+ return true;
+ }
+ else if ( tempRoute.IsDefault () )
+ {
+ route = tempRoute;
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace ns3
--- a/src/node/ipv4.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4.h Fri Sep 28 11:59:46 2007 +0100
@@ -24,13 +24,126 @@
#include <stdint.h>
#include "ns3/ipv4-address.h"
#include "ns3/object.h"
+#include "ns3/callback.h"
#include "ipv4-route.h"
namespace ns3 {
+class Node;
class NetDevice;
class Packet;
class Ipv4Route;
+class Ipv4Header; // FIXME: ipv4-header.h needs to move from module
+ // "internet-node" to module "node"
+
+/**
+ * \brief Base class for IPv4 routing protocols.
+ *
+ * This class represents the interface between the IPv4 routing core
+ * and a specific IPv4 routing protocol. The interface is
+ * asynchronous (callback based) in order to support reactive routing
+ * protocols (e.g. AODV).
+ */
+class Ipv4RoutingProtocol : public Object
+{
+public:
+ // void (*RouteReply) (bool found, Ipv4Route route, Packet packet, Ipv4Header const &ipHeader);
+
+
+ /**
+ * \brief Callback to be invoked when route discovery is completed
+ *
+ * \param bool flag indicating whether a route was actually found;
+ * when this is false, the Ipv4Route parameter is ignored
+ *
+ * \param Ipv4Route the route found
+ *
+ * \param Packet the packet for which a route was requested; can be
+ * modified by the routing protocol
+ *
+ * \param Ipv4Header the IP header supplied to the route request
+ * method (possibly modified in case a new routing header is
+ * inserted and consequently the protocol type has to change).
+ *
+ */
+ typedef Callback<void, bool, const Ipv4Route&, Packet, const Ipv4Header&> RouteReplyCallback;
+
+ /**
+ * \brief Asynchronously requests a route for a given packet and IP header
+ *
+ * \param ifIndex The interface index on which the packet was received.
+ * \param ipHeader IP header of the packet
+ * \param packet packet that is being sent or forwarded
+ * \param routeReply callback that will receive the route reply
+ *
+ * \returns true if the routing protocol should be able to get the
+ * route, false otherwise.
+ *
+ * This method is called whenever a node's IPv4 forwarding engine
+ * needs to lookup a route for a given packet and IP header.
+ *
+ * The routing protocol implementation may determine immediately it
+ * should not be handling this particular the route request. For
+ * instance, a routing protocol may decline to search for routes for
+ * certain classes of addresses, like link-local. In this case,
+ * RequestRoute() should return false and the routeReply callback
+ * must not be invoked.
+ *
+ * If the routing protocol implementations assumes it can provide
+ * the requested route, then it should return true, and the
+ * routeReply callback must be invoked, either immediately before
+ * returning true (synchronously), or in the future (asynchronous).
+ * The routing protocol may use any information available in the IP
+ * header and packet as routing key, although most routing protocols
+ * use only the destination address (as given by
+ * ipHeader.GetDestination ()). The routing protocol is also
+ * allowed to add a new header to the packet, which will appear
+ * immediately after the IP header, although most routing do not
+ * insert any extra header.
+ */
+ virtual bool RequestRoute (uint32_t ifIndex,
+ const Ipv4Header &ipHeader,
+ Packet packet,
+ RouteReplyCallback routeReply) = 0;
+
+/**
+ * \brief Synchronously check to see if we can determine the interface index
+ * that will be used if a packet is sent to this destination.
+ *
+ * This method addresses a problem in the IP stack where a destination address
+ * must be present and checksummed into the IP header before the actual
+ * interface over which the packet is sent can be determined. The answer is
+ * to implement a known and intentional cross-layer violation. This is the
+ * endpoint of a call chain that started up quite high in the stack (sockets)
+ * and has found its way down to the Ipv4L3Protocol which is consulting the
+ * routing protocols for what they would do if presented with a packet of the
+ * given destination.
+ *
+ * Note that the a single interface index is returned. This means that if
+ * the destination address is a multicast, and an explicit route is present
+ * that includeds multiple output interfaces, that route cannot be used.
+ *
+ * If there are multiple paths out of the node, the resolution is performed
+ * by Ipv4L3Protocol::GetIfIndexforDestination which has access to more
+ * contextual information that is useful for making a determination.
+ *
+ * \param destination The Ipv4Address if the destination of a hypothetical
+ * packet. This may be a multicast group address.
+ * \param ifIndex A reference to the interface index over which a packet
+ * sent to this destination would be sent.
+ * \return Returns true if a route is found to the destination that involves
+ * a single output interface index, otherwise false.
+ *
+ * \see Ipv4StaticRouting
+ * \see Ipv4RoutingProtocol
+ * \see Ipv4L3Protocol
+ */
+ virtual bool RequestIfIndex (Ipv4Address destination,
+ uint32_t& ifIndex) = 0;
+
+ static const uint32_t IF_INDEX_ANY = 0xffffffff;
+};
+
/**
* \brief Access to the Ipv4 forwarding table and to the ipv4 interfaces
*
@@ -47,7 +160,20 @@
static const InterfaceId iid;
Ipv4 ();
virtual ~Ipv4 ();
-
+
+ /**
+ * \brief Register a new routing protocol to be used in this IPv4 stack
+ *
+ * \param routingProtocol new routing protocol implementation object
+ * \param priority priority to give to this routing protocol.
+ * Values may range between -32768 and +32767. The priority 0
+ * corresponds to static routing table lookups, higher values have
+ * more priority. The order by which routing protocols with the
+ * same priority value are consulted is undefined.
+ */
+ virtual void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+ int16_t priority) = 0;
+
/**
* \param dest destination address
* \param nextHop address of next hop.
@@ -107,17 +233,69 @@
* \returns the number of entries in the routing table.
*/
virtual uint32_t GetNRoutes (void) = 0;
+
/**
* \param i index of route to return
* \returns the route whose index is i
*/
virtual Ipv4Route GetRoute (uint32_t i) = 0;
+
/**
* \param i index of route to remove from routing table.
*/
virtual void RemoveRoute (uint32_t i) = 0;
+
+ /**
+ * \brief Add a static multicast route for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ * \param inputInterface The interface index over which the packet arrived.
+ * \param outputInterfaces The list of output interface indices over which
+ * the packet should be sent (excluding the inputInterface).
+ */
+ virtual void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces) = 0;
+ /**
+ * \brief Remove a static multicast route for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ * \param inputInterface The interface index over which the packet arrived.
+ */
+ virtual void RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface) = 0;
/**
+ * \brief Set the default static multicast route.
+ *
+ * \param outputInterface The network output interface index over which
+ * packets without specific routes should be sent.
+ */
+ virtual void SetDefaultMulticastRoute (uint32_t outputInterface) = 0;
+
+ /**
+ * \returns the number of entries in the multicast routing table.
+ */
+ virtual uint32_t GetNMulticastRoutes (void) const = 0;
+
+ /**
+ * \param i index of route to return
+ * \returns the route whose index is i
+ */
+ virtual Ipv4MulticastRoute GetMulticastRoute (uint32_t i) const = 0;
+
+ /**
+ * \param i index of route to remove from routing table.
+ */
+ virtual void RemoveMulticastRoute (uint32_t i) = 0;
+
+ /**
* \param device device to add to the list of ipv4 interfaces
* which can be used as output interfaces during packet forwarding.
* \returns the index of the ipv4 interface added.
@@ -127,49 +305,120 @@
* make sure that it is never used during packet forwarding.
*/
virtual uint32_t AddInterface (Ptr<NetDevice> device) = 0;
+
/**
* \returns the number of interfaces added by the user.
*/
virtual uint32_t GetNInterfaces (void) = 0;
/**
+ * \brief Find and return the interface ID of the interface that has been
+ * assigned the specified IP address.
+ * \param addr The IP address assigned to the interface of interest.
+ * \returns The index of the ipv4 interface with the given address.
+ *
+ * Each IP interface has an IP address associated with it. It is often
+ * useful to search the list of interfaces for one that corresponds to
+ * a known IP Address. This call takes an IP address as a parameter and
+ * returns the interface index of the first interface that has been assigned
+ * that address. If the address is not found, this function asserts.
+ */
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr) const = 0;
+
+ /**
+ * \brief Find and return the interface ID of the interface that has been
+ * assigned the specified (masked) IP address.
+ * \param addr The IP address assigned to the interface of interest.
+ * \param mask The address mask to be used in address matching.
+ * \returns The index of the ipv4 interface with the given address.
+ *
+ * Each IP interface has an IP address associated with it. It is often
+ * useful to search the list of interfaces for one that corresponds to
+ * a known IP Address. This call takes an IP address and an IP address
+ * mask as parameters and returns the interface index of the first interface
+ * that matches the masked IP address.
+ */
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr,
+ Ipv4Mask mask) const = 0;
+
+ /**
* \param i index of ipv4 interface
* \returns the NetDevice associated with the ipv4 interface index
*/
virtual Ptr<NetDevice> GetNetDevice (uint32_t i) = 0;
/**
+ * \brief Join a multicast group for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ */
+ virtual void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group) = 0;
+
+ /**
+ * \brief Leave a multicast group for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ */
+ virtual void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group) = 0;
+
+ /**
* \param i index of ipv4 interface
* \param address address to associate to the underlying ipv4 interface
*/
virtual void SetAddress (uint32_t i, Ipv4Address address) = 0;
+
/**
* \param i index of ipv4 interface
* \param mask mask to associate to the underlying ipv4 interface
*/
virtual void SetNetworkMask (uint32_t i, Ipv4Mask mask) = 0;
+
/**
* \param i index of ipv4 interface
* \returns the mask associated to the underlying ipv4 interface
*/
virtual Ipv4Mask GetNetworkMask (uint32_t i) const = 0;
+
/**
* \param i index of ipv4 interface
* \returns the address associated to the underlying ipv4 interface
*/
virtual Ipv4Address GetAddress (uint32_t i) const = 0;
+
+ /**
+ * \param destination The IP address of a hypothetical destination.
+ * \returns The IP address assigned to the interface that will be used
+ * if we were to send a packet to destination.
+ */
+ virtual Ipv4Address GetSourceAddress (Ipv4Address destination) const = 0;
+
+ /**
+ * \param destination The IP address of a hypothetical destination.
+ * \param ifIndex filled in with the interface index that will be used to
+ * send a packet to the hypothetical destination.
+ * \returns True if a single interface can be identified, false otherwise.
+ */
+ virtual bool GetIfIndexForDestination (Ipv4Address dest,
+ uint32_t &ifIndex) const = 0;
+
/**
* \param i index of ipv4 interface
* \returns the Maximum Transmission Unit (in bytes) associated
* to the underlying ipv4 interface
*/
virtual uint16_t GetMtu (uint32_t i) const = 0;
+
/**
* \param i index of ipv4 interface
* \returns true if the underlying interface is in the "up" state,
* false otherwise.
*/
virtual bool IsUp (uint32_t i) const = 0;
+
/**
* \param i index of ipv4 interface
*
@@ -177,6 +426,7 @@
* considered valid during ipv4 forwarding.
*/
virtual void SetUp (uint32_t i) = 0;
+
/**
* \param i index of ipv4 interface
*
@@ -184,7 +434,17 @@
* ignored during ipv4 forwarding.
*/
virtual void SetDown (uint32_t i) = 0;
-
+
+/**
+ * Convenience functions (Doxygen still needed)
+ *
+ * Return the ifIndex corresponding to the Ipv4Address provided.
+ */
+ static uint32_t GetIfIndexByAddress (Ptr<Node> node, Ipv4Address a,
+ Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+
+ static bool GetRouteToDestination (Ptr<Node> node, Ipv4Route& route,
+ Ipv4Address a, Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
};
} // namespace ns3
--- a/src/node/llc-snap-header.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/llc-snap-header.cc Fri Sep 28 11:59:46 2007 +0100
@@ -19,17 +19,24 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+#include "llc-snap-header.h"
#include "ns3/assert.h"
-
-#include "llc-snap-header.h"
+#include <string>
namespace ns3 {
+NS_HEADER_ENSURE_REGISTERED (LlcSnapHeader);
+
+uint32_t
+LlcSnapHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<LlcSnapHeader> ("LlcSnapHeader.ns3");
+ return uid;
+}
+
LlcSnapHeader::LlcSnapHeader ()
{}
-LlcSnapHeader::~LlcSnapHeader ()
-{}
void
LlcSnapHeader::SetType (uint16_t type)
{
@@ -47,18 +54,24 @@
return 1 + 1 + 1 + 3 + 2;
}
-void
-LlcSnapHeader::PrintTo (std::ostream &os) const
+std::string
+LlcSnapHeader::GetName (void) const
{
- os << "(mac)"
- << " EtherType: ";
+ return "LLCSNAP";
+}
+
+void
+LlcSnapHeader::Print (std::ostream &os) const
+{
+ os << "(type 0x";
os.setf (std::ios::hex, std::ios::basefield);
os << m_etherType;
os.setf (std::ios::dec, std::ios::basefield);
+ os << ")";
}
void
-LlcSnapHeader::SerializeTo (Buffer::Iterator start) const
+LlcSnapHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
uint8_t buf[] = {0xaa, 0xaa, 0x03, 0, 0, 0};
@@ -66,7 +79,7 @@
i.WriteHtonU16 (m_etherType);
}
uint32_t
-LlcSnapHeader::DeserializeFrom (Buffer::Iterator start)
+LlcSnapHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
i.Next (5+1);
@@ -75,4 +88,4 @@
}
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/llc-snap-header.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/llc-snap-header.h Fri Sep 28 11:59:46 2007 +0100
@@ -23,27 +23,30 @@
#define LLC_SNAP_HEADER_H
#include <stdint.h>
+#include <string>
#include "ns3/header.h"
namespace ns3 {
-class LlcSnapHeader : public Header {
- public:
+class LlcSnapHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
+
LlcSnapHeader ();
- virtual ~LlcSnapHeader ();
-
void SetType (uint16_t type);
uint16_t GetType (void);
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
private:
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
uint16_t m_etherType;
};
-}; // namespace ns3
+} // namespace ns3
#endif /* LLC_SNAP_HEADER_H */
--- a/src/node/mac-address.cc Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include <iostream>
-#include <iomanip>
-#include "ns3/assert.h"
-#include "mac-address.h"
-
-#define ASCII_a (0x41)
-#define ASCII_z (0x5a)
-#define ASCII_A (0x61)
-#define ASCII_Z (0x7a)
-#define ASCII_COLON (0x3a)
-#define ASCII_ZERO (0x30)
-
-namespace ns3 {
-
-static char
-AsciiToLowCase (char c)
-{
- if (c >= ASCII_a && c <= ASCII_z) {
- return c;
- } else if (c >= ASCII_A && c <= ASCII_Z) {
- return c + (ASCII_a - ASCII_A);
- } else {
- return c;
- }
-}
-
-
-MacAddress::MacAddress () : m_len(0)
-{
- for (int i=0; i < MacAddress::MAX_LEN; i++)
- {
- m_address[i] = 0;
- }
-}
-
-MacAddress::MacAddress (uint8_t const *address, uint8_t len)
-{
- NS_ASSERT (len <= MacAddress::MAX_LEN);
- for (int i=0; i < len; i++)
- {
- m_address[i] = address[i];
- }
- for (int i=len; i < MacAddress::MAX_LEN; i++)
- {
- m_address[i] = 0;
- }
- m_len = len;
-}
-
-MacAddress::MacAddress (char const *str)
-{
- int i = 0;
- while (*str != 0 && i < MacAddress::MAX_LEN) {
- uint8_t byte = 0;
- while (*str != ASCII_COLON && *str != 0) {
- byte <<= 4;
- char low = AsciiToLowCase (*str);
- if (low >= ASCII_a) {
- byte |= low - ASCII_a + 10;
- } else {
- byte |= low - ASCII_ZERO;
- }
- str++;
- }
- m_address[i] = byte;
- i++;
- if (*str == 0) {
- break;
- }
- str++;
- }
- m_len = i;
-}
-
-MacAddress::~MacAddress ()
-{}
-
-bool
-MacAddress::IsEqual (MacAddress other) const
-{
- if (memcmp(other.m_address, m_address, m_len))
- {
- return false;
- }
- else
- {
- return true;
- }
-}
-
-void
-MacAddress::Print (std::ostream &os) const
-{
- int i;
- if (m_len == 0)
- {
- os << "NULL-ADDRESS";
- return;
- }
- os.setf (std::ios::hex, std::ios::basefield);
- std::cout.fill('0');
- for (i=0; i< (m_len-1); i++)
- {
- os << std::setw(2) << (uint32_t)m_address[i] << ":";
- }
- // Final byte not suffixed by ":"
- os << std::setw(2) << (uint32_t)m_address[i];
- os.setf (std::ios::dec, std::ios::basefield);
- std::cout.fill(' ');
-}
-
-uint8_t
-MacAddress::GetLength () const
-{
- return m_len;
-}
-
-void
-MacAddress::Peek (uint8_t ad[MacAddress::MAX_LEN]) const
-{
- memcpy (ad, m_address, MacAddress::MAX_LEN);
-}
-void
-MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len)
-{
- memcpy (m_address, ad, MacAddress::MAX_LEN);
- m_len = len;
-}
-
-bool operator == (MacAddress const&a, MacAddress const&b)
-{
- return a.IsEqual (b);
-}
-
-bool operator != (MacAddress const&a, MacAddress const&b)
-{
- return !a.IsEqual (b);
-}
-
-bool operator < (MacAddress const&a, MacAddress const&b)
-{
- uint8_t a_p[MacAddress::MAX_LEN];
- uint8_t b_p[MacAddress::MAX_LEN];
- a.Peek (a_p);
- b.Peek (b_p);
- NS_ASSERT (a.GetLength() == b.GetLength());
- for (uint8_t i = 0; i < a.GetLength(); i++)
- {
- if (a_p[i] < b_p[i])
- {
- return true;
- }
- else if (a_p[i] > b_p[i])
- {
- return false;
- }
- }
- return false;
-}
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address)
-{
- address.Print (os);
- return os;
-}
-
-
-}; // namespace ns3
--- a/src/node/mac-address.h Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef MAC_ADDRESS_H
-#define MAC_ADDRESS_H
-
-#include <stdint.h>
-#include <ostream>
-
-namespace ns3 {
-
-/**
- * \brief base class for Network Device addresses
- *
- * This class is a base class for different types of Network
- * Device addresses. It generically stores an address of
- * MAX_ADDR_LEN bytes, and provides methods to compare, print, and set
- * the address.
- */
-class MacAddress {
-public:
- enum {
- MAX_LEN = 32
- };
- /**
- * \brief Construct a null MacAddress
- *
- * This MacAddress has length of zero, and is internally all zeros
- */
- MacAddress (void);
- /**
- * \brief Construct a MacAddress from a byte-array
- *
- * low byte should be first.
- * \param address a byte array indicating the address
- * \param len length, in bytes, of the address points to
- */
- MacAddress (uint8_t const *address, uint8_t len);
- /**
- * \brief Construct a MacAddress from a C-string
- *
- * The string should look like this:
- * hh:xx:xx:xx:xx:ll
- * where hh is the high byte and ll is
- * the low byte.
- * \param address the C-string representation of the address
- */
- MacAddress (char const *address);
- ~MacAddress ();
-
- /**
- * \brief Comparison operation between MacAddresses
- * \param other The address against which to compare this one
- * \return True if they are equal, false otherwise.
- */
- bool IsEqual (MacAddress other) const;
- /**
- * \brief Print this MacAddress to a stream
- *
- * The format is colon seperated groups of two hexadecimal digits
- * \param os The output stream desired
- */
- void Print (std::ostream &os) const;
-
- /**
- * \return The length in bytes of this MacAddress
- */
- uint8_t GetLength() const;
- /**
- * \brief Copy routine to peek the contents of the MacAddress
- *
- * \param ad Output parameter which holds a copy of this MacAddress
- */
- void Peek (uint8_t ad[MAX_LEN]) const;
- /**
- * \brief Sets this MacAddress to a specific value
- * \param ad byte buffer to set the MacAddress to
- * \param len the length of the buffer
- */
- void Set (uint8_t const ad[MAX_LEN], uint8_t len);
-
-private:
- uint8_t m_address[MAX_LEN];
- uint8_t m_len;
-};
-
-bool operator == (MacAddress const&a, MacAddress const&b);
-bool operator != (MacAddress const&a, MacAddress const&b);
-bool operator < (MacAddress const&a, MacAddress const&b);
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address);
-
-}; // namespace ns3
-
-#endif /* MAC_ADDRESS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac48-address.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "mac48-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+ if (c >= ASCII_a && c <= ASCII_z) {
+ return c;
+ } else if (c >= ASCII_A && c <= ASCII_Z) {
+ return c + (ASCII_a - ASCII_A);
+ } else {
+ return c;
+ }
+}
+
+
+Mac48Address::Mac48Address ()
+{
+ memset (m_address, 0, 6);
+}
+Mac48Address::Mac48Address (const char *str)
+{
+ int i = 0;
+ while (*str != 0 && i < 6)
+ {
+ uint8_t byte = 0;
+ while (*str != ASCII_COLON && *str != 0)
+ {
+ byte <<= 4;
+ char low = AsciiToLowCase (*str);
+ if (low >= ASCII_a)
+ {
+ byte |= low - ASCII_a + 10;
+ }
+ else
+ {
+ byte |= low - ASCII_ZERO;
+ }
+ str++;
+ }
+ m_address[i] = byte;
+ i++;
+ if (*str == 0)
+ {
+ break;
+ }
+ str++;
+ }
+ NS_ASSERT (i == 6);
+}
+void
+Mac48Address::CopyFrom (const uint8_t buffer[6])
+{
+ memcpy (m_address, buffer, 6);
+}
+void
+Mac48Address::CopyTo (uint8_t buffer[6]) const
+{
+ memcpy (buffer, m_address, 6);
+}
+
+bool
+Mac48Address::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 6);
+}
+Mac48Address::operator Address ()
+{
+ return ConvertTo ();
+}
+Address
+Mac48Address::ConvertTo (void) const
+{
+ return Address (GetType (), m_address, 6);
+}
+Mac48Address
+Mac48Address::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 6));
+ Mac48Address retval;
+ address.CopyTo (retval.m_address);
+ return retval;
+}
+Mac48Address
+Mac48Address::Allocate (void)
+{
+ static uint64_t id = 0;
+ id++;
+ Mac48Address address;
+ address.m_address[0] = (id >> 40) & 0xff;
+ address.m_address[1] = (id >> 32) & 0xff;
+ address.m_address[2] = (id >> 24) & 0xff;
+ address.m_address[3] = (id >> 16) & 0xff;
+ address.m_address[4] = (id >> 8) & 0xff;
+ address.m_address[5] = (id >> 0) & 0xff;
+ return address;
+}
+uint8_t
+Mac48Address::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+bool operator == (const Mac48Address &a, const Mac48Address &b)
+{
+ uint8_t ada[6];
+ uint8_t adb[6];
+ a.CopyTo (ada);
+ b.CopyTo (adb);
+ return memcmp (ada, adb, 6) == 0;
+}
+bool operator != (const Mac48Address &a, const Mac48Address &b)
+{
+ return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Mac48Address & address)
+{
+ uint8_t ad[6];
+ address.CopyTo (ad);
+
+ os.setf (std::ios::hex, std::ios::basefield);
+ os.fill('0');
+ for (uint8_t i=0; i < 5; i++)
+ {
+ os << std::setw(2) << (uint32_t)ad[i] << ":";
+ }
+ // Final byte not suffixed by ":"
+ os << std::setw(2) << (uint32_t)ad[5];
+ os.setf (std::ios::dec, std::ios::basefield);
+ os.fill(' ');
+ return os;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac48-address.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef EUI48_ADDRESS_H
+#define EUI48_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-48 address
+ *
+ * This class can contain 48 bit IEEE addresses.
+ */
+class Mac48Address
+{
+public:
+ Mac48Address ();
+ /**
+ * \param str a string representing the new Mac48Address
+ *
+ * The format of the string is "xx:xx:xx:xx:xx:xx"
+ */
+ Mac48Address (const char *str);
+
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the input address to our internal buffer.
+ */
+ void CopyFrom (const uint8_t buffer[6]);
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the internal address to the input buffer.
+ */
+ void CopyTo (uint8_t buffer[6]) const;
+
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ operator Address ();
+ /**
+ * \param address a polymorphic address
+ * \returns a new Mac48Address from the polymorphic address
+ *
+ * This function performs a type check and asserts if the
+ * type of the input address is not compatible with an
+ * Mac48Address.
+ */
+ static Mac48Address ConvertFrom (const Address &address);
+ /**
+ * \returns true if the address matches, false otherwise.
+ */
+ static bool IsMatchingType (const Address &address);
+ /**
+ * Allocate a new Mac48Address.
+ */
+ static Mac48Address Allocate (void);
+private:
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ Address ConvertTo (void) const;
+ static uint8_t GetType (void);
+ uint8_t m_address[6];
+};
+
+bool operator == (const Mac48Address &a, const Mac48Address &b);
+bool operator != (const Mac48Address &a, const Mac48Address &b);
+std::ostream& operator<< (std::ostream& os, const Mac48Address & address);
+
+} // namespace ns3
+
+#endif /* EUI48_ADDRESS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac64-address.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "mac64-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+ if (c >= ASCII_a && c <= ASCII_z) {
+ return c;
+ } else if (c >= ASCII_A && c <= ASCII_Z) {
+ return c + (ASCII_a - ASCII_A);
+ } else {
+ return c;
+ }
+}
+
+
+Mac64Address::Mac64Address ()
+{
+ memset (m_address, 0, 8);
+}
+Mac64Address::Mac64Address (const char *str)
+{
+ int i = 0;
+ while (*str != 0 && i < 8)
+ {
+ uint8_t byte = 0;
+ while (*str != ASCII_COLON && *str != 0)
+ {
+ byte <<= 4;
+ char low = AsciiToLowCase (*str);
+ if (low >= ASCII_a)
+ {
+ byte |= low - ASCII_a + 10;
+ }
+ else
+ {
+ byte |= low - ASCII_ZERO;
+ }
+ str++;
+ }
+ m_address[i] = byte;
+ i++;
+ if (*str == 0)
+ {
+ break;
+ }
+ str++;
+ }
+ NS_ASSERT (i == 6);
+}
+void
+Mac64Address::CopyFrom (const uint8_t buffer[8])
+{
+ memcpy (m_address, buffer, 8);
+}
+void
+Mac64Address::CopyTo (uint8_t buffer[8]) const
+{
+ memcpy (buffer, m_address, 8);
+}
+
+bool
+Mac64Address::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 8);
+}
+Mac64Address::operator Address ()
+{
+ return ConvertTo ();
+}
+Mac64Address
+Mac64Address::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 8));
+ Mac64Address retval;
+ address.CopyTo (retval.m_address);
+ return retval;
+}
+Address
+Mac64Address::ConvertTo (void) const
+{
+ return Address (GetType (), m_address, 8);
+}
+
+Mac64Address
+Mac64Address::Allocate (void)
+{
+ static uint64_t id = 0;
+ id++;
+ Mac64Address address;
+ address.m_address[0] = (id >> 56) & 0xff;
+ address.m_address[1] = (id >> 48) & 0xff;
+ address.m_address[2] = (id >> 40) & 0xff;
+ address.m_address[3] = (id >> 32) & 0xff;
+ address.m_address[4] = (id >> 24) & 0xff;
+ address.m_address[5] = (id >> 16) & 0xff;
+ address.m_address[6] = (id >> 8) & 0xff;
+ address.m_address[7] = (id >> 0) & 0xff;
+ return address;
+}
+uint8_t
+Mac64Address::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+bool operator == (const Mac64Address &a, const Mac64Address &b)
+{
+ uint8_t ada[8];
+ uint8_t adb[8];
+ a.CopyTo (ada);
+ b.CopyTo (adb);
+ return memcmp (ada, adb, 8) == 0;
+}
+bool operator != (const Mac64Address &a, const Mac64Address &b)
+{
+ return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Mac64Address & address)
+{
+ uint8_t ad[8];
+ address.CopyTo (ad);
+
+ os.setf (std::ios::hex, std::ios::basefield);
+ os.fill('0');
+ for (uint8_t i=0; i < 7; i++)
+ {
+ os << std::setw(2) << (uint32_t)ad[i] << ":";
+ }
+ // Final byte not suffixed by ":"
+ os << std::setw(2) << (uint32_t)ad[7];
+ os.setf (std::ios::dec, std::ios::basefield);
+ os.fill(' ');
+ return os;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac64-address.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef EUI64_ADDRESS_H
+#define EUI64_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-64 address
+ *
+ * This class can contain 64 bit IEEE addresses.
+ */
+class Mac64Address
+{
+public:
+ Mac64Address ();
+ /**
+ * \param str a string representing the new Mac64Address
+ *
+ * The format of the string is "xx:xx:xx:xx:xx:xx"
+ */
+ Mac64Address (const char *str);
+
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the input address to our internal buffer.
+ */
+ void CopyFrom (const uint8_t buffer[8]);
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the internal address to the input buffer.
+ */
+ void CopyTo (uint8_t buffer[8]) const;
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ operator Address ();
+ /**
+ * \param address a polymorphic address
+ * \returns a new Mac64Address from the polymorphic address
+ *
+ * This function performs a type check and asserts if the
+ * type of the input address is not compatible with an
+ * Mac64Address.
+ */
+ static Mac64Address ConvertFrom (const Address &address);
+ /**
+ * \returns true if the address matches, false otherwise.
+ */
+ static bool IsMatchingType (const Address &address);
+ /**
+ * Allocate a new Mac64Address.
+ */
+ static Mac64Address Allocate (void);
+private:
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ Address ConvertTo (void) const;
+ static uint8_t GetType (void);
+ uint8_t m_address[8];
+};
+
+bool operator == (const Mac64Address &a, const Mac64Address &b);
+bool operator != (const Mac64Address &a, const Mac64Address &b);
+std::ostream& operator<< (std::ostream& os, const Mac64Address & address);
+
+} // namespace ns3
+
+#endif /* EUI64_ADDRESS_H */
--- a/src/node/net-device.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/net-device.cc Fri Sep 28 11:59:46 2007 +0100
@@ -22,17 +22,19 @@
#include <iostream>
#include "ns3/assert.h"
#include "ns3/object.h"
-
+#include "ns3/log.h"
+#include "ns3/trace-resolver.h"
#include "channel.h"
#include "net-device.h"
-#include "llc-snap-header.h"
#include "node.h"
+NS_LOG_COMPONENT_DEFINE ("NetDevice");
+
namespace ns3 {
const InterfaceId NetDevice::iid = MakeInterfaceId ("NetDevice", Object::iid);
-NetDevice::NetDevice(Ptr<Node> node, const MacAddress& addr) :
+NetDevice::NetDevice(Ptr<Node> node, const Address& addr) :
m_node (node),
m_name(""),
m_ifIndex (0),
@@ -43,22 +45,27 @@
m_isMulticast (false),
m_isPointToPoint (false)
{
+ NS_LOG_FUNCTION;
SetInterfaceId (NetDevice::iid);
m_node->AddDevice (this);
}
NetDevice::~NetDevice ()
-{}
+{
+ NS_LOG_FUNCTION;
+}
-MacAddress
+Address
NetDevice::GetAddress (void) const
{
+ NS_LOG_FUNCTION;
return m_address;
}
bool
NetDevice::SetMtu (const uint16_t mtu)
{
+ NS_LOG_FUNCTION;
m_mtu = mtu;
return true;
}
@@ -66,60 +73,71 @@
uint16_t
NetDevice::GetMtu (void) const
{
+ NS_LOG_FUNCTION;
return m_mtu;
}
void
NetDevice::SetName(const std::string name)
{
+ NS_LOG_FUNCTION;
m_name = name;
}
std::string
NetDevice::GetName(void) const
{
+ NS_LOG_FUNCTION;
return m_name;
}
void
NetDevice::SetIfIndex(uint32_t index)
{
+ NS_LOG_FUNCTION;
m_ifIndex = index;
}
uint32_t
NetDevice::GetIfIndex(void) const
{
+ NS_LOG_FUNCTION;
return m_ifIndex;
}
bool
NetDevice::IsLinkUp (void) const
{
+ NS_LOG_FUNCTION;
return m_isUp;
}
void
NetDevice::SetLinkChangeCallback (Callback<void> callback)
{
+ NS_LOG_FUNCTION;
m_linkChangeCallback = callback;
}
bool
NetDevice::IsBroadcast (void) const
{
+ NS_LOG_FUNCTION;
return m_isBroadcast;
}
-MacAddress const &
+
+Address const &
NetDevice::GetBroadcast (void) const
{
+ NS_LOG_FUNCTION;
NS_ASSERT (m_isBroadcast);
return m_broadcast;
}
void
-NetDevice::EnableBroadcast (MacAddress broadcast)
+NetDevice::EnableBroadcast (Address broadcast)
{
+ NS_LOG_FUNCTION;
m_isBroadcast = true;
m_broadcast = broadcast;
}
@@ -127,55 +145,79 @@
void
NetDevice::DisableBroadcast (void)
{
+ NS_LOG_FUNCTION;
m_isBroadcast = false;
}
bool
NetDevice::IsMulticast (void) const
{
+ NS_LOG_FUNCTION;
return m_isMulticast;
}
+Address
+NetDevice::GetMulticast (void) const
+{
+ NS_LOG_FUNCTION;
+ NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+ "Invalid operation when not IsMulticast ()");
+ return m_multicast;
+}
+
+Address
+NetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+ NS_LOG_FUNCTION;
+ NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+ "Invalid operation when not IsMulticast ()");
+ return m_multicast;
+}
+
void
-NetDevice::EnableMulticast (void)
+NetDevice::EnableMulticast (Address multicast)
{
+ NS_LOG_FUNCTION;
m_isMulticast = true;
+ m_multicast = multicast;
}
void
NetDevice::DisableMulticast (void)
{
+ NS_LOG_FUNCTION;
m_isMulticast = false;
}
bool
NetDevice::IsPointToPoint (void) const
{
+ NS_LOG_FUNCTION;
return m_isPointToPoint;
}
void
NetDevice::EnablePointToPoint (void)
{
+ NS_LOG_FUNCTION;
m_isPointToPoint = true;
}
void
NetDevice::DisablePointToPoint (void)
{
+ NS_LOG_FUNCTION;
m_isPointToPoint = false;
}
// Receive packet from above
bool
-NetDevice::Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber)
+NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber)
{
+ NS_LOG_FUNCTION;
if (m_isUp)
{
- LlcSnapHeader llc;
- llc.SetType (protocolNumber);
- p.AddHeader (llc);
- return SendTo(p, dest);
+ return SendTo(p, dest, protocolNumber);
}
else
{
@@ -183,35 +225,38 @@
}
}
-TraceResolver *
-NetDevice::CreateTraceResolver (TraceContext const &context)
-{
- return DoCreateTraceResolver (context);
-}
-
Ptr<Channel>
NetDevice::GetChannel (void) const
{
+ NS_LOG_FUNCTION;
return DoGetChannel ();
}
-// Receive packet from below
+// Receive packets from below
bool
-NetDevice::ForwardUp (Packet& packet)
+NetDevice::ForwardUp(const Packet& p, uint16_t param, const Address &from)
{
+ NS_LOG_FUNCTION;
bool retval = false;
- LlcSnapHeader llc;
- packet.RemoveHeader (llc);
+
+ NS_LOG_LOGIC ("UID is " << p.GetUid() << " device is: " << GetName());
+
if (!m_receiveCallback.IsNull ())
{
- retval = m_receiveCallback (this, packet, llc.GetType ());
+ retval = m_receiveCallback (this, p, param, from);
+ }
+ else
+ {
+ NS_LOG_WARN ("NetDevice::Receive call back is NULL");
}
- return retval;
+
+ return retval;
}
void
NetDevice::NotifyLinkUp (void)
{
+ NS_LOG_FUNCTION;
m_isUp = true;
if (!m_linkChangeCallback.IsNull ())
{
@@ -222,6 +267,7 @@
void
NetDevice::NotifyLinkDown (void)
{
+ NS_LOG_FUNCTION;
m_isUp = false;
if (!m_linkChangeCallback.IsNull ())
{
@@ -232,24 +278,28 @@
Ptr<Node>
NetDevice::GetNode (void) const
{
+ NS_LOG_FUNCTION;
return m_node;
}
bool
NetDevice::NeedsArp (void) const
{
+ NS_LOG_FUNCTION;
return DoNeedsArp ();
}
void
-NetDevice::SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb)
+NetDevice::SetReceiveCallback (ReceiveCallback cb)
{
+ NS_LOG_FUNCTION;
m_receiveCallback = cb;
}
void
NetDevice::DoDispose()
{
+ NS_LOG_FUNCTION;
m_node = 0;
}
--- a/src/node/net-device.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/net-device.h Fri Sep 28 11:59:46 2007 +0100
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Modified by Emmanuelle Laprise to remove dependance on LLC headers
*/
#ifndef NET_DEVICE_H
#define NET_DEVICE_H
@@ -27,7 +28,8 @@
#include "ns3/packet.h"
#include "ns3/object.h"
#include "ns3/ptr.h"
-#include "mac-address.h"
+#include "address.h"
+#include "ipv4-address.h"
namespace ns3 {
@@ -61,14 +63,6 @@
static const InterfaceId iid;
virtual ~NetDevice();
- /**
- * \param context the trace context to use to construct the
- * TraceResolver to return
- * \returns a TraceResolver which can resolve all traces
- * performed in this object. The caller must
- * delete the returned object.
- */
- TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \return the channel this NetDevice is connected to. The value
@@ -78,9 +72,9 @@
Ptr<Channel> GetChannel (void) const;
/**
- * \return the current MacAddress of this interface.
+ * \return the current Address of this interface.
*/
- MacAddress GetAddress (void) const;
+ Address GetAddress (void) const;
/**
* \param mtu MTU value, in bytes, to set for the device
* \return whether the MTU value was within legal bounds
@@ -136,11 +130,70 @@
* Calling this method is invalid if IsBroadcast returns
* not true.
*/
- MacAddress const &GetBroadcast (void) const;
+ Address const &GetBroadcast (void) const;
+
/**
* \return value of m_isMulticast flag
*/
bool IsMulticast (void) const;
+
+ /**
+ * \brief Return the MAC multicast base address used when mapping multicast
+ * groups to MAC multicast addresses.
+ *
+ * Typically when one constructs a multicast MAC addresses, some bits from
+ * the IP multicast group are copied into a corresponding MAC multicast
+ * group. In EUI-48, for example, the low order 23 bits of the multicast
+ * group are copied to the MAC multicast group base address.
+ *
+ * This method allows access to the underlying MAC multicast group base
+ * address. It is expected that in most cases, a net device client will
+ * allow the net device to perform the actual construction of the multicast
+ * address. Use of this method is discouraged unless you have a good reason
+ * to perform a custom mapping. You should prefer
+ * NetDevice::MakeMulticastAddress which will do the RFC-specified mapping
+ * for the net device in question.
+ *
+ * \return The multicast address supported by this net device.
+ *
+ * \warning Calling this method is invalid if IsMulticast returns not true.
+ * The method NS_ASSERTs if the device is not a multicast device.
+ * \see NetDevice::MakeMulticastAddress
+ */
+ Address GetMulticast (void) const;
+
+ /**
+ * \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
+ * 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). Similar RFCs exist for Ipv6 and Eui64 mappings.
+ * This method performs the multicast address creation function appropriate
+ * to the underlying MAC address of the device. This MAC address is
+ * encapsulated in an abstract Address to avoid dependencies on the exact
+ * MAC address format.
+ *
+ * A default imlementation of MakeMulticastAddress is provided, but this
+ * method simply NS_ASSERTS. In the case of net devices that do not support
+ * multicast, clients are expected to test NetDevice::IsMulticast and avoid
+ * attempting to map multicast packets. Subclasses of NetDevice that do
+ * support multicasting are expected to override this method and provide an
+ * implementation appropriate to the particular device.
+ *
+ * \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
+ * multicast group.
+ *
+ * \warning Calling this method is invalid if IsMulticast returns not true.
+ * \see Ipv4Address
+ * \see Address
+ * \see NetDevice::IsMulticast
+ */
+ virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
/**
* \return value of m_isPointToPoint flag
*/
@@ -153,11 +206,11 @@
* is received.
*
* Called from higher layer to send packet into Network Device
- * to the specified destination MacAddress
+ * to the specified destination Address
*
* \return whether the Send operation succeeded
*/
- bool Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber);
+ bool Send(const Packet& p, const Address& dest, uint16_t protocolNumber);
/**
* \returns the node base class which contains this network
* interface.
@@ -177,30 +230,44 @@
bool NeedsArp (void) const;
/**
+ * \param device a pointer to the net device which is calling this callback
+ * \param packet the packet received
+ * \param protocol the 16 bit protocol number associated with this packet.
+ * This protocol number is expected to be the same protocol number
+ * given to the Send method by the user on the sender side.
+ * \param address the address of the sender
+ * \returns true if the callback could handle the packet successfully, false
+ * otherwise.
+ */
+ typedef Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t,const Address &> ReceiveCallback;
+
+ /**
* \param cb callback to invoke whenever a packet has been received and must
* be forwarded to the higher layers.
+ *
*/
- void SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb);
+ void SetReceiveCallback (ReceiveCallback cb);
protected:
/**
* \param node base class node pointer of device's node
* \param addr MAC address of this device.
*/
- NetDevice(Ptr<Node> node, const MacAddress& addr);
+ NetDevice(Ptr<Node> node, const Address& addr);
/**
* Enable broadcast support. This method should be
* called by subclasses from their constructor
*/
- void EnableBroadcast (MacAddress broadcast);
+ void EnableBroadcast (Address broadcast);
/**
* Set m_isBroadcast flag to false
*/
void DisableBroadcast (void);
/**
- * Set m_isMulticast flag to true
+ * Enable multicast support. This method should be
+ * called by subclasses from their constructor
*/
- void EnableMulticast (void);
+ void EnableMulticast (Address multicast);
/**
* Set m_isMulticast flag to false
*/
@@ -227,6 +294,9 @@
/**
* \param p packet sent from below up to Network Device
+ * \param param Extra parameter extracted from header and needed by
+ * some protocols
+ * \param address the address of the sender of this packet.
* \returns true if the packet was forwarded successfully,
* false otherwise.
*
@@ -234,7 +304,8 @@
* forwards it to the higher layers by calling this method
* which is responsible for passing it up to the Rx callback.
*/
- bool ForwardUp (Packet& p);
+ bool ForwardUp (const Packet& p, uint16_t param, const Address &address);
+
/**
* The dispose method for this NetDevice class.
@@ -248,6 +319,7 @@
/**
* \param p packet to send
* \param dest address of destination to which packet must be sent
+ * \param protocolNumber Number of the protocol (used with some protocols)
* \returns true if the packet could be sent successfully, false
* otherwise.
*
@@ -255,7 +327,7 @@
* method. When the link is Up, this method is invoked to ask
* subclasses to forward packets. Subclasses MUST override this method.
*/
- virtual bool SendTo (Packet& p, const MacAddress& dest) = 0;
+ virtual bool SendTo (const Packet& p, const Address &dest, uint16_t protocolNumber) = 0;
/**
* \returns true if this NetDevice needs the higher-layers
* to perform ARP over it, false otherwise.
@@ -264,33 +336,25 @@
*/
virtual bool DoNeedsArp (void) const = 0;
/**
- * \param context the trace context to associated to the
- * trace resolver.
- * \returns a trace resolver associated to the input context.
- * the caller takes ownership of the pointer returned.
- *
- * Subclasses must implement this method.
- */
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
- /**
* \returns the channel associated to this NetDevice.
*
* Subclasses must implement this method.
*/
virtual Ptr<Channel> DoGetChannel (void) const = 0;
- Ptr<Node> m_node;
+ Ptr<Node> m_node;
std::string m_name;
uint16_t m_ifIndex;
- MacAddress m_address;
- MacAddress m_broadcast;
+ Address m_address;
+ Address m_broadcast;
+ Address m_multicast;
uint16_t m_mtu;
bool m_isUp;
bool m_isBroadcast;
bool m_isMulticast;
bool m_isPointToPoint;
Callback<void> m_linkChangeCallback;
- Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> m_receiveCallback;
+ ReceiveCallback m_receiveCallback;
};
}; // namespace ns3
--- a/src/node/node-list.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node-list.cc Fri Sep 28 11:59:46 2007 +0100
@@ -20,25 +20,42 @@
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
*/
-#include "ns3/array-trace-resolver.h"
-#include "ns3/trace-root.h"
+#include "ns3/composite-trace-resolver.h"
#include "ns3/simulator.h"
#include "ns3/simulation-singleton.h"
#include "node-list.h"
#include "node.h"
-namespace {
-static class Initialization
+namespace ns3 {
+
+NodeListIndex::NodeListIndex ()
+ : m_index (0)
+{}
+NodeListIndex::NodeListIndex (uint32_t index)
+ : m_index (index)
+{}
+void
+NodeListIndex::Print (std::ostream &os)
{
-public:
- Initialization ()
- {
- ns3::TraceRoot::Register ("nodes", ns3::MakeCallback (&ns3::NodeList::CreateTraceResolver));
- }
-} g_initialization;
+ os << "nodeid=" << m_index;
+}
+uint16_t
+NodeListIndex::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<NodeListIndex> ("NodeListIndex");
+ return uid;
+}
+uint32_t
+NodeListIndex::Get (void) const
+{
+ return m_index;
+}
+std::string
+NodeListIndex::GetTypeName (void) const
+{
+ return "ns3::NodeListIndex";
}
-namespace ns3 {
/**
* The private node list used by the static-based API
@@ -50,10 +67,9 @@
~NodeListPriv ();
uint32_t Add (Ptr<Node> node);
- NodeList::Iterator Begin (void);
- NodeList::Iterator End (void);
- TraceResolver *CreateTraceResolver (TraceContext const &context);
- Node *PeekNode (uint32_t n);
+ NodeList::Iterator Begin (void) const;
+ NodeList::Iterator End (void) const;
+ Ptr<TraceResolver> GetTraceResolver (void) const;
Ptr<Node> GetNode (uint32_t n);
uint32_t GetNNodes (void);
@@ -85,12 +101,12 @@
}
NodeList::Iterator
-NodeListPriv::Begin (void)
+NodeListPriv::Begin (void) const
{
return m_nodes.begin ();
}
NodeList::Iterator
-NodeListPriv::End (void)
+NodeListPriv::End (void) const
{
return m_nodes.end ();
}
@@ -99,11 +115,6 @@
{
return m_nodes.size ();
}
-Node *
-NodeListPriv::PeekNode (uint32_t n)
-{
- return PeekPointer (m_nodes[n]);
-}
Ptr<Node>
NodeListPriv::GetNode (uint32_t n)
@@ -112,14 +123,11 @@
}
-TraceResolver *
-NodeListPriv::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+NodeListPriv::GetTraceResolver (void) const
{
- ArrayTraceResolver<Node> *resolver =
- new ArrayTraceResolver<Node>
- (context,
- MakeCallback (&NodeListPriv::GetNNodes, this),
- MakeCallback (&NodeListPriv::PeekNode, this));
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ resolver->AddArray ("nodes", Begin (), End (), NodeListIndex ());
return resolver;
}
@@ -147,17 +155,30 @@
{
return SimulationSingleton<NodeListPriv>::Get ()->End ();
}
-TraceResolver *
-NodeList::CreateTraceResolver (TraceContext const &context)
-{
- return SimulationSingleton<NodeListPriv>::Get ()->CreateTraceResolver (context);
-}
Ptr<Node>
NodeList::GetNode (uint32_t n)
{
return SimulationSingleton<NodeListPriv>::Get ()->GetNode (n);
}
-
-
+void
+NodeList::Connect (std::string name, const CallbackBase &cb)
+{
+ SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->Connect (name, cb, TraceContext ());
+}
+void
+NodeList::Disconnect (std::string name, const CallbackBase &cb)
+{
+ SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->Disconnect (name, cb);
+}
+void
+NodeList::TraceAll (std::ostream &os)
+{
+ SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->TraceAll (os, TraceContext ());
+}
+Ptr<TraceResolver>
+NodeList::GetTraceResolver (void)
+{
+ return SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ();
+}
}//namespace ns3
--- a/src/node/node-list.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node-list.h Fri Sep 28 11:59:46 2007 +0100
@@ -23,14 +23,34 @@
#define NODE_LIST_H
#include <vector>
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
#include "ns3/ptr.h"
namespace ns3 {
class Node;
+class CallbackBase;
class TraceResolver;
-class TraceContext;
+
+/**
+ * \brief hold in a TraceContext the index of a node within a NodeList.
+ */
+class NodeListIndex : public TraceContextElement
+{
+public:
+ NodeListIndex ();
+ NodeListIndex (uint32_t index);
+ void Print (std::ostream &os);
+ static uint16_t GetUid (void);
+ /**
+ * \returns the index of the node within the NodeList
+ */
+ uint32_t Get (void) const;
+ std::string GetTypeName (void) const;
+private:
+ uint32_t m_index;
+};
+
/**
* \brief the list of simulation nodes.
@@ -40,8 +60,7 @@
class NodeList
{
public:
- typedef ArrayTraceResolver<Node>::Index NodeIndex;
- typedef std::vector< Ptr<Node> >::iterator Iterator;
+ typedef std::vector< Ptr<Node> >::const_iterator Iterator;
/**
* \param node node to add
@@ -62,18 +81,49 @@
*/
static Iterator End (void);
/**
- * \param context trace context to use for trace resolver
- * to create.
- * \returns the requested trace resolver. The caller
- * takes ownership of the returned pointer.
- */
- static TraceResolver *CreateTraceResolver (TraceContext const &context);
-
- /**
* \param n index of requested node.
* \returns the Node associated to index n.
*/
static Ptr<Node> GetNode (uint32_t n);
+ /**
+ * \param name namespace regexp to match
+ * \param cb callback to connect
+ *
+ * Connect input callback to all trace sources which match
+ * the input namespace regexp.
+ * A tutorial which explains how to use this method can be
+ * found in the \ref tracing section.
+ */
+ static void Connect (std::string name, const CallbackBase &cb);
+ /**
+ * \param name namespace regexp to match
+ * \param cb callback to connect
+ *
+ * Disconnect input callback from all trace sources which match
+ * the input namespace regexp.
+ */
+ static void Disconnect (std::string name, const CallbackBase &cb);
+ /**
+ * \param os the output stream on which the content of each trace event should be
+ * dumped in ascii format.
+ *
+ * Enable _every_ trace source accessible from the NodeList and write to the
+ * output stream an ascii representation of each trace event.
+ * This method is very useful to get quick-and-dirty trace output from a
+ * simulation.
+ * More fancy tracing output could be generated with the ns3::NodeList::Connect
+ * method as explained in the \ref tracing section.
+ */
+ static void TraceAll (std::ostream &os);
+ /**
+ * \returns the trace resolver used by the ns3::NodeList::Connect,
+ * ns3::NodeList::Disconnect, and, ns3::NodeList::TraceAll methods.
+ *
+ * Using this method directly is not really recommended. Instead, users
+ * should use one of the three methods ns3::NodeList::Connect,
+ * ns3::NodeList::Disconnect, or, ns3::NodeList::TraceAll methods.
+ */
+ static Ptr<TraceResolver> GetTraceResolver (void);
};
}//namespace ns3
--- a/src/node/node.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,60 +1,98 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Implement the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "node.h"
#include "node-list.h"
#include "net-device.h"
#include "application.h"
+#include "packet-socket-factory.h"
#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
namespace ns3{
const InterfaceId Node::iid = MakeInterfaceId ("Node", Object::iid);
+NodeNetDeviceIndex::NodeNetDeviceIndex ()
+ : m_index (0)
+{}
+NodeNetDeviceIndex::NodeNetDeviceIndex (uint32_t index)
+ : m_index (index)
+{}
+uint32_t
+NodeNetDeviceIndex::Get (void) const
+{
+ return m_index;
+}
+void
+NodeNetDeviceIndex::Print (std::ostream &os) const
+{
+ os << "device=" << m_index;
+}
+uint16_t
+NodeNetDeviceIndex::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<NodeNetDeviceIndex> ("NodeNetDeviceIndex");
+ return uid;
+}
+std::string
+NodeNetDeviceIndex::GetTypeName (void) const
+{
+ return "ns3::NodeNetDeviceIndex";
+}
+
+
+
Node::Node()
: m_id(0),
m_sid(0)
{
- SetInterfaceId (Node::iid);
- m_id = NodeList::Add (this);
+ Construct ();
}
Node::Node(uint32_t sid)
: m_id(0),
m_sid(sid)
{
+ Construct ();
+}
+
+void
+Node::Construct (void)
+{
SetInterfaceId (Node::iid);
m_id = NodeList::Add (this);
+ Ptr<PacketSocketFactory> socketFactory = Create<PacketSocketFactory> ();
+ AddInterface (socketFactory);
}
Node::~Node ()
{}
-TraceResolver *
-Node::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Node::GetTraceResolver (void) const
{
- return DoCreateTraceResolver (context);
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ resolver->AddArray ("devices", m_devices.begin (), m_devices.end (), NodeNetDeviceIndex ());
+ resolver->SetParentResolver (Object::GetTraceResolver ());
+ return resolver;
}
uint32_t
@@ -74,8 +112,9 @@
{
uint32_t index = m_devices.size ();
m_devices.push_back (device);
- DoAddDevice (device);
device->SetIfIndex(index);
+ device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this));
+ NotifyDeviceAdded (device);
return index;
}
Ptr<NetDevice>
@@ -107,8 +146,8 @@
return m_applications.size ();
}
-
-void Node::DoDispose()
+void
+Node::DoDispose()
{
for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
i != m_devices.end (); i++)
@@ -129,4 +168,56 @@
Object::DoDispose ();
}
+void
+Node::NotifyDeviceAdded (Ptr<NetDevice> device)
+{}
+
+void
+Node::RegisterProtocolHandler (ProtocolHandler handler,
+ uint16_t protocolType,
+ Ptr<NetDevice> device)
+{
+ struct Node::ProtocolHandlerEntry entry;
+ entry.handler = handler;
+ entry.protocol = protocolType;
+ entry.device = device;
+ m_handlers.push_back (entry);
+}
+
+void
+Node::UnregisterProtocolHandler (ProtocolHandler handler)
+{
+ for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+ i != m_handlers.end (); i++)
+ {
+ if (i->handler.IsEqual (handler))
+ {
+ m_handlers.erase (i);
+ break;
+ }
+ }
+}
+
+bool
+Node::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from)
+{
+ bool found = false;
+ for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+ i != m_handlers.end (); i++)
+ {
+ if (i->device == 0 ||
+ (i->device != 0 && i->device == device))
+ {
+ if (i->protocol == 0 ||
+ i->protocol == protocol)
+ {
+ i->handler (device, packet, protocol, from);
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
}//namespace ns3
--- a/src/node/node.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,33 +1,31 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Define the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-#ifndef I_NODE_H
-#define I_NODE_H
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef NODE_H
+#define NODE_H
#include <vector>
#include "ns3/object.h"
+#include "ns3/callback.h"
+#include "ns3/trace-context-element.h"
namespace ns3 {
@@ -35,6 +33,28 @@
class TraceResolver;
class NetDevice;
class Application;
+class Packet;
+class Address;
+class CompositeTraceResolver;
+
+/**
+ * \brief hold in a TraceContext the index of a NetDevice within a Node
+ */
+class NodeNetDeviceIndex : public TraceContextElement
+{
+public:
+ NodeNetDeviceIndex ();
+ NodeNetDeviceIndex (uint32_t index);
+ /**
+ * \returns the index of the NetDevice within its container Node.
+ */
+ uint32_t Get (void) const;
+ void Print (std::ostream &os) const;
+ std::string GetTypeName (void) const;
+ static uint16_t GetUid (void);
+private:
+ uint32_t m_index;
+};
/**
* \brief A network Node.
@@ -58,18 +78,18 @@
public:
static const InterfaceId iid;
- virtual ~Node();
-
+ /**
+ * Must be invoked by subclasses only.
+ */
+ Node();
/**
- * \param context the trace context for the TraceResolver to create
- * \returns a newly-created TraceResolver. The caller takes
- * ownership of the returned pointer.
+ * \param systemId a unique integer used for parallel simulations.
*
- * Request the Node to create a trace resolver. This method
- * could be used directly by a user who needs access to very low-level
- * trace configuration.
+ * Must be invoked by subclasses only.
*/
- TraceResolver *CreateTraceResolver (TraceContext const &context);
+ Node(uint32_t systemId);
+
+ virtual ~Node();
/**
* \returns the unique id of this node.
@@ -93,11 +113,15 @@
* Associate this device to this node.
* This method is called automatically from NetDevice::NetDevice
* so the user has little reason to call this method himself.
+ * The index returned is always non-zero.
*/
uint32_t AddDevice (Ptr<NetDevice> device);
/**
* \param index the index of the requested NetDevice
* \returns the requested NetDevice associated to this Node.
+ *
+ * The indexes used by the GetDevice method start at one and
+ * end at GetNDevices ()
*/
Ptr<NetDevice> GetDevice (uint32_t index) const;
/**
@@ -127,17 +151,35 @@
*/
uint32_t GetNApplications (void) const;
-protected:
/**
- * Must be invoked by subclasses only.
+ * A protocol handler
*/
- Node();
+ typedef Callback<void,Ptr<NetDevice>, const Packet &,uint16_t,const Address &> ProtocolHandler;
/**
- * \param systemId a unique integer used for parallel simulations.
+ * \param handler the handler to register
+ * \param protocolType the type of protocol this handler is
+ * interested in. This protocol type is a so-called
+ * EtherType, as registered here:
+ * http://standards.ieee.org/regauth/ethertype/eth.txt
+ * the value zero is interpreted as matching all
+ * protocols.
+ * \param device the device attached to this handler. If the
+ * value is zero, the handler is attached to all
+ * devices on this node.
+ */
+ void RegisterProtocolHandler (ProtocolHandler handler,
+ uint16_t protocolType,
+ Ptr<NetDevice> device);
+ /**
+ * \param handler the handler to unregister
*
- * Must be invoked by subclasses only.
+ * After this call returns, the input handler will never
+ * be invoked anymore.
*/
- Node(uint32_t systemId);
+ void UnregisterProtocolHandler (ProtocolHandler handler);
+
+protected:
+ virtual Ptr<TraceResolver> GetTraceResolver (void) const;
/**
* The dispose method. Subclasses must override this method
* and must chain up to it by calling Node::DoDispose at the
@@ -145,13 +187,7 @@
*/
virtual void DoDispose (void);
private:
- /**
- * \param context the trace context
- * \returns a trace resolver to the user. The user must delete it.
- *
- * Subclasses must implement this method.
- */
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
+
/**
* \param device the device added to this Node.
*
@@ -160,14 +196,25 @@
* at this point to setup the node's receive function for
* the NetDevice packets.
*/
- virtual void DoAddDevice (Ptr<NetDevice> device) const = 0;
+ virtual void NotifyDeviceAdded (Ptr<NetDevice> device);
+
+ bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from);
+ void Construct (void);
+ struct ProtocolHandlerEntry {
+ ProtocolHandler handler;
+ uint16_t protocol;
+ Ptr<NetDevice> device;
+ };
+ typedef std::vector<struct Node::ProtocolHandlerEntry> ProtocolHandlerList;
uint32_t m_id; // Node id for this node
uint32_t m_sid; // System id for this node
std::vector<Ptr<NetDevice> > m_devices;
std::vector<Ptr<Application> > m_applications;
+ ProtocolHandlerList m_handlers;
};
} //namespace ns3
-#endif /* I_NODE_H */
+#endif /* NODE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "packet-socket-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+PacketSocketAddress::PacketSocketAddress ()
+{}
+void
+PacketSocketAddress::SetProtocol (uint16_t protocol)
+{
+ m_protocol = protocol;
+}
+void
+PacketSocketAddress::SetAllDevices (void)
+{
+ m_isSingleDevice = false;
+ m_device = 0;
+}
+void
+PacketSocketAddress::SetSingleDevice (uint32_t index)
+{
+ m_isSingleDevice = true;
+ m_device = index;
+}
+void
+PacketSocketAddress::SetPhysicalAddress (const Address address)
+{
+ m_address = address;
+}
+
+uint16_t
+PacketSocketAddress::GetProtocol (void) const
+{
+ return m_protocol;
+}
+bool
+PacketSocketAddress::IsSingleDevice (void) const
+{
+ return m_isSingleDevice;
+}
+uint32_t
+PacketSocketAddress::GetSingleDevice (void) const
+{
+ return m_device;
+}
+Address
+PacketSocketAddress::GetPhysicalAddress (void) const
+{
+ return m_address;
+}
+
+PacketSocketAddress::operator Address () const
+{
+ return ConvertTo ();
+}
+
+Address
+PacketSocketAddress::ConvertTo (void) const
+{
+ Address address;
+ uint8_t buffer[Address::MAX_SIZE];
+ buffer[0] = m_protocol & 0xff;
+ buffer[1] = (m_protocol >> 8) & 0xff;
+ buffer[2] = (m_device >> 24) & 0xff;
+ buffer[3] = (m_device >> 16) & 0xff;
+ buffer[4] = (m_device >> 8) & 0xff;
+ buffer[5] = (m_device >> 0) & 0xff;
+ buffer[6] = m_isSingleDevice?1:0;
+ uint32_t copied = m_address.CopyAllTo (buffer + 7, Address::MAX_SIZE - 7);
+ return Address (GetType (), buffer, 7 + copied);
+}
+PacketSocketAddress
+PacketSocketAddress::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (IsMatchingType (address));
+ uint8_t buffer[Address::MAX_SIZE];
+ address.CopyTo (buffer);
+ uint16_t protocol = buffer[0] | (buffer[1] << 8);
+ uint32_t device = 0;
+ device |= buffer[2];
+ device <<= 8;
+ device |= buffer[3];
+ device <<= 8;
+ device |= buffer[4];
+ device <<= 8;
+ device |= buffer[5];
+ bool isSingleDevice = (buffer[6] == 1)?true:false;
+ Address physical;
+ physical.CopyAllFrom (buffer + 7, Address::MAX_SIZE - 7);
+ PacketSocketAddress ad;
+ ad.SetProtocol (protocol);
+ if (isSingleDevice)
+ {
+ ad.SetSingleDevice (device);
+ }
+ else
+ {
+ ad.SetAllDevices ();
+ }
+ ad.SetPhysicalAddress (physical);
+ return ad;
+}
+bool
+PacketSocketAddress::IsMatchingType (const Address &address)
+{
+ return address.IsMatchingType (GetType ());
+}
+uint8_t
+PacketSocketAddress::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_SOCKET_ADDRESS_H
+#define PACKET_SOCKET_ADDRESS_H
+
+#include "ns3/ptr.h"
+#include "address.h"
+#include "mac48-address.h"
+#include "mac64-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+class NetDevice;
+
+class PacketSocketAddress
+{
+ public:
+ PacketSocketAddress ();
+ void SetProtocol (uint16_t protocol);
+
+ void SetAllDevices (void);
+ void SetSingleDevice (uint32_t device);
+ void SetPhysicalAddress (const Address address);
+
+ uint16_t GetProtocol (void) const;
+ uint32_t GetSingleDevice (void) const;
+ bool IsSingleDevice (void) const;
+ Address GetPhysicalAddress (void) const;
+
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ operator Address () const;
+ /**
+ * \param address a polymorphic address
+ *
+ * Convert a polymorphic address to an Mac48Address instance.
+ * The conversion performs a type check.
+ */
+ static PacketSocketAddress ConvertFrom (const Address &address);
+ /**
+ * \returns true if the address matches, false otherwise.
+ */
+ static bool IsMatchingType (const Address &address);
+ private:
+ static uint8_t GetType (void);
+ Address ConvertTo (void) const;
+ uint16_t m_protocol;
+ bool m_isSingleDevice;
+ uint32_t m_device;
+ Address m_address;
+};
+
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_ADDRESS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,41 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#include "packet-socket-factory.h"
+#include "node.h"
+#include "packet-socket.h"
+
+namespace ns3 {
+
+const InterfaceId PacketSocketFactory::iid = MakeInterfaceId ("Packet",
+ SocketFactory::iid);
+
+PacketSocketFactory::PacketSocketFactory ()
+{
+ SetInterfaceId (PacketSocketFactory::iid);
+}
+
+Ptr<Socket> PacketSocketFactory::CreateSocket (void)
+{
+ Ptr<Node> node = QueryInterface<Node> (Node::iid);
+ Ptr<PacketSocket> socket = Create<PacketSocket> (node);
+ return socket;
+}
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,51 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#ifndef PACKET_SOCKET_FACTORY_H
+#define PACKET_SOCKET_FACTORY_H
+
+#include "socket-factory.h"
+
+namespace ns3 {
+
+class Socket;
+
+/**
+ * This can be used as an interface in a node in order for the node to
+ * generate PacketSockets that can connect to net devices.
+ */
+class PacketSocketFactory : public SocketFactory
+{
+public:
+ static const InterfaceId iid; /// Interface identifier
+
+ PacketSocketFactory ();
+
+ /**
+ * Creates a PacketSocket and returns a pointer to it.
+ *
+ * \return a pointer to the created socket
+ */
+ virtual Ptr<Socket> CreateSocket (void);
+};
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_FACTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "packet-socket.h"
+#include "packet-socket-address.h"
+#include "ns3/log.h"
+#include "ns3/node.h"
+
+NS_LOG_COMPONENT_DEFINE ("PacketSocket");
+
+namespace ns3 {
+
+PacketSocket::PacketSocket (Ptr<Node> node)
+ : m_node (node)
+{
+ NS_LOG_FUNCTION;
+ Init();
+}
+
+void
+PacketSocket::Init()
+{
+ NS_LOG_FUNCTION;
+ m_state = STATE_OPEN;
+ m_shutdownSend = false;
+ m_shutdownRecv = false;
+ m_errno = ERROR_NOTERROR;
+}
+
+PacketSocket::~PacketSocket ()
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+PacketSocket::DoDispose (void)
+{
+ NS_LOG_FUNCTION;
+ m_device = 0;
+}
+
+enum Socket::SocketErrno
+PacketSocket::GetErrno (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_errno;
+}
+
+Ptr<Node>
+PacketSocket::GetNode (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_node;
+}
+
+int
+PacketSocket::Bind (void)
+{
+ NS_LOG_FUNCTION;
+ PacketSocketAddress address;
+ address.SetProtocol (0);
+ address.SetAllDevices ();
+ return DoBind (address);
+}
+
+int
+PacketSocket::Bind (const Address &address)
+{
+ NS_LOG_FUNCTION;
+ if (!PacketSocketAddress::IsMatchingType (address))
+ {
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (address);
+ return DoBind (ad);
+}
+
+int
+PacketSocket::DoBind (const PacketSocketAddress &address)
+{
+ NS_LOG_FUNCTION;
+ if (m_state == STATE_BOUND ||
+ m_state == STATE_CONNECTED)
+ {
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ Ptr<NetDevice> dev ;
+ if (address.IsSingleDevice ())
+ {
+ dev = 0;
+ }
+ else
+ {
+ m_node->GetDevice (address.GetSingleDevice ());
+ }
+ m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
+ address.GetProtocol (), dev);
+ m_state = STATE_BOUND;
+ m_protocol = address.GetProtocol ();
+ m_isSingleDevice = address.IsSingleDevice ();
+ m_device = address.GetSingleDevice ();
+ return 0;
+}
+
+int
+PacketSocket::ShutdownSend (void)
+{
+ NS_LOG_FUNCTION;
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ m_shutdownSend = true;
+ return 0;
+}
+
+int
+PacketSocket::ShutdownRecv (void)
+{
+ NS_LOG_FUNCTION;
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ m_shutdownRecv = false;
+ return 0;
+}
+
+int
+PacketSocket::Close(void)
+{
+ NS_LOG_FUNCTION;
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ m_state = STATE_CLOSED;
+ NotifyCloseCompleted ();
+ return 0;
+}
+
+int
+PacketSocket::Connect(const Address &ad)
+{
+ NS_LOG_FUNCTION;
+ PacketSocketAddress address;
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ goto error;
+ }
+ if (m_state == STATE_OPEN)
+ {
+ // connect should happen _after_ bind.
+ m_errno = ERROR_INVAL; // generic error condition.
+ goto error;
+ }
+ if (m_state == STATE_CONNECTED)
+ {
+ m_errno = ERROR_ISCONN;
+ goto error;
+ }
+ if (!PacketSocketAddress::IsMatchingType (ad))
+ {
+ m_errno = ERROR_AFNOSUPPORT;
+ goto error;
+ }
+ m_destAddr = ad;
+ m_state = STATE_CONNECTED;
+ NotifyConnectionSucceeded ();
+ return 0;
+ error:
+ NotifyConnectionFailed ();
+ return -1;
+}
+
+int
+PacketSocket::Send (const Packet &p)
+{
+ NS_LOG_FUNCTION;
+ if (m_state == STATE_OPEN ||
+ m_state == STATE_BOUND)
+ {
+ m_errno = ERROR_NOTCONN;
+ return -1;
+ }
+ return SendTo (m_destAddr, p);
+}
+
+int
+PacketSocket::SendTo(const Address &address, const Packet &p)
+{
+ NS_LOG_FUNCTION;
+ PacketSocketAddress ad;
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ if (m_state == STATE_OPEN)
+ {
+ // XXX should return another error here.
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ if (m_shutdownSend)
+ {
+ m_errno = ERROR_SHUTDOWN;
+ return -1;
+ }
+ if (!PacketSocketAddress::IsMatchingType (address))
+ {
+ m_errno = ERROR_AFNOSUPPORT;
+ return -1;
+ }
+ ad = PacketSocketAddress::ConvertFrom (address);
+
+ bool error = false;
+ Address dest = ad.GetPhysicalAddress ();
+ if (ad.IsSingleDevice ())
+ {
+ Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
+ if (!device->Send (p, dest, ad.GetProtocol ()))
+ {
+ error = true;
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
+ {
+ Ptr<NetDevice> device = m_node->GetDevice (i);
+ if (!device->Send (p, dest, ad.GetProtocol ()))
+ {
+ error = true;
+ }
+ }
+ }
+ if (!error)
+ {
+ NotifyDataSent (p.GetSize ());
+ }
+
+ if (error)
+ {
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void
+PacketSocket::ForwardUp (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from)
+{
+ NS_LOG_FUNCTION;
+ if (m_shutdownRecv)
+ {
+ return;
+ }
+
+ Packet p = packet;
+
+ PacketSocketAddress address;
+ address.SetPhysicalAddress (from);
+ address.SetSingleDevice (device->GetIfIndex ());
+ address.SetProtocol (protocol);
+
+ NS_LOG_LOGIC ("UID is " << packet.GetUid() << " PacketSocket " << this);
+ NotifyDataReceived (p, address);
+}
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>,
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_SOCKET_H
+#define PACKET_SOCKET_H
+
+#include <stdint.h>
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "ns3/socket.h"
+
+namespace ns3 {
+
+class Node;
+class Packet;
+class NetDevice;
+class PacketSocketAddress;
+
+/**
+ * \brief A PacketSocket is a link between an application and a net device.
+ *
+ * A PacketSocket can be used to connect an application to a net
+ * device. The application provides the buffers of data, the socket
+ * conserts them to a raw packet and the net device then adds the
+ * protocol specific headers and trailers. This socket type
+ * is very similar to the linux and BSD "packet" sockets.
+ *
+ * Here is a summary of the semantics of this class:
+ * - Bind: Bind uses only the protocol and device fields of the
+ * PacketSocketAddress. If none are provided, Bind uses
+ * zero for both, which means that the socket is bound
+ * to all protocols on all devices on the node.
+ *
+ * - Connect: uses only the protocol, device and "physical address"
+ * field of the PacketSocketAddress. It is used to set the default
+ * destination address for outgoing packets.
+ *
+ * - Send: send the input packet to the underlying NetDevices
+ * with the default destination address. The socket must
+ * be bound and connected.
+ *
+ * - SendTo: uses the protocol, device, and "physical address"
+ * fields of the PacketSocketAddress. The device value is
+ * used to specialize the packet transmission to a single
+ * device, the protocol value specifies the protocol of this
+ * packet only and the "physical address" field is used to override the
+ * default destination address. The socket must be bound.
+ *
+ * - Recv: The address represents the address of the packer originator.
+ * The fields "physical address", device, and protocol are filled.
+ *
+ * - Accept: not allowed
+ */
+class PacketSocket : public Socket
+{
+public:
+ PacketSocket (Ptr<Node> node);
+ virtual ~PacketSocket ();
+
+ virtual enum SocketErrno GetErrno (void) const;
+ virtual Ptr<Node> GetNode (void) const;
+ virtual int Bind (void);
+ virtual int Bind (const Address & address);
+ virtual int Close (void);
+ virtual int ShutdownSend (void);
+ virtual int ShutdownRecv (void);
+ virtual int Connect(const Address &address);
+ virtual int Send (const Packet &p);
+ virtual int SendTo(const Address &address,const Packet &p);
+
+
+private:
+
+private:
+ void Init (void);
+ void ForwardUp (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from);
+ int DoBind (const PacketSocketAddress &address);
+ virtual void DoDispose (void);
+
+ enum State {
+ STATE_OPEN,
+ STATE_BOUND, // open and bound
+ STATE_CONNECTED, // open, bound and connected
+ STATE_CLOSED
+ };
+ Ptr<Node> m_node;
+ enum SocketErrno m_errno;
+ bool m_shutdownSend;
+ bool m_shutdownRecv;
+ enum State m_state;
+ uint16_t m_protocol;
+ bool m_isSingleDevice;
+ uint32_t m_device;
+ Address m_destAddr; /// Default destination address
+};
+
+}//namespace ns3
+
+#endif /* PACKET_SOCKET_H */
+
+
--- a/src/node/queue.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/queue.cc Fri Sep 28 11:59:46 2007 +0100
@@ -17,13 +17,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "ns3/debug.h"
+#include "ns3/log.h"
#include "ns3/composite-trace-resolver.h"
#include "ns3/default-value.h"
#include "ns3/component-manager.h"
#include "queue.h"
-NS_DEBUG_COMPONENT_DEFINE ("Queue");
+NS_LOG_COMPONENT_DEFINE ("Queue");
namespace ns3 {
@@ -31,6 +31,72 @@
static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue",
Queue::iid, "DropTailQueue");
+
+std::string
+QueueTraceType::GetTypeName (void) const
+{
+ NS_LOG_FUNCTION;
+ return "ns3::QueueTraceType";
+}
+
+uint16_t
+QueueTraceType::GetUid (void)
+{
+ NS_LOG_FUNCTION;
+ static uint16_t uid = AllocateUid<QueueTraceType> ("QueueTraceType");
+ return uid;
+}
+
+QueueTraceType::QueueTraceType ()
+ : m_type (QueueTraceType::ENQUEUE)
+{
+ NS_LOG_FUNCTION;
+}
+
+QueueTraceType::QueueTraceType (enum Type type)
+ : m_type (type)
+{
+ NS_LOG_FUNCTION;
+}
+
+bool
+QueueTraceType::IsEnqueue (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_type == ENQUEUE;
+}
+
+bool
+QueueTraceType::IsDequeue (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_type == DEQUEUE;
+}
+
+bool
+QueueTraceType::IsDrop (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_type == DROP;
+}
+
+void
+QueueTraceType::Print (std::ostream &os) const
+{
+ os << "queue-";
+ switch (m_type) {
+ case QueueTraceType::ENQUEUE:
+ os << "enqueue";
+ break;
+ case QueueTraceType::DEQUEUE:
+ os << "dequeue";
+ break;
+ case QueueTraceType::DROP:
+ os << "drop";
+ break;
+ }
+}
+
Queue::Queue() :
m_nBytes(0),
m_nTotalReceivedBytes(0),
@@ -39,31 +105,42 @@
m_nTotalDroppedBytes(0),
m_nTotalDroppedPackets(0)
{
+ NS_LOG_FUNCTION;
SetInterfaceId (Queue::iid);
- NS_DEBUG("Queue::Queue ()");
}
Queue::~Queue()
{
- NS_DEBUG("Queue::~Queue ()");
+ NS_LOG_FUNCTION;
}
-TraceResolver *
-Queue::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Queue::GetTraceResolver (void) const
{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- resolver->Add ("enqueue", m_traceEnqueue, Queue::ENQUEUE);
- resolver->Add ("dequeue", m_traceDequeue, Queue::DEQUEUE);
- resolver->Add ("drop", m_traceDrop, Queue::DROP);
+ NS_LOG_FUNCTION;
+ Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ resolver->AddSource ("enqueue",
+ TraceDoc ("store packet in queue",
+ "const Packet &", "packet queued"),
+ m_traceEnqueue, QueueTraceType (QueueTraceType::ENQUEUE));
+ resolver->AddSource ("dequeue",
+ TraceDoc ("remove packet from queue",
+ "const Packet &", "packet dequeued"),
+ m_traceDequeue, QueueTraceType (QueueTraceType::DEQUEUE));
+ resolver->AddSource ("drop",
+ TraceDoc ("drop packet from queue",
+ "const Packet &", "packet dropped"),
+ m_traceDrop, QueueTraceType (QueueTraceType::DROP));
+ resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}
bool
Queue::Enqueue (const Packet& p)
{
- NS_DEBUG("Queue::Enqueue (" << &p << ")");
-
- NS_DEBUG("Queue::Enqueue (): m_traceEnqueue (p)");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
+ NS_LOG_LOGIC ("m_traceEnqueue (p)");
m_traceEnqueue (p);
@@ -79,7 +156,8 @@
bool
Queue::Dequeue (Packet &p)
{
- NS_DEBUG("Queue::Dequeue (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
bool retval = DoDequeue (p);
@@ -91,7 +169,7 @@
NS_ASSERT (m_nBytes >= 0);
NS_ASSERT (m_nPackets >= 0);
- NS_DEBUG("Queue::Dequeue (): m_traceDequeue (p)");
+ NS_LOG_LOGIC("m_traceDequeue (p)");
const Packet packet = p;
m_traceDequeue (packet);
@@ -103,16 +181,15 @@
void
Queue::DequeueAll (void)
{
- NS_DEBUG("Queue::DequeueAll ()");
-
- NS_ASSERT (!"Don't know what to do with dequeued packets!");
+ NS_LOG_FUNCTION;
+ NS_ASSERT_MSG (0, "Don't know what to do with dequeued packets!");
}
bool
Queue::Peek (Packet &p)
{
- NS_DEBUG("Queue::Peek (" << &p << ")");
-
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
return DoPeek (p);
}
@@ -120,66 +197,63 @@
uint32_t
Queue::GetNPackets (void)
{
- NS_DEBUG("Queue::GetNPackets () <= " << m_nPackets);
-
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC ("returns " << m_nPackets);
return m_nPackets;
}
uint32_t
Queue::GetNBytes (void)
{
- NS_DEBUG("Queue::GetNBytes () <= " << m_nBytes);
-
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC (" returns " << m_nBytes);
return m_nBytes;
}
-
bool
Queue::IsEmpty (void)
{
- NS_DEBUG("Queue::IsEmpty () <= " << (m_nPackets == 0));
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC ("returns " << (m_nPackets == 0));
return m_nPackets == 0;
}
uint32_t
Queue::GetTotalReceivedBytes (void)
{
- NS_DEBUG("Queue::GetTotalReceivedBytes () <= " << m_nTotalReceivedBytes);
-
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC("returns " << m_nTotalReceivedBytes);
return m_nTotalReceivedBytes;
}
uint32_t
Queue::GetTotalReceivedPackets (void)
{
- NS_DEBUG("Queue::GetTotalReceivedPackets () <= " << m_nTotalReceivedPackets);
-
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC ("returns " << m_nTotalReceivedPackets);
return m_nTotalReceivedPackets;
}
uint32_t
Queue:: GetTotalDroppedBytes (void)
{
- NS_DEBUG(
- "Queue::GetTotalDroppedBytes () <= " << m_nTotalDroppedBytes
- );
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC ("returns " << m_nTotalDroppedBytes);
return m_nTotalDroppedBytes;
}
uint32_t
Queue::GetTotalDroppedPackets (void)
{
- NS_DEBUG(
- "Queue::GetTotalDroppedPackets () <= " << m_nTotalDroppedPackets);
-
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC("returns " << m_nTotalDroppedPackets);
return m_nTotalDroppedPackets;
}
void
Queue::ResetStatistics (void)
{
- NS_DEBUG("Queue::ResetStatistics ()");
-
+ NS_LOG_FUNCTION;
m_nTotalReceivedBytes = 0;
m_nTotalReceivedPackets = 0;
m_nTotalDroppedBytes = 0;
@@ -189,18 +263,20 @@
void
Queue::Drop (const Packet& p)
{
- NS_DEBUG("Queue::Drop (" << &p << ")");
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << &p << ")");
m_nTotalDroppedPackets++;
m_nTotalDroppedBytes += p.GetSize ();
- NS_DEBUG("Queue::Drop (): m_traceDrop (p)");
+ NS_LOG_LOGIC ("m_traceDrop (p)");
m_traceDrop (p);
}
Ptr<Queue>
Queue::CreateDefault (void)
{
+ NS_LOG_FUNCTION;
ClassId classId = g_classIdDefaultValue.GetValue ();
Ptr<Queue> queue = ComponentManager::Create<Queue> (classId, Queue::iid);
return queue;
--- a/src/node/queue.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/queue.h Fri Sep 28 11:59:46 2007 +0100
@@ -31,12 +31,46 @@
#include "ns3/object.h"
#include "ns3/callback-trace-source.h"
#include "ns3/trace-resolver.h"
+#include "ns3/trace-context-element.h"
namespace ns3 {
class StringEnumDefaultValue;
/**
+ * \brief hold in a TraceContext the type of a trace source
+ */
+class QueueTraceType : public TraceContextElement
+{
+public:
+ enum Type {
+ ENQUEUE,
+ DEQUEUE,
+ DROP
+ };
+ static uint16_t GetUid (void);
+ QueueTraceType ();
+ QueueTraceType (enum Type type);
+ /**
+ * \returns true if this is an enqueue event, false otherwise.
+ */
+ bool IsEnqueue (void) const;
+ /**
+ * \returns true if this is a dequeue event, false otherwise.
+ */
+ bool IsDequeue (void) const;
+ /**
+ * \returns true if this is a drop event, false otherwise.
+ */
+ bool IsDrop (void) const;
+ void Print (std::ostream &os) const;
+ std::string GetTypeName (void) const;
+private:
+ enum Type m_type;
+};
+
+
+/**
* \brief Abstract base class for packet Queues
*
* This class defines the base APIs for packet queues in the ns-3 system
@@ -46,15 +80,8 @@
public:
static const InterfaceId iid;
- enum TraceType {
- ENQUEUE,
- DEQUEUE,
- DROP,
- };
Queue ();
virtual ~Queue ();
-
- TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \return true if the queue is empty; false otherwise
@@ -151,6 +178,7 @@
virtual bool DoPeek (Packet &p) = 0;
protected:
+ Ptr<TraceResolver> GetTraceResolver (void) const;
// called by subclasses to notify parent of packet drops.
void Drop (const Packet& p);
--- a/src/node/socket.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/socket.cc Fri Sep 28 11:59:46 2007 +0100
@@ -1,81 +1,176 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ * 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "ns3/log.h"
+#include "ns3/packet.h"
#include "socket.h"
+NS_LOG_COMPONENT_DEFINE ("Socket");
+
namespace ns3 {
Socket::~Socket ()
-{}
+{
+ NS_LOG_FUNCTION;
+}
+
+void
+Socket::SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted)
+{
+ NS_LOG_FUNCTION;
+ m_closeCompleted = closeCompleted;
+}
+
+void
+Socket::SetConnectCallback (
+ Callback<void, Ptr<Socket> > connectionSucceeded,
+ Callback<void, Ptr<Socket> > connectionFailed,
+ Callback<void, Ptr<Socket> > halfClose)
+{
+ NS_LOG_FUNCTION;
+ m_connectionSucceeded = connectionSucceeded;
+ m_connectionFailed = connectionFailed;
+ m_halfClose = halfClose;
+}
void
-Socket::Close(Callback<void, Ptr<Socket> > closeCompleted)
+Socket::SetAcceptCallback (
+ Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+ Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+ Callback<void, Ptr<Socket> > closeRequested)
+{
+ NS_LOG_FUNCTION;
+ m_connectionRequest = connectionRequest;
+ m_newConnectionCreated = newConnectionCreated;
+ m_closeRequested = closeRequested;
+}
+
+void
+Socket::SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent)
+{
+ NS_LOG_FUNCTION;
+ m_dataSent = dataSent;
+}
+
+void
+Socket::SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData)
{
- DoClose (closeCompleted);
+ NS_LOG_FUNCTION;
+ m_receivedData = receivedData;
+}
+
+void
+Socket::NotifyCloseCompleted (void)
+{
+ NS_LOG_FUNCTION;
+ if (!m_closeCompleted.IsNull ())
+ {
+ m_closeCompleted (this);
+ }
+}
+
+void
+Socket::NotifyConnectionSucceeded (void)
+{
+ NS_LOG_FUNCTION;
+ if (!m_connectionSucceeded.IsNull ())
+ {
+ m_connectionSucceeded (this);
+ }
}
void
-Socket::Connect(const Ipv4Address & address,
- uint16_t portNumber,
- Callback<void, Ptr<Socket> > connectionSucceeded,
- Callback<void, Ptr<Socket> > connectionFailed,
- Callback<void, Ptr<Socket> > halfClose)
+Socket::NotifyConnectionFailed (void)
{
- DoConnect (address, portNumber, connectionSucceeded, connectionFailed, halfClose);
+ NS_LOG_FUNCTION;
+ if (!m_connectionFailed.IsNull ())
+ {
+ m_connectionFailed (this);
+ }
}
-int
-Socket::Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- Callback<void, Ptr<Socket> > closeRequested)
-{
- return DoAccept (connectionRequest, newConnectionCreated, closeRequested);
-}
-int
-Socket::Send (const uint8_t* buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent)
+
+void
+Socket::NotifyHalfClose (void)
{
- return DoSend (buffer, size, dataSent);
+ NS_LOG_FUNCTION;
+ if (!m_halfClose.IsNull ())
+ {
+ m_halfClose (this);
+ }
}
-int
-Socket::SendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent)
+
+bool
+Socket::NotifyConnectionRequest (const Address &from)
{
- return DoSendTo (address, port, buffer, size, dataSent);
-}
-void
-Socket::Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
- DoRecv (callback);
-}
-void
-Socket::RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
- DoRecvDummy (callback);
+ NS_LOG_FUNCTION;
+ if (!m_connectionRequest.IsNull ())
+ {
+ return m_connectionRequest (this, from);
+ }
+ else
+ {
+ // refuse all incomming connections by default.
+ return false;
+ }
}
+void
+Socket::NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from)
+{
+ NS_LOG_FUNCTION;
+ if (!m_newConnectionCreated.IsNull ())
+ {
+ m_newConnectionCreated (socket, from);
+ }
+}
-bool
-Socket::RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port)
-{
- return false;
-}
void
-Socket::DummyCallbackVoidSocket (Ptr<Socket> socket)
-{}
-void
-Socket::DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t)
-{}
+Socket::NotifyCloseRequested (void)
+{
+ NS_LOG_FUNCTION;
+ if (!m_closeRequested.IsNull ())
+ {
+ m_closeRequested (this);
+ }
+}
+
void
-Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t)
-{}
+Socket::NotifyDataSent (uint32_t size)
+{
+ NS_LOG_FUNCTION;
+ if (!m_dataSent.IsNull ())
+ {
+ m_dataSent (this, size);
+ }
+}
+
void
-Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t,
- const Ipv4Address &, uint16_t)
-{}
-void
-Socket::DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t)
-{}
-
+Socket::NotifyDataReceived (const Packet &p, const Address &from)
+{
+ NS_LOG_FUNCTION;
+ if (!m_receivedData.IsNull ())
+ {
+ m_receivedData (this, p, from);
+ }
+}
}//namespace ns3
--- a/src/node/socket.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/socket.h Fri Sep 28 11:59:46 2007 +0100
@@ -1,42 +1,44 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ * 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include "ns3/callback.h"
#include "ns3/ptr.h"
-#include "ipv4-address.h"
#include "ns3/object.h"
+#include "address.h"
#include <stdint.h>
namespace ns3 {
class Node;
+class Packet;
/**
* \brief Define a Socket API based on the BSD Socket API.
*
* Contrary to the original BSD socket API, this API is asynchronous:
- * it does not contain blocking calls. This API also does not use
- * the dreaded BSD sockaddr_t type. Other than that, it tries to stick
+ * it does not contain blocking calls. Other than that, it tries to stick
* to the BSD API to make it easier those who know the BSD API to use
* this API.
*/
@@ -53,6 +55,10 @@
ERROR_AGAIN,
ERROR_SHUTDOWN,
ERROR_OPNOTSUPP,
+ ERROR_AFNOSUPPORT,
+ ERROR_INVAL,
+ ERROR_BADF,
+ ERROR_NOROUTETOHOST,
SOCKET_ERRNO_LAST
};
@@ -68,53 +74,77 @@
*/
virtual Ptr<Node> GetNode (void) const = 0;
+ /**
+ * \param closeCompleted Callback invoked when the close operation is
+ * completed.
+ */
+ void SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted);
+
+ /**
+ * \param connectionSucceeded this callback is invoked when the connection request
+ * initiated by the user is successfully completed. The callback is passed
+ * back a pointer to the same socket object.
+ * \param connectionFailed this callback is invoked when the connection request
+ * initiated by the user is unsuccessfully completed. The callback is passed
+ * back a pointer to the same socket object.
+ * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
+ * other side closes the connection ? Or when I call Close ?
+ */
+ void SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
+ Callback<void, Ptr<Socket> > connectionFailed,
+ Callback<void, Ptr<Socket> > halfClose);
+ /**
+ * \brief Accept connection requests from remote hosts
+ * \param connectionRequest Callback for connection request from peer.
+ * This user callback is passed a pointer to this socket, the
+ * ip address and the port number of the connection originator.
+ * This callback must return true to accept the incoming connection,
+ * false otherwise. If the connection is accepted, the
+ * "newConnectionCreated" callback will be invoked later to give access
+ * to the user to the socket created to match this new connection. If the
+ * user does not explicitely specify this callback, all incoming
+ * connections will be refused.
+ * \param newConnectionCreated Callback for new connection: when a new
+ * is accepted, it is created and the corresponding socket is passed
+ * back to the user through this callback. This user callback is passed
+ * a pointer to the new socket, and the ip address and port number
+ * of the connection originator.
+ * \param closeRequested Callback for connection close request from peer.
+ * XXX: when is this callback invoked ?
+ */
+ void SetAcceptCallback (Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+ Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+ Callback<void, Ptr<Socket> > closeRequested);
+ void SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent);
+ /**
+ * \brief Receive data
+ * \param receivedData Invoked whenever new data is received.
+ *
+ */
+ void SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData);
+
/**
- * Allocate a free port number and
- * bind this socket to this port number on all
- * interfaces of this system.
+ * \param address the address to try to allocate
+ * \returns 0 on success, -1 on failure.
+ *
+ * Allocate a local endpoint for this socket.
+ */
+ virtual int Bind (const Address &address) = 0;
+
+ /**
+ * Allocate a local endpoint for this socket.
*
* \returns 0 on success, -1 on failure.
*/
- virtual int Bind (void) = 0;
-
- /**
- * Allocate a free port number and
- * bind this socket to this port number on the
- * specified interface.
- *
- * \param address address of interface to bind to.
- * \returns 0 on success, -1 on failure.
- */
- virtual int Bind (Ipv4Address address) = 0;
-
- /**
- * Bind this socket to this port number
- * on all interfaces of this system.
- *
- * \param port port to bind to on all interfaces
- * \returns 0 on success, -1 on failure.
- */
- virtual int Bind (uint16_t port) = 0;
-
- /**
- * Bind this socket to this port number
- * on the interface specified by address.
- *
- * \param address address of interface to bind to.
- * \param port port to bind to on specified interface
- * \returns 0 on success, -1 on failure.
- */
- virtual int Bind (Ipv4Address address, uint16_t port) = 0;
+ virtual int Bind () = 0;
/**
* \brief Close a socket.
- * \param closeCompleted Callback invoked when the close operation is
- * completed.
*
* After the Close call, the socket is no longer valid, and cannot
* safely be used for subsequent operations.
*/
- void Close(Callback<void, Ptr<Socket> > closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket));
+ virtual int Close(void) = 0;
/**
* \returns zero on success, -1 on failure.
@@ -134,127 +164,47 @@
/**
* \brief Initiate a connection to a remote host
- * \param address IP Address of remote.
- * \param portNumber Port number of remote
- * \param connectionSucceeded this callback is invoked when the connection request
- * initiated by the user is successfully completed. The callback is passed
- * back a pointer to the same socket object.
- * \param connectionFailed this callback is invoked when the connection request
- * initiated by the user is unsuccessfully completed. The callback is passed
- * back a pointer to the same socket object.
- * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
- * other side closes the connection ? Or when I call Close ?
+ * \param address Address of remote.
*/
- void Connect(const Ipv4Address & address,
- uint16_t portNumber,
- Callback<void, Ptr<Socket> > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket),
- Callback<void, Ptr<Socket> > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket),
- Callback<void, Ptr<Socket> > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket));
+ virtual int Connect(const Address &address) = 0;
/**
- * \brief Accept connection requests from remote hosts
- * \param connectionRequest Callback for connection request from peer.
- * This user callback is passed a pointer to this socket, the
- * ip address and the port number of the connection originator.
- * This callback must return true to accept the incoming connection,
- * false otherwise. If the connection is accepted, the
- * "newConnectionCreated" callback will be invoked later to give access
- * to the user to the socket created to match this new connection. If the
- * user does not explicitely specify this callback, all incoming
- * connections will be refused.
- * \param newConnectionCreated Callback for new connection: when a new
- * is accepted, it is created and the corresponding socket is passed
- * back to the user through this callback. This user callback is passed
- * a pointer to the new socket, and the ip address and port number
- * of the connection originator.
- * \param closeRequested Callback for connection close request from peer.
- * XXX: when is this callback invoked ?
- */
- int Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest =
- MakeCallback(&Socket::RefuseAllConnections),
- Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated =
- MakeCallback (&Socket::DummyCallbackVoidSocketIpv4AddressUi16),
- Callback<void, Ptr<Socket> > closeRequested = MakeCallback (&Socket::DummyCallbackVoidSocket));
-
- /**
* \brief Send data (or dummy data) to the remote host
- * \param buffer Data to send (nil if dummy data).
- * \param size Number of bytes to send.
- * \param dataSent Data sent callback.
+ * \param p packet to send
* \returns -1 in case of error or the number of bytes copied in the
* internal buffer and accepted for transmission.
*/
- int Send (const uint8_t* buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
+ virtual int Send (const Packet &p) = 0;
/**
* \brief Send data to a specified peer.
* \param address IP Address of remote host
- * \param port port number
- * \param buffer Data to send (nil if dummy data).
- * \param size Number of bytes to send.
- * \param dataSent Data sent callback.
+ * \param p packet to send
* \returns -1 in case of error or the number of bytes copied in the
* internal buffer and accepted for transmission.
*/
- int SendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
-
- /**
- * \brief Receive data
- * \param receivedData Invoked whenever new data is received.
- *
- * If you wish to transport only dummy packets, this method is not a very
- * efficient way to receive these dummy packets: it will trigger a memory
- * allocation to hold the dummy memory into a buffer which can be passed
- * to the user. Instead, consider using the RecvDummy method.
- */
- void Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receivedData =
- MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16));
-
- /**
- * \brief Receive data
- * \param receivedData Invoked whenever new data is received.
- *
- * This method is included because it is vastly more efficient than the
- * Recv method when you use dummy payload.
- */
- void RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> receivedData =
- MakeCallback (&Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16));
+ virtual int SendTo(const Address &address,const Packet &p) = 0;
-private:
- virtual void DoClose(Callback<void, Ptr<Socket> > closeCompleted) = 0;
- virtual void DoConnect(const Ipv4Address & address,
- uint16_t portNumber,
- Callback<void, Ptr<Socket> > connectionSucceeded,
- Callback<void, Ptr<Socket> > connectionFailed,
- Callback<void, Ptr<Socket> > halfClose) = 0;
- virtual int DoAccept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- Callback<void, Ptr<Socket> > closeRequested) = 0;
- virtual int DoSend (const uint8_t* buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
- virtual int DoSendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
- virtual void DoRecv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receive) = 0;
- virtual void DoRecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>) = 0;
+protected:
+ void NotifyCloseCompleted (void);
+ void NotifyConnectionSucceeded (void);
+ void NotifyConnectionFailed (void);
+ void NotifyHalfClose (void);
+ bool NotifyConnectionRequest (const Address &from);
+ void NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from);
+ void NotifyCloseRequested (void);
+ void NotifyDataSent (uint32_t size);
+ void NotifyDataReceived (const Packet &p, const Address &from);
-
- static bool RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port);
- static void DummyCallbackVoidSocket (Ptr<Socket> socket);
- static void DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t);
- static void DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t);
- static void DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t,
- const Ipv4Address &, uint16_t);
- static void DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t);
+ Callback<void,Ptr<Socket> > m_closeCompleted;
+ Callback<void, Ptr<Socket> > m_connectionSucceeded;
+ Callback<void, Ptr<Socket> > m_connectionFailed;
+ Callback<void, Ptr<Socket> > m_halfClose;
+ Callback<void, Ptr<Socket> > m_closeRequested;
+ Callback<bool, Ptr<Socket>, const Address &> m_connectionRequest;
+ Callback<void, Ptr<Socket>, const Address&> m_newConnectionCreated;
+ Callback<void, Ptr<Socket>, uint32_t> m_dataSent;
+ Callback<void, Ptr<Socket>, const Packet &,const Address&> m_receivedData;
};
} //namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/node/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -1,20 +1,20 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-def configure(conf):
- conf.env.append_value('NS3_MODULES', 'ns3-node')
-
-
def build(bld):
- node = bld.create_obj('cpp', 'shlib')
- node.name = 'ns3-node'
- node.target = node.name
- node.uselib_local = ['ns3-core', 'ns3-common', 'ns3-simulator']
+ node = bld.create_ns3_module('node', ['core', 'common', 'simulator'])
node.source = [
+ 'address.cc',
+ 'mac48-address.cc',
+ 'mac64-address.cc',
+ 'inet-socket-address.cc',
+ 'packet-socket-address.cc',
'node.cc',
'ipv4-address.cc',
'net-device.cc',
- 'mac-address.cc',
+ 'address-utils.cc',
'llc-snap-header.cc',
+ 'ethernet-header.cc',
+ 'ethernet-trailer.cc',
'ipv4-route.cc',
'queue.cc',
'drop-tail-queue.cc',
@@ -22,6 +22,8 @@
'node-list.cc',
'socket.cc',
'socket-factory.cc',
+ 'packet-socket-factory.cc',
+ 'packet-socket.cc',
'udp.cc',
'ipv4.cc',
'application.cc',
@@ -29,18 +31,26 @@
headers = bld.create_obj('ns3header')
headers.source = [
+ 'address.h',
+ 'mac48-address.h',
+ 'mac64-address.h',
+ 'inet-socket-address.h',
+ 'packet-socket-address.h',
'node.h',
'ipv4-address.h',
'net-device.h',
- 'mac-address.h',
+ 'address-utils.h',
'ipv4-route.h',
'queue.h',
'drop-tail-queue.h',
'llc-snap-header.h',
+ 'ethernet-header.h',
+ 'ethernet-trailer.h',
'channel.h',
'node-list.h',
'socket.h',
'socket-factory.h',
+ 'packet-socket-factory.h',
'udp.h',
'ipv4.h',
'application.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,146 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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/log.h"
+#include "ns3/assert.h"
+#include "candidate-queue.h"
+
+NS_LOG_COMPONENT_DEFINE ("CandidateQueue");
+
+namespace ns3 {
+
+CandidateQueue::CandidateQueue()
+ : m_candidates ()
+{
+ NS_LOG_FUNCTION;
+}
+
+CandidateQueue::~CandidateQueue()
+{
+ NS_LOG_FUNCTION;
+ Clear ();
+}
+
+ void
+CandidateQueue::Clear (void)
+{
+ NS_LOG_FUNCTION;
+ while (!m_candidates.empty ())
+ {
+ SPFVertex *p = Pop ();
+ delete p;
+ p = 0;
+ }
+}
+
+ void
+CandidateQueue::Push (SPFVertex *vNew)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << vNew << ")");
+
+ CandidateList_t::iterator i = m_candidates.begin ();
+
+ for (; i != m_candidates.end (); i++)
+ {
+ SPFVertex *v = *i;
+ if (vNew->GetDistanceFromRoot () < v->GetDistanceFromRoot ())
+ {
+ break;
+ }
+ }
+ m_candidates.insert(i, vNew);
+}
+
+ SPFVertex *
+CandidateQueue::Pop (void)
+{
+ NS_LOG_FUNCTION;
+ if (m_candidates.empty ())
+ {
+ return 0;
+ }
+
+ SPFVertex *v = m_candidates.front ();
+ m_candidates.pop_front ();
+ return v;
+}
+
+ SPFVertex *
+CandidateQueue::Top (void) const
+{
+ NS_LOG_FUNCTION;
+ if (m_candidates.empty ())
+ {
+ return 0;
+ }
+
+ return m_candidates.front ();
+}
+
+ bool
+CandidateQueue::Empty (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_candidates.empty ();
+}
+
+ uint32_t
+CandidateQueue::Size (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_candidates.size ();
+}
+
+ SPFVertex *
+CandidateQueue::Find (const Ipv4Address addr) const
+{
+ NS_LOG_FUNCTION;
+ CandidateList_t::const_iterator i = m_candidates.begin ();
+
+ for (; i != m_candidates.end (); i++)
+ {
+ SPFVertex *v = *i;
+ if (v->GetVertexId() == addr)
+ {
+ return v;
+ }
+ }
+
+ return 0;
+}
+
+ void
+CandidateQueue::Reorder (void)
+{
+ NS_LOG_FUNCTION;
+ std::list<SPFVertex*> temp;
+
+ while (!m_candidates.empty ()) {
+ SPFVertex *v = m_candidates.front ();
+ m_candidates.pop_front ();
+ temp.push_back(v);
+ }
+
+ while (!temp.empty ()) {
+ Push (temp.front ());
+ temp.pop_front ();
+ }
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,185 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Author: Craig Dowell (craigdo@ee.washington.edu)
+ */
+
+#ifndef CANDIDATE_QUEUE_H
+#define CANDIDATE_QUEUE_H
+
+#include <stdint.h>
+#include <list>
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+/**
+ * \brief A Candidate Queue used in static routing.
+ *
+ * The CandidateQueue is used in the OSPF shortest path computations. It
+ * is a priority queue used to store candidates for the shortest path to a
+ * given network.
+ *
+ * The queue holds Shortest Path First Vertex pointers and orders them
+ * according to the lowest value of the field m_distanceFromRoot. Remaining
+ * vertices are ordered according to increasing distance. This implements a
+ * priority queue.
+ *
+ * Although a STL priority_queue almost does what we want, the requirement
+ * for a Find () operation, the dynamic nature of the data and the derived
+ * requirement for a Reorder () operation led us to implement this simple
+ * enhanced priority queue.
+ */
+class CandidateQueue
+{
+public:
+/**
+ * @brief Create an empty SPF Candidate Queue.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+ CandidateQueue ();
+
+/**
+ * @internal Destroy an SPF Candidate Queue and release any resources held
+ * by the contents.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+ virtual ~CandidateQueue ();
+
+/**
+ * @brief Empty the Candidate Queue and release all of the resources
+ * associated with the Shortest Path First Vertex pointers in the queue.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+ void Clear (void);
+
+/**
+ * @brief Push a Shortest Path First Vertex pointer onto the queue according
+ * to the priority scheme.
+ * @internal
+ *
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot. Remaining vertices are ordered according to
+ * increasing distance.
+ *
+ * @see SPFVertex
+ * @param vNew The Shortest Path First Vertex to add to the queue.
+ */
+ void Push (SPFVertex *vNew);
+
+/**
+ * @brief Pop the Shortest Path First Vertex pointer at the top of the queue.
+ * @internal
+ *
+ * The caller is given the responsiblity for releasing the resources
+ * associated with the vertex.
+ *
+ * @see SPFVertex
+ * @see Top ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+ SPFVertex* Pop (void);
+
+/**
+ * @brief Return the Shortest Path First Vertex pointer at the top of the
+ * queue.
+ * @internal
+ *
+ * This method does not pop the SPFVertex* off of the queue, it simply
+ * returns the pointer.
+ *
+ * @see SPFVertex
+ * @see Pop ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+ SPFVertex* Top (void) const;
+
+/**
+ * @brief Test the Candidate Queue to determine if it is empty.
+ * @internal
+ *
+ * @returns True if the queue is empty, false otherwise.
+ */
+ bool Empty (void) const;
+
+/**
+ * @brief Return the number of Shortest Path First Vertex pointers presently
+ * stored in the Candidate Queue.
+ * @internal
+ *
+ * @see SPFVertex
+ * @returns The number of SPFVertex* pointers in the Candidate Queue.
+ */
+ uint32_t Size (void) const;
+
+/**
+ * @brief Searches the Candidate Queue for a Shortest Path First Vertex
+ * pointer that points to a vertex having the given IP address.
+ * @internal
+ *
+ * @see SPFVertex
+ * @param addr The IP address to search for.
+ * @returns The SPFVertex* pointer corresponding to the given IP address.
+ */
+ SPFVertex* Find (const Ipv4Address addr) const;
+
+/**
+ * @brief Reorders the Candidate Queue according to the priority scheme.
+ * @internal
+ *
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot. Remaining vertices are ordered according to
+ * increasing distance.
+ *
+ * This method is provided in case the values of m_distanceFromRoot change
+ * during the routing calculations.
+ *
+ * @see SPFVertex
+ */
+ void Reorder (void);
+
+protected:
+ typedef std::list<SPFVertex*> CandidateList_t;
+ CandidateList_t m_candidates;
+
+private:
+/**
+ * Candidate Queue copy construction is disallowed (not implemented) to
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+ CandidateQueue (CandidateQueue& sr);
+
+/**
+ * Candidate Queue assignment operator is disallowed (not implemented) to
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+ CandidateQueue& operator= (CandidateQueue& sr);
+};
+
+} // namespace ns3
+
+#endif /* CANDIDATE_QUEUE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1625 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 2007 University of Washington
+ * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * 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: Tom Henderson (tomhend@u.washington.edu)
+ *
+ * Kunihiro Ishigura, Toshiaki Takada (GNU Zebra) are attributed authors
+ * of the quagga 0.99.7/src/ospfd/ospf_spf.c code which was ported here
+ */
+
+#include <utility>
+#include <vector>
+#include <queue>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/log.h"
+#include "ns3/node-list.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+#include "global-route-manager-impl.h"
+#include "candidate-queue.h"
+
+NS_LOG_COMPONENT_DEFINE ("GlobalRouteManager");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// SPFVertex Implementation
+//
+// ---------------------------------------------------------------------------
+
+SPFVertex::SPFVertex () :
+ m_vertexType (VertexUnknown),
+ m_vertexId ("255.255.255.255"),
+ m_lsa (0),
+ m_distanceFromRoot (SPF_INFINITY),
+ m_rootOif (SPF_INFINITY),
+ m_nextHop ("0.0.0.0"),
+ m_parent (0),
+ m_children ()
+{
+ NS_LOG_FUNCTION;
+}
+
+SPFVertex::SPFVertex (GlobalRoutingLSA* lsa) :
+ m_vertexId (lsa->GetLinkStateId ()),
+ m_lsa (lsa),
+ m_distanceFromRoot (SPF_INFINITY),
+ m_rootOif (SPF_INFINITY),
+ m_nextHop ("0.0.0.0"),
+ m_parent (0),
+ m_children ()
+{
+ NS_LOG_FUNCTION;
+ if (lsa->GetLSType () == GlobalRoutingLSA::RouterLSA)
+ {
+ NS_LOG_LOGIC ("Setting m_vertexType to VertexRouter");
+ m_vertexType = SPFVertex::VertexRouter;
+ }
+ else if (lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA)
+ {
+ NS_LOG_LOGIC ("Setting m_vertexType to VertexNetwork");
+ m_vertexType = SPFVertex::VertexNetwork;
+ }
+}
+
+SPFVertex::~SPFVertex ()
+{
+ NS_LOG_FUNCTION;
+ for ( ListOfSPFVertex_t::iterator i = m_children.begin ();
+ i != m_children.end ();
+ i++)
+ {
+ SPFVertex *p = *i;
+ delete p;
+ p = 0;
+ *i = 0;
+ }
+ m_children.clear ();
+}
+
+ void
+SPFVertex::SetVertexType (SPFVertex::VertexType type)
+{
+ NS_LOG_FUNCTION;
+ m_vertexType = type;
+}
+
+ SPFVertex::VertexType
+SPFVertex::GetVertexType (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_vertexType;
+}
+
+ void
+SPFVertex::SetVertexId (Ipv4Address id)
+{
+ NS_LOG_FUNCTION;
+ m_vertexId = id;
+}
+
+ Ipv4Address
+SPFVertex::GetVertexId (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_vertexId;
+}
+
+ void
+SPFVertex::SetLSA (GlobalRoutingLSA* lsa)
+{
+ NS_LOG_FUNCTION;
+ m_lsa = lsa;
+}
+
+ GlobalRoutingLSA*
+SPFVertex::GetLSA (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_lsa;
+}
+
+ void
+SPFVertex::SetDistanceFromRoot (uint32_t distance)
+{
+ NS_LOG_FUNCTION;
+ m_distanceFromRoot = distance;
+}
+
+ uint32_t
+SPFVertex::GetDistanceFromRoot (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_distanceFromRoot;
+}
+
+ void
+SPFVertex::SetOutgoingInterfaceId (uint32_t id)
+{
+ NS_LOG_FUNCTION;
+ m_rootOif = id;
+}
+
+ uint32_t
+SPFVertex::GetOutgoingInterfaceId (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_rootOif;
+}
+
+ void
+SPFVertex::SetNextHop (Ipv4Address nextHop)
+{
+ NS_LOG_FUNCTION;
+ m_nextHop = nextHop;
+}
+
+ Ipv4Address
+SPFVertex::GetNextHop (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_nextHop;
+}
+
+ void
+SPFVertex::SetParent (SPFVertex* parent)
+{
+ NS_LOG_FUNCTION;
+ m_parent = parent;
+}
+
+ SPFVertex*
+SPFVertex::GetParent (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_parent;
+}
+
+ uint32_t
+SPFVertex::GetNChildren (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_children.size ();
+}
+
+ SPFVertex*
+SPFVertex::GetChild (uint32_t n) const
+{
+ NS_LOG_FUNCTION;
+ uint32_t j = 0;
+
+ for ( ListOfSPFVertex_t::const_iterator i = m_children.begin ();
+ i != m_children.end ();
+ i++, j++)
+ {
+ if (j == n)
+ {
+ return *i;
+ }
+ }
+ NS_ASSERT_MSG(false, "Index <n> out of range.");
+ return 0;
+}
+
+ uint32_t
+SPFVertex::AddChild (SPFVertex* child)
+{
+ NS_LOG_FUNCTION;
+ m_children.push_back (child);
+ return m_children.size ();
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerLSDB Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerLSDB::GlobalRouteManagerLSDB ()
+:
+ m_database ()
+{
+ NS_LOG_FUNCTION;
+}
+
+GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ()
+{
+ NS_LOG_FUNCTION;
+ LSDBMap_t::iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ NS_LOG_LOGIC ("free LSA");
+ GlobalRoutingLSA* temp = i->second;
+ delete temp;
+ }
+ NS_LOG_LOGIC ("clear map");
+ m_database.clear ();
+}
+
+ void
+GlobalRouteManagerLSDB::Initialize ()
+{
+ NS_LOG_FUNCTION;
+ LSDBMap_t::iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ GlobalRoutingLSA* temp = i->second;
+ temp->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+ }
+}
+
+ void
+GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRoutingLSA* lsa)
+{
+ NS_LOG_FUNCTION;
+ m_database.insert (LSDBPair_t (addr, lsa));
+}
+
+ GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const
+{
+ NS_LOG_FUNCTION;
+//
+// Look up an LSA by its address.
+//
+ LSDBMap_t::const_iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ if (i->first == addr)
+ {
+ return i->second;
+ }
+ }
+ return 0;
+}
+
+ GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSAByLinkData (Ipv4Address addr) const
+{
+ NS_LOG_FUNCTION;
+//
+// Look up an LSA by its address.
+//
+ LSDBMap_t::const_iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ GlobalRoutingLSA* temp = i->second;
+// Iterate among temp's Link Records
+ for (uint32_t j = 0; j < temp->GetNLinkRecords (); j++)
+ {
+ GlobalRoutingLinkRecord *lr = temp->GetLinkRecord (j);
+ if ( lr->GetLinkType () == GlobalRoutingLinkRecord::TransitNetwork &&
+ lr->GetLinkData () == addr)
+ {
+ return temp;
+ }
+ }
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerImpl Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerImpl::GlobalRouteManagerImpl ()
+:
+ m_spfroot (0)
+{
+ NS_LOG_FUNCTION;
+ m_lsdb = new GlobalRouteManagerLSDB ();
+}
+
+GlobalRouteManagerImpl::~GlobalRouteManagerImpl ()
+{
+ NS_LOG_FUNCTION;
+ if (m_lsdb)
+ {
+ delete m_lsdb;
+ }
+}
+
+ void
+GlobalRouteManagerImpl::DebugUseLsdb (GlobalRouteManagerLSDB* lsdb)
+{
+ NS_LOG_FUNCTION;
+ if (m_lsdb)
+ {
+ delete m_lsdb;
+ }
+ m_lsdb = lsdb;
+}
+
+//
+// In order to build the routing database, we need at least one of the nodes
+// to participate as a router. Eventually we expect to provide a mechanism
+// for selecting a subset of the nodes to participate; for now, we just make
+// all nodes routers. We do this by walking the list of nodes in the system
+// and aggregating a Global Router Interface to each of the nodes.
+//
+ void
+GlobalRouteManagerImpl::SelectRouterNodes ()
+{
+ NS_LOG_FUNCTION;
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+ NS_LOG_LOGIC ("Adding GlobalRouter interface to node " <<
+ node->GetId ());
+
+ Ptr<GlobalRouter> globalRouter = Create<GlobalRouter> (node);
+ node->AddInterface (globalRouter);
+ }
+}
+
+//
+// In order to build the routing database, we need to walk the list of nodes
+// in the system and look for those that support the GlobalRouter interface.
+// These routers will export a number of Link State Advertisements (LSAs)
+// that describe the links and networks that are "adjacent" (i.e., that are
+// on the other side of a point-to-point link). We take these LSAs and put
+// add them to the Link State DataBase (LSDB) from which the routes will
+// ultimately be computed.
+//
+ void
+GlobalRouteManagerImpl::BuildGlobalRoutingDatabase ()
+{
+ NS_LOG_FUNCTION;
+//
+// Walk the list of nodes looking for the GlobalRouter Interface.
+//
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// Ignore nodes that aren't participating in routing.
+//
+ if (!rtr)
+ {
+ continue;
+ }
+//
+// You must call DiscoverLSAs () before trying to use any routing info or to
+// update LSAs. DiscoverLSAs () drives the process of discovering routes in
+// the GlobalRouter. Afterward, you may use GetNumLSAs (), which is a very
+// computationally inexpensive call. If you call GetNumLSAs () before calling
+// DiscoverLSAs () will get zero as the number since no routes have been
+// found.
+//
+ uint32_t numLSAs = rtr->DiscoverLSAs ();
+ NS_LOG_LOGIC ("Found " << numLSAs << " LSAs");
+
+ for (uint32_t j = 0; j < numLSAs; ++j)
+ {
+ GlobalRoutingLSA* lsa = new GlobalRoutingLSA ();
+//
+// This is the call to actually fetch a Link State Advertisement from the
+// router.
+//
+ rtr->GetLSA (j, *lsa);
+ NS_LOG_LOGIC (*lsa);
+//
+// Write the newly discovered link state advertisement to the database.
+//
+ m_lsdb->Insert (lsa->GetLinkStateId (), lsa);
+ }
+ }
+}
+
+//
+// For each node that is a global router (which is determined by the presence
+// of an aggregated GlobalRouter interface), run the Dijkstra SPF calculation
+// on the database rooted at that router, and populate the node forwarding
+// tables.
+//
+// This function parallels RFC2328, Section 16.1.1, and quagga ospfd
+//
+// This calculation yields the set of intra-area routes associated
+// with an area (called hereafter Area A). A router calculates the
+// shortest-path tree using itself as the root. The formation
+// of the shortest path tree is done here in two stages. In the
+// first stage, only links between routers and transit networks are
+// considered. Using the Dijkstra algorithm, a tree is formed from
+// this subset of the link state database. In the second stage,
+// leaves are added to the tree by considering the links to stub
+// networks.
+//
+// The area's link state database is represented as a directed graph.
+// The graph's vertices are routers, transit networks and stub networks.
+//
+// The first stage of the procedure (i.e., the Dijkstra algorithm)
+// can now be summarized as follows. At each iteration of the
+// algorithm, there is a list of candidate vertices. Paths from
+// the root to these vertices have been found, but not necessarily
+// the shortest ones. However, the paths to the candidate vertex
+// that is closest to the root are guaranteed to be shortest; this
+// vertex is added to the shortest-path tree, removed from the
+// candidate list, and its adjacent vertices are examined for
+// possible addition to/modification of the candidate list. The
+// algorithm then iterates again. It terminates when the candidate
+// list becomes empty.
+//
+ void
+GlobalRouteManagerImpl::InitializeRoutes ()
+{
+ NS_LOG_FUNCTION;
+//
+// Walk the list of nodes in the system.
+//
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+//
+// Look for the GlobalRouter interface that indicates that the node is
+// participating in routing.
+//
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// if the node has a global router interface, then run the global routing
+// algorithms.
+//
+ if (rtr && rtr->GetNumLSAs () )
+ {
+ SPFCalculate (rtr->GetRouterId ());
+ }
+ }
+}
+
+//
+// This method is derived from quagga ospf_spf_next (). See RFC2328 Section
+// 16.1 (2) for further details.
+//
+// We're passed a parameter <v> that is a vertex which is already in the SPF
+// tree. A vertex represents a router node. We also get a reference to the
+// SPF candidate queue, which is a priority queue containing the shortest paths
+// to the networks we know about.
+//
+// We examine the links in v's LSA and update the list of candidates with any
+// vertices not already on the list. If a lower-cost path is found to a
+// vertex already on the candidate list, store the new (lower) cost.
+//
+ void
+GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate)
+{
+ NS_LOG_FUNCTION;
+
+ SPFVertex* w = 0;
+ GlobalRoutingLSA* w_lsa = 0;
+ GlobalRoutingLinkRecord *l = 0;
+ uint32_t distance = 0;
+ uint32_t numRecordsInVertex = 0;
+//
+// V points to a Router-LSA or Network-LSA
+// Loop over the links in router LSA or attached routers in Network LSA
+//
+ if (v->GetVertexType () == SPFVertex::VertexRouter)
+ {
+ numRecordsInVertex = v->GetLSA ()->GetNLinkRecords ();
+ }
+ if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+ numRecordsInVertex = v->GetLSA ()->GetNAttachedRouters ();
+ }
+
+ for (uint32_t i = 0; i < numRecordsInVertex; i++)
+ {
+// Get w_lsa: In case of V is Router-LSA
+ if (v->GetVertexType () == SPFVertex::VertexRouter)
+ {
+ NS_LOG_LOGIC ("Examining " << v->GetVertexId () << "'s " <<
+ v->GetLSA ()->GetNLinkRecords () << " link records");
+//
+// (a) If this is a link to a stub network, examine the next link in V's LSA.
+// Links to stub networks will be considered in the second stage of the
+// shortest path calculation.
+//
+ l = v->GetLSA ()->GetLinkRecord (i);
+ if (l->GetLinkType () == GlobalRoutingLinkRecord::StubNetwork)
+ {
+ NS_LOG_LOGIC ("Found a Stub record to " << l->GetLinkId ());
+ continue;
+ }
+//
+// (b) Otherwise, W is a transit vertex (router or transit network). Look up
+// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state
+// database.
+//
+ if (l->GetLinkType () == GlobalRoutingLinkRecord::PointToPoint)
+ {
+//
+// Lookup the link state advertisement of the new link -- we call it <w> in
+// the link state database.
+//
+ w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+ NS_ASSERT (w_lsa);
+ NS_LOG_LOGIC ("Found a P2P record from " <<
+ v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+ }
+ else if (l->GetLinkType () ==
+ GlobalRoutingLinkRecord::TransitNetwork)
+ {
+ w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+ NS_ASSERT (w_lsa);
+ NS_LOG_LOGIC ("Found a Transit record from " <<
+ v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+ }
+ else
+ {
+ NS_ASSERT_MSG (0, "illegal Link Type");
+ }
+ }
+// Get w_lsa: In case of V is Network-LSA
+ if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+ w_lsa = m_lsdb->GetLSAByLinkData
+ (v->GetLSA ()->GetAttachedRouter (i));
+ if (!w_lsa)
+ {
+ continue;
+ }
+ NS_LOG_LOGIC ("Found a Network LSA from " <<
+ v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+ }
+
+// Note: w_lsa at this point may be either RouterLSA or NetworkLSA
+//
+// (c) If vertex W is already on the shortest-path tree, examine the next
+// link in the LSA.
+//
+// If the link is to a router that is already in the shortest path first tree
+// then we have it covered -- ignore it.
+//
+ if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_IN_SPFTREE)
+ {
+ NS_LOG_LOGIC ("Skipping -> LSA "<<
+ w_lsa->GetLinkStateId () << " already in SPF tree");
+ continue;
+ }
+//
+// (d) Calculate the link state cost D of the resulting path from the root to
+// vertex W. D is equal to the sum of the link state cost of the (already
+// calculated) shortest path to vertex V and the advertised cost of the link
+// between vertices V and W.
+//
+ if (v->GetLSA ()->GetLSType () == GlobalRoutingLSA::RouterLSA)
+ {
+ distance = v->GetDistanceFromRoot () + l->GetMetric ();
+ }
+ else
+ {
+ distance = v->GetDistanceFromRoot ();
+ }
+
+ NS_LOG_LOGIC ("Considering w_lsa " << w_lsa->GetLinkStateId ());
+
+// Is there already vertex w in candidate list?
+ if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+ {
+
+// prepare vertex w
+ w = new SPFVertex (w_lsa);
+// Calculate nexthop to w
+// We need to figure out how to actually get to the new router represented
+// by <w>. This will (among other things) find the next hop address to send
+// packets destined for this network to, and also find the outbound interface
+// used to forward the packets.
+//
+ if (SPFNexthopCalculation (v, w, l, distance))
+ {
+ w_lsa->SetStatus (GlobalRoutingLSA::LSA_SPF_CANDIDATE);
+//
+// Push this new vertex onto the priority queue (ordered by distance from the
+// root node).
+//
+ candidate.Push (w);
+ NS_LOG_LOGIC ("Pushing " <<
+ w->GetVertexId () << ", parent vertexId: " <<
+ v->GetVertexId ());
+ }
+ }
+ else if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_CANDIDATE)
+ {
+//
+// We have already considered the link represented by <w>. What wse have to
+// do now is to decide if this new router represents a route with a shorter
+// distance metric.
+//
+// So, locate the vertex in the candidate queue and take a look at the
+// distance.
+ w = candidate.Find (w_lsa->GetLinkStateId ());
+ if (w->GetDistanceFromRoot () < distance)
+ {
+//
+// This is not a shorter path, so don't do anything.
+//
+ continue;
+ }
+ else if (w->GetDistanceFromRoot () == distance)
+ {
+//
+// This path is one with an equal cost. Do nothing for now -- we're not doing
+// equal-cost multipath cases yet.
+//
+ }
+ else
+ {
+//
+// this path represents a new, lower-cost path to <w> (the vertex we found in
+// the current link record of the link state advertisement of the current root
+// (vertex <v>)
+//
+// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop
+// it will call spf_add_parents, which will flush the old parents
+//
+ if (SPFNexthopCalculation (v, w, l, distance))
+ {
+//
+// If we've changed the cost to get to the vertex represented by <w>, we
+// must reorder the priority queue keyed to that cost.
+//
+ candidate.Reorder ();
+ }
+ } // new lower cost path found
+ } // end W is already on the candidate list
+ } // end loop over the links in V's LSA
+}
+
+//
+// This method is derived from quagga ospf_next_hop_calculation() 16.1.1.
+//
+// Calculate nexthop from root through V (parent) to vertex W (destination)
+// with given distance from root->W.
+//
+// As appropriate, set w's parent, distance, and nexthop information
+//
+// For now, this is greatly simplified from the quagga code
+//
+ int
+GlobalRouteManagerImpl::SPFNexthopCalculation (
+ SPFVertex* v,
+ SPFVertex* w,
+ GlobalRoutingLinkRecord* l,
+ uint32_t distance)
+{
+ NS_LOG_FUNCTION;
+//
+// If w is a NetworkVertex, l should be null
+/*
+ if (w->GetVertexType () == SPFVertex::VertexNetwork && l)
+ {
+ NS_ASSERT_MSG(0, "Error: SPFNexthopCalculation parameter problem");
+ }
+*/
+
+//
+// The vertex m_spfroot is a distinguished vertex representing the node at
+// the root of the calculations. That is, it is the node for which we are
+// calculating the routes.
+//
+// There are two distinct cases for calculating the next hop information.
+// First, if we're considering a hop from the root to an "adjacent" network
+// (one that is on the other side of a point-to-point link connected to the
+// root), then we need to store the information needed to forward down that
+// link. The second case is if the network is not directly adjacent. In that
+// case we need to use the forwarding information from the vertex on the path
+// to the destination that is directly adjacent [node 1] in both cases of the
+// diagram below.
+//
+// (1) [root] -> [point-to-point] -> [node 1]
+// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2]
+//
+// We call the propagation of next hop information down vertices of a path
+// "inheriting" the next hop information.
+//
+// The point-to-point link information is only useful in this calculation when
+// we are examining the root node.
+//
+ if (v == m_spfroot)
+ {
+//
+// In this case <v> is the root node, which means it is the starting point
+// for the packets forwarded by that node. This also means that the next hop
+// address of packets headed for some arbitrary off-network destination must
+// be the destination at the other end of one of the links off of the root
+// node if this root node is a router. We then need to see if this node <w>
+// is a router.
+//
+ if (w->GetVertexType () == SPFVertex::VertexRouter)
+ {
+//
+// In the case of point-to-point links, the link data field (m_linkData) of a
+// Global Router Link Record contains the local IP address. If we look at the
+// link record describing the link from the perspecive of <w> (the remote
+// node from the viewpoint of <v>) back to the root node, we can discover the
+// IP address of the router to which <v> is adjacent. This is a distinguished
+// address -- the next hop address to get from <v> to <w> and all networks
+// accessed through that path.
+//
+// SPFGetNextLink () is a little odd. used in this way it is just going to
+// return the link record describing the link from <w> to <v>. Think of it as
+// SPFGetLink.
+//
+ NS_ASSERT(l);
+ GlobalRoutingLinkRecord *linkRemote = 0;
+ linkRemote = SPFGetNextLink (w, v, linkRemote);
+//
+// At this point, <l> is the Global Router Link Record describing the point-
+// to point link from <v> to <w> from the perspective of <v>; and <linkRemote>
+// is the Global Router Link Record describing that same link from the
+// perspective of <w> (back to <v>). Now we can just copy the next hop
+// address from the m_linkData member variable.
+//
+// The next hop member variable we put in <w> has the sense "in order to get
+// from the root node to the host represented by vertex <w>, you have to send
+// the packet to the next hop address specified in w->m_nextHop.
+//
+ w->SetNextHop(linkRemote->GetLinkData ());
+//
+// Now find the outgoing interface corresponding to the point to point link
+// from the perspective of <v> -- remember that <l> is the link "from"
+// <v> "to" <w>.
+//
+ w->SetOutgoingInterfaceId (
+ FindOutgoingInterfaceId (l->GetLinkData ()));
+
+ NS_LOG_LOGIC ("Next hop from " <<
+ v->GetVertexId () << " to " << w->GetVertexId () <<
+ " goes through next hop " << w->GetNextHop () <<
+ " via outgoing interface " << w->GetOutgoingInterfaceId ());
+ } // end W is a router vertes
+ else
+ {
+ NS_ASSERT (w->GetVertexType () == SPFVertex::VertexNetwork);
+// W is a directly connected network; no next hop is required
+ GlobalRoutingLSA* w_lsa = w->GetLSA ();
+ NS_ASSERT (w_lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA);
+// Find outgoing interface ID for this network
+ w->SetOutgoingInterfaceId (
+ FindOutgoingInterfaceId (w_lsa->GetLinkStateId (),
+ w_lsa->GetNetworkLSANetworkMask () ));
+ w->SetDistanceFromRoot (distance);
+ w->SetParent (v);
+ NS_LOG_LOGIC ("Next hop from " <<
+ v->GetVertexId () << " to network " << w->GetVertexId () <<
+ " via outgoing interface " << w->GetOutgoingInterfaceId ());
+ return 1;
+ }
+ } // end v is the root
+ else if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+// See if any of v's parents are the root
+ if (v->GetParent () == m_spfroot)
+ {
+// 16.1.1 para 5. ...the parent vertex is a network that
+// directly connects the calculating router to the destination
+// router. The list of next hops is then determined by
+// examining the destination's router-LSA...
+ NS_ASSERT (w->GetVertexType () == SPFVertex::VertexRouter);
+ GlobalRoutingLinkRecord *linkRemote = 0;
+ while ((linkRemote = SPFGetNextLink (w, v, linkRemote)))
+ {
+/* ...For each link in the router-LSA that points back to the
+ * parent network, the link's Link Data field provides the IP
+ * address of a next hop router. The outgoing interface to
+ * use can then be derived from the next hop IP address (or
+ * it can be inherited from the parent network).
+ */
+ w->SetNextHop(linkRemote->GetLinkData ());
+ w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+ NS_LOG_LOGIC ("Next hop from " <<
+ v->GetVertexId () << " to " << w->GetVertexId () <<
+ " goes through next hop " << w->GetNextHop () <<
+ " via outgoing interface " << w->GetOutgoingInterfaceId ());
+ }
+ }
+ else
+ {
+ w->SetNextHop (v->GetNextHop ());
+ w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+ }
+ }
+ else
+ {
+//
+// If we're calculating the next hop information from a node (v) that is
+// *not* the root, then we need to "inherit" the information needed to
+// forward the packet from the vertex closer to the root. That is, we'll
+// still send packets to the next hop address of the router adjacent to the
+// root on the path toward <w>.
+//
+// Above, when we were considering the root node, we calculated the next hop
+// address and outgoing interface required to get off of the root network.
+// At this point, we are further away from the root network along one of the
+// (shortest) paths. So the next hop and outoing interface remain the same
+// (are inherited).
+//
+ w->SetNextHop (v->GetNextHop ());
+ w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+ }
+//
+// In all cases, we need valid values for the distance metric and a parent.
+//
+ w->SetDistanceFromRoot (distance);
+ w->SetParent (v);
+
+ return 1;
+}
+
+//
+// This method is derived from quagga ospf_get_next_link ()
+//
+// First search the Global Router Link Records of vertex <v> for one
+// representing a point-to point link to vertex <w>.
+//
+// What is done depends on prev_link. Contrary to appearances, prev_link just
+// acts as a flag here. If prev_link is NULL, we return the first Global
+// Router Link Record we find that describes a point-to-point link from <v>
+// to <w>. If prev_link is not NULL, we return a Global Router Link Record
+// representing a possible *second* link from <v> to <w>.
+//
+ GlobalRoutingLinkRecord*
+GlobalRouteManagerImpl::SPFGetNextLink (
+ SPFVertex* v,
+ SPFVertex* w,
+ GlobalRoutingLinkRecord* prev_link)
+{
+ NS_LOG_FUNCTION;
+
+ bool skip = true;
+ bool found_prev_link = false;
+ GlobalRoutingLinkRecord* l;
+//
+// If prev_link is 0, we are really looking for the first link, not the next
+// link.
+//
+ if (prev_link == 0)
+ {
+ skip = false;
+ found_prev_link = true;
+ }
+//
+// Iterate through the Global Router Link Records advertised by the vertex
+// <v> looking for records representing the point-to-point links off of this
+// vertex.
+//
+ for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i)
+ {
+ l = v->GetLSA ()->GetLinkRecord (i);
+//
+// The link ID of a link record representing a point-to-point link is set to
+// the router ID of the neighboring router -- the router to which the link
+// connects from the perspective of <v> in this case. The vertex ID is also
+// set to the router ID (using the link state advertisement of a router node).
+// We're just checking to see if the link <l> is actually the link from <v> to
+// <w>.
+//
+ if (l->GetLinkId () == w->GetVertexId ())
+ {
+ if (!found_prev_link)
+ {
+ NS_LOG_LOGIC ("Skipping links before prev_link found");
+ found_prev_link = true;
+ continue;
+ }
+
+ NS_LOG_LOGIC ("Found matching link l: linkId = " <<
+ l->GetLinkId () << " linkData = " << l->GetLinkData ());
+//
+// If skip is false, don't (not too surprisingly) skip the link found -- it's
+// the one we're interested in. That's either because we didn't pass in a
+// previous link, and we're interested in the first one, or because we've
+// skipped a previous link and moved forward to the next (which is then the
+// one we want).
+//
+ if (skip == false)
+ {
+ NS_LOG_LOGIC ("Returning the found link");
+ return l;
+ }
+ else
+ {
+//
+// Skip is true and we've found a link from <v> to <w>. We want the next one.
+// Setting skip to false gets us the next point-to-point global router link
+// record in the LSA from <v>.
+//
+ NS_LOG_LOGIC ("Skipping the found link");
+ skip = false;
+ continue;
+ }
+ }
+ }
+ return 0;
+}
+
+//
+// Used for unit tests.
+//
+ void
+GlobalRouteManagerImpl::DebugSPFCalculate (Ipv4Address root)
+{
+ NS_LOG_FUNCTION;
+ SPFCalculate (root);
+}
+
+// quagga ospf_spf_calculate
+ void
+GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << root << ")");
+
+ SPFVertex *v;
+//
+// Initialize the Link State Database.
+//
+ m_lsdb->Initialize ();
+//
+// The candidate queue is a priority queue of SPFVertex objects, with the top
+// of the queue being the closest vertex in terms of distance from the root
+// of the tree. Initially, this queue is empty.
+//
+ CandidateQueue candidate;
+ NS_ASSERT(candidate.Size () == 0);
+//
+// Initialize the shortest-path tree to only contain the router doing the
+// calculation. Each router (and corresponding network) is a vertex in the
+// shortest path first (SPF) tree.
+//
+ v = new SPFVertex (m_lsdb->GetLSA (root));
+//
+// This vertex is the root of the SPF tree and it is distance 0 from the root.
+// We also mark this vertex as being in the SPF tree.
+//
+ m_spfroot= v;
+ v->SetDistanceFromRoot (0);
+ v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+
+ for (;;)
+ {
+//
+// The operations we need to do are given in the OSPF RFC which we reference
+// as we go along.
+//
+// RFC2328 16.1. (2).
+//
+// We examine the Global Router Link Records in the Link State
+// Advertisements of the current vertex. If there are any point-to-point
+// links to unexplored adjacent vertices we add them to the tree and update
+// the distance and next hop information on how to get there. We also add
+// the new vertices to the candidate queue (the priority queue ordered by
+// shortest path). If the new vertices represent shorter paths, we use them
+// and update the path cost.
+//
+ SPFNext (v, candidate);
+//
+// RFC2328 16.1. (3).
+//
+// If at this step the candidate list is empty, the shortest-path tree (of
+// transit vertices) has been completely built and this stage of the
+// procedure terminates.
+//
+ if (candidate.Size () == 0)
+ {
+ break;
+ }
+//
+// Choose the vertex belonging to the candidate list that is closest to the
+// root, and add it to the shortest-path tree (removing it from the candidate
+// list in the process).
+//
+// Recall that in the previous step, we created SPFVertex structures for each
+// of the routers found in the Global Router Link Records and added tehm to
+// the candidate list.
+//
+ v = candidate.Pop ();
+ NS_LOG_LOGIC ("Popped vertex " << v->GetVertexId ());
+//
+// Update the status field of the vertex to indicate that it is in the SPF
+// tree.
+//
+ v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+//
+// The current vertex has a parent pointer. By calling this rather oddly
+// named method (blame quagga) we add the current vertex to the list of
+// children of that parent vertex. In the next hop calculation called during
+// SPFNext, the parent pointer was set but the vertex has been orphaned up
+// to now.
+//
+ SPFVertexAddParent (v);
+//
+// Note that when there is a choice of vertices closest to the root, network
+// vertices must be chosen before router vertices in order to necessarily
+// find all equal-cost paths. We don't do this at this moment, we should add
+// the treatment above codes. -- kunihiro.
+//
+// RFC2328 16.1. (4).
+//
+// This is the method that actually adds the routes. It'll walk the list
+// of nodes in the system, looking for the node corresponding to the router
+// ID of the root of the tree -- that is the router we're building the routes
+// for. It looks for the Ipv4 interface of that node and remembers it. So
+// we are only actually adding routes to that one node at the root of the SPF
+// tree.
+//
+// We're going to pop of a pointer to every vertex in the tree except the
+// root in order of distance from the root. For each of the vertices, we call
+// SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the
+// point-to-point Global Router Link Records (the links to nodes adjacent to
+// the node represented by the vertex). We add a route to the IP address
+// specified by the m_linkData field of each of those link records. This will
+// be the *local* IP address associated with the interface attached to the
+// link. We use the outbound interface and next hop information present in
+// the vertex <v> which have possibly been inherited from the root.
+//
+// To summarize, we're going to look at the node represented by <v> and loop
+// through its point-to-point links, adding a *host* route to the local IP
+// address (at the <v> side) for each of those links.
+//
+ if (v->GetVertexType () == SPFVertex::VertexRouter)
+ {
+ SPFIntraAddRouter (v);
+ }
+ else if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+ SPFIntraAddTransit (v);
+ }
+ else
+ {
+ NS_ASSERT_MSG(0, "illegal SPFVertex type");
+ }
+//
+// RFC2328 16.1. (5).
+//
+// Iterate the algorithm by returning to Step 2 until there are no more
+// candidate vertices.
+//
+ }
+//
+// Second stage of SPF calculation procedure's
+// NOTYET: ospf_spf_process_stubs (area, area->spf, new_table);
+//
+// We're all done setting the routing information for the node at the root of
+// the SPF tree. Delete all of the vertices and corresponding resources. Go
+// possibly do it again for the next router.
+//
+ delete m_spfroot;
+ m_spfroot = 0;
+}
+
+//
+// Return the interface index corresponding to a given IP address
+// This is a wrapper around GetIfIndexByIpv4Address(), but we first
+// have to find the right node pointer to pass to that function.
+//
+ uint32_t
+GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask)
+{
+ NS_LOG_FUNCTION;
+//
+// We have an IP address <a> and a vertex ID of the root of the SPF tree.
+// The question is what interface index does this address correspond to.
+// The answer is a little complicated since we have to find a pointer to
+// the node corresponding to the vertex ID, find the Ipv4 interface on that
+// node in order to iterate the interfaces and find the one corresponding to
+// the address in question.
+//
+ Ipv4Address routerId = m_spfroot->GetVertexId ();
+//
+// Walk the list of nodes in the system looking for the one corresponding to
+// the node at the root of the SPF tree. This is the node for which we are
+// building the routing table.
+//
+ NodeList::Iterator i = NodeList::Begin ();
+ for (; i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// If the node doesn't have a GlobalRouter interface it can't be the one
+// we're interested in.
+//
+ if (rtr == 0)
+ {
+ continue;
+ }
+
+ if (rtr->GetRouterId () == routerId)
+ {
+//
+// This is the node we're building the routing table for. We're going to need
+// the Ipv4 interface to look for the ipv4 interface index. Since this node
+// is participating in routing IP version 4 packets, it certainly must have
+// an Ipv4 interface.
+//
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4,
+ "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+ "QI for <Ipv4> interface failed");
+//
+// Look through the interfaces on this node for one that has the IP address
+// we're looking for. If we find one, return the corresponding interface
+// index.
+//
+ return (Ipv4::GetIfIndexByAddress (node, a, amask) );
+ }
+ }
+//
+// Couldn't find it.
+//
+ return 0;
+}
+
+//
+// This method is derived from quagga ospf_intra_add_router ()
+//
+// This is where we are actually going to add the host routes to the routing
+// tables of the individual nodes.
+//
+// The vertex passed as a parameter has just been added to the SPF tree.
+// This vertex must have a valid m_root_oid, corresponding to the outgoing
+// interface on the root router of the tree that is the first hop on the path
+// to the vertex. The vertex must also have a next hop address, corresponding
+// to the next hop on the path to the vertex. The vertex has an m_lsa field
+// that has some number of link records. For each point to point link record,
+// the m_linkData is the local IP address of the link. This corresponds to
+// a destination IP address, reachable from the root, to which we add a host
+// route.
+//
+ void
+GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v)
+{
+ NS_LOG_FUNCTION;
+
+ NS_ASSERT_MSG (m_spfroot,
+ "GlobalRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are
+// going to write the actual routing table entries. The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node. We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+ Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+ NS_LOG_LOGIC ("Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex. This is the one we're going to write
+// the routing information to.
+//
+ NodeList::Iterator i = NodeList::Begin ();
+ for (; i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface. If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+//
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+ if (rtr == 0)
+ {
+ NS_LOG_LOGIC ("No GlobalRouter interface on node " <<
+ node->GetId ());
+ continue;
+ }
+//
+// If the router ID of the current node is equal to the router ID of the
+// root of the SPF tree, then this node is the one for which we need to
+// write the routing tables.
+//
+ NS_LOG_LOGIC ("Considering router " << rtr->GetRouterId ());
+
+ if (rtr->GetRouterId () == routerId)
+ {
+ NS_LOG_LOGIC ("Setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface. We need to QI
+// for that interface. If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4,
+ "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to. The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node. We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+ GlobalRoutingLSA *lsa = v->GetLSA ();
+ NS_ASSERT_MSG (lsa,
+ "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "Expected valid LSA in SPFVertex* v");
+
+ uint32_t nLinkRecords = lsa->GetNLinkRecords ();
+//
+// Iterate through the link records on the vertex to which we're going to add
+// routes. To make sure we're being clear, we're going to add routing table
+// entries to the tables on the node corresping to the root of the SPF tree.
+// These entries will have routes to the IP addresses we find from looking at
+// the local side of the point-to-point links found on the node described by
+// the vertex <v>.
+//
+ for (uint32_t j = 0; j < nLinkRecords; j += 2)
+ {
+//
+// We are only concerned about point-to-point links
+//
+ GlobalRoutingLinkRecord *lr = lsa->GetLinkRecord (j);
+ if (lr->GetLinkType () != GlobalRoutingLinkRecord::PointToPoint)
+ {
+ continue;
+ }
+
+ NS_LOG_LOGIC (" Node " << node->GetId () <<
+ " add route to " << lr->GetLinkData () <<
+ " using next hop " << v->GetNextHop () <<
+ " via interface " << v->GetOutgoingInterfaceId ());
+//
+// Here's why we did all of that work. We're going to add a host route to the
+// host address found in the m_linkData field of the point-to-point link
+// record. In the case of a point-to-point link, this is the local IP address
+// of the node connected to the link. Each of these point-to-point links
+// will correspond to a local interface that has an IP address to which
+// the node at the root of the SPF tree can send packets. The vertex <v>
+// (corresponding to the node that has these links and interfaces) has
+// an m_nextHop address precalculated for us that is the address to which the
+// root node should send packets to be forwarded to these IP addresses.
+// Similarly, the vertex <v> has an m_rootOif (outbound interface index) to
+// which the packets should be send for forwarding.
+//
+ ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (),
+ v->GetOutgoingInterfaceId ());
+ }
+//
+// Done adding the routes for the selected node.
+//
+ return;
+ }
+ }
+}
+ void
+GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v)
+{
+ NS_LOG_FUNCTION;
+
+ NS_ASSERT_MSG (m_spfroot,
+ "GlobalRouteManagerImpl::SPFIntraAddTransit (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are
+// going to write the actual routing table entries. The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node. We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+ Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+ NS_LOG_LOGIC ("Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex. This is the one we're going to write
+// the routing information to.
+//
+ NodeList::Iterator i = NodeList::Begin ();
+ for (; i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface. If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+//
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+ if (rtr == 0)
+ {
+ NS_LOG_LOGIC ("No GlobalRouter interface on node " <<
+ node->GetId ());
+ continue;
+ }
+//
+// If the router ID of the current node is equal to the router ID of the
+// root of the SPF tree, then this node is the one for which we need to
+// write the routing tables.
+//
+ NS_LOG_LOGIC ("Considering router " << rtr->GetRouterId ());
+
+ if (rtr->GetRouterId () == routerId)
+ {
+ NS_LOG_LOGIC ("setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface. We need to QI
+// for that interface. If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4,
+ "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to. The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node. We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+ GlobalRoutingLSA *lsa = v->GetLSA ();
+ NS_ASSERT_MSG (lsa,
+ "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "Expected valid LSA in SPFVertex* v");
+ Ipv4Mask tempmask = lsa->GetNetworkLSANetworkMask ();
+ Ipv4Address tempip = lsa->GetLinkStateId ();
+ tempip = tempip.CombineMask (tempmask);
+ ipv4->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (),
+ v->GetOutgoingInterfaceId ());
+ NS_LOG_LOGIC ("Node " << node->GetId () <<
+ " add network route to " << tempip <<
+ " using next hop " << v->GetNextHop () <<
+ " via interface " << v->GetOutgoingInterfaceId ());
+ }
+ }
+}
+
+// Derived from quagga ospf_vertex_add_parents ()
+//
+// This is a somewhat oddly named method (blame quagga). Although you might
+// expect it to add a parent *to* something, it actually adds a vertex
+// to the list of children *in* each of its parents.
+//
+// Given a pointer to a vertex, it links back to the vertex's parent that it
+// already has set and adds itself to that vertex's list of children.
+//
+// For now, only one parent (not doing equal-cost multipath)
+//
+ void
+GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v)
+{
+ NS_LOG_FUNCTION;
+ v->GetParent ()->AddChild (v);
+}
+
+} // namespace ns3
+
+#ifdef RUN_SELF_TESTS
+
+// ---------------------------------------------------------------------------
+//
+// Unit Tests
+//
+// ---------------------------------------------------------------------------
+
+#include "ns3/test.h"
+#include "ns3/simulator.h"
+
+namespace ns3 {
+
+class GlobalRouteManagerImplTest : public Test {
+public:
+ GlobalRouteManagerImplTest ();
+ virtual ~GlobalRouteManagerImplTest ();
+ virtual bool RunTests (void);
+};
+
+GlobalRouteManagerImplTest::GlobalRouteManagerImplTest ()
+ : Test ("GlobalRouteManagerImpl")
+{
+}
+
+GlobalRouteManagerImplTest::~GlobalRouteManagerImplTest ()
+{}
+
+ bool
+GlobalRouteManagerImplTest::RunTests (void)
+{
+ bool ok = true;
+
+ CandidateQueue candidate;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ SPFVertex *v = new SPFVertex;
+ v->SetDistanceFromRoot (rand () % 100);
+ candidate.Push (v);
+ }
+
+ uint32_t lastDistance = 0;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ SPFVertex *v = candidate.Pop ();
+ if (v->GetDistanceFromRoot () < lastDistance)
+ {
+ ok = false;
+ }
+ lastDistance = v->GetDistanceFromRoot ();
+ delete v;
+ v = 0;
+ }
+
+ // Build fake link state database; four routers (0-3), 3 point-to-point
+ // links
+ //
+ // n0
+ // \ link 0
+ // \ link 2
+ // n2 -------------------------n3
+ // /
+ // / link 1
+ // n1
+ //
+ // link0: 10.1.1.1/30, 10.1.1.2/30
+ // link1: 10.1.2.1/30, 10.1.2.2/30
+ // link2: 10.1.3.1/30, 10.1.3.2/30
+ //
+ // Router 0
+ GlobalRoutingLinkRecord* lr0 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.2", // router ID 0.0.0.2
+ "10.1.1.1", // local ID
+ 1); // metric
+
+ GlobalRoutingLinkRecord* lr1 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.1.1",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa0 = new GlobalRoutingLSA ();
+ lsa0->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa0->SetLinkStateId ("0.0.0.0");
+ lsa0->SetAdvertisingRouter ("0.0.0.0");
+ lsa0->AddLinkRecord (lr0);
+ lsa0->AddLinkRecord (lr1);
+
+ // Router 1
+ GlobalRoutingLinkRecord* lr2 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.2",
+ "10.1.2.1",
+ 1);
+
+ GlobalRoutingLinkRecord* lr3 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.2.1",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa1 = new GlobalRoutingLSA ();
+ lsa1->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa1->SetLinkStateId ("0.0.0.1");
+ lsa1->SetAdvertisingRouter ("0.0.0.1");
+ lsa1->AddLinkRecord (lr2);
+ lsa1->AddLinkRecord (lr3);
+
+ // Router 2
+ GlobalRoutingLinkRecord* lr4 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.0",
+ "10.1.1.2",
+ 1);
+
+ GlobalRoutingLinkRecord* lr5 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.1.2",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLinkRecord* lr6 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.1",
+ "10.1.2.2",
+ 1);
+
+ GlobalRoutingLinkRecord* lr7 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.2.2",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLinkRecord* lr8 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.3",
+ "10.1.3.2",
+ 1);
+
+ GlobalRoutingLinkRecord* lr9 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.3.2",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa2 = new GlobalRoutingLSA ();
+ lsa2->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa2->SetLinkStateId ("0.0.0.2");
+ lsa2->SetAdvertisingRouter ("0.0.0.2");
+ lsa2->AddLinkRecord (lr4);
+ lsa2->AddLinkRecord (lr5);
+ lsa2->AddLinkRecord (lr6);
+ lsa2->AddLinkRecord (lr7);
+ lsa2->AddLinkRecord (lr8);
+ lsa2->AddLinkRecord (lr9);
+
+ // Router 3
+ GlobalRoutingLinkRecord* lr10 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.2",
+ "10.1.2.1",
+ 1);
+
+ GlobalRoutingLinkRecord* lr11 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.2.1",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa3 = new GlobalRoutingLSA ();
+ lsa3->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa3->SetLinkStateId ("0.0.0.3");
+ lsa3->SetAdvertisingRouter ("0.0.0.3");
+ lsa3->AddLinkRecord (lr10);
+ lsa3->AddLinkRecord (lr11);
+
+ // Test the database
+ GlobalRouteManagerLSDB* srmlsdb = new GlobalRouteManagerLSDB ();
+ srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0);
+ srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1);
+ srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2);
+ srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3);
+ NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ()));
+
+ // next, calculate routes based on the manually created LSDB
+ GlobalRouteManagerImpl* srm = new GlobalRouteManagerImpl ();
+ srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB
+ // Note-- this will succeed without any nodes in the topology
+ // because the NodeList is empty
+ srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0
+
+ Simulator::Run ();
+
+// XXX here we should do some verification of the routes built
+
+ Simulator::Destroy ();
+
+ // This delete clears the srm, which deletes the LSDB, which clears
+ // all of the LSAs, which each destroys the attached LinkRecords.
+ delete srm;
+
+ return ok;
+}
+
+// Instantiate this class for the unit tests
+static GlobalRouteManagerImplTest g_globalRouteManagerTest;
+
+} // namespace ns3
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,768 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Authors: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_IMPL_H
+#define GLOBAL_ROUTE_MANAGER_IMPL_H
+
+#include <stdint.h>
+#include <list>
+#include <queue>
+#include <map>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "global-router-interface.h"
+
+namespace ns3 {
+
+const uint32_t SPF_INFINITY = 0xffffffff;
+
+class CandidateQueue;
+
+/**
+ * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328,
+ * Section 16.
+ *
+ * Each router in the simulation is associated with an SPFVertex object. When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes. Each of these
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is the SPFVertex representing the router that is having
+ * its routing tables set. The SPFVertex objects representing other routers
+ * or networks in the simulation are arranged in the SPF tree. It is this
+ * tree that represents the Shortest Paths to the other networks.
+ *
+ * Each SPFVertex has a pointer to the Global Router Link State Advertisement
+ * (LSA) that its underlying router has exported. Within these LSAs are
+ * Global Router Link Records that describe the point to point links from the
+ * underlying router to other nodes (represented by other SPFVertex objects)
+ * in the simulation topology. The combination of the arrangement of the
+ * SPFVertex objects in the SPF tree, along with the details of the link
+ * records that connect them provide the information required to construct the
+ * required routes.
+ */
+class SPFVertex
+{
+public:
+/**
+ * @brief Enumeration of the possible types of SPFVertex objects.
+ * @internal
+ *
+ * Currently we use VertexRouter to identify objects that represent a router
+ * in the simulation topology, and VertexNetwork to identify objects that
+ * represent a network.
+ */
+ enum VertexType {
+ VertexUnknown = 0, /**< Uninitialized Link Record */
+ VertexRouter, /**< Vertex representing a router in the topology */
+ VertexNetwork /**< Vertex representing a network in the topology */
+ };
+
+/**
+ * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First
+ * Vertex).
+ * @internal
+ *
+ * The Vertex Type is set to VertexUnknown, the Vertex ID is set to
+ * 255.255.255.255, and the distance from root is set to infinity
+ * (UINT32_MAX). The referenced Link State Advertisement (LSA) is set to
+ * null as is the parent SPFVertex. The outgoing interface index is set to
+ * infinity, the next hop address is set to 0.0.0.0 and the list of children
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see VertexType
+ */
+ SPFVertex();
+
+/**
+ * @brief Construct an initialized SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The Vertex Type is initialized to VertexRouter and the Vertex ID is found
+ * from the Link State ID of the Link State Advertisement (LSA) passed as a
+ * parameter. The Link State ID is set to the Router ID of the advertising
+ * router. The referenced LSA (m_lsa) is set to the given LSA. Other than
+ * these members, initialization is as in the default constructor.
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see SPFVertex::SPFVertex ()
+ * @see VertexType
+ * @see GlobalRoutingLSA
+ * @param lsa The Link State Advertisement used for finding initial values.
+ */
+ SPFVertex(GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Destroy an SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The children vertices of the SPFVertex are recursively deleted.
+ *
+ * @see SPFVertex::SPFVertex ()
+ */
+ ~SPFVertex();
+
+/**
+ * @brief Get the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @returns The VertexType of the current SPFVertex object.
+ */
+ VertexType GetVertexType (void) const;
+
+/**
+ * @brief Set the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @param type The new VertexType for the current SPFVertex object.
+ */
+ void SetVertexType (VertexType type);
+
+/**
+ * @brief Get the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents. Typically, this is the Router ID for SPFVertex objects
+ * representing routers, and comes from the Link State Advertisement of a
+ * router aggregated to a node in the simulation. These IDs are allocated
+ * automatically by the routing environment and look like IP addresses
+ * beginning at 0.0.0.0 and monotonically increasing as new routers are
+ * instantiated.
+ *
+ * @returns The Ipv4Address Vertex ID of the current SPFVertex object.
+ */
+ Ipv4Address GetVertexId (void) const;
+
+/**
+ * @brief Set the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents. Typically, this is the Router ID for SPFVertex objects
+ * representing routers, and comes from the Link State Advertisement of a
+ * router aggregated to a node in the simulation. These IDs are allocated
+ * automatically by the routing environment and look like IP addresses
+ * beginning at 0.0.0.0 and monotonically increase as new routers are
+ * instantiated. This method is an explicit override of the automatically
+ * generated value.
+ *
+ * @param id The new Ipv4Address Vertex ID for the current SPFVertex object.
+ */
+ void SetVertexId (Ipv4Address id);
+
+/**
+ * @brief Get the Global Router Link State Advertisement returned by the
+ * Global Router represented by this SPFVertex during the route discovery
+ * process.
+ * @internal
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @returns A pointer to the GlobalRoutingLSA found by the router represented
+ * by this SPFVertex object.
+ */
+ GlobalRoutingLSA* GetLSA (void) const;
+
+/**
+ * @brief Set the Global Router Link State Advertisement returned by the
+ * Global Router represented by this SPFVertex during the route discovery
+ * process.
+ * @internal
+ *
+ * @see SPFVertex::GetLSA ()
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You
+ * must not delete the LSA after calling this method.
+ * @param lsa A pointer to the GlobalRoutingLSA.
+ */
+ void SetLSA (GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Get the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object. When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes. Each of these
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root. The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * The distance is calculated during route discovery and is stored in a
+ * member variable. This method simply fetches that value.
+ *
+ * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex.
+ */
+ uint32_t GetDistanceFromRoot (void) const;
+
+/**
+ * @brief Set the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object. When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes. Each of these
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root. The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * @param distance The distance, in hops, from the root SPFVertex to "this"
+ * SPFVertex.
+ */
+ void SetDistanceFromRoot (uint32_t distance);
+
+/**
+ * @brief Get the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter. These interfaces are used to
+ * forward packets off of the root's network down those links. As other
+ * vertices are discovered which are further away from the root, they will
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which of my local interfaces
+ * should I use to get a packet to the network or host represented by 'this'
+ * SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The interface index to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+ uint32_t GetOutgoingInterfaceId (void) const;
+
+/**
+ * @brief Set the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter. These interfaces are used to
+ * forward packets off of the root's network down those links. As other
+ * vertices are discovered which are further away from the root, they will
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, we are letting the root node know which of its local
+ * interfaces it should use to get a packet to the network or host represented
+ * by "this" SPFVertex.
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param id The interface index to use when forwarding packets to the host or
+ * network represented by "this" SPFVertex.
+ */
+ void SetOutgoingInterfaceId (uint32_t id);
+
+/**
+ * @brief Get the IP address that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The IP address that we're asking for is the address on the
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter. This
+ * address is used to forward packets off of the root's network down those
+ * links. As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which router should I send a
+ * packet to in order to get that packet to the network or host represented
+ * by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+ Ipv4Address GetNextHop (void) const;
+
+/**
+ * @brief Set the IP address that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The IP address that we're asking for is the address on the
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter. This
+ * address is used to forward packets off of the root's network down those
+ * links. As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method we are telling the root node which router it should send
+ * should I send a packet to in order to get that packet to the network or
+ * host represented by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param nextHop The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+ void SetNextHop (Ipv4Address nextHop);
+
+/**
+ * @brief Get a pointer to the SPFVector that is the parent of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method returns a pointer to the parent node of "this" SPFVertex
+ * (both of which reside in that SPF tree).
+ *
+ * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex
+ * in the SPF tree.
+ */
+ SPFVertex* GetParent (void) const;
+
+/**
+ * @brief Set the pointer to the SPFVector that is the parent of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method sets the parent pointer of "this" SPFVertex (both of which
+ * reside in that SPF tree).
+ *
+ * @param parent A pointer to the SPFVertex that is the parent of "this"
+ * SPFVertex* in the SPF tree.
+ */
+ void SetParent (SPFVertex* parent);
+
+/**
+ * @brief Get the number of children of "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree. Each vertex
+ * in the SPF tree can have a number of children that represent host or
+ * network routes available via that vertex.
+ *
+ * This method returns the number of children of "this" SPFVertex (which
+ * reside in the SPF tree).
+ *
+ * @returns The number of children of "this" SPFVertex (which reside in the
+ * SPF tree).
+ */
+ uint32_t GetNChildren (void) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree. Each vertex
+ * in the SPF tree can have a number of children that represent host or
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @param n The index (from 0 to the number of children minus 1) of the
+ * child SPFVertex to return.
+ * @warning The pointer returned by GetChild () is a borrowed pointer. You
+ * do not have any ownership of the underlying object and must not delete
+ * that object.
+ * @returns A pointer to the specified child SPFVertex (which resides in the
+ * SPF tree).
+ */
+ SPFVertex* GetChild (uint32_t n) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree. Each vertex
+ * in the SPF tree can have a number of children that represent host or
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @warning Ownership of the pointer added to the children of "this"
+ * SPFVertex is transferred to the "this" SPFVertex. You must not delete the
+ * (now) child SPFVertex after calling this method.
+ * @param child A pointer to the SPFVertex (which resides in the SPF tree) to
+ * be added to the list of children of "this" SPFVertex.
+ * @returns The number of children of "this" SPFVertex after the addition of
+ * the new child.
+ */
+ uint32_t AddChild (SPFVertex* child);
+
+private:
+ VertexType m_vertexType;
+ Ipv4Address m_vertexId;
+ GlobalRoutingLSA* m_lsa;
+ uint32_t m_distanceFromRoot;
+ uint32_t m_rootOif;
+ Ipv4Address m_nextHop;
+ SPFVertex* m_parent;
+ typedef std::list<SPFVertex*> ListOfSPFVertex_t;
+ ListOfSPFVertex_t m_children;
+
+/**
+ * @brief The SPFVertex copy construction is disallowed. There's no need for
+ * it and a compiler provided shallow copy would be wrong.
+ */
+ SPFVertex (SPFVertex& v);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ SPFVertex& operator= (SPFVertex& v);
+};
+
+/**
+ * @brief The Link State DataBase (LSDB) of the Global Route Manager.
+ *
+ * Each node in the simulation participating in global routing has a
+ * GlobalRouter interface. The primary job of this interface is to export
+ * Global Router Link State Advertisements (LSAs). These advertisements in
+ * turn contain a number of Global Router Link Records that describe the
+ * point to point links from the underlying node to other nodes (that will
+ * also export their own LSAs.
+ *
+ * This class implements a searchable database of LSAs gathered from every
+ * router in the simulation.
+ */
+class GlobalRouteManagerLSDB
+{
+public:
+/**
+ * @brief Construct an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map composing the Link State Database is initialized in
+ * this constructor.
+ */
+ GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Destroy an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map is walked and all of the Link State Advertisements stored
+ * in the database are freed; then the database map itself is clear ()ed to
+ * release any remaining resources.
+ */
+ ~GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Insert an IP address / Link State Advertisement pair into the Link
+ * State Database.
+ * @internal
+ *
+ * The IPV4 address and the GlobalRoutingLSA given as parameters are converted
+ * to an STL pair and are inserted into the database map.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA. Typically the Router
+ * ID.
+ * @param lsa A pointer to the Link State Advertisement for the router.
+ */
+ void Insert(Ipv4Address addr, GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address).
+ * @internal
+ *
+ * The database map is searched for the given IPV4 address and corresponding
+ * GlobalRoutingLSA is returned.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA. Typically the Router
+ * ID.
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ */
+ GlobalRoutingLSA* GetLSA (Ipv4Address addr) const;
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address). This is a variation of the GetLSA call
+ * to allow the LSA to be found by matching addr with the LinkData field
+ * of the TransitNetwork link record.
+ * @internal
+ *
+ * @see GetLSA
+ * @param addr The IP address associated with the LSA. Typically the Router
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ * ID.
+ */
+ GlobalRoutingLSA* GetLSAByLinkData (Ipv4Address addr) const;
+
+/**
+ * @brief Set all LSA flags to an initialized state, for SPF computation
+ * @internal
+ *
+ * This function walks the database and resets the status flags of all of the
+ * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done
+ * prior to each SPF calculation to reset the state of the SPFVertex structures
+ * that will reference the LSAs during the calculation.
+ *
+ * @see GlobalRoutingLSA
+ * @see SPFVertex
+ */
+ void Initialize ();
+
+private:
+ typedef std::map<Ipv4Address, GlobalRoutingLSA*> LSDBMap_t;
+ typedef std::pair<Ipv4Address, GlobalRoutingLSA*> LSDBPair_t;
+
+ LSDBMap_t m_database;
+/**
+ * @brief GlobalRouteManagerLSDB copy construction is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ GlobalRouteManagerLSDB (GlobalRouteManagerLSDB& lsdb);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ GlobalRouteManagerLSDB& operator= (GlobalRouteManagerLSDB& lsdb);
+};
+
+/**
+ * @brief A global router implementation.
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface. For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers,
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManagerImpl
+{
+public:
+ GlobalRouteManagerImpl ();
+ virtual ~GlobalRouteManagerImpl ();
+/**
+ * @brief Select which nodes in the system are to be router nodes and
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+ virtual void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ */
+ virtual void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+ virtual void InitializeRoutes ();
+
+/**
+ * @brief Debugging routine; allow client code to supply a pre-built LSDB
+ * @internal
+ */
+ void DebugUseLsdb (GlobalRouteManagerLSDB*);
+
+/**
+ * @brief Debugging routine; call the core SPF from the unit tests
+ * @internal
+ */
+ void DebugSPFCalculate (Ipv4Address root);
+
+private:
+/**
+ * @brief GlobalRouteManagerImpl copy construction is disallowed.
+ * There's no need for it and a compiler provided shallow copy would be
+ * wrong.
+ */
+ GlobalRouteManagerImpl (GlobalRouteManagerImpl& srmi);
+
+/**
+ * @brief Global Route Manager Implementation assignment operator is
+ * disallowed. There's no need for it and a compiler provided shallow copy
+ * would be hopelessly wrong.
+ */
+ GlobalRouteManagerImpl& operator= (GlobalRouteManagerImpl& srmi);
+
+ SPFVertex* m_spfroot;
+ GlobalRouteManagerLSDB* m_lsdb;
+ void SPFCalculate (Ipv4Address root);
+ void SPFNext (SPFVertex*, CandidateQueue&);
+ int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w,
+ GlobalRoutingLinkRecord* l, uint32_t distance);
+ void SPFVertexAddParent (SPFVertex* v);
+ GlobalRoutingLinkRecord* SPFGetNextLink (SPFVertex* v, SPFVertex* w,
+ GlobalRoutingLinkRecord* prev_link);
+ void SPFIntraAddRouter (SPFVertex* v);
+ void SPFIntraAddTransit (SPFVertex* v);
+ uint32_t FindOutgoingInterfaceId (Ipv4Address a,
+ Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_IMPL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Author: Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulation-singleton.h"
+#include "global-route-manager.h"
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManager Implementation
+//
+// ---------------------------------------------------------------------------
+
+ void
+GlobalRouteManager::PopulateRoutingTables ()
+{
+ SelectRouterNodes ();
+ BuildGlobalRoutingDatabase ();
+ InitializeRoutes ();
+}
+
+ void
+GlobalRouteManager::SelectRouterNodes ()
+{
+ SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+ SelectRouterNodes ();
+}
+
+ void
+GlobalRouteManager::BuildGlobalRoutingDatabase ()
+{
+ SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+ BuildGlobalRoutingDatabase ();
+}
+
+ void
+GlobalRouteManager::InitializeRoutes ()
+{
+ SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+ InitializeRoutes ();
+}
+
+ uint32_t
+GlobalRouteManager::AllocateRouterId ()
+{
+ static uint32_t routerId = 0;
+ return routerId++;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,98 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Authors: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_H
+#define GLOBAL_ROUTE_MANAGER_H
+
+namespace ns3 {
+
+/**
+ * @brief A global global router
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface. For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers,
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManager
+{
+public:
+/**
+ * @brief Build a routing database and initialize the routing tables of
+ * the nodes in the simulation.
+ *
+ * All this function does is call BuildGlobalRoutingDatabase () and
+ * InitializeRoutes ().
+ *
+ * @see BuildGlobalRoutingDatabase ();
+ * @see InitializeRoutes ();
+ */
+ static void PopulateRoutingTables ();
+
+/**
+ * @brief Allocate a 32-bit router ID from monotonically increasing counter.
+ */
+ static uint32_t AllocateRouterId ();
+
+private:
+/**
+ * @brief Select which nodes in the system are to be router nodes and
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+ static void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ *
+ */
+ static void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+ static void InitializeRoutes ();
+
+/**
+ * @brief Global Route Manager copy construction is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ *
+ */
+ GlobalRouteManager (GlobalRouteManager& srm);
+
+/**
+ * @brief Global Router copy assignment operator is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ GlobalRouteManager& operator= (GlobalRouteManager& srm);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,851 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Authors: Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/channel.h"
+#include "ns3/net-device.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+
+NS_LOG_COMPONENT_DEFINE ("GlobalRouter");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLinkRecord Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ()
+:
+ m_linkId ("0.0.0.0"),
+ m_linkData ("0.0.0.0"),
+ m_linkType (Unknown),
+ m_metric (0)
+{
+ NS_LOG_FUNCTION;
+}
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord (
+ LinkType linkType,
+ Ipv4Address linkId,
+ Ipv4Address linkData,
+ uint32_t metric)
+:
+ m_linkId (linkId),
+ m_linkData (linkData),
+ m_linkType (linkType),
+ m_metric (metric)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << linkType << ", " << linkId << ", " << linkData <<
+ ", " << metric << ")");
+}
+
+GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord ()
+{
+ NS_LOG_FUNCTION;
+}
+
+ Ipv4Address
+GlobalRoutingLinkRecord::GetLinkId (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_linkId;
+}
+
+ void
+GlobalRoutingLinkRecord::SetLinkId (Ipv4Address addr)
+{
+ NS_LOG_FUNCTION;
+ m_linkId = addr;
+}
+
+ Ipv4Address
+GlobalRoutingLinkRecord::GetLinkData (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_linkData;
+}
+
+ void
+GlobalRoutingLinkRecord::SetLinkData (Ipv4Address addr)
+{
+ NS_LOG_FUNCTION;
+ m_linkData = addr;
+}
+
+ GlobalRoutingLinkRecord::LinkType
+GlobalRoutingLinkRecord::GetLinkType (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_linkType;
+}
+
+ void
+GlobalRoutingLinkRecord::SetLinkType (
+ GlobalRoutingLinkRecord::LinkType linkType)
+{
+ NS_LOG_FUNCTION;
+ m_linkType = linkType;
+}
+
+ uint32_t
+GlobalRoutingLinkRecord::GetMetric (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_metric;
+}
+
+ void
+GlobalRoutingLinkRecord::SetMetric (uint32_t metric)
+{
+ NS_LOG_FUNCTION;
+ m_metric = metric;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLSA Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLSA::GlobalRoutingLSA()
+ :
+ m_lsType (GlobalRoutingLSA::Unknown),
+ m_linkStateId("0.0.0.0"),
+ m_advertisingRtr("0.0.0.0"),
+ m_linkRecords(),
+ m_networkLSANetworkMask("0.0.0.0"),
+ m_attachedRouters(),
+ m_status(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+{
+ NS_LOG_FUNCTION;
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (
+ GlobalRoutingLSA::SPFStatus status,
+ Ipv4Address linkStateId,
+ Ipv4Address advertisingRtr)
+:
+ m_lsType (GlobalRoutingLSA::Unknown),
+ m_linkStateId(linkStateId),
+ m_advertisingRtr(advertisingRtr),
+ m_linkRecords(),
+ m_networkLSANetworkMask("0.0.0.0"),
+ m_attachedRouters(),
+ m_status(status)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_PARAM ("(" << status << ", " << linkStateId << ", " <<
+ advertisingRtr << ")");
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (GlobalRoutingLSA& lsa)
+ : m_lsType(lsa.m_lsType), m_linkStateId(lsa.m_linkStateId),
+ m_advertisingRtr(lsa.m_advertisingRtr),
+ m_networkLSANetworkMask(lsa.m_networkLSANetworkMask),
+ m_status(lsa.m_status)
+{
+ NS_LOG_FUNCTION;
+ NS_ASSERT_MSG(IsEmpty(),
+ "GlobalRoutingLSA::GlobalRoutingLSA (): Non-empty LSA in constructor");
+ CopyLinkRecords (lsa);
+}
+
+ GlobalRoutingLSA&
+GlobalRoutingLSA::operator= (const GlobalRoutingLSA& lsa)
+{
+ NS_LOG_FUNCTION;
+ m_lsType = lsa.m_lsType;
+ m_linkStateId = lsa.m_linkStateId;
+ m_advertisingRtr = lsa.m_advertisingRtr;
+ m_networkLSANetworkMask = lsa.m_networkLSANetworkMask,
+ m_status = lsa.m_status;
+
+ ClearLinkRecords ();
+ CopyLinkRecords (lsa);
+ return *this;
+}
+
+ void
+GlobalRoutingLSA::CopyLinkRecords (const GlobalRoutingLSA& lsa)
+{
+ NS_LOG_FUNCTION;
+ for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin ();
+ i != lsa.m_linkRecords.end ();
+ i++)
+ {
+ GlobalRoutingLinkRecord *pSrc = *i;
+ GlobalRoutingLinkRecord *pDst = new GlobalRoutingLinkRecord;
+
+ pDst->SetLinkType (pSrc->GetLinkType ());
+ pDst->SetLinkId (pSrc->GetLinkId ());
+ pDst->SetLinkData (pSrc->GetLinkData ());
+
+ m_linkRecords.push_back(pDst);
+ pDst = 0;
+ }
+
+ m_attachedRouters = lsa.m_attachedRouters;
+}
+
+GlobalRoutingLSA::~GlobalRoutingLSA()
+{
+ NS_LOG_FUNCTION;
+ ClearLinkRecords ();
+}
+
+ void
+GlobalRoutingLSA::ClearLinkRecords(void)
+{
+ NS_LOG_FUNCTION;
+ for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin ();
+ i != m_linkRecords.end ();
+ i++)
+ {
+ NS_LOG_LOGIC ("Free link record");
+
+ GlobalRoutingLinkRecord *p = *i;
+ delete p;
+ p = 0;
+
+ *i = 0;
+ }
+ NS_LOG_LOGIC ("Clear list");
+ m_linkRecords.clear();
+}
+
+ uint32_t
+GlobalRoutingLSA::AddLinkRecord (GlobalRoutingLinkRecord* lr)
+{
+ NS_LOG_FUNCTION;
+ m_linkRecords.push_back (lr);
+ return m_linkRecords.size ();
+}
+
+ uint32_t
+GlobalRoutingLSA::GetNLinkRecords (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_linkRecords.size ();
+}
+
+ GlobalRoutingLinkRecord *
+GlobalRoutingLSA::GetLinkRecord (uint32_t n) const
+{
+ NS_LOG_FUNCTION;
+ uint32_t j = 0;
+ for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+ i != m_linkRecords.end ();
+ i++, j++)
+ {
+ if (j == n)
+ {
+ return *i;
+ }
+ }
+ NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetLinkRecord (): invalid index");
+ return 0;
+}
+
+ bool
+GlobalRoutingLSA::IsEmpty (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_linkRecords.size () == 0;
+}
+
+ GlobalRoutingLSA::LSType
+GlobalRoutingLSA::GetLSType (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_lsType;
+}
+
+ void
+GlobalRoutingLSA::SetLSType (GlobalRoutingLSA::LSType typ)
+{
+ NS_LOG_FUNCTION;
+ m_lsType = typ;
+}
+
+ Ipv4Address
+GlobalRoutingLSA::GetLinkStateId (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_linkStateId;
+}
+
+ void
+GlobalRoutingLSA::SetLinkStateId (Ipv4Address addr)
+{
+ NS_LOG_FUNCTION;
+ m_linkStateId = addr;
+}
+
+ Ipv4Address
+GlobalRoutingLSA::GetAdvertisingRouter (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_advertisingRtr;
+}
+
+ void
+GlobalRoutingLSA::SetAdvertisingRouter (Ipv4Address addr)
+{
+ NS_LOG_FUNCTION;
+ m_advertisingRtr = addr;
+}
+
+ void
+GlobalRoutingLSA::SetNetworkLSANetworkMask (Ipv4Mask mask)
+{
+ NS_LOG_FUNCTION;
+ m_networkLSANetworkMask = mask;
+}
+
+ Ipv4Mask
+GlobalRoutingLSA::GetNetworkLSANetworkMask (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_networkLSANetworkMask;
+}
+
+ GlobalRoutingLSA::SPFStatus
+GlobalRoutingLSA::GetStatus (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_status;
+}
+
+ uint32_t
+GlobalRoutingLSA::AddAttachedRouter (Ipv4Address addr)
+{
+ NS_LOG_FUNCTION;
+ m_attachedRouters.push_back (addr);
+ return m_attachedRouters.size ();
+}
+
+ uint32_t
+GlobalRoutingLSA::GetNAttachedRouters (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_attachedRouters.size ();
+}
+
+ Ipv4Address
+GlobalRoutingLSA::GetAttachedRouter (uint32_t n) const
+{
+ NS_LOG_FUNCTION;
+ uint32_t j = 0;
+ for ( ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin ();
+ i != m_attachedRouters.end ();
+ i++, j++)
+ {
+ if (j == n)
+ {
+ return *i;
+ }
+ }
+ NS_ASSERT_MSG(false,
+ "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
+ return Ipv4Address("0.0.0.0");
+}
+
+ void
+GlobalRoutingLSA::SetStatus (GlobalRoutingLSA::SPFStatus status)
+{
+ NS_LOG_FUNCTION;
+ m_status = status;
+}
+
+ void
+GlobalRoutingLSA::Print (std::ostream &os) const
+{
+ os << "m_lsType = " << m_lsType << std::endl <<
+ "m_linkStateId = " << m_linkStateId << std::endl <<
+ "m_advertisingRtr = " << m_advertisingRtr << std::endl;
+
+ if (m_lsType == GlobalRoutingLSA::RouterLSA)
+ {
+ for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+ i != m_linkRecords.end ();
+ i++)
+ {
+ GlobalRoutingLinkRecord *p = *i;
+ os << "----------" << std::endl;
+ os << "m_linkId = " << p->GetLinkId () << std::endl;
+ os << "m_linkData = " << p->GetLinkData () << std::endl;
+ }
+ }
+ else if (m_lsType == GlobalRoutingLSA::NetworkLSA)
+ {
+ os << "----------" << std::endl;
+ os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask
+ << std::endl;
+ for ( ListOfAttachedRouters_t::const_iterator i =
+ m_attachedRouters.begin ();
+ i != m_attachedRouters.end ();
+ i++)
+ {
+ Ipv4Address p = *i;
+ os << "attachedRouter = " << p << std::endl;
+ }
+ }
+ else
+ {
+ NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType);
+ }
+}
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa)
+{
+ lsa.Print (os);
+ return os;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouter Implementation
+//
+// ---------------------------------------------------------------------------
+
+const InterfaceId GlobalRouter::iid =
+ MakeInterfaceId ("GlobalRouter", Object::iid);
+
+GlobalRouter::GlobalRouter (Ptr<Node> node)
+ : m_node(node), m_LSAs()
+{
+ NS_LOG_FUNCTION;
+ SetInterfaceId (GlobalRouter::iid);
+ m_routerId.Set(GlobalRouteManager::AllocateRouterId ());
+}
+
+GlobalRouter::~GlobalRouter ()
+{
+ NS_LOG_FUNCTION;
+ ClearLSAs();
+}
+
+void
+GlobalRouter::DoDispose ()
+{
+ NS_LOG_FUNCTION;
+ m_node = 0;
+ Object::DoDispose ();
+}
+
+ void
+GlobalRouter::ClearLSAs ()
+{
+ NS_LOG_FUNCTION;
+ for ( ListOfLSAs_t::iterator i = m_LSAs.begin ();
+ i != m_LSAs.end ();
+ i++)
+ {
+ NS_LOG_LOGIC ("Free LSA");
+
+ GlobalRoutingLSA *p = *i;
+ delete p;
+ p = 0;
+
+ *i = 0;
+ }
+ NS_LOG_LOGIC ("Clear list");
+ m_LSAs.clear();
+}
+
+ Ipv4Address
+GlobalRouter::GetRouterId (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_routerId;
+}
+
+//
+// Go out and discover any adjacent routers and build the Link State
+// Advertisements that reflect them and their associated networks.
+//
+ uint32_t
+GlobalRouter::DiscoverLSAs (void)
+{
+ NS_LOG_FUNCTION;
+ NS_LOG_LOGIC("For node " << m_node->GetId () );
+ NS_ASSERT_MSG(m_node,
+ "GlobalRouter::DiscoverLSAs (): <Node> interface not set");
+
+ ClearLSAs ();
+
+// While building the router-LSA, keep a list of those NetDevices for
+// which I am the designated router and need to later build a NetworkLSA
+ std::list<Ptr<NetDevice> > listOfDRInterfaces;
+
+//
+// We're aggregated to a node. We need to ask the node for a pointer to its
+// Ipv4 interface. This is where the information regarding the attached
+// interfaces lives.
+//
+ Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG(ipv4Local,
+ "GlobalRouter::DiscoverLSAs (): QI for <Ipv4> interface failed");
+//
+// Each node originates a Router-LSA
+//
+ GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+ pLSA->SetLSType (GlobalRoutingLSA::RouterLSA);
+ pLSA->SetLinkStateId (m_routerId);
+ pLSA->SetAdvertisingRouter (m_routerId);
+ pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+//
+// We need to ask the node for the number of net devices attached. This isn't
+// necessarily equal to the number of links to adjacent nodes (other routers)
+// as the number of devices may include those for stub networks (e.g.,
+// ethernets, etc.).
+//
+ uint32_t numDevices = m_node->GetNDevices();
+ NS_LOG_LOGIC ("numDevices = " << numDevices);
+ for (uint32_t i = 0; i < numDevices; ++i)
+ {
+ Ptr<NetDevice> ndLocal = m_node->GetDevice(i);
+
+ if (ndLocal->IsBroadcast () && !ndLocal->IsPointToPoint () )
+ {
+ NS_LOG_LOGIC ("Broadcast link");
+ GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+//
+// We need to determine whether we are on a transit or stub network
+// If we find at least one more router on this channel, we are a transit
+//
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we
+// just found. This is still the IP on the local side of the channel. There
+// is a function to do this used down in the guts of the stack, but it's not
+// exported so we had to whip up an equivalent.
+//
+ uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+ NS_LOG_LOGIC ("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of
+// the point-to-point channel we now know we have. This is where our adjacent
+// router (to use OSPF lingo) is running.
+//
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ uint32_t nDevices = ch->GetNDevices();
+ if (nDevices == 1)
+ {
+ // This is a stub broadcast interface
+ NS_LOG_LOGIC("Router-LSA stub broadcast link");
+ // XXX in future, need to consider if >1 includes other routers
+ plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+ // Link ID is IP network number of attached network
+ plr->SetLinkId (addrLocal.CombineMask(maskLocal));
+ // Link Data is network mask; convert to Ipv4Address
+ Ipv4Address maskLocalAddr;
+ maskLocalAddr.Set(maskLocal.GetHostOrder ());
+ plr->SetLinkData (maskLocalAddr);
+ // Cost is interface's configured output cost (NOTYET)
+ plr->SetMetric (1);
+ pLSA->AddLinkRecord(plr);
+ plr = 0;
+ continue;
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Router-LSA Broadcast link");
+ // multiple routers on a broadcast interface
+ // lowest IP address is designated router
+ plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork);
+ // Link ID is IP interface address of designated router
+ Ipv4Address desigRtr =
+ FindDesignatedRouterForLink (m_node, ndLocal);
+ if (desigRtr == addrLocal)
+ {
+ listOfDRInterfaces.push_back (ndLocal);
+ NS_LOG_LOGIC (m_node->GetId () << " is a DR");
+ }
+ plr->SetLinkId (desigRtr);
+ // Link Data is router's own IP address
+ plr->SetLinkData (addrLocal);
+ // Cost is interface's configured output cost (NOTYET)
+ plr->SetMetric (1);
+ pLSA->AddLinkRecord (plr);
+ plr = 0;
+ continue;
+ }
+ }
+ else if (ndLocal->IsPointToPoint () )
+ {
+ NS_LOG_LOGIC ("Router-LSA Point-to-point device");
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we
+// just found. This is still the IP on the local side of the channel. There
+// is a function to do this used down in the guts of the stack, but it's not
+// exported so we had to whip up an equivalent.
+//
+ uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+//
+// Now that we have the Ipv4 interface index, we can get the address and mask
+// we need.
+//
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+ NS_LOG_LOGIC ("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of
+// the point-to-point channel we now know we have. This is where our adjacent
+// router (to use OSPF lingo) is running.
+//
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
+//
+// The adjacent net device is aggregated to a node. We need to ask that net
+// device for its node, then ask that node for its Ipv4 interface.
+//
+ Ptr<Node> nodeRemote = ndRemote->GetNode();
+ Ptr<Ipv4> ipv4Remote = nodeRemote->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG(ipv4Remote,
+ "GlobalRouter::DiscoverLSAs (): QI for remote <Ipv4> failed");
+//
+// Per the OSPF spec, we're going to need the remote router ID, so we might as
+// well get it now.
+//
+ Ptr<GlobalRouter> srRemote =
+ nodeRemote->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+ NS_ASSERT_MSG(srRemote,
+ "GlobalRouter::DiscoverLSAs():QI for remote <GlobalRouter> failed");
+ Ipv4Address rtrIdRemote = srRemote->GetRouterId();
+ NS_LOG_LOGIC ("Working with remote router " << rtrIdRemote);
+//
+// Now, just like we did above, we need to get the IP interface index for the
+// net device on the other end of the point-to-point channel.
+//
+ uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote);
+//
+// Now that we have the Ipv4 interface, we can get the (remote) address and
+// mask we need.
+//
+ Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote);
+ Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote);
+ NS_LOG_LOGIC ("Working with remote address " << addrRemote);
+//
+// Now we can fill out the link records for this link. There are always two
+// link records; the first is a point-to-point record describing the link and
+// the second is a stub network record with the network number.
+//
+ GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+ plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint);
+ plr->SetLinkId (rtrIdRemote);
+ plr->SetLinkData (addrLocal);
+ pLSA->AddLinkRecord (plr);
+ plr = 0;
+
+ plr = new GlobalRoutingLinkRecord;
+ plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+ plr->SetLinkId (addrRemote);
+ plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown
+ pLSA->AddLinkRecord (plr);
+ plr = 0;
+ }
+ else
+ {
+ NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type");
+ }
+
+ }
+//
+// The LSA goes on a list of LSAs in case we want to begin exporting other
+// kinds of advertisements (than Router LSAs).
+ m_LSAs.push_back (pLSA);
+ NS_LOG_LOGIC (*pLSA);
+
+// Now, determine whether we need to build a NetworkLSA
+ if (listOfDRInterfaces.size () > 0)
+ {
+ for (std::list<Ptr<NetDevice> >::iterator i = listOfDRInterfaces.begin ();
+ i != listOfDRInterfaces.end (); i++)
+ {
+// Build one NetworkLSA for each interface that is a DR
+ Ptr<NetDevice> ndLocal = *i;
+ uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+ GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+ pLSA->SetLSType (GlobalRoutingLSA::NetworkLSA);
+ pLSA->SetLinkStateId (addrLocal);
+ pLSA->SetAdvertisingRouter (m_routerId);
+ pLSA->SetNetworkLSANetworkMask (maskLocal);
+ pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+// Build list of AttachedRouters
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ uint32_t nDevices = ch->GetNDevices();
+ NS_ASSERT (nDevices);
+ for (uint32_t i = 0; i < nDevices; i++)
+ {
+ Ptr<NetDevice> tempNd = ch->GetDevice (i);
+ NS_ASSERT (tempNd);
+ Ptr<Node> tempNode = tempNd->GetNode ();
+ uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+ Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT (tempIpv4);
+ Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+ pLSA->AddAttachedRouter (tempAddr);
+ }
+ m_LSAs.push_back (pLSA);
+ NS_LOG_LOGIC (*pLSA);
+ }
+ }
+
+ return m_LSAs.size ();
+}
+
+ Ipv4Address
+GlobalRouter::FindDesignatedRouterForLink (Ptr<Node> node,
+ Ptr<NetDevice> ndLocal) const
+{
+ uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
+ Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT (ipv4Local);
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ uint32_t nDevices = ch->GetNDevices();
+ NS_ASSERT (nDevices);
+ Ipv4Address lowest = addrLocal;
+ // iterate all NetDevices and return the lowest numbered IP address
+ for (uint32_t i = 0; i < nDevices; i++)
+ {
+ Ptr<NetDevice> tempNd = ch->GetDevice (i);
+ NS_ASSERT (tempNd);
+ Ptr<Node> tempNode = tempNd->GetNode ();
+ uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+ Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT (tempIpv4);
+ Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+ if (tempAddr < addrLocal)
+ {
+ addrLocal = tempAddr;
+ }
+ }
+ return addrLocal;
+}
+
+ uint32_t
+GlobalRouter::GetNumLSAs (void) const
+{
+ NS_LOG_FUNCTION;
+ return m_LSAs.size ();
+}
+
+//
+// Get the nth link state advertisement from this router.
+//
+ bool
+GlobalRouter::GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const
+{
+ NS_LOG_FUNCTION;
+ NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA");
+//
+// All of the work was done in GetNumLSAs. All we have to do here is to
+// walk the list of link state advertisements created there and return the
+// one the client is interested in.
+//
+ ListOfLSAs_t::const_iterator i = m_LSAs.begin ();
+ uint32_t j = 0;
+
+ for (; i != m_LSAs.end (); i++, j++)
+ {
+ if (j == n)
+ {
+ GlobalRoutingLSA *p = *i;
+ lsa = *p;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Link through the given channel and find the net device that's on the
+// other end. This only makes sense with a point-to-point channel.
+//
+ Ptr<NetDevice>
+GlobalRouter::GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const
+{
+ NS_LOG_FUNCTION;
+ NS_ASSERT_MSG(ch->GetNDevices() == 2,
+ "GlobalRouter::GetAdjacent (): Channel with other than two devices");
+//
+// This is a point to point channel with two endpoints. Get both of them.
+//
+ Ptr<NetDevice> nd1 = ch->GetDevice(0);
+ Ptr<NetDevice> nd2 = ch->GetDevice(1);
+//
+// One of the endpoints is going to be "us" -- that is the net device attached
+// to the node on which we're running -- i.e., "nd". The other endpoint (the
+// one to which we are connected via the channel) is the adjacent router.
+//
+ if (nd1 == nd)
+ {
+ return nd2;
+ }
+ else if (nd2 == nd)
+ {
+ return nd1;
+ }
+ else
+ {
+ NS_ASSERT_MSG(false,
+ "GlobalRouter::GetAdjacent (): Wrong or confused channel?");
+ return 0;
+ }
+}
+
+//
+// Given a node and a net device, find the IPV4 interface index that
+// corresponds to that net device.
+//
+ uint32_t
+GlobalRouter::FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const
+{
+ NS_LOG_FUNCTION;
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG(ipv4, "QI for <Ipv4> interface failed");
+ for (uint32_t i = 0; i < ipv4->GetNInterfaces(); ++i )
+ {
+ if (ipv4->GetNetDevice(i) == nd)
+ {
+ return i;
+ }
+ }
+
+ NS_ASSERT_MSG(0, "Cannot find interface for device");
+ return 0;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.h Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,672 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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
+ *
+ * Authors: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#ifndef GLOBAL_ROUTER_INTERFACE_H
+#define GLOBAL_ROUTER_INTERFACE_H
+
+#include <stdint.h>
+#include <list>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/global-route-manager.h"
+
+namespace ns3 {
+
+/**
+ * @brief A single link record for a link state advertisement.
+ *
+ * The GlobalRoutingLinkRecord is modeled after the OSPF link record field of
+ * a Link State Advertisement. Right now we will only see two types of link
+ * records corresponding to a stub network and a point-to-point link (channel).
+ */
+class GlobalRoutingLinkRecord
+{
+public:
+/**
+ * @enum LinkType
+ * @brief Enumeration of the possible types of Global Routing Link Records.
+ *
+ * These values are defined in the OSPF spec. We currently only use
+ * PointToPoint and StubNetwork types.
+ */
+ enum LinkType {
+ Unknown = 0, /**< Uninitialized Link Record */
+ PointToPoint, /**< Record representing a point to point channel */
+ TransitNetwork, /**< Unused -- for future OSPF compatibility */
+ StubNetwork, /**< Record represents a leaf node network */
+ VirtualLink /**< Unused -- for future OSPF compatibility */
+ };
+
+/**
+ * @brief Construct an empty ("uninitialized") Global Routing Link Record.
+ *
+ * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0";
+ * The Link Type is set to Unknown;
+ * The metric is set to 0.
+ */
+ GlobalRoutingLinkRecord ();
+
+/**
+ * Construct an initialized Global Routing Link Record.
+ *
+ * @param linkType The type of link record to construct.
+ * @param linkId The link ID for the record.
+ * @param linkData The link data field for the record.
+ * @param metric The metric field for the record.
+ * @see LinkType
+ * @see SetLinkId
+ * @see SetLinkData
+ */
+ GlobalRoutingLinkRecord (
+ LinkType linkType,
+ Ipv4Address linkId,
+ Ipv4Address linkData,
+ uint32_t metric);
+
+/**
+ * @brief Destroy a Global Routing Link Record.
+ *
+ * Currently does nothing. Here as a placeholder only.
+ */
+ ~GlobalRoutingLinkRecord ();
+
+/**
+ * Get the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent
+ * neighbor's IP address
+ *
+ * @returns The Ipv4Address corresponding to the Link ID field of the record.
+ */
+ Ipv4Address GetLinkId(void) const;
+
+/**
+ * @brief Set the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent
+ * neighbor's IP address
+ *
+ * @param addr An Ipv4Address to store in the Link ID field of the record.
+ */
+ void SetLinkId(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data will be the
+ * network mask
+ *
+ * @returns The Ipv4Address corresponding to the Link Data field of the record.
+ */
+ Ipv4Address GetLinkData(void) const;
+
+/**
+ * @brief Set the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the
+ * network mask
+ *
+ * @param addr An Ipv4Address to store in the Link Data field of the record.
+ */
+ void SetLinkData(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents. The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @returns The LinkType of the current Global Routing Link Record.
+ */
+ LinkType GetLinkType(void) const;
+
+/**
+ * @brief Set the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents. The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @param linkType The new LinkType for the current Global Routing Link Record.
+ */
+ void SetLinkType(LinkType linkType);
+
+/**
+ * @brief Get the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link. A sum of metrics must have a well-defined meaning. That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @returns The metric field of the Global Routing Link Record.
+ */
+ uint32_t GetMetric(void) const;
+
+/**
+ * @brief Set the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link. A sum of metrics must have a well-defined meaning. That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @param metric The new metric for the current Global Routing Link Record.
+ */
+ void SetMetric(uint32_t metric);
+
+private:
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings
+ * depending on the type of link a given link records represents. They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkId to Router ID of
+ * neighboring router.
+ *
+ * For Type 3 link (Stub), set m_linkId to neighbor's IP address
+ */
+ Ipv4Address m_linkId;
+
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings
+ * depending on the type of link a given link records represents. They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkData to local IP address
+ *
+ * For Type 3 link (Stub), set m_linkData to mask
+ */
+ Ipv4Address m_linkData; // for links to RouterLSA,
+
+/**
+ * The type of the Global Routing Link Record. Defined in the OSPF spec.
+ * We currently only use PointToPoint and StubNetwork types.
+ */
+ LinkType m_linkType;
+
+/**
+ * The metric for a given link.
+ *
+ * A metric is abstract cost associated with forwarding a packet across a
+ * link. A sum of metrics must have a well-defined meaning. That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth
+ * of two hops relate to the cost of sending a packet); rather you should
+ * use something like delay.
+ */
+ uint32_t m_metric;
+};
+
+/**
+ * @brief a Link State Advertisement (LSA) for a router, used in global
+ * routing.
+ *
+ * Roughly equivalent to a global incarnation of the OSPF link state header
+ * combined with a list of Link Records. Since it's global, there's
+ * no need for age or sequence number. See RFC 2328, Appendix A.
+ */
+class GlobalRoutingLSA
+{
+public:
+/**
+ * @enum LSType
+ * @brief corresponds to LS type field of RFC 2328 OSPF LSA header
+ */
+ enum LSType {
+ Unknown = 0, /**< Uninitialized Type */
+ RouterLSA,
+ NetworkLSA,
+ SummaryLSA,
+ SummaryLSA_ASBR,
+ ASExternalLSAs
+ };
+/**
+ * @enum SPFStatus
+ * @brief Enumeration of the possible values of the status flag in the Routing
+ * Link State Advertisements.
+ */
+ enum SPFStatus {
+ LSA_SPF_NOT_EXPLORED = 0, /**< New vertex not yet considered */
+ LSA_SPF_CANDIDATE, /**< Vertex is in the SPF candidate queue */
+ LSA_SPF_IN_SPFTREE /**< Vertex is in the SPF tree */
+ };
+/**
+ * @brief Create a blank Global Routing Link State Advertisement.
+ *
+ * On completion Ipv4Address variables initialized to 0.0.0.0 and the
+ * list of Link State Records is empty.
+ */
+ GlobalRoutingLSA();
+
+/**
+ * @brief Create an initialized Global Routing Link State Advertisement.
+ *
+ * On completion the list of Link State Records is empty.
+ *
+ * @param status The status to of the new LSA.
+ * @param linkStateId The Ipv4Address for the link state ID field.
+ * @param advertisingRtr The Ipv4Address for the advertising router field.
+ */
+ GlobalRoutingLSA(SPFStatus status, Ipv4Address linkStateId,
+ Ipv4Address advertisingRtr);
+
+/**
+ * @brief Copy constructor for a Global Routing Link State Advertisement.
+ *
+ * Takes a piece of memory and constructs a semantically identical copy of
+ * the given LSA.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ */
+ GlobalRoutingLSA (GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Destroy an existing Global Routing Link State Advertisement.
+ *
+ * Any Global Routing Link Records present in the list are freed.
+ */
+ ~GlobalRoutingLSA();
+
+/**
+ * @brief Assignment operator for a Global Routing Link State Advertisement.
+ *
+ * Takes an existing Global Routing Link State Advertisement and overwrites
+ * it to make a semantically identical copy of a given prototype LSA.
+ *
+ * If there are any Global Routing Link Records present in the existing
+ * LSA, they are freed before the assignment happens.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ * @returns Reference to the overwritten LSA.
+ */
+ GlobalRoutingLSA& operator= (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Copy any Global Routing Link Records in a given Global Routing Link
+ * State Advertisement to the current LSA.
+ *
+ * Existing Link Records are not deleted -- this is a concatenation of Link
+ * Records.
+ *
+ * @see ClearLinkRecords ()
+ * @param lsa The LSA to copy the Link Records from.
+ */
+ void CopyLinkRecords (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Add a given Global Routing Link Record to the LSA.
+ *
+ * @param lr The Global Routing Link Record to be added.
+ * @returns The number of link records in the list.
+ */
+ uint32_t AddLinkRecord (GlobalRoutingLinkRecord* lr);
+
+/**
+ * @brief Return the number of Global Routing Link Records in the LSA.
+ *
+ * @returns The number of link records in the list.
+ */
+ uint32_t GetNLinkRecords (void) const;
+
+/**
+ * @brief Return a pointer to the specified Global Routing Link Record.
+ *
+ * @param n The LSA number desired.
+ * @returns The number of link records in the list.
+ */
+ GlobalRoutingLinkRecord* GetLinkRecord (uint32_t n) const;
+
+/**
+ * @brief Release all of the Global Routing Link Records present in the Global
+ * Routing Link State Advertisement and make the list of link records empty.
+ */
+ void ClearLinkRecords(void);
+
+/**
+ * @brief Check to see if the list of Global Routing Link Records present in the
+ * Global Routing Link State Advertisement is empty.
+ *
+ * @returns True if the list is empty, false otherwise.
+ */
+ bool IsEmpty(void) const;
+
+/**
+ * @brief Print the contents of the Global Routing Link State Advertisement and
+ * any Global Routing Link Records present in the list. Quite verbose.
+ */
+ void Print (std::ostream &os) const;
+
+/**
+ * @brief Return the LSType field of the LSA
+ */
+ LSType GetLSType (void) const;
+/**
+ * @brief Set the LS type field of the LSA
+ */
+ void SetLSType (LSType typ);
+
+/**
+ * @brief Get the Link State ID as defined by the OSPF spec. We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the link state ID.
+ */
+ Ipv4Address GetLinkStateId (void) const;
+
+/**
+ * @brief Set the Link State ID is defined by the OSPF spec. We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ void SetLinkStateId (Ipv4Address addr);
+
+/**
+ * @brief Get the Advertising Router as defined by the OSPF spec. We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the advetising router.
+ */
+ Ipv4Address GetAdvertisingRouter (void) const;
+
+/**
+ * @brief Set the Advertising Router as defined by the OSPF spec. We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ void SetAdvertisingRouter (Ipv4Address rtr);
+
+/**
+ * @brief For a Network LSA, set the Network Mask field that precedes
+ * the list of attached routers.
+ */
+ void SetNetworkLSANetworkMask (Ipv4Mask mask);
+
+/**
+ * @brief For a Network LSA, get the Network Mask field that precedes
+ * the list of attached routers.
+ *
+ * @returns the NetworkLSANetworkMask
+ */
+ Ipv4Mask GetNetworkLSANetworkMask (void) const;
+
+/**
+ * @brief Add an attached router to the list in the NetworkLSA
+ *
+ * @param addr The Ipv4Address of the interface on the network link
+ * @returns The number of addresses in the list.
+ */
+ uint32_t AddAttachedRouter (Ipv4Address addr);
+
+/**
+ * @brief Return the number of attached routers listed in the NetworkLSA
+ *
+ * @returns The number of attached routers.
+ */
+ uint32_t GetNAttachedRouters (void) const;
+
+/**
+ * @brief Return an Ipv4Address corresponding to the specified attached router
+ *
+ * @param n The attached router number desired (number in the list).
+ * @returns The Ipv4Address of the requested router
+ */
+ Ipv4Address GetAttachedRouter (uint32_t n) const;
+
+/**
+ * @brief Get the SPF status of the advertisement.
+ *
+ * @see SPFStatus
+ * @returns The SPFStatus of the LSA.
+ */
+ SPFStatus GetStatus (void) const;
+
+/**
+ * @brief Set the SPF status of the advertisement
+ *
+ * @see SPFStatus
+ */
+ void SetStatus (SPFStatus status);
+
+private:
+/**
+ * The type of the LSA. Each LSA type has a separate advertisement
+ * format.
+ */
+ LSType m_lsType;
+/**
+ * The Link State ID is defined by the OSPF spec. We always set it to the
+ * router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ Ipv4Address m_linkStateId;
+
+/**
+ * The Advertising Router is defined by the OSPF spec. We always set it to
+ * the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ Ipv4Address m_advertisingRtr;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+ typedef std::list<GlobalRoutingLinkRecord*> ListOfLinkRecords_t;
+
+/**
+ * Each Link State Advertisement contains a number of Link Records that
+ * describe the kinds of links that are attached to a given node. We
+ * consider PointToPoint and StubNetwork links.
+ *
+ * m_linkRecords is an STL list container to hold the Link Records that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+ ListOfLinkRecords_t m_linkRecords;
+
+/**
+ * Each Network LSA contains the network mask of the attached network
+ */
+ Ipv4Mask m_networkLSANetworkMask;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+ typedef std::list<Ipv4Address> ListOfAttachedRouters_t;
+
+/**
+ * Each Network LSA contains a list of attached routers
+ *
+ * m_attachedRouters is an STL list container to hold the addresses that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+ ListOfAttachedRouters_t m_attachedRouters;
+
+/**
+ * This is a tristate flag used internally in the SPF computation to mark
+ * if an SPFVertex (a data structure representing a vertex in the SPF tree
+ * -- a router) is new, is a candidate for a shortest path, or is in its
+ * proper position in the tree.
+ */
+ SPFStatus m_status;
+};
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa);
+
+/**
+ * @brief An interface aggregated to a node to provide global routing info
+ *
+ * An interface aggregated to a node that provides global routing information
+ * to a global route manager. The presence of the interface indicates that
+ * the node is a router. The interface is the mechanism by which the router
+ * advertises its connections to neighboring routers. We're basically
+ * allowing the route manager to query for link state advertisements.
+ */
+class GlobalRouter : public Object
+{
+public:
+/**
+ * @brief The Interface ID of the Global Router interface.
+ *
+ * @see Object::QueryInterface ()
+ */
+ static const InterfaceId iid;
+
+/**
+ * @brief Create a Global Router class and aggregate its interface onto the
+ * Node provided.
+ *
+ * @param node The existing Node onto which this router will be aggregated.
+ */
+ GlobalRouter (Ptr<Node> node);
+
+/**
+ * @brief Get the Router ID associated with this Global Router.
+ *
+ * The Router IDs are allocated in the RoutingEnvironment -- one per Router,
+ * starting at 0.0.0.1 and incrementing with each instantiation of a router.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @returns The Router ID associated with the Global Router.
+ */
+ Ipv4Address GetRouterId (void) const;
+
+/**
+ * @brief Walk the connected channels, discover the adjacent routers and build
+ * the associated number of Global Routing Link State Advertisements that
+ * this router can export.
+ *
+ * This is a fairly expensive operation in that every time it is called
+ * the current list of LSAs is built by walking connected point-to-point
+ * channels and peeking into adjacent IPV4 stacks to get address information.
+ * This is done to allow for limited dymanics of the Global Routing
+ * environment. By that we mean that you can discover new link state
+ * advertisements after a network topology change by calling DiscoverLSAs
+ * and then by reading those advertisements.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+ uint32_t DiscoverLSAs (void);
+
+/**
+ * @brief Get the Number of Global Routing Link State Advertisements that this
+ * router can export.
+ *
+ * To get meaningful information you must have previously called DiscoverLSAs.
+ * After you know how many LSAs are present in the router, you may call
+ * GetLSA () to retrieve the actual advertisement.
+ *
+ * @see GlobalRouterLSA
+ * @see GlobalRouting::DiscoverLSAs ()
+ * @see GlobalRouting::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+ uint32_t GetNumLSAs (void) const;
+
+/**
+ * @brief Get a Global Routing Link State Advertisements that this router has
+ * said that it can export.
+ *
+ * This is a fairly inexpensive expensive operation in that the hard work
+ * was done in GetNumLSAs. We just copy the indicated Global Routing Link
+ * State Advertisement into the requested GlobalRoutingLSA object.
+ *
+ * You must call GlobalRouter::GetNumLSAs before calling this method in
+ * order to discover the adjacent routers and build the advertisements.
+ * GetNumLSAs will return the number of LSAs this router advertises.
+ * The parameter n (requested LSA number) must be in the range 0 to
+ * GetNumLSAs() - 1.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouting::GetNumLSAs ()
+ * @param n The index number of the LSA you want to read.
+ * @param lsa The GlobalRoutingLSA class to receive the LSA information.
+ * @returns The number of Global Router Link State Advertisements.
+ */
+ bool GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const;
+
+private:
+ virtual ~GlobalRouter ();
+ void ClearLSAs (void);
+
+ Ptr<NetDevice> GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const;
+ uint32_t FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const;
+ Ipv4Address FindDesignatedRouterForLink (Ptr<Node> node,
+ Ptr<NetDevice> ndLocal) const;
+
+ Ptr<Node> m_node;
+
+ typedef std::list<GlobalRoutingLSA*> ListOfLSAs_t;
+ ListOfLSAs_t m_LSAs;
+
+ Ipv4Address m_routerId;
+
+ // inherited from Object
+ virtual void DoDispose (void);
+
+/**
+ * @brief Global Router copy construction is disallowed.
+ */
+ GlobalRouter (GlobalRouter& sr);
+
+/**
+ * @brief Global Router assignment operator is disallowed.
+ */
+ GlobalRouter& operator= (GlobalRouter& sr);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTER_INTERFACE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,17 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ module = bld.create_ns3_module('global-routing', ['node'])
+ module.source = [
+ 'global-router-interface.cc',
+ 'global-route-manager.cc',
+ 'global-route-manager-impl.cc',
+ 'candidate-queue.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'global-router-interface.h',
+ 'global-route-manager.h',
+ 'candidate-queue.h',
+ ]
+
--- a/src/simulator/event-id.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-id.cc Fri Sep 28 11:59:46 2007 +0100
@@ -30,7 +30,7 @@
m_uid (0)
{}
-EventId::EventId (EventImpl *impl, uint64_t ts, uint32_t uid)
+EventId::EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid)
: m_eventImpl (impl),
m_ts (ts),
m_uid (uid)
@@ -38,26 +38,22 @@
void
EventId::Cancel (void)
{
- if (!IsExpired ())
- {
- m_eventImpl->Cancel ();
- m_eventImpl = 0;
- }
+ Simulator::Cancel (*this);
}
bool
-EventId::IsExpired (void)
+EventId::IsExpired (void) const
{
return Simulator::IsExpired (*this);
}
bool
-EventId::IsRunning (void)
+EventId::IsRunning (void) const
{
return !IsExpired ();
}
EventImpl *
-EventId::GetEventImpl (void) const
+EventId::PeekEventImpl (void) const
{
- return m_eventImpl;
+ return PeekPointer (m_eventImpl);
}
uint64_t
EventId::GetTs (void) const
--- a/src/simulator/event-id.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-id.h Fri Sep 28 11:59:46 2007 +0100
@@ -22,6 +22,8 @@
#define EVENT_ID_H
#include <stdint.h>
+#include "ns3/ptr.h"
+#include "event-impl.h"
namespace ns3 {
@@ -33,7 +35,7 @@
class EventId {
public:
EventId ();
- EventId (EventImpl *impl, uint64_t ts, uint32_t uid);
+ EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid);
/**
* This method is syntactic sugar for the ns3::Simulator::cancel
* method.
@@ -44,19 +46,19 @@
* method.
* \returns true if the event has expired, false otherwise.
*/
- bool IsExpired (void);
- bool IsRunning (void);
+ bool IsExpired (void) const;
+ bool IsRunning (void) const;
public:
/* The following methods are semi-private
* they are supposed to be invoked only by
* subclasses of the Scheduler base class.
*/
- EventImpl *GetEventImpl (void) const;
+ EventImpl *PeekEventImpl (void) const;
uint64_t GetTs (void) const;
uint32_t GetUid (void) const;
private:
friend bool operator == (const EventId &a, const EventId &b);
- EventImpl *m_eventImpl;
+ Ptr<EventImpl> m_eventImpl;
uint64_t m_ts;
uint32_t m_uid;
};
--- a/src/simulator/event-impl.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-impl.cc Fri Sep 28 11:59:46 2007 +0100
@@ -29,7 +29,8 @@
{}
EventImpl::EventImpl ()
- : m_cancel (false)
+ : m_cancel (false),
+ m_count (1)
{}
void
EventImpl::Invoke (void)
--- a/src/simulator/event-impl.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-impl.h Fri Sep 28 11:59:46 2007 +0100
@@ -28,6 +28,8 @@
class EventImpl {
public:
EventImpl ();
+ inline void Ref (void) const;
+ inline void Unref (void) const;
virtual ~EventImpl () = 0;
void Invoke (void);
void Cancel (void);
@@ -37,8 +39,28 @@
private:
friend class Event;
bool m_cancel;
+ mutable uint32_t m_count;
};
}; // namespace ns3
+namespace ns3 {
+
+void
+EventImpl::Ref (void) const
+{
+ m_count++;
+}
+void
+EventImpl::Unref (void) const
+{
+ m_count--;
+ if (m_count == 0)
+ {
+ delete this;
+ }
+}
+
+} // namespace ns3
+
#endif /* EVENT_IMPL_H */
--- a/src/simulator/high-precision-128.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/high-precision-128.h Fri Sep 28 11:59:46 2007 +0100
@@ -222,7 +222,9 @@
HP128INC (m_nslowcmps);
return SlowCompare (o);
}
-
+ // The below statement is unreachable but necessary for optimized
+ // builds with gcc-4.0.x due to a compiler bug.
+ return 0;
}
HighPrecision
HighPrecision::Zero (void)
--- a/src/simulator/scheduler-heap.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-heap.cc Fri Sep 28 11:59:46 2007 +0100
@@ -170,7 +170,7 @@
}
bool
-SchedulerHeap::RealIsEmpty (void) const
+SchedulerHeap::IsEmpty (void) const
{
return (m_heap.size () == 1)?true:false;
}
@@ -223,9 +223,11 @@
void
-SchedulerHeap::RealInsert (EventId id)
+SchedulerHeap::Insert (const EventId &id)
{
- EventImpl *event = id.GetEventImpl ();
+ // acquire single ref
+ EventImpl *event = id.PeekEventImpl ();
+ event->Ref ();
Scheduler::EventKey key;
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
@@ -234,29 +236,34 @@
}
EventId
-SchedulerHeap::RealPeekNext (void) const
+SchedulerHeap::PeekNext (void) const
{
std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
return EventId (next.first, next.second.m_ts, next.second.m_uid);
}
-void
-SchedulerHeap::RealRemoveNext (void)
+EventId
+SchedulerHeap::RemoveNext (void)
{
+ std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
Exch (Root (), Last ());
m_heap.pop_back ();
TopDown (Root ());
+ return EventId (Ptr<EventImpl> (next.first, false), next.second.m_ts, next.second.m_uid);
}
bool
-SchedulerHeap::RealRemove (EventId id)
+SchedulerHeap::Remove (const EventId &id)
{
uint32_t uid = id.GetUid ();
for (uint32_t i = 1; i < m_heap.size (); i++)
{
if (uid == m_heap[i].second.m_uid)
{
- NS_ASSERT (m_heap[i].first == id.GetEventImpl ());
+ NS_ASSERT (m_heap[i].first == id.PeekEventImpl ());
+ std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[i];
+ // release single ref
+ next.first->Unref ();
Exch (i, Last ());
m_heap.pop_back ();
TopDown (i);
--- a/src/simulator/scheduler-heap.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-heap.h Fri Sep 28 11:59:46 2007 +0100
@@ -35,13 +35,13 @@
SchedulerHeap ();
virtual ~SchedulerHeap ();
+ virtual void Insert (const EventId &id);
+ virtual bool IsEmpty (void) const;
+ virtual EventId PeekNext (void) const;
+ virtual EventId RemoveNext (void);
+ virtual bool Remove (const EventId &ev);
+
private:
- virtual void RealInsert (EventId id);
- virtual bool RealIsEmpty (void) const;
- virtual EventId RealPeekNext (void) const;
- virtual void RealRemoveNext (void);
- virtual bool RealRemove (EventId ev);
-
typedef std::vector<std::pair<EventImpl *, Scheduler::EventKey> > BinaryHeap;
inline uint32_t Parent (uint32_t id) const;
--- a/src/simulator/scheduler-list.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-list.cc Fri Sep 28 11:59:46 2007 +0100
@@ -67,10 +67,12 @@
}
void
-SchedulerList::RealInsert (EventId id)
+SchedulerList::Insert (const EventId &id)
{
Scheduler::EventKey key;
- EventImpl *event = id.GetEventImpl ();
+ // acquire refcount on EventImpl
+ EventImpl *event = id.PeekEventImpl ();
+ event->Ref ();
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
for (EventsI i = m_events.begin (); i != m_events.end (); i++)
@@ -84,31 +86,35 @@
m_events.push_back (std::make_pair (event, key));
}
bool
-SchedulerList::RealIsEmpty (void) const
+SchedulerList::IsEmpty (void) const
{
return m_events.empty ();
}
EventId
-SchedulerList::RealPeekNext (void) const
+SchedulerList::PeekNext (void) const
{
std::pair<EventImpl *, EventKey> next = m_events.front ();
return EventId (next.first, next.second.m_ts, next.second.m_uid);
}
-void
-SchedulerList::RealRemoveNext (void)
+EventId
+SchedulerList::RemoveNext (void)
{
+ std::pair<EventImpl *, EventKey> next = m_events.front ();
m_events.pop_front ();
+ return EventId (Ptr<EventImpl> (next.first,false), next.second.m_ts, next.second.m_uid);
}
bool
-SchedulerList::RealRemove (EventId id)
+SchedulerList::Remove (const EventId &id)
{
for (EventsI i = m_events.begin (); i != m_events.end (); i++)
{
if (i->second.m_uid == id.GetUid ())
{
- NS_ASSERT (id.GetEventImpl () == i->first);
+ NS_ASSERT (id.PeekEventImpl () == i->first);
+ // release single acquire ref.
+ i->first->Unref ();
m_events.erase (i);
return true;
}
--- a/src/simulator/scheduler-list.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-list.h Fri Sep 28 11:59:46 2007 +0100
@@ -37,13 +37,13 @@
SchedulerList ();
virtual ~SchedulerList ();
+ virtual void Insert (const EventId &id);
+ virtual bool IsEmpty (void) const;
+ virtual EventId PeekNext (void) const;
+ virtual EventId RemoveNext (void);
+ virtual bool Remove (const EventId &ev);
+
private:
- virtual void RealInsert (EventId id);
- virtual bool RealIsEmpty (void) const;
- virtual EventId RealPeekNext (void) const;
- virtual void RealRemoveNext (void);
- virtual bool RealRemove (EventId ev);
-
inline bool IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const;
typedef std::list<std::pair<EventImpl*, EventKey> > Events;
--- a/src/simulator/scheduler-map.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-map.cc Fri Sep 28 11:59:46 2007 +0100
@@ -88,9 +88,11 @@
void
-SchedulerMap::RealInsert (EventId id)
+SchedulerMap::Insert (const EventId &id)
{
- EventImpl *event = id.GetEventImpl ();
+ // acquire a single ref
+ EventImpl *event = id.PeekEventImpl ();
+ event->Ref ();
Scheduler::EventKey key;
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
@@ -100,33 +102,38 @@
}
bool
-SchedulerMap::RealIsEmpty (void) const
+SchedulerMap::IsEmpty (void) const
{
return m_list.empty ();
}
EventId
-SchedulerMap::RealPeekNext (void) const
+SchedulerMap::PeekNext (void) const
{
EventMapCI i = m_list.begin ();
NS_ASSERT (i != m_list.end ());
return EventId (i->second, i->first.m_ts, i->first.m_uid);
}
-void
-SchedulerMap::RealRemoveNext (void)
+EventId
+SchedulerMap::RemoveNext (void)
{
- m_list.erase (m_list.begin ());
+ EventMapI i = m_list.begin ();
+ std::pair<Scheduler::EventKey, EventImpl*> next = *i;
+ m_list.erase (i);
+ return EventId (Ptr<EventImpl> (next.second, false), next.first.m_ts, next.first.m_uid);
}
bool
-SchedulerMap::RealRemove (EventId id)
+SchedulerMap::Remove (const EventId &id)
{
Scheduler::EventKey key;
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
EventMapI i = m_list.find (key);
- NS_ASSERT (i->second == id.GetEventImpl ());
+ NS_ASSERT (i->second == id.PeekEventImpl ());
+ // release single ref.
+ i->second->Unref ();
m_list.erase (i);
return true;
}
--- a/src/simulator/scheduler-map.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-map.h Fri Sep 28 11:59:46 2007 +0100
@@ -36,12 +36,12 @@
SchedulerMap ();
virtual ~SchedulerMap ();
+ virtual void Insert (const EventId &id);
+ virtual bool IsEmpty (void) const;
+ virtual EventId PeekNext (void) const;
+ virtual EventId RemoveNext (void);
+ virtual bool Remove (const EventId &ev);
private:
- virtual void RealInsert (EventId id);
- virtual bool RealIsEmpty (void) const;
- virtual EventId RealPeekNext (void) const;
- virtual void RealRemoveNext (void);
- virtual bool RealRemove (EventId ev);
class EventKeyCompare {
public:
--- a/src/simulator/scheduler.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler.cc Fri Sep 28 11:59:46 2007 +0100
@@ -27,33 +27,4 @@
Scheduler::~Scheduler ()
{}
-void
-Scheduler::Insert (EventId id)
-{
- return RealInsert (id);
-}
-bool
-Scheduler::IsEmpty (void) const
-{
- return RealIsEmpty ();
-}
-EventId
-Scheduler::PeekNext (void) const
-{
- NS_ASSERT (!RealIsEmpty ());
- return RealPeekNext ();
-}
-void
-Scheduler::RemoveNext (void)
-{
- NS_ASSERT (!RealIsEmpty ());
- return RealRemoveNext ();
-}
-bool
-Scheduler::Remove (EventId id)
-{
- NS_ASSERT (!RealIsEmpty ());
- return RealRemove (id);
-}
-
}; // namespace ns3
--- a/src/simulator/scheduler.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler.h Fri Sep 28 11:59:46 2007 +0100
@@ -27,21 +27,18 @@
namespace ns3 {
-class EventImpl;
-
/**
* \brief Maintain the event list
*
* This base class specifies the interface used to maintain the
* event list. If you want to provide a new event list scheduler,
* you need to create a subclass of this base class and implement
- * all the private pure virtual methods defined here. Namely:
- * - ns3::Scheduler::realInsert
- * - ns3::Scheduler::realIsEmpty
- * - ns3::Scheduler::realPeekNext
- * - ns3::Scheduler::realPeekNextKey
- * - ns3::Scheduler::realRemoveNext
- * - ns3::Scheduler::realRemove
+ * all the pure virtual methods defined here. Namely:
+ * - ns3::Scheduler::Insert
+ * - ns3::Scheduler::IsEmpty
+ * - ns3::Scheduler::PeekNext
+ * - ns3::Scheduler::RemoveNext
+ * - ns3::Scheduler::Remove
*
* If you need to provide a new event list scheduler without
* editing the main simulator class, you need to also implement
@@ -60,41 +57,36 @@
virtual ~Scheduler () = 0;
- void Insert (EventId id);
- bool IsEmpty (void) const;
- EventId PeekNext (void) const;
- void RemoveNext (void);
- bool Remove (EventId);
-
-private:
/**
- * \param id the event id to store.
+ * \param id event to store in the event list
*
+ * This method takes ownership of the event pointer.
*/
- virtual void RealInsert (EventId id) = 0;
+ virtual void Insert (const EventId &id) = 0;
/**
* \returns true if the event list is empty and false otherwise.
*/
- virtual bool RealIsEmpty (void) const = 0;
+ virtual bool IsEmpty (void) const = 0;
/**
- * \returns a the next earliest event.
+ * \returns a pointer to the next earliest event. The caller
+ * takes ownership of the returned pointer.
*
* This method cannot be invoked if the list is empty.
*/
- virtual EventId RealPeekNext (void) const = 0;
+ virtual EventId PeekNext (void) const = 0;
/**
* This method cannot be invoked if the list is empty.
* Remove the next earliest event from the event list.
*/
- virtual void RealRemoveNext (void) = 0;
+ virtual EventId RemoveNext (void) = 0;
/**
* \param id the id of the event to remove
- * \returns true if the event was found and removed
+ * \returns true if the id was found and removed
* successfully, false otherwise.
*
* This methods cannot be invoked if the list is empty.
*/
- virtual bool RealRemove (EventId id) = 0;
+ virtual bool Remove (const EventId &id) = 0;
};
}; // namespace ns3
--- a/src/simulator/simulator.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/simulator.cc Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,7 @@
#include "scheduler.h"
#include "event-impl.h"
+#include "ns3/ptr.h"
#include "ns3/assert.h"
#include "ns3/default-value.h"
@@ -61,12 +62,12 @@
Time Next (void) const;
void Stop (void);
void StopAt (Time const &time);
- EventId Schedule (Time const &time, EventImpl *event);
- EventId ScheduleNow (EventImpl *event);
- EventId ScheduleDestroy (EventImpl *event);
- void Remove (EventId ev);
- void Cancel (EventId &ev);
- bool IsExpired (EventId ev);
+ EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+ EventId ScheduleNow (const Ptr<EventImpl> &event);
+ EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+ void Remove (const EventId &ev);
+ void Cancel (const EventId &ev);
+ bool IsExpired (const EventId &ev);
void Run (void);
Time Now (void) const;
@@ -114,13 +115,12 @@
{
while (!m_destroyEvents.empty ())
{
- EventImpl *ev = m_destroyEvents.front ().GetEventImpl ();
+ Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
m_destroyEvents.pop_front ();
TRACE ("handle destroy " << ev);
if (!ev->IsCancelled ())
{
ev->Invoke ();
- delete ev;
}
}
delete m_events;
@@ -138,8 +138,7 @@
void
SimulatorPrivate::ProcessOneEvent (void)
{
- EventId next = m_events->PeekNext ();
- m_events->RemoveNext ();
+ EventId next = m_events->RemoveNext ();
NS_ASSERT (next.GetTs () >= m_currentTs);
--m_unscheduledEvents;
@@ -151,9 +150,8 @@
{
m_log << "e "<<next.GetUid () << " " << next.GetTs () << std::endl;
}
- EventImpl *event = next.GetEventImpl ();
+ EventImpl *event = next.PeekEventImpl ();
event->Invoke ();
- delete event;
}
bool
@@ -204,7 +202,7 @@
m_stopAt = at.GetTimeStep ();
}
EventId
-SimulatorPrivate::Schedule (Time const &time, EventImpl *event)
+SimulatorPrivate::Schedule (Time const &time, const Ptr<EventImpl> &event)
{
NS_ASSERT (time.IsPositive ());
NS_ASSERT (time >= TimeStep (m_currentTs));
@@ -221,7 +219,7 @@
return id;
}
EventId
-SimulatorPrivate::ScheduleNow (EventImpl *event)
+SimulatorPrivate::ScheduleNow (const Ptr<EventImpl> &event)
{
EventId id (event, m_currentTs, m_uid);
if (m_logEnable)
@@ -235,7 +233,7 @@
return id;
}
EventId
-SimulatorPrivate::ScheduleDestroy (EventImpl *event)
+SimulatorPrivate::ScheduleDestroy (const Ptr<EventImpl> &event)
{
EventId id (event, m_currentTs, 2);
m_destroyEvents.push_back (id);
@@ -255,7 +253,7 @@
}
void
-SimulatorPrivate::Remove (EventId ev)
+SimulatorPrivate::Remove (const EventId &ev)
{
if (ev.GetUid () == 2)
{
@@ -267,7 +265,7 @@
m_destroyEvents.erase (i);
break;
}
- }
+ }
return;
}
if (IsExpired (ev))
@@ -275,7 +273,8 @@
return;
}
m_events->Remove (ev);
- delete ev.GetEventImpl ();
+ Cancel (ev);
+
if (m_logEnable)
{
m_log << "r " << m_currentUid << " " << m_currentTs << " "
@@ -285,19 +284,34 @@
}
void
-SimulatorPrivate::Cancel (EventId &id)
+SimulatorPrivate::Cancel (const EventId &id)
{
- id.Cancel ();
+ if (!IsExpired (id))
+ {
+ id.PeekEventImpl ()->Cancel ();
+ }
}
bool
-SimulatorPrivate::IsExpired (EventId ev)
+SimulatorPrivate::IsExpired (const EventId &ev)
{
- if (ev.GetEventImpl () == 0 ||
+ if (ev.GetUid () == 2)
+ {
+ // destroy events.
+ for (DestroyEvents::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.GetEventImpl ()->IsCancelled ())
+ ev.PeekEventImpl ()->IsCancelled ())
{
return true;
}
@@ -323,20 +337,20 @@
void Simulator::SetLinkedList (void)
{
- Bind ("Scheduler", "List");
+ DefaultValue::Bind ("Scheduler", "List");
}
void Simulator::SetBinaryHeap (void)
{
- Bind ("Scheduler", "BinaryHeap");
+ DefaultValue::Bind ("Scheduler", "BinaryHeap");
}
void Simulator::SetStdMap (void)
{
- Bind ("Scheduler", "Map");
+ DefaultValue::Bind ("Scheduler", "Map");
}
void
Simulator::SetExternal (const std::string &external)
{
- Bind ("Scheduler", external);
+ DefaultValue::Bind ("Scheduler", external);
}
void Simulator::EnableLogTo (char const *filename)
{
@@ -398,39 +412,39 @@
return GetPriv ()->Now ();
}
-EventImpl *
+Ptr<EventImpl>
Simulator::MakeEvent (void (*f) (void))
{
// zero arg version
class EventFunctionImpl0 : public EventImpl {
public:
- typedef void (*F)(void);
+ typedef void (*F)(void);
- EventFunctionImpl0 (F function)
- : m_function (function)
- {}
- virtual ~EventFunctionImpl0 () {}
+ EventFunctionImpl0 (F function)
+ : m_function (function)
+ {}
+ virtual ~EventFunctionImpl0 () {}
protected:
- virtual void Notify (void) {
- (*m_function) ();
- }
+ virtual void Notify (void) {
+ (*m_function) ();
+ }
private:
F m_function;
} *ev = new EventFunctionImpl0 (f);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
EventId
-Simulator::Schedule (Time const &time, EventImpl *ev)
+Simulator::Schedule (Time const &time, const Ptr<EventImpl> &ev)
{
return GetPriv ()->Schedule (Now () + time, ev);
}
EventId
-Simulator::ScheduleNow (EventImpl *ev)
+Simulator::ScheduleNow (const Ptr<EventImpl> &ev)
{
return GetPriv ()->ScheduleNow (ev);
}
EventId
-Simulator::ScheduleDestroy (EventImpl *ev)
+Simulator::ScheduleDestroy (const Ptr<EventImpl> &ev)
{
return GetPriv ()->ScheduleDestroy (ev);
}
@@ -452,18 +466,18 @@
void
-Simulator::Remove (EventId ev)
+Simulator::Remove (const EventId &ev)
{
return GetPriv ()->Remove (ev);
}
void
-Simulator::Cancel (EventId &ev)
+Simulator::Cancel (const EventId &ev)
{
return GetPriv ()->Cancel (ev);
}
bool
-Simulator::IsExpired (EventId id)
+Simulator::IsExpired (const EventId &id)
{
return GetPriv ()->IsExpired (id);
}
@@ -494,20 +508,45 @@
static void foo4 (int, int, int, int)
{}
static void foo5 (int, int, int, int, int)
-{}
+{}
+
+#if 1
+static void ber1 (int &)
+{}
+static void ber2 (int &, int &)
+{}
+static void ber3 (int &, int &, int &)
+{}
+static void ber4 (int &, int &, int &, int &)
+{}
+static void ber5 (int &, int &, int &, int &, int &)
+{}
+#endif
+
+static void cber1 (const int &)
+{}
+static void cber2 (const int &, const int &)
+{}
+static void cber3 (const int &, const int &, const int &)
+{}
+static void cber4 (const int &, const int &, const int &, const int &)
+{}
+static void cber5 (const int &, const int &, const int &, const int &, const int &)
+{}
class SimulatorTests : public Test {
public:
SimulatorTests ();
// only here for testing of Ptr<>
- void Ref (void);
- void Unref (void);
+ void Ref (void) const;
+ void Unref (void) const;
virtual ~SimulatorTests ();
virtual bool RunTests (void);
private:
uint64_t NowUs ();
bool RunOneTest (void);
+ void RunTestsConst (void) const;
void A (int a);
void B (int b);
void C (int c);
@@ -518,12 +557,43 @@
void bar3 (int, int, int);
void bar4 (int, int, int, int);
void bar5 (int, int, int, int, int);
+ void baz1 (int &);
+ void baz2 (int &, int &);
+ void baz3 (int &, int &, int &);
+ void baz4 (int &, int &, int &, int &);
+ void baz5 (int &, int &, int &, int &, int &);
+ void cbaz1 (const int &);
+ void cbaz2 (const int &, const int &);
+ void cbaz3 (const int &, const int &, const int &);
+ void cbaz4 (const int &, const int &, const int &, const int &);
+ void cbaz5 (const int &, const int &, const int &, const int &, const int &);
+
+ void bar0c (void) const;
+ void bar1c (int) const;
+ void bar2c (int, int) const;
+ void bar3c (int, int, int) const;
+ void bar4c (int, int, int, int) const;
+ void bar5c (int, int, int, int, int) const;
+ void baz1c (int &) const;
+ void baz2c (int &, int &) const;
+ void baz3c (int &, int &, int &) const;
+ void baz4c (int &, int &, int &, int &) const;
+ void baz5c (int &, int &, int &, int &, int &) const;
+ void cbaz1c (const int &) const;
+ void cbaz2c (const int &, const int &) const;
+ void cbaz3c (const int &, const int &, const int &) const;
+ void cbaz4c (const int &, const int &, const int &, const int &) const;
+ void cbaz5c (const int &, const int &, const int &, const int &, const int &) const;
+
+ void destroy (void);
bool m_b;
bool m_a;
bool m_c;
bool m_d;
EventId m_idC;
+ bool m_destroy;
+ EventId m_destroyId;
};
SimulatorTests::SimulatorTests ()
@@ -532,10 +602,10 @@
SimulatorTests::~SimulatorTests ()
{}
void
-SimulatorTests::Ref (void)
+SimulatorTests::Ref (void) const
{}
void
-SimulatorTests::Unref (void)
+SimulatorTests::Unref (void) const
{}
uint64_t
SimulatorTests::NowUs (void)
@@ -579,6 +649,14 @@
m_d = true;
}
}
+void
+SimulatorTests::destroy (void)
+{
+ if (m_destroyId.IsExpired ())
+ {
+ m_destroy = true;
+ }
+}
void
SimulatorTests::bar0 (void)
{}
@@ -598,10 +676,93 @@
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 &)
+{}
+
+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 &)
+{}
+
+void
+SimulatorTests::bar0c (void) const
+{}
+void
+SimulatorTests::bar1c (int) const
+{}
+void
+SimulatorTests::bar2c (int, int) const
+{}
+void
+SimulatorTests::bar3c (int, int, int) const
+{}
+void
+SimulatorTests::bar4c (int, int, int, int) const
+{}
+void
+SimulatorTests::bar5c (int, int, int, int, int) const
+{}
+
+void
+SimulatorTests::baz1c (int &) const
+{}
+void
+SimulatorTests::baz2c (int &, int &) const
+{}
+void
+SimulatorTests::baz3c (int &, int &, int &) const
+{}
+void
+SimulatorTests::baz4c (int &, int &, int &, int &) const
+{}
+void
+SimulatorTests::baz5c (int &, int &, int &, int &, int &) const
+{}
+
+void
+SimulatorTests::cbaz1c (const int &) const
+{}
+void
+SimulatorTests::cbaz2c (const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz3c (const int &, const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz4c (const int &, const int &, const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz5c (const int &, const int &, const int &, const int &, const int &) const
+{}
+
bool
SimulatorTests::RunOneTest (void)
{
- bool ok = true;
+ bool result = true;
m_a = true;
m_b = false;
m_c = true;
@@ -611,48 +772,113 @@
Simulator::Schedule (MicroSeconds (11), &SimulatorTests::B, this, 2);
m_idC = Simulator::Schedule (MicroSeconds (12), &SimulatorTests::C, this, 3);
- if (m_idC.IsExpired ())
- {
- ok = false;
- }
- if (a.IsExpired ())
- {
- ok = false;
- }
+ NS_TEST_ASSERT (!m_idC.IsExpired ());
+ NS_TEST_ASSERT (!a.IsExpired ());
Simulator::Cancel (a);
- if (!a.IsExpired ())
- {
- ok = false;
- }
+ NS_TEST_ASSERT (a.IsExpired ());
Simulator::Run ();
+ NS_TEST_ASSERT (m_a);
+ NS_TEST_ASSERT (m_b);
+ NS_TEST_ASSERT (m_c);
+ NS_TEST_ASSERT (m_d);
+ return result;
+}
+void
+SimulatorTests::RunTestsConst (void) const
+{
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, this);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1c, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2c, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3c, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar0c, this);
+ Simulator::ScheduleNow (&SimulatorTests::bar1c, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar2c, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar3c, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz1c, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz2c, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+ Simulator::ScheduleNow (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar0c, this);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar1c, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar2c, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar3c, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz1c, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz2c, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+ Simulator::ScheduleDestroy (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1c, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2c, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3c, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz4c, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz1c, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz2c, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz3c, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz1c, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz2c, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz3c, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
- if (!m_a || !m_b || !m_c || !m_d)
- {
- ok = false;
- }
- return ok;
+ Simulator::Run ();
+ Simulator::Destroy ();
}
+
bool
SimulatorTests::RunTests (void)
{
- bool ok = true;
+ bool result = true;
+ Simulator::Destroy ();
Simulator::SetLinkedList ();
if (!RunOneTest ())
{
- ok = false;
+ result = false;
}
Simulator::Destroy ();
Simulator::SetBinaryHeap ();
if (!RunOneTest ())
{
- ok = false;
+ result = false;
}
Simulator::Destroy ();
Simulator::SetStdMap ();
if (!RunOneTest ())
{
- ok = false;
+ result = false;
}
Simulator::Destroy ();
@@ -663,6 +889,11 @@
Simulator::Schedule (Seconds (0.0), &foo3, 0, 0, 0);
Simulator::Schedule (Seconds (0.0), &foo4, 0, 0, 0, 0);
Simulator::Schedule (Seconds (0.0), &foo5, 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &cber1, 0);
+ Simulator::Schedule (Seconds (0.0), &cber2, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &cber3, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &cber4, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &cber5, 0, 0, 0, 0, 0);
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0, this);
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1, this, 0);
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2, this, 0, 0);
@@ -675,18 +906,33 @@
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3, Ptr<SimulatorTests> (this), 0, 0, 0);
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4, Ptr<SimulatorTests> (this), 0, 0, 0, 0);
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5, Ptr<SimulatorTests> (this), 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz4, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz5, this, 0, 0, 0, 0, 0);
Simulator::ScheduleNow (&foo0);
Simulator::ScheduleNow (&foo1, 0);
Simulator::ScheduleNow (&foo2, 0, 0);
Simulator::ScheduleNow (&foo3, 0, 0, 0);
Simulator::ScheduleNow (&foo4, 0, 0, 0, 0);
Simulator::ScheduleNow (&foo5, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&cber1, 0);
+ Simulator::ScheduleNow (&cber2, 0, 0);
+ Simulator::ScheduleNow (&cber3, 0, 0, 0);
+ Simulator::ScheduleNow (&cber4, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&cber5, 0, 0, 0, 0, 0);
Simulator::ScheduleNow (&SimulatorTests::bar0, this);
Simulator::ScheduleNow (&SimulatorTests::bar1, this, 0);
Simulator::ScheduleNow (&SimulatorTests::bar2, this, 0, 0);
Simulator::ScheduleNow (&SimulatorTests::bar3, this, 0, 0, 0);
Simulator::ScheduleNow (&SimulatorTests::bar4, this, 0, 0, 0, 0);
Simulator::ScheduleNow (&SimulatorTests::bar5, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz1, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz2, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz3, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz4, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz5, this, 0, 0, 0, 0, 0);
Simulator::ScheduleNow (&SimulatorTests::bar0, Ptr<SimulatorTests> (this));
Simulator::ScheduleNow (&SimulatorTests::bar1, Ptr<SimulatorTests> (this), 0);
Simulator::ScheduleNow (&SimulatorTests::bar2, Ptr<SimulatorTests> (this), 0, 0);
@@ -699,12 +945,22 @@
Simulator::ScheduleDestroy (&foo3, 0, 0, 0);
Simulator::ScheduleDestroy (&foo4, 0, 0, 0, 0);
Simulator::ScheduleDestroy (&foo5, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&cber1, 0);
+ Simulator::ScheduleDestroy (&cber2, 0, 0);
+ Simulator::ScheduleDestroy (&cber3, 0, 0, 0);
+ Simulator::ScheduleDestroy (&cber4, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&cber5, 0, 0, 0, 0, 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar0, this);
Simulator::ScheduleDestroy (&SimulatorTests::bar1, this, 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar2, this, 0, 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar3, this, 0, 0, 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar4, this, 0, 0, 0, 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar5, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz1, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz2, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz3, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz4, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz5, this, 0, 0, 0, 0, 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar0, Ptr<SimulatorTests> (this));
Simulator::ScheduleDestroy (&SimulatorTests::bar1, Ptr<SimulatorTests> (this), 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar2, Ptr<SimulatorTests> (this), 0, 0);
@@ -712,13 +968,67 @@
Simulator::ScheduleDestroy (&SimulatorTests::bar4, Ptr<SimulatorTests> (this), 0, 0, 0, 0);
Simulator::ScheduleDestroy (&SimulatorTests::bar5, Ptr<SimulatorTests> (this), 0, 0, 0, 0, 0);
+
+ // the code below does not compile, as expected.
+ //Simulator::Schedule (Seconds (0.0), &cber1, 0.0);
+
+#if 1
+ Simulator::Schedule (Seconds (0.0), &ber1, 0);
+ Simulator::Schedule (Seconds (0.0), &ber2, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &ber3, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &ber4, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &ber5, 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz4, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&ber1, 0);
+ Simulator::ScheduleNow (&ber2, 0, 0);
+ Simulator::ScheduleNow (&ber3, 0, 0, 0);
+ Simulator::ScheduleNow (&ber4, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&ber5, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz1, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz2, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz3, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz4, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&ber1, 0);
+ Simulator::ScheduleDestroy (&ber2, 0, 0);
+ Simulator::ScheduleDestroy (&ber3, 0, 0, 0);
+ Simulator::ScheduleDestroy (&ber4, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&ber5, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz1, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz2, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz3, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz4, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
+#endif
+
+ RunTestsConst ();
+
EventId nowId = Simulator::ScheduleNow (&foo0);
- EventId destroyId = Simulator::ScheduleDestroy (&foo0);
+ m_destroyId = Simulator::ScheduleDestroy (&SimulatorTests::destroy, this);
+ NS_TEST_ASSERT (!m_destroyId.IsExpired ());
+
+ Simulator::Run ();
+ m_destroy = false;
+ Simulator::Destroy ();
+ NS_TEST_ASSERT (m_destroy);
+
+ EventId anId = Simulator::ScheduleNow (&foo0);
+ EventId anotherId = anId;
+ NS_TEST_ASSERT (!(anId.IsExpired () || anotherId.IsExpired ()));
+
+ Simulator::Remove (anId);
+ NS_TEST_ASSERT (anId.IsExpired ());
+ NS_TEST_ASSERT (anotherId.IsExpired ());
Simulator::Run ();
Simulator::Destroy ();
+
- return ok;
+ return result;
}
SimulatorTests gSimulatorTests;
--- a/src/simulator/simulator.h Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/simulator.h Fri Sep 28 11:59:46 2007 +0100
@@ -26,6 +26,7 @@
#include "event-id.h"
#include "event-impl.h"
#include "nstime.h"
+#include "ns3/type-traits.h"
namespace ns3 {
@@ -162,8 +163,8 @@
* @param obj the object on which to invoke the member method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj);
+ template <typename MEM, typename OBJ>
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -171,8 +172,8 @@
* @param a1 the first argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ, typename T1>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+ template <typename MEM, typename OBJ, typename T1>
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -181,8 +182,8 @@
* @param a2 the second argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ, typename T1, typename T2>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
+ template <typename MEM, typename OBJ, typename T1, typename T2>
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -192,8 +193,9 @@
* @param a3 the third argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
+ 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
@@ -204,8 +206,9 @@
* @param a4 the fourth argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
+ 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,8 +220,9 @@
* @param a5 the fifth argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj,
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
/**
* @param time the relative expiration time of the event.
@@ -232,8 +236,8 @@
* @param a1 the first argument to pass to the function to invoke
* @returns an id for the scheduled event.
*/
- template <typename T1>
- static EventId Schedule (Time const &time, void (*f) (T1), T1 a1);
+ template <typename U1, typename T1>
+ 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
@@ -241,8 +245,8 @@
* @param a2 the second argument to pass to the function to invoke
* @returns an id for the scheduled event.
*/
- template <typename T1, typename T2>
- static EventId Schedule (Time const &time, void (*f) (T1,T2), T1 a1, T2 a2);
+ template <typename U1, typename U2, typename T1, typename T2>
+ 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
@@ -251,8 +255,8 @@
* @param a3 the third argument to pass to the function to invoke
* @returns an id for the scheduled event.
*/
- template <typename T1, typename T2, typename T3>
- static EventId Schedule (Time const &time, void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
+ template <typename U1, typename U2, typename U3, typename T1, typename T2, typename T3>
+ 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
@@ -262,8 +266,9 @@
* @param a4 the fourth argument to pass to the function to invoke
* @returns an id for the scheduled event.
*/
- template <typename T1, typename T2, typename T3, typename T4>
- static EventId Schedule (Time const &time, void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
+ 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
@@ -274,8 +279,9 @@
* @param a5 the fifth argument to pass to the function to invoke
* @returns an id for the scheduled event.
*/
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId Schedule (Time const &time, void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ 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);
/**
@@ -286,23 +292,25 @@
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
*/
- template <typename T, typename OBJ>
- static EventId ScheduleNow (void (T::*mem_ptr) (void), OBJ obj);
+ template <typename MEM, typename OBJ>
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1>
- static EventId ScheduleNow (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+ template <typename MEM, typename OBJ,
+ typename T1>
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
* @param a2 the second argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2>
- static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2>
+ 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
@@ -310,8 +318,9 @@
* @param a2 the second argument to pass to the invoked method
* @param a3 the third argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3>
- static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
+ 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
@@ -320,9 +329,10 @@
* @param a3 the third argument to pass to the invoked method
* @param a4 the fourth argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
- static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -332,9 +342,10 @@
* @param a4 the fourth argument to pass to the invoked method
* @param a5 the fifth argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
/**
* @param f the function to invoke
*/
@@ -343,23 +354,26 @@
* @param f the function to invoke
* @param a1 the first argument to pass to the function to invoke
*/
- template <typename T1>
- static EventId ScheduleNow (void (*f) (T1), T1 a1);
+ template <typename U1,
+ typename T1>
+ 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
* @param a2 the second argument to pass to the function to invoke
*/
- template <typename T1, typename T2>
- static EventId ScheduleNow (void (*f) (T1,T2), T1 a1, T2 a2);
+ template <typename U1, typename U2,
+ typename T1, typename T2>
+ 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
* @param a2 the second argument to pass to the function to invoke
* @param a3 the third argument to pass to the function to invoke
*/
- template <typename T1, typename T2, typename T3>
- static EventId ScheduleNow (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
+ template <typename U1, typename U2, typename U3,
+ typename T1, typename T2, typename T3>
+ 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
@@ -367,8 +381,9 @@
* @param a3 the third argument to pass to the function to invoke
* @param a4 the fourth argument to pass to the function to invoke
*/
- template <typename T1, typename T2, typename T3, typename T4>
- static EventId ScheduleNow (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
+ 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
@@ -377,8 +392,9 @@
* @param a4 the fourth argument to pass to the function to invoke
* @param a5 the fifth argument to pass to the function to invoke
*/
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId ScheduleNow (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ 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);
/**
@@ -390,23 +406,25 @@
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
*/
- template <typename T, typename OBJ>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj);
+ template <typename MEM, typename OBJ>
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+ template <typename MEM, typename OBJ,
+ typename T1>
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
* @param a2 the second argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2>
+ 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
@@ -414,8 +432,9 @@
* @param a2 the second argument to pass to the invoked method
* @param a3 the third argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
+ 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
@@ -424,9 +443,10 @@
* @param a3 the third argument to pass to the invoked method
* @param a4 the fourth argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -436,9 +456,10 @@
* @param a4 the fourth argument to pass to the invoked method
* @param a5 the fifth argument to pass to the invoked method
*/
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
/**
* @param f the function to invoke
*/
@@ -447,23 +468,26 @@
* @param f the function to invoke
* @param a1 the first argument to pass to the function to invoke
*/
- template <typename T1>
- static EventId ScheduleDestroy (void (*f) (T1), T1 a1);
+ template <typename U1,
+ typename T1>
+ 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
* @param a2 the second argument to pass to the function to invoke
*/
- template <typename T1, typename T2>
- static EventId ScheduleDestroy (void (*f) (T1,T2), T1 a1, T2 a2);
+ template <typename U1, typename U2,
+ typename T1, typename T2>
+ 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
* @param a2 the second argument to pass to the function to invoke
* @param a3 the third argument to pass to the function to invoke
*/
- template <typename T1, typename T2, typename T3>
- static EventId ScheduleDestroy (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
+ template <typename U1, typename U2, typename U3,
+ typename T1, typename T2, typename T3>
+ 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
@@ -471,8 +495,9 @@
* @param a3 the third argument to pass to the function to invoke
* @param a4 the fourth argument to pass to the function to invoke
*/
- template <typename T1, typename T2, typename T3, typename T4>
- static EventId ScheduleDestroy (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
+ 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
@@ -481,8 +506,9 @@
* @param a4 the fourth argument to pass to the function to invoke
* @param a5 the fifth argument to pass to the function to invoke
*/
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId ScheduleDestroy (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+ static EventId ScheduleDestroy (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
/**
* Remove an event from the event list.
@@ -495,7 +521,7 @@
*
* @param id the event to remove from the list of scheduled events.
*/
- static void Remove (EventId id);
+ static void Remove (const EventId &id);
/**
* Set the cancel bit on this event: the event's associated function
* will not be invoked when it expires.
@@ -508,7 +534,7 @@
*
* @param id the event to cancel
*/
- static void Cancel (EventId &id);
+ static void Cancel (const EventId &id);
/**
* This method has O(1) complexity.
* Note that it is not possible to test for the expiration of
@@ -521,7 +547,7 @@
* @param id the event to test for expiration
* @returns true if the event has expired, false otherwise.
*/
- static bool IsExpired (EventId id);
+ static bool IsExpired (const EventId &id);
/**
* Return the "current simulation time".
*/
@@ -529,35 +555,46 @@
private:
Simulator ();
~Simulator ();
- template <typename T, typename OBJ>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj);
- template <typename T, typename OBJ, typename T1>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
- template <typename T, typename OBJ, typename T1, typename T2>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
- template <typename T, typename OBJ, typename T1, typename T2, typename T3>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
- template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
- static EventImpl *MakeEvent (void (*f) (void));
- template <typename T1>
- static EventImpl *MakeEvent (void (*f) (T1), T1 a1);
- template <typename T1, typename T2>
- static EventImpl *MakeEvent (void (*f) (T1,T2), T1 a1, T2 a2);
- template <typename T1, typename T2, typename T3>
- static EventImpl *MakeEvent (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
- template <typename T1, typename T2, typename T3, typename T4>
- static EventImpl *MakeEvent (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventImpl *MakeEvent (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+
+ template <typename MEM, typename OBJ>
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj);
+ template <typename MEM, typename OBJ,
+ typename T1>
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2>
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ static Ptr<EventImpl> MakeEvent (void (*f) (void));
+ template <typename U1,
+ typename T1>
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1), T1 a1);
+ template <typename U1, typename U2,
+ typename T1, typename T2>
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2);
+ template <typename U1, typename U2, typename U3,
+ typename T1, typename T2, typename T3>
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
+ template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
static SimulatorPrivate *GetPriv (void);
- static EventId Schedule (Time const &time, EventImpl *event);
- static EventId ScheduleDestroy (EventImpl *event);
- static EventId ScheduleNow (EventImpl *event);
+ static EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+ static EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+ static EventId ScheduleNow (const Ptr<EventImpl> &event);
static SimulatorPrivate *m_priv;
};
@@ -584,47 +621,46 @@
namespace ns3 {
template <typename T>
-struct EventMemberImplTraits;
+struct EventMemberImplObjTraits;
template <typename T>
-struct EventMemberImplTraits<T *>
+struct EventMemberImplObjTraits<T *>
{
static T &GetReference (T *p) {
return *p;
}
};
-template <typename T, typename OBJ>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj)
+template <typename MEM, typename OBJ>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj)
{
// zero argument version
class EventMemberImpl0 : public EventImpl {
public:
- typedef void (T::*F)(void);
- EventMemberImpl0 (OBJ obj, F function)
+ EventMemberImpl0 (OBJ obj, MEM function)
: m_obj (obj),
m_function (function)
{}
virtual ~EventMemberImpl0 () {}
private:
virtual void Notify (void) {
- (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) ();
+ (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) ();
}
OBJ m_obj;
- F m_function;
- } *ev = new EventMemberImpl0 (obj, mem_ptr);
- return ev;
+ MEM m_function;
+ } * ev = new EventMemberImpl0 (obj, mem_ptr);
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ, typename T1>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
+template <typename MEM, typename OBJ,
+ typename T1>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1)
{
// one argument version
class EventMemberImpl1 : public EventImpl {
public:
- typedef void (T::*F)(T1);
- EventMemberImpl1 (OBJ obj, F function, T1 a1)
+ EventMemberImpl1 (OBJ obj, MEM function, T1 a1)
: m_obj (obj),
m_function (function),
m_a1 (a1)
@@ -633,24 +669,23 @@
virtual ~EventMemberImpl1 () {}
private:
virtual void Notify (void) {
- (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
+ (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
}
OBJ m_obj;
- F m_function;
- T1 m_a1;
+ MEM m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
} *ev = new EventMemberImpl1 (obj, mem_ptr, a1);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ, typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
// two argument version
class EventMemberImpl2 : public EventImpl {
public:
- typedef void (T::*F)(T1, T2);
-
- EventMemberImpl2 (OBJ obj, F function, T1 a1, T2 a2)
+ EventMemberImpl2 (OBJ obj, MEM function, T1 a1, T2 a2)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -660,25 +695,24 @@
virtual ~EventMemberImpl2 () {}
private:
virtual void Notify (void) {
- (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2);
+ (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2);
}
OBJ m_obj;
- F m_function;
- T1 m_a1;
- T2 m_a2;
+ MEM m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
} *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
// three argument version
class EventMemberImpl3 : public EventImpl {
public:
- typedef void (T::*F)(T1, T2, T3);
-
- EventMemberImpl3 (OBJ obj, F function, T1 a1, T2 a2, T3 a3)
+ EventMemberImpl3 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -689,26 +723,25 @@
virtual ~EventMemberImpl3 () {}
private:
virtual void Notify (void) {
- (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3);
+ (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3);
}
OBJ m_obj;
- F m_function;
- T1 m_a1;
- T2 m_a2;
- T3 m_a3;
+ MEM m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
+ typename TypeTraits<T3>::ReferencedType m_a3;
} *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
// four argument version
class EventMemberImpl4 : public EventImpl {
public:
- typedef void (T::*F)(T1, T2, T3, T4);
-
- EventMemberImpl4 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4)
+ EventMemberImpl4 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -720,28 +753,27 @@
virtual ~EventMemberImpl4 () {}
private:
virtual void Notify (void) {
- (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4);
+ (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4);
}
OBJ m_obj;
- F m_function;
- T1 m_a1;
- T2 m_a2;
- T3 m_a3;
- T4 m_a4;
+ MEM m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
+ typename TypeTraits<T3>::ReferencedType m_a3;
+ typename TypeTraits<T4>::ReferencedType m_a4;
} *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
// five argument version
class EventMemberImpl5 : public EventImpl {
public:
- typedef void (T::*F)(T1, T2, T3, T4, T5);
-
- EventMemberImpl5 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+ EventMemberImpl5 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -754,223 +786,235 @@
virtual ~EventMemberImpl5 () {}
private:
virtual void Notify (void) {
- (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
+ (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
}
OBJ m_obj;
- F m_function;
- T1 m_a1;
- T2 m_a2;
- T3 m_a3;
- T4 m_a4;
- T5 m_a5;
+ MEM m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
+ typename TypeTraits<T3>::ReferencedType m_a3;
+ typename TypeTraits<T4>::ReferencedType m_a4;
+ typename TypeTraits<T5>::ReferencedType m_a5;
} *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T1>
-EventImpl *Simulator::MakeEvent (void (*f) (T1), T1 a1)
+template <typename U1, typename T1>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1), T1 a1)
{
// one arg version
class EventFunctionImpl1 : public EventImpl {
public:
- typedef void (*F)(T1);
+ typedef void (*F)(U1);
- EventFunctionImpl1 (F function, T1 a1)
- : m_function (function),
- m_a1 (a1)
- { }
+ EventFunctionImpl1 (F function, T1 a1)
+ : m_function (function),
+ m_a1 (a1)
+ { }
protected:
- virtual ~EventFunctionImpl1 () {}
+ virtual ~EventFunctionImpl1 () {}
private:
- virtual void Notify (void) {
- (*m_function) (m_a1);
- }
- F m_function;
- T1 m_a1;
- } *ev = new EventFunctionImpl1(f, a1);
- return ev;
+ virtual void Notify (void) {
+ (*m_function) (m_a1);
+ }
+ F m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ } *ev = new EventFunctionImpl1 (f, a1);
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2), T1 a1, T2 a2)
+template <typename U1, typename U2, typename T1, typename T2>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2)
{
// two arg version
class EventFunctionImpl2 : public EventImpl {
public:
- typedef void (*F)(T1, T2);
+ typedef void (*F)(U1, U2);
- EventFunctionImpl2 (F function, T1 a1, T2 a2)
- : m_function (function),
- m_a1 (a1),
- m_a2 (a2)
- { }
+ EventFunctionImpl2 (F function, T1 a1, T2 a2)
+ : m_function (function),
+ m_a1 (a1),
+ m_a2 (a2)
+ {}
protected:
- virtual ~EventFunctionImpl2 () {}
+ virtual ~EventFunctionImpl2 () {}
private:
- virtual void Notify (void) {
- (*m_function) (m_a1, m_a2);
- }
- F m_function;
- T1 m_a1;
- T2 m_a2;
+ virtual void Notify (void) {
+ (*m_function) (m_a1, m_a2);
+ }
+ F m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
} *ev = new EventFunctionImpl2 (f, a1, a2);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+template <typename U1, typename U2, typename U3,
+ typename T1, typename T2, typename T3>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
{
// three arg version
class EventFunctionImpl3 : public EventImpl {
public:
- typedef void (*F)(T1, T2, T3);
+ 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)
- { }
+ EventFunctionImpl3 (F function, T1 a1, T2 a2, T3 a3)
+ : m_function (function),
+ m_a1 (a1),
+ m_a2 (a2),
+ m_a3 (a3)
+ { }
protected:
- virtual ~EventFunctionImpl3 () {}
+ virtual ~EventFunctionImpl3 () {}
private:
- virtual void Notify (void) {
- (*m_function) (m_a1, m_a2, m_a3);
- }
- F m_function;
- T1 m_a1;
- T2 m_a2;
- T3 m_a3;
+ virtual void Notify (void) {
+ (*m_function) (m_a1, m_a2, m_a3);
+ }
+ F m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
+ typename TypeTraits<T3>::ReferencedType m_a3;
} *ev = new EventFunctionImpl3 (f, a1, a2, a3);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4)
+template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4)
{
// four arg version
class EventFunctionImpl4 : public EventImpl {
public:
- typedef void (*F)(T1, T2, T3, T4);
+ 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)
- { }
+ 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 () {}
+ virtual ~EventFunctionImpl4 () {}
private:
- virtual void Notify (void) {
- (*m_function) (m_a1, m_a2, m_a3, m_a4);
- }
- F m_function;
- T1 m_a1;
- T2 m_a2;
- T3 m_a3;
- T4 m_a4;
+ virtual void Notify (void) {
+ (*m_function) (m_a1, m_a2, m_a3, m_a4);
+ }
+ F m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
+ typename TypeTraits<T3>::ReferencedType m_a3;
+ typename TypeTraits<T4>::ReferencedType m_a4;
} *ev = new EventFunctionImpl4 (f, a1, a2, a3, a4);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
// five arg version
class EventFunctionImpl5 : public EventImpl {
public:
- typedef void (*F)(T1, T2, T3, T4, T5);
+ 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)
- { }
+ 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 () {}
+ virtual ~EventFunctionImpl5 () {}
private:
- virtual void Notify (void) {
- (*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
- }
- F m_function;
- T1 m_a1;
- T2 m_a2;
- T3 m_a3;
- T4 m_a4;
- T5 m_a5;
+ virtual void Notify (void) {
+ (*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
+ }
+ F m_function;
+ typename TypeTraits<T1>::ReferencedType m_a1;
+ typename TypeTraits<T2>::ReferencedType m_a2;
+ typename TypeTraits<T3>::ReferencedType m_a3;
+ typename TypeTraits<T4>::ReferencedType m_a4;
+ typename TypeTraits<T5>::ReferencedType m_a5;
} *ev = new EventFunctionImpl5 (f, a1, a2, a3, a4, a5);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj)
+template <typename MEM, typename OBJ>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj)
{
return Schedule (time, MakeEvent (mem_ptr, obj));
}
-template <typename T, typename OBJ, typename T1>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
+template <typename MEM, typename OBJ,
+ typename T1>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1));
}
-template <typename T, typename OBJ, typename T1, typename T2>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
}
-template <typename T1>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1), T1 a1)
+template <typename U1, typename T1>
+EventId Simulator::Schedule (Time const &time, void (*f) (U1), T1 a1)
{
return Schedule (time, MakeEvent (f, a1));
}
-template <typename T1, typename T2>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2), T1 a1, T2 a2)
+template <typename U1, typename U2,
+ typename T1, typename T2>
+EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2), T1 a1, T2 a2)
{
return Schedule (time, MakeEvent (f, a1, a2));
}
-template <typename T1, typename T2, typename T3>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+template <typename U1, typename U2, typename U3,
+ typename T1, typename T2, typename T3>
+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));
}
-template <typename T1, typename T2, typename T3, typename T4>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4)
+template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
+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));
}
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
+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));
}
@@ -978,162 +1022,182 @@
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (void), OBJ obj)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj)
{
return ScheduleNow (MakeEvent (mem_ptr, obj));
}
-template <typename T, typename OBJ, typename T1>
+template <typename MEM, typename OBJ,
+ typename T1>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1));
}
-template <typename T, typename OBJ, typename T1, typename T2>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj,
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
}
-template <typename T1>
+template <typename U1,
+ typename T1>
EventId
-Simulator::ScheduleNow (void (*f) (T1), T1 a1)
+Simulator::ScheduleNow (void (*f) (U1), T1 a1)
{
return ScheduleNow (MakeEvent (f, a1));
}
-template <typename T1, typename T2>
+template <typename U1, typename U2,
+ typename T1, typename T2>
EventId
-Simulator::ScheduleNow (void (*f) (T1,T2), T1 a1, T2 a2)
+Simulator::ScheduleNow (void (*f) (U1,U2), T1 a1, T2 a2)
{
return ScheduleNow (MakeEvent (f, a1, a2));
}
-template <typename T1, typename T2, typename T3>
+template <typename U1, typename U2, typename U3,
+ typename T1, typename T2, typename T3>
EventId
-Simulator::ScheduleNow (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleNow (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
{
return ScheduleNow (MakeEvent (f, a1, a2, a3));
}
-template <typename T1, typename T2, typename T3, typename T4>
+template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
EventId
-Simulator::ScheduleNow (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4)
+Simulator::ScheduleNow (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4)
{
return ScheduleNow (MakeEvent (f, a1, a2, a3, a4));
}
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
EventId
-Simulator::ScheduleNow (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+Simulator::ScheduleNow (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return ScheduleNow (MakeEvent (f, a1, a2, a3, a4, a5));
}
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj));
}
-template <typename T, typename OBJ, typename T1>
+template <typename MEM, typename OBJ,
+ typename T1>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1));
}
-template <typename T, typename OBJ, typename T1, typename T2>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
}
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename MEM, typename OBJ,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj,
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
}
-template <typename T1>
+template <typename U1,
+ typename T1>
EventId
-Simulator::ScheduleDestroy (void (*f) (T1), T1 a1)
+Simulator::ScheduleDestroy (void (*f) (U1), T1 a1)
{
return ScheduleDestroy (MakeEvent (f, a1));
}
-template <typename T1, typename T2>
+template <typename U1, typename U2,
+ typename T1, typename T2>
EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2), T1 a1, T2 a2)
+Simulator::ScheduleDestroy (void (*f) (U1,U2), T1 a1, T2 a2)
{
return ScheduleDestroy (MakeEvent (f, a1, a2));
}
-template <typename T1, typename T2, typename T3>
+template <typename U1, typename U2, typename U3,
+ typename T1, typename T2, typename T3>
EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleDestroy (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
{
return ScheduleDestroy (MakeEvent (f, a1, a2, a3));
}
-template <typename T1, typename T2, typename T3, typename T4>
+template <typename U1, typename U2, typename U3, typename U4,
+ typename T1, typename T2, typename T3, typename T4>
EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4)
+Simulator::ScheduleDestroy (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4)
{
return ScheduleDestroy (MakeEvent (f, a1, a2, a3, a4));
}
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+ typename T1, typename T2, typename T3, typename T4, typename T5>
EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+Simulator::ScheduleDestroy (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return ScheduleDestroy (MakeEvent (f, a1, a2, a3, a4, a5));
}
--- a/src/simulator/time.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/time.cc Fri Sep 28 11:59:46 2007 +0100
@@ -191,7 +191,28 @@
std::ostream&
operator<< (std::ostream& os, Time const& time)
{
- os << time.GetTimeStep () << "ts";
+ std::string unit;
+ switch (TimeStepPrecision::Get ()) {
+ case TimeStepPrecision::S:
+ unit = "s";
+ break;
+ case TimeStepPrecision::MS:
+ unit = "ms";
+ break;
+ case TimeStepPrecision::US:
+ unit = "us";
+ break;
+ case TimeStepPrecision::NS:
+ unit = "ns";
+ break;
+ case TimeStepPrecision::PS:
+ unit = "ps";
+ break;
+ case TimeStepPrecision::FS:
+ unit = "fs";
+ break;
+ }
+ os << time.GetTimeStep () << unit;
return os;
}
@@ -393,12 +414,12 @@
TimeStepPrecision::Set (TimeStepPrecision::NS);
- Bind ("TimeStepPrecision", "S");
- Bind ("TimeStepPrecision", "MS");
- Bind ("TimeStepPrecision", "US");
- Bind ("TimeStepPrecision", "NS");
- Bind ("TimeStepPrecision", "PS");
- Bind ("TimeStepPrecision", "FS");
+ DefaultValue::Bind ("TimeStepPrecision", "S");
+ DefaultValue::Bind ("TimeStepPrecision", "MS");
+ DefaultValue::Bind ("TimeStepPrecision", "US");
+ DefaultValue::Bind ("TimeStepPrecision", "NS");
+ DefaultValue::Bind ("TimeStepPrecision", "PS");
+ DefaultValue::Bind ("TimeStepPrecision", "FS");
return ok;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/simulator/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -15,8 +15,6 @@
def configure(conf):
- conf.env.append_value('NS3_MODULES', 'ns3-simulator')
-
if Params.g_options.high_precision_as_double:
conf.add_define('USE_HIGH_PRECISION_DOUBLE', 1)
conf.env['USE_HIGH_PRECISION_DOUBLE'] = 1
@@ -49,11 +47,7 @@
def build(bld):
- sim = bld.create_obj('cpp', 'shlib')
- sim.name = 'ns3-simulator'
- sim.target = sim.name
- sim.uselib_local = ['ns3-core']
-
+ sim = bld.create_ns3_module('simulator', ['core'])
sim.source = [
'high-precision.cc',
'time.cc',
@@ -65,7 +59,9 @@
'scheduler-map.cc',
'event-impl.cc',
'simulator.cc',
+ 'time-default-value.cc',
]
+
headers = bld.create_obj('ns3header')
headers.source = [
'high-precision.h',
@@ -76,6 +72,7 @@
'scheduler.h',
'scheduler-factory.h',
'simulation-singleton.h',
+ 'time-default-value.h',
]
env = bld.env_of_name('default')
--- a/src/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/src/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -2,6 +2,7 @@
import os, os.path
import shutil
+import types
import Action
import Common
@@ -9,35 +10,59 @@
import Params
-all_modules = [
+all_modules = (
'core',
'common',
'simulator',
'node',
'internet-node',
- 'devices/p2p',
- 'applications',
- ]
-
+ 'devices/point-to-point',
+ 'devices/csma',
+ 'applications/onoff',
+ 'applications/packet-sink',
+ 'applications/udp-echo',
+ 'routing/global-routing',
+ 'mobility',
+ )
def set_options(opt):
opt.sub_options('simulator')
-
+
+ opt.add_option('--enable-rpath',
+ help=("Link programs with rpath"
+ " (normally not needed, see "
+ " --run and --shell; moreover, only works in some"
+ " specific platforms, such as Linux and Solaris)"),
+ action="store_true", dest='enable_rpath', default=False)
+
+
def configure(conf):
conf.sub_config('core')
conf.sub_config('simulator')
blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant()))
- for module in all_modules:
- conf.sub_config(module)
- conf.env.append_value('NS3_MODULE_PATH', os.path.join(blddir, 'src', module))
+ conf.env['NS3_MODULE_PATH'] = [os.path.join(blddir)]
+ if Params.g_options.enable_rpath:
+ conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),))
+
+ ## Used to link the 'run-tests' program with all of ns-3 code
+ conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
+def create_ns3_module(bld, name, dependencies=()):
+ module = bld.create_obj('cpp', 'objects')
+ module.name = 'ns3-' + name
+ module.target = module.name
+ module.add_objects = ['ns3-' + dep for dep in dependencies]
+ module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
+ return module
+
def build(bld):
Object.register('ns3header', Ns3Header)
- Action.Action('ns3_headers', func=_ns3_headers_inst, color='BLUE')
+ Action.Action('ns3header', func=_ns3_headers_inst, color='BLUE')
+ bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
- bld.add_subdirs(all_modules)
+ bld.add_subdirs(list(all_modules))
class Ns3Header(Object.genobj):
@@ -52,19 +77,15 @@
def apply(self):
ns3_dir_node = Params.g_build.m_srcnode.find_dir("ns3")
- inputs = []
- outputs = []
for filename in self.to_list(self.source):
src_node = self.path.find_source(filename)
if src_node is None:
Params.fatal("source ns3 header file %s not found" % (filename,))
dst_node = ns3_dir_node.find_build(os.path.basename(filename))
assert dst_node is not None
- inputs.append(src_node)
- outputs.append(dst_node)
- task = self.create_task('ns3_headers', self.env, 1)
- task.set_inputs(inputs)
- task.set_outputs(outputs)
+ task = self.create_task('ns3header', self.env, 1)
+ task.set_inputs([src_node])
+ task.set_outputs([dst_node])
def install(self):
for i in self.m_tasks:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/hello-simulator.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,29 @@
+/* -*- 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"
+
+NS_LOG_COMPONENT_DEFINE ("HelloSimulator");
+
+using namespace ns3;
+
+int
+main (int argc, char *argv[])
+{
+ LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO);
+
+ NS_LOG_INFO ("Hello Simulator");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-1.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,81 @@
+/* -*- 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-node.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"
+#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<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ Ptr<CsmaChannel> lan =
+ CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+ uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan,
+ "08:00:2e:00:00:00");
+
+ uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan,
+ "08:00:2e:00:00:01");
+
+ uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan,
+ "08:00:2e:00:00:02");
+
+ uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan,
+ "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");
+
+ uint16_t port = 7;
+
+ Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port,
+ 1, Seconds(1.), 1024);
+
+ Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
+
+ server->Start(Seconds(1.));
+ client->Start(Seconds(2.));
+
+ server->Stop (Seconds(10.));
+ client->Stop (Seconds(10.));
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-2.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,86 @@
+/* -*- 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-node.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"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/ascii-trace.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<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ Ptr<CsmaChannel> lan =
+ CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+ uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan,
+ "08:00:2e:00:00:00");
+
+ uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan,
+ "08:00:2e:00:00:01");
+
+ uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan,
+ "08:00:2e:00:00:02");
+
+ uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan,
+ "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");
+
+ uint16_t port = 7;
+
+ Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port,
+ 1, Seconds(1.), 1024);
+
+ Ptr<UdpEchoServer> server = Create<UdpEchoServer> (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 ();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-3.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,90 @@
+/* -*- 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-node.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"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.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<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ Ptr<CsmaChannel> lan =
+ CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+ uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan,
+ "08:00:2e:00:00:00");
+
+ uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan,
+ "08:00:2e:00:00:01");
+
+ uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan,
+ "08:00:2e:00:00:02");
+
+ uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan,
+ "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");
+
+ uint16_t port = 7;
+
+ Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port,
+ 1, Seconds(1.), 1024);
+
+ Ptr<UdpEchoServer> server = Create<UdpEchoServer> (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 ();
+
+ PcapTrace pcaptrace ("tutorial.pcap");
+ pcaptrace.TraceAllIp ();
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-4.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,137 @@
+/* -*- 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-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/csma-channel.h"
+#include "ns3/mac48-address.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/point-to-point-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"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/global-route-manager.h"
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation");
+
+using namespace ns3;
+
+// Network topology
+//
+// point to point
+// +--------------+
+// | |
+// n0 n1 n2 n3 n4 n5 n6 n7
+// | | | | | | | |
+// ================ ================
+// lan0 lan1
+//
+int
+main (int argc, char *argv[])
+{
+ LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO);
+
+ NS_LOG_INFO ("UDP Echo Simulation");
+
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ Ptr<Node> n4 = Create<InternetNode> ();
+ Ptr<Node> n5 = Create<InternetNode> ();
+ Ptr<Node> n6 = Create<InternetNode> ();
+ Ptr<Node> n7 = Create<InternetNode> ();
+
+ Ptr<CsmaChannel> lan1 =
+ CsmaTopology::CreateCsmaChannel (DataRate (5000000), 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");
+
+ Ptr<CsmaChannel> lan2 =
+ CsmaTopology::CreateCsmaChannel (DataRate (5000000), 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");
+
+ Ptr<PointToPointChannel> link = PointToPointTopology::AddPointToPointLink (
+ n3, n4, DataRate (500000), MilliSeconds (20));
+
+ PointToPointTopology::AddIpv4Addresses (link, n3, "10.1.3.1",
+ n4, "10.1.3.2");
+
+ uint16_t port = 7;
+
+ Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.2.4", port,
+ 1, Seconds(1.), 1024);
+
+ Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n7, port);
+
+ server->Start(Seconds(1.));
+ client->Start(Seconds(2.));
+
+ server->Stop (Seconds(10.));
+ client->Stop (Seconds(10.));
+
+ AsciiTrace asciitrace ("tutorial-4.tr");
+ asciitrace.TraceAllQueues ();
+ asciitrace.TraceAllNetDeviceRx ();
+
+ PcapTrace pcaptrace ("tutorial-4.pcap");
+ pcaptrace.TraceAllIp ();
+
+ GlobalRouteManager::PopulateRoutingTables ();
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,22 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_program('hello-simulator',
+ ['core'])
+ obj.source = 'hello-simulator.cc'
+
+ obj = bld.create_ns3_program('tutorial-1',
+ ['core'])
+ obj.source = 'tutorial-1.cc'
+
+ obj = bld.create_ns3_program('tutorial-2',
+ ['core'])
+ obj.source = 'tutorial-2.cc'
+
+ obj = bld.create_ns3_program('tutorial-3',
+ ['core'])
+ obj.source = 'tutorial-3.cc'
+
+ obj = bld.create_ns3_program('tutorial-4',
+ ['core'])
+ obj.source = 'tutorial-4.cc'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-0 Fri Sep 28 11:59:46 2007 +0100
@@ -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('hello-simulator',
+ ['core'])
+ obj.source = 'hello-simulator.cc'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-1 Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,10 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_program('hello-simulator',
+ ['core'])
+ obj.source = 'hello-simulator.cc'
+
+ obj = bld.create_ns3_program('tutorial-1',
+ ['core'])
+ obj.source = 'tutorial-1.cc'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-2 Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,14 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_program('hello-simulator',
+ ['core'])
+ obj.source = 'hello-simulator.cc'
+
+ obj = bld.create_ns3_program('tutorial-1',
+ ['core'])
+ obj.source = 'tutorial-1.cc'
+
+ obj = bld.create_ns3_program('tutorial-2',
+ ['core'])
+ obj.source = 'tutorial-2.cc'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-3 Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,18 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_program('hello-simulator',
+ ['core'])
+ obj.source = 'hello-simulator.cc'
+
+ obj = bld.create_ns3_program('tutorial-1',
+ ['core'])
+ obj.source = 'tutorial-1.cc'
+
+ obj = bld.create_ns3_program('tutorial-2',
+ ['core'])
+ obj.source = 'tutorial-2.cc'
+
+ obj = bld.create_ns3_program('tutorial-3',
+ ['core'])
+ obj.source = 'tutorial-3.cc'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-4 Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,22 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_program('hello-simulator',
+ ['core'])
+ obj.source = 'hello-simulator.cc'
+
+ obj = bld.create_ns3_program('tutorial-1',
+ ['core'])
+ obj.source = 'tutorial-1.cc'
+
+ obj = bld.create_ns3_program('tutorial-2',
+ ['core'])
+ obj.source = 'tutorial-2.cc'
+
+ obj = bld.create_ns3_program('tutorial-3',
+ ['core'])
+ obj.source = 'tutorial-3.cc'
+
+ obj = bld.create_ns3_program('tutorial-4',
+ ['core'])
+ obj.source = 'tutorial-4.cc'
--- a/utils/bench-packets.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/utils/bench-packets.cc Fri Sep 28 11:59:46 2007 +0100
@@ -18,97 +18,181 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
-#include "ns3/wall-clock-ms.h"
+#include "ns3/system-wall-clock-ms.h"
#include "ns3/packet.h"
-#include "ns3/chunk-constant-data.h"
-#include "ns3/chunk-udp.h"
-#include "ns3/chunk-ipv4.h"
+#include "ns3/packet-metadata.h"
#include <iostream>
+#include <sstream>
using namespace ns3;
+template <int N>
+class BenchHeader : public Header
+{
+public:
+ BenchHeader ();
+ bool IsOk (void) const;
+
+ static uint32_t GetUid (void);
+
+ static std::string GetName (void);
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
+private:
+ bool m_ok;
+};
+
+template <int N>
+BenchHeader<N>::BenchHeader ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+BenchHeader<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+uint32_t
+BenchHeader<N>::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<BenchHeader<N> > (GetName ());
+ return uid;
+}
+
+template <int N>
+std::string
+BenchHeader<N>::GetName (void)
+{
+ std::ostringstream oss;
+ oss << "BenchHeader" << N;
+ return oss.str ();
+}
+
+template <int N>
+void
+BenchHeader<N>::Print (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+BenchHeader<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+BenchHeader<N>::Serialize (Buffer::Iterator start) const
+{
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+BenchHeader<N>::Deserialize (Buffer::Iterator start)
+{
+ m_ok = true;
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+
+
static void
benchPtrA (uint32_t n)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
- ChunkIpv4 ipv4;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
for (uint32_t i = 0; i < n; i++) {
- Packet p;
- p.add (&data);
- p.add (&udp);
- p.add (&ipv4);
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
Packet o = p;
- o.peek (&ipv4);
- o.remove (&ipv4);
- o.peek (&udp);
- o.remove (&udp);
- o.peek (&data);
- o.remove (&data);
+ o.RemoveHeader (ipv4);
+ o.RemoveHeader (udp);
}
}
static void
benchPtrB (uint32_t n)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
- ChunkIpv4 ipv4;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
for (uint32_t i = 0; i < n; i++) {
- Packet p;
- p.add (&data);
- p.add (&udp);
- p.add (&ipv4);
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
}
}
static void
ptrC2 (Packet p)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
+ BenchHeader<8> udp;
- p.peek (&udp);
- p.remove (&udp);
- p.peek (&data);
- p.remove (&data);
+ p.RemoveHeader (udp);
}
static void
ptrC1 (Packet p)
{
- ChunkIpv4 ipv4;
- p.peek (&ipv4);
- p.remove (&ipv4);
+ BenchHeader<25> ipv4;
+ p.RemoveHeader (ipv4);
ptrC2 (p);
}
static void
benchPtrC (uint32_t n)
{
- ChunkConstantData data = ChunkConstantData (2000, 1);
- ChunkUdp udp;
- ChunkIpv4 ipv4;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
for (uint32_t i = 0; i < n; i++) {
- Packet p;
- p.add (&data);
- p.add (&udp);
- p.add (&ipv4);
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
ptrC1 (p);
}
}
+#if 0
+static void
+benchPrint (uint32_t n)
+{
+ PacketPrinter printer;
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
+ Packet p (2000);
+ p.AddHeader (udp);
+ p.AddHeader (ipv4);
+
+ for (uint32_t i = 0; i < n; i++)
+ {
+ p.Print (std::cerr, printer);
+ }
+}
+#endif
+
static void
runBench (void (*bench) (uint32_t), uint32_t n, char const *name)
{
- WallClockMs time;
- time.start ();
+ SystemWallClockMs time;
+ time.Start ();
(*bench) (n);
- unsigned long long deltaMs = time.end ();
+ unsigned long long deltaMs = time.End ();
double ps = n;
ps *= 1000;
ps /= deltaMs;
@@ -119,17 +203,31 @@
{
uint32_t n = 0;
while (argc > 0) {
- if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0) {
+ if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0)
+ {
char const *nAscii = argv[0] + strlen ("--n=");
n = atoi (nAscii);
- }
+ }
argc--;
argv++;
}
+
runBench (&benchPtrA, n, "a");
runBench (&benchPtrB, n, "b");
runBench (&benchPtrC, n, "c");
+ Packet::EnableMetadata ();
+ //runBench (&benchPrint, n, "print");
+ PacketMetadata::SetOptOne (false);
+ runBench (&benchPtrA, n, "meta-a");
+ runBench (&benchPtrB, n, "meta-b");
+ runBench (&benchPtrC, n, "meta-c");
+ PacketMetadata::SetOptOne (true);
+ runBench (&benchPtrA, n, "meta-a-opt");
+ runBench (&benchPtrB, n, "meta-b-opt");
+ runBench (&benchPtrC, n, "meta-c-opt");
+
+
return 0;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/print-trace-sources.cc Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,100 @@
+#include "ns3/internet-node.h"
+#include "ns3/ptr.h"
+#include "ns3/trace-resolver.h"
+#include "ns3/node-list.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/queue.h"
+#include "ns3/mobility-model-notifier.h"
+
+using namespace ns3;
+
+void
+PrintSimpleText (const TraceResolver::SourceCollection *sources, std::ostream &os)
+{
+ for (TraceResolver::SourceCollection::Iterator i = sources->Begin (); i != sources->End (); i++)
+ {
+ os << "source=" << i->path << std::endl;
+ os << "TraceContext=[";
+ i->context.PrintAvailable (os, ",");
+ os << "]" << std::endl;
+ os << "help=\"" << i->doc.GetHelp () << "\"" << std::endl;
+ os << "void TraceSinkCallback (const TraceContext &";
+ for (TraceDoc::Iterator k = i->doc.ArgsBegin (); k != i->doc.ArgsEnd (); k++)
+ {
+ os << ", " << k->first;
+ }
+ os << ")" << std::endl;
+ os << "argument 1 -- the trace context associated to the connected trace source." << std::endl;
+ uint32_t k = 2;
+ for (TraceDoc::Iterator j = i->doc.ArgsBegin (); j != i->doc.ArgsEnd (); j++)
+ {
+ os << "argument " << k << " -- " << j->second << "." << std::endl;
+ k++;
+ }
+ os << std::endl;
+ }
+}
+void
+PrintDoxygenText (const TraceResolver::SourceCollection *sources, std::ostream &os)
+{
+ uint32_t z = 0;
+ for (TraceResolver::SourceCollection::Iterator i = sources->Begin (); i != sources->End (); i++)
+ {
+ os << "///" << std::endl;
+ os << "/// \\ingroup TraceSourceList" << std::endl;
+ os << "/// \\brief " << i->doc.GetHelp () << std::endl;
+ os << "/// \\param arg1 the trace context associated to the connected trace source." << std::endl;
+ uint32_t j = 2;
+ for (TraceDoc::Iterator l = i->doc.ArgsBegin (); l != i->doc.ArgsEnd (); l++)
+ {
+ os << "/// \\param arg" << j << " " << l->second << "." << std::endl;
+ j++;
+ }
+ os << "///" << std::endl;
+ os << "///" << std::endl;
+ os << "/// The path to this trace source is: " << i->path << "." << std::endl;
+ os << "///" << std::endl;
+ if (i->context.Begin ().IsLast ())
+ {
+ os << "/// No data can be extracted from \\p arg1 with ns3::TraceContext::GetElement." << std::endl;
+ }
+ else
+ {
+ os << "/// The following classes can be extracted from \\p arg1 with " << std::endl;
+ os << "/// ns3::TraceContext::GetElement:" << std::endl;
+ for (TraceContext::Iterator m = i->context.Begin (); !m.IsLast (); m.Next ())
+ {
+ os << "/// - " << m.Get () << std::endl;
+ }
+ }
+ os << "void TraceSinkCallback" << z << " (const TraceContext & arg1" ;
+ j = 2;
+ for (TraceDoc::Iterator k = i->doc.ArgsBegin (); k != i->doc.ArgsEnd (); k++)
+ {
+ os << ", " << k->first << " arg" << j;
+ j++;
+ }
+ os << ");" << std::endl;
+ os << std::endl;
+ z++;
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ Ptr<Node> node = Create<InternetNode> ();
+ node->AddInterface (Create<MobilityModelNotifier> ());
+
+ Ptr<PointToPointNetDevice> p2p = Create<PointToPointNetDevice> (node);
+ p2p->AddQueue (Queue::CreateDefault ());
+ Ptr<CsmaNetDevice> csma = Create<CsmaNetDevice> (node);
+ csma->AddQueue (Queue::CreateDefault ());
+
+ TraceResolver::SourceCollection collection;
+ NodeList::GetTraceResolver ()->CollectSources ("", TraceContext (), &collection);
+ PrintDoxygenText (&collection, std::cout);
+
+ return 0;
+}
--- a/utils/run-tests.cc Thu Jul 19 13:17:35 2007 +0200
+++ b/utils/run-tests.cc Fri Sep 28 11:59:46 2007 +0100
@@ -20,10 +20,13 @@
*/
#include "ns3/test.h"
+#include "ns3/packet-metadata.h"
+
int main (int argc, char *argv[])
{
#ifdef RUN_SELF_TESTS
+ ns3::PacketMetadata::Enable ();
ns3::TestManager::EnableVerbose ();
bool success = ns3::TestManager::RunTests ();
if (!success)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- a/utils/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/utils/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -4,20 +4,22 @@
def build(bld):
env = bld.env_of_name('default')
- def create_ns_prog(name, source):
- obj = bld.create_obj('cpp', 'program')
- obj.target = name
- obj.source = source
- return obj
-
- unit_tests = create_ns_prog('run-tests', 'run-tests.cc')
+ unit_tests = bld.create_ns3_program('run-tests')
unit_tests.install_var = 0 # do not install
unit_tests.unit_test = 1 # runs on 'waf check'
+ unit_tests.source = 'run-tests.cc'
## link unit test program with all ns3 modules
- unit_tests.uselib_local = env['NS3_MODULES']
+ unit_tests.uselib_local = 'ns3'
- obj = create_ns_prog('bench-simulator', 'bench-simulator.cc')
- obj.uselib_local = "ns3-core ns3-common ns3-simulator"
+ obj = bld.create_ns3_program('bench-simulator', ['simulator'])
+ obj.source = 'bench-simulator.cc'
+
+ obj = bld.create_ns3_program('bench-packets', ['common'])
+ obj.source = 'bench-packets.cc'
- obj = create_ns_prog('replay-simulation', 'replay-simulation.cc')
- obj.uselib_local = "ns3-core ns3-common ns3-simulator"
+ obj = bld.create_ns3_program('replay-simulation', ['simulator'])
+ obj.source = 'replay-simulation.cc'
+
+ obj = bld.create_ns3_program('print-trace-sources',
+ ['internet-node', 'csma-cd', 'point-to-point'])
+ obj.source = 'print-trace-sources.cc'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,369 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005, 2006, 2007 (ita)
+
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import os, sys
+if 'PSYCOWAF' in os.environ:
+ try:
+ import psyco
+ psyco.full()
+ except:
+ pass
+
+VERSION="1.2.0"
+REVISION="1894439586"
+INSTALL=sys.platform=='win32' and 'c:/temp' or '/usr/local'
+cwd = os.getcwd()
+
+def decodeAscii85(s):
+ out=[]
+ app=out.append
+ s=''.join(s.split()).replace('z','!!!!!')
+ p1,p2=divmod(len(s), 5)
+ stop=5*p1
+ p3,p4=s[0:stop],s[stop:]
+ for i in range(p1):
+ off=i*5
+ a=ord(p3[off])-33
+ b=ord(p3[off+1])-33
+ c=ord(p3[off+2])-33
+ d=ord(p3[off+3])-33
+ e=ord(p3[off+4])-33
+ num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+ x,p=divmod(num,256)
+ x,o=divmod(x,256)
+ m,n=divmod(x,256)
+ app(chr(m)+chr(n)+chr(o)+chr(p))
+ if p2:
+ while len(p4)<5: p4=p4+'!'
+ a=ord(p4[0])-33
+ b=ord(p4[1])-33
+ c=ord(p4[2])-33
+ d=ord(p4[3])-33
+ e=ord(p4[4])-33
+ num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+ x,p=divmod(num,256)
+ x,o=divmod(x,256)
+ m,n=divmod(x, 256)
+ if p2==2: app(chr(m))
+ elif p2==3: app(chr(m)+chr(n))
+ elif p2==4: app(chr(m)+chr(n)+chr(o))
+ return ''.join(out)
+
+# wafdir is needed to parse the command-line arguments or print the version number
+wafdir=None # SPECIAL LINE
+
+def uncompress_wafdir(newdir):
+ file = open(sys.argv[0], 'rb')
+ while 1:
+ line = file.readline()
+ if not line:
+ print "This is a stripped-down waf, there is no wafadmin directory available"
+ print "Please set WAFDIR to a directory containing a directory named wafadmin"
+ print "Or use the full waf version available freely at http://freehackers.org/~tnagy/bksys.html"
+ print "\033[91mNo wafadmin: cannot execute anything (error)\033[0m"
+ sys.exit(1)
+ line=line.rstrip()
+ if line=='# ===>BEGIN WOOF<===':
+ cnt = file.readline()
+ if not cnt:
+ print "Corrupted waf (1)"
+ sys.exit(1)
+
+ line = file.readline().rstrip()
+ if line!='# ===>END WOOF<===':
+ print "Corrupted waf (2)"
+ sys.exit(1)
+ break
+ if not cnt:
+ print "Corrupted waf (3)"
+ sys.exit(1)
+
+ cnt = decodeAscii85(cnt[1:])
+
+ # create wafadmin
+ import shutil
+ try: shutil.rmtree(newdir)
+ except OSError: pass
+ try: os.makedirs(newdir)
+ except OSError:
+ print "Could uncompress waf-local into %s"%newdir
+ print "Please install waf system-wide or move waf in a writeable directory"
+ sys.exit(1)
+
+ os.chdir(newdir)
+ file = open('wafadmin.tar.bz2', 'wb')
+ file.write(cnt)
+ file.close()
+
+ # now we have the tar file to open
+ import tarfile
+ tar = tarfile.open('wafadmin.tar.bz2')
+ for tarinfo in tar:
+ tar.extract(tarinfo)
+ tar.close()
+
+ # cleanup the tarfile and chdir to the previous directory
+ os.chmod('wafadmin', 0755)
+ os.chmod('wafadmin'+os.sep+'Tools', 0755)
+ os.unlink('wafadmin.tar.bz2')
+ os.chdir(cwd)
+
+ global wafdir
+ wafdir = newdir
+
+def try_wafdir(dir):
+ global wafdir
+ if wafdir: return
+ try:
+ os.stat(os.path.join(dir, 'wafadmin'))
+ wafdir = os.path.abspath(dir)
+ except OSError:
+ pass
+
+def find_wafadmin():
+ global wafdir
+ name = sys.argv[0]
+
+ # wafadmin may be in $WAFDIR (developers)
+ if 'WAFDIR' in os.environ:
+ try_wafdir(os.environ['WAFDIR'])
+ if wafdir: return
+
+ # waf-light is a special beast
+ if name[-5:] == 'light':
+ try_wafdir(os.path.dirname(os.path.abspath(name)))
+ if wafdir: return
+ print "\033[91mwaf-light in use, wafadmin not found -> export WAFDIR=/folder\033[0m"
+ sys.exit(1)
+
+ if not wafdir:
+ dir = "/lib/waf-%s-%s/" % (VERSION, REVISION)
+ for i in [INSTALL, '/usr', '/usr/local', '/opt']:
+ try_wafdir(i+dir)
+ if wafdir: return
+
+ # remove $HOME/.waf-version if asked to
+ if wafdir:
+ if "--nocache" in sys.argv:
+ import shutil
+ print "removing the local wafdir", wafdir
+ try: shutil.rmtree(wafdir)
+ except OSError: pass
+ try: os.stat(wafdir)
+ except OSError: wafdir=None
+
+ if wafdir: return
+
+ # look in the directory containing waf
+ if sys.platform == 'win32': s='waf-%s-%s'
+ else: s='.waf-%s-%s'
+ dir = os.path.join(os.path.dirname(os.path.abspath(name)), s % (VERSION, REVISION))
+ try_wafdir(dir)
+ if wafdir: return
+
+ # not found, uncompress
+ wafdir = dir
+ uncompress_wafdir(dir)
+
+# run the test
+find_wafadmin()
+if "-vv" in sys.argv: print "wafdir is ", wafdir
+
+# Update sys.path and import our modules
+wafadmindir = os.path.join(wafdir, 'wafadmin')
+tooldir = os.path.join(wafadmindir, 'Tools')
+sys.path = [wafadmindir, tooldir] + sys.path
+
+import Options, Params, Utils
+from Params import fatal, warning
+
+# Set the directory containing the tools
+Params.g_tooldir = [tooldir]
+Params.g_cwd_launch = cwd
+
+if Params.g_version != VERSION:
+ fatal('version mismatch waf %s <-> wafadmin %s (wafdir %s)' % (VERSION, Params.g_version, wafdir))
+
+# some command-line options can be processed immediately
+if '--version' in sys.argv:
+ opt_obj = Options.Handler()
+ opt_obj.parse_args()
+ sys.exit(0)
+
+# now find the wscript file
+msg1 = 'Waf: *** Nothing to do! Please run waf from a directory containing a file named "wscript"'
+
+# Some people want to configure their projects gcc-style:
+# mkdir build && cd build && ../waf configure && ../waf
+# check that this is really what is wanted
+build_dir_override = None
+candidate = None
+
+lst = os.listdir(cwd)
+xml = 0
+#check if a wscript or a wscript_xml file is in current directory
+if (not 'wscript' in lst) and (not 'wscript_xml' in lst):
+ if 'configure' in sys.argv:
+ #set the build directory with the current directory
+ build_dir_override = cwd
+ if 'wscript_build' in lst:
+ #try to find the wscript root
+ candidate = cwd
+else:
+ #wscript or wscript_xml is in current directory, use this directory as candidate
+ candidate = cwd
+
+try:
+ #check the following dirs for wscript or wscript_xml
+ search_for_candidate = True
+ if not candidate:
+ #check first the calldir if there is wscript or wscript_xml
+ #for example: /usr/src/configure the calldir would be /usr/src
+ calldir = os.path.abspath(os.path.dirname(sys.argv[0]))
+ lst_calldir = os.listdir(calldir)
+ if 'wscript' in lst_calldir:
+ candidate = calldir
+ search_for_candidate = False
+ if 'wscript_xml' in lst_calldir:
+ candidate = calldir
+ xml = 1
+ search_for_candidate = False
+ if "--make-waf" in sys.argv and candidate:
+ search_for_candidate = False
+
+ #check all directories above current dir for wscript or wscript_xml if still not found
+ while search_for_candidate:
+ if len(cwd) <= 3:
+ break # stop at / or c:
+ dirlst = os.listdir(cwd)
+ if 'wscript' in dirlst:
+ candidate = cwd
+ xml = 0
+ if 'wscript_xml' in dirlst:
+ candidate = cwd
+ xml = 1
+ break
+ if 'configure' in sys.argv and candidate:
+ break
+ if Params.g_lockfile in dirlst:
+ break
+ cwd = cwd[:cwd.rfind(os.sep)] # climb up
+except:
+ fatal(msg1)
+
+if not candidate:
+ # check if the user only wanted to display the help
+ if '-h' in sys.argv or '--help' in sys.argv:
+ warning('No wscript file found: the help message may be incomplete')
+ opt_obj = Options.Handler()
+ opt_obj.parse_args()
+ sys.exit(0)
+ else:
+ fatal(msg1)
+
+# We have found wscript, but there is no guarantee that it is valid
+os.chdir(candidate)
+
+# xml -> jump to the parser
+if xml:
+ from XMLScripting import compile
+ compile(candidate+os.sep+'wscript_xml')
+else:
+ # define the main module containing the functions init, shutdown, ..
+ Utils.set_main_module(os.path.join(candidate, 'wscript'))
+
+if build_dir_override:
+ d = getattr(Utils.g_module, 'blddir', None)
+ if d:
+ # test if user has set the blddir in wscript.
+ msg = 'Overriding build directory %s with %s' % (d, build_dir_override)
+ Params.niceprint(msg, 'WARNING', 'waf')
+ Utils.g_module.blddir = build_dir_override
+
+# fetch the custom command-line options recursively and in a procedural way
+opt_obj = Options.Handler()
+opt_obj.sub_options('') # will look in wscript
+opt_obj.parse_args()
+
+# use the parser results
+if Params.g_commands['dist']:
+ # try to use the user-defined dist function first, fallback to the waf scheme
+ fun = getattr(Utils.g_module, 'dist', None)
+ if fun: fun(); sys.exit(0)
+
+ appname = getattr(Utils.g_module, 'APPNAME', 'noname')
+
+ get_version = getattr(Utils.g_module, 'get_version', None)
+ if get_version: version = get_version()
+ else: version = getattr(Utils.g_module, 'VERSION', None)
+ if not version: version = '1.0'
+
+ from Scripting import Dist
+ Dist(appname, version)
+ sys.exit(0)
+elif Params.g_commands['distclean']:
+ # try to use the user-defined distclean first, fallback to the waf scheme
+ fun = getattr(Utils.g_module, 'distclean', None)
+ if fun: fun(); sys.exit(0)
+ from Scripting import DistClean
+ DistClean()
+ sys.exit(0)
+elif Params.g_commands['distcheck']:
+ # try to use the user-defined dist function first, fallback to the waf scheme
+ fun = getattr(Utils.g_module, 'dist', None)
+ if fun: fun(); sys.exit(0)
+
+ appname = getattr(Utils.g_module, 'APPNAME', 'noname')
+
+ get_version = getattr(Utils.g_module, 'get_version', None)
+ if get_version: version = get_version()
+ else: version = getattr(Utils.g_module, 'VERSION', None)
+ if not version: version = '1.0'
+
+ from Scripting import DistCheck
+ DistCheck(appname, version)
+ sys.exit(0)
+
+fun=getattr(Utils.g_module, 'init', None)
+if fun: fun()
+
+import Scripting
+try: Scripting.Main()
+except KeyboardInterrupt: Params.fatal('build interrupted')
+#import hotshot
+#prof=hotshot.Profile("/tmp/proftest.txt")
+#prof.runcall(Scripting.Main)
+#prof.close()
+
+# ===>BEGIN WOOF<===
+#6<\%_0gSqh;d&8a."hY1OoPI]s33l[s8W-!s8W-!s8W*!!Wdft#_7^K&3(:4<!k$^E1ZIME;K>0z!!7\Dz"YX3.>Ua!cn$B0FZeC1s-G%_tZWApt.W&DGM$bVO@&o0CEd+s=G/Nd^pX5e>N=FBRpTWt1^%$LHDcbW`[>)02T7(ps_s`T.kL"l/\9A)`TmI!0l\=fqPOH0]hO`!Ne(ZW@C:2FCX1=2ShWEY_!'RTEm^mX6mY`Nae(33tHcJXL'?JqagU_U8cM&4Zd+*Mffsc=>iBVhEgYWCS!!!&(4mrEhV0Y/o545T;+*i:#aG2sFqdQ2uU:AbZT\Ym1K1[`)@=V/\&O\*6O@0G=Prh&$T"$l4CWt=8g/gPg]/"MoXDH&V^:O2&lRe[>ms=V,[U"71kIoc"IC1-mbJhr^4dEJ!Z`WWX4n#l:Y<HpL`f@9FaAdur/Tn*WY;Z-%g`6L2q`M!=P=Il%O.FpLF:P3cGC.4#VRcfrpQrU6oXXTXT0PBM6e8F7#J-<(efD@^m.US*lXO]LmbZ^3o=k*:p(+,][r6H-\ro!ihX.RYq.^G3qjs]lE6)C5mk9U^2g9TB]_?]mHeZ-`>Hl(\[`?A!)Z"YgluhXC>oc?tm-9bgFa(jkGE7&`Y1i_jYIj70]"NN?n%'+7GM[1tT\hKUVVHj*i*4In_;ARF2nM4sY;/`BC!b3DRM71hBk;oJpClkj03:lk>&SU`[[W0m\GJJd)XR%[K(/4*X,%KR\Pb&2OOp`Z>t4YQ5+2,%kQ#M'D+V0[Af&k[#49GU]\5+Y?GTgYNS3@L55BV1pp;G;3qP;WDm+=4YA1e,;d%^TIC%`kmChrN*P1^C?;'aFS[$LA(^d%d"t=qMRhSq1qaG;3HU)s+he.A'\U7BI9hP-hp%R8(H1?MZ*=Y@3C#i^igU\rVX_5t(NT],skl]A5UV?Hef>?tq#M7IgqV?n%HY[tNfqTP]h`?0q\&(Sc[cp-R4]gAJMHdOMWjc$cf^'CBB%^,NG/tIXVUZG,;bh#l]68)*\]h:YY3Biu\`EJ=S*d;bl]nmn!hq<_<Hb0$mH,?`Q[MY7oYY03hfmq*fc73*40rXpje4u"/.<]4ma:KGnF4W4f@K]JH>cdumGC\7#u(sr"9C=\!1=`P-3@Xi"N"[rVhqAoSqT#XW:ZZ[+mM3X9`_VmVY*5(THXq5"NVfSH3HF2H>FkJ_DNBjoc$V$:`=#c_D3o=OMM#)1hZqV+s;IAVG/h5d1b$-VkP(=:XTg'%7Ur)&0?W^)5mN8!!!$IW_uAYdmfSn;*@Y<6RSktPR",h-6Vs]z!&OZU!!3jrJcRS-BE9r]R[C)A1s0MgC/7dY4f51N+0%P)fVbZYAu:N<O9)!S!!Gk!&-Mtu!WZ.64H,#o]erU5MOmbh126#j6dcKA*hXRI!!!"I5Oa1%s&K)0!I"?)gs*A/8+HVt+RM#*pZXt[gG6CZKg1/)S3f+BI'AQ?D:YIuYB_3K]mm>qAdB/[%*UXGpjQS:jj;)=hK*$T^0/THkrEP%=]e+Wd;DA#G?I;s2uV-QdMr,f7bNOiJ<N;3g]YCG!A=?$F!Q1H@qG.rCmndkK5@WpQ8NNW:UHS9)rHdY#Hif'H^hZ>?:EsZ_NX(e27u8ggHZ2's0dYiFEaqs%V(2*$S!t=!CA1K+sDVtJq-sr&5]&c&+>&LnV'J!_Mea;.6n4:-#f29$Qm9G[S_T[?sH]HC@hr9!"0R<7`m3R+&klF!(D]3&qg;]Tj/^*;:->Tpmuc"Q<@b<VQXZ;X$RsI@ni(:<*-P6%5Kda,h41HL8%YDA?uGj1sff,,dS1a_T@n^VAfUgbXTu+L^Qg(>9u(&N0p?7@qM+8"cT8+>)G(PVM#/Jfcj?e?kU:h@+-j*7;1=2Q%n%*f#3621*^>*1F.sC;Gng:>%8sR8OUg5-7"j7b`\\IAMm(R@hR4T0P!kO@;.5<'JfrW+W?3%Cm8Zh;J\sme=%U".P,1F`+cJ"1pMWN`\!=/db9Z%Ah#Br2)\/E0r._oMNFQCBUVR,@MViqbqu8[Lqs.#Bi.Qt.8:Zo9,UEjOeHGk9/SV+#b"kkQAM)I(1n4ZP=24DVHHJ7-Bgf.6T#c>8Q8)K7?#JH.[\H0@[WHXBd"D>9J\*)%:Um2PS(0Y,U?tkVM6rOZs+J-;c8iJ2'n_LP"DNEQ9pQ8;A2q08s<h^R),4i,tUrZdA/[T,8O!UfdgNdUeIMW`6>2p[VSg:2A%d5,702`e>\2U9Rmbt[$`\2V?ETf,*Ak1KIdR1/K6udb92WmMC#NlZl)c$'Gb;tBdkos5c/A?YYhcA9beMpP/PaB93I_c-j<$TN+CTifZ)$j`C5Y%(tgg4Q:WKU8?uqXg+=^ND&+[%R+!WDZkOFR(.MtpP)WA&;J@PdC;Ca^=Y+7*W2gY"ChjAe`(6/VN?jgSg.6j3&n=LtVI;A/0t(!tRA`I)/XFL(a:t"mP+mr!0c%i\^f`-rJh3Y'"'0086qnCNUp61#Xg'=?M4l.P##dik9sU)-ALI]E[I%d.!NE(%JDbB+^sF=+=Cg/EV4uBT.P.&E`+G-JC0F4Y;`1H*[a`[X9X78?PAM5U2G,-W1GG;06s=E.bn`rENMakBAQ'<O88:WI)Q'Kt1pYjkOIAX4c*<7B2.kQ/.8U[5W)<dL66f#7BduH/X(9dc7^acs.7l<2/=)GC[';O/fVk0/[4JCqbuW(l0Vfp1[OiiSR&*?^U8=)k)U-jA-F0INZPFH9Q:AkG6B*,AZRII_MTqD!8O+Pi8u?>]MTJo=P-dZ_[P;9,%B-?3Rj=2,12L?\2@5Vi,;>l>MaajC2706>$<`*>(,/BNN00)<=^+4k`[.G08r[=a1f,rc;Im`q-Ifkc7A@bp[M7.m8[:c6B[Hjf@kuan;R7l(<0:RgBPj&LVFtA39WBea5tS)rW\q12[+(Ir)b,cs%@Ko@7&iM2[$3nS;Jh;s%&5DRA@4j<R&_R49boUkW`7E2KLX-C0Uegl;/%OiW2roOVUSg>NJc)MgE\RR',<uNYt:dL'r$m`[A>3e&oF:8Ro-:%[%T8&2V=g?=Y.]fbr1iS[OiqA`+rnlAW"o:.mjYAWM\;s2Fs#\8Q&N@bu0D,@4%rfNGU!dRl*KGVFX[peL\/Wb1bSb<Iuu'&f9X^RR4*F"Y<'pPqn80<Kgn/BUY*kQAlb-b`^4c/OW^@dahtf<(REq,uJ4,AkY(J<?`WQejMqYBj4<4-I"+hM\;K3;.R&!,tc?GAD+3*BLsET8k^MR'.F@30T!&u@oX6hUqVmnk)(Z'Q&V`"VD#g#a5bd_jO8H##`5JCQQSJaUHWOT)W*H95N*mf;?$C)(^EVpfRIq'GPY:>YLh%7n:m.c4C_nuD.nbIJNa[=hSG+gUif!!M#VoF1WnT$0e)l7YqXNJO4`QfX\hAn@M:(EU[6C3L8aG_l;.+5LrL>OkY"[]`E4hKd^.M"#2`Hk.t`8$ObOD@9gt\j5O;NfCIKN77pPIt/if)X"="S.8PV+fAiJfXb@=akO5uZnlf2['NX_kP-h(e+*@JX^*Vl8ZJM`WY7%LP#MWYl1^E[0e0S#k+bPjXCUPNUOPIGHl60sOVJqDte#i*%7S[j_$Od4bXk+Wd^K*Y2RUI<(#*C&?Qs1P\MF)YW"E8ZfuC*E)h0W_@ia?=56#t(cuks8Qp_XPg,/[dH0A@Vr_fsu4>?On6+EQu\Ngb_tAr@tbUCfF(hIqMc#o$"X$<fU^&M;`_TN:*Fee\p$IJ_*X#1"%)K:Ti@a9N<FmPuJt(*HTq[S&?"uAMJ+/@%1:*78WB+%!BM6r5bVuJ^[cJRo*:$GO4BZ+6VH?Hi=E,k;H4'l5gG%)nbu,ha1N1AQD'&b83VQ>8a@Dg#Bk8A;,jkTjjnY+Z*2j,(_qr-]/3>iNW8#1HHJ<s5(OP2AJnP6_X;QrSaQPI?OBp<?(`GajB%AS"!ntD7]8"Q+%ZO[[;N3'4BPTa<-<N@H\]$(qm8f0?L%C*ODd:+MoP;I'Z5\Yr^!5"gC`,&q`PiEXXMoGtq_Hh+U85K+eIRi>WG<A2n+f,cj[u+!E\i4"6sXCAPWHmGb_JZaN/QT#!,E*Am,(fWoDNegUnLNpIKRV=8!npq1n2f=GHI%lmcm9VUn^<CD.rUM]a99fMPt_VrG='^G?ll\&`oF!_Dc-unGLguLgFoHDcM[\l7WktMW/hi3\c75.]'e/1/QKT62U20.n95lsf4%[k5YFUj`klKrQ=28<G;3_$aKUM/PpKFSJC@uYZ_G1Q:'G&GnL4<71P#K?oOcRm'Nm`(>/.GM6L0ussCjqs0L1P;/j;lQ<m8[cVs*@AA:Ruhp).('g"]'G!S2QW-VN.$I#)4d8.%*I'PnhHAuCI>aJJOUV8kF(3=5`fok[<:]-kk&PV$/mncL-E(6YbgcmF>OI%X&gae5-f6q(rKr`<n=IP]7%;$r:^:,6.53YA\JXA`KT!1iNCCGj(0,:$V_;`rV.;P0si@G%.*;]OonDfrGb-,W1</d[JX2uK>a6@`VD;F2TLPU&#<=lbTqX5K*],n2[@uM*Of#cHXq']`sT,jg<%R^XdZKJ9Hkj/Ep,j[XIG..#,=Xr&RQCLRr+mWLq"r57Mtu1f--$Z4Wt$^g.$q8<pW?-ibRPu-B0jC*@TUslE+hQqgGb;e7"i(YR<S.NOq`8CYZbC,ub,\PP7`7"J_$Z*,g/U2Y<`b%RNlrXka_6;O!u3fUWMHKT/Sp-IcS5%mp:1cC.;TX.'9V/eF@eZ$J13&$>9>Om+'&QZl46h3nmih_0P.8:8-TC6?q90(6.j8o[aN3bV'7PZM_%aQ+%N8tXZ-im@?G^TRhbNVIb4qTsRE"NsIW7\F]<!]o;5-@>KTT*U*dB56E8;E+;*img_NR26p1[_&Cp2rT0![(\'2OkrqW:[p^Y<-j;J1JpZtX4iu1jdGr)S^H@`DUcejMhm]16l^CG'_A\5%^ZPrrQBbQ6\hJST$W[o50kk2.7s1-]&`U4:@9D5ZZ2tlH.FlgYBm9M/)/)s\-pTE3)#?97,(=`A)L2IqJ%7sj"'6VpaWX3fZ$,>66\*sU-9<%=<8BYU[>#H;=DqTFX2G;a%6CEkKqB3l#Cf648;L,DP5XDN[MQ4%&5iW^l@s+=CW52N\4jI&p8L;EB68s$n:OjV!UYj(B.B>S\J[Jp?,UGk+B;K*RgdLP+ul<V[:P74m4-6A$tQl;Uh8EWNha><(pJR]b05AL?nrC;hUUX3+AG3+X9tk#I\gO7a,R#D"S62MNt,[KNOYmbrO'8lTJD9C:b"*oBM&[[f,RYF2@Os3J7oUa<,EYn$Z_=H'soVe%4Wsr3oPA5Ds'EHQj'u%g0^%(T/u5X]0N2nW)2(B&KKMQR(AQNN8@1]!jKjVlrV_>"h:+PU%S=&3.QK8GRrXYb#b+\V%uNT"08t\m>f6eEFYNn;<DAV`[>@5pV,MI!D+4h'oM]j)S5,F^sQ-0<P\<Usj1LlH)WaQ%lg!1@CLc9()JE1V/37;@PKidu+flNlX[O*d-_H[Uc&kL^t5j,c(!O;r1$6FPfNh:@<A>".d>A.9j./&T2`H90:7jQY:KA+nE<G[gj)*GXlM>9R:b#%c'u5cae%"8A/-U/Z*G^4@2@:b&*tHd^QDZq+eU#:Iph:n@4a@TpV!O,4lij"LVoHm?SYg&UpNVf*r1q`;6;t+4<U$2DVSZ5:Eimk$I+GP:O+R#3pO*Xd<%Cf^-nI.P9pA'bS;naCM#6m>FZE]_1>mlSpW+a6S3&oZZ"Id9->COH!.i@Qf_\&aAQ()bm+<ob$u2)H/NEj`[oP=Qc1oVO@mW\M5AG%isOd)fA"dA$R<nkfLkIf^-E\!YWU=>@i3FK9`#pq)3tRc1?pu=Gk=P5>PC6qRa<$E/<PBKrW6.WK(>j%-SF#oX>H9YOK6Z/59f'pce+KSKs@iEq<o=N*59K[[(,>4q`;"3-Tho">2[BF.@Gb8q`l(;Bfo1N@*t"T.)hrdrr+D,T[Z8;9kM6/t7$#6!d>R`@:bKf!]$pF-K1X*>[r1%bNkSFn+ogWUg]D4siuA0Ls;;h#%#A5?<2FNGRsT^71%Q?F:I:::]o\os:5`%`B912UZ2J35,fo]14XVLOV/4Sb(rqbOB*aqF1qD8Z??#G7qaX%,!WZQ\GY[8*ZR9BmNOK?R4UcGKLrgg_D?::Kc_9jgSl&.8^/L8df$()3]6-k=9)=R.fYlHpQXLiuBG*?[l9b9Q@%J:4'VBR6Tha\b=Y+>bc[bNT;X?;%P"8NrCUc'.5$qR3:69=R<Hl+>GdsI<Ua*n\hd[hZ\lM?_qt,0]M0k;e%*@KosM^k;7'OD7%c&[%iP23@uhN\`J^4/]ir\fh)F[-oG]+e1n[kN);RpQhf[Wp@F+[(^sm`JH>iQJAg>CimGR]&ASk[&<d`?88q06&e_,k84Z;'diNMda,S0p-,S1D/aC%^b5GsIn%L^-LNN*W@sT4fHDs8/5#(uZp6m0(GT)3aRBER7>@`lIRg-ZEXFhEeZaM;,)Je3\G(r5Dh`ZImo\UY)+(le_lLbQI_8(G+miE7Y<#";RT(rkD+]/.oDI2m/D:Z41oJ.p@82a5WU\4RjE5%lU7MOp=WdYXD1`+aNf;Y<W0t*b#SU]F>M=76b,BP0$53[3t]],D,(0\f`VuVTmR0XaGpnj?d>3ui5De82,jZKl9G^h)\\a'R[l&X]IMGjG]_'qtAd7c*2kmf!JZW.UjNa6[CC>D'D0H3ulI7FeI@crQ-G]HjskHD7;j0F]emk&W-\$VKWLe0\@oBff9?(@C4VR6i/2#*]_W:lJfFaQG[FUns1:;ZdRlW_+Sb,mkUmcg',YtfPnQ$$6IVV$dmEjKedhCF#88a"go"p3bD(Zis5mB5CGc@5QY:."N2A$_j$s)oW/r2,;)"([kr5n;(gSM^0RJPsH"&C`\PJQkj],hj^o6;+hCKT$u5`q`LQb7T%H_Qg1p/5rAgDsE-NleO)?30IZk=t%?O0qPlf(HM0l!^urmP6EF1o_8"/oT9"gd'W5ml0jhbc99P4@dt<,hfI\p]6baV8WL3Dqb4;^_^TO$8^@Ym$L=!in93J]_%7P*j&*ND4'.qb&K(@Sl_E(8VN/aaLQQV/S8GO26bae8IK$6faTpuF=PR3b'%_!I\J"CRl:rE0=Q;@r,>Z3H3*W+p:&CsPWACT<:>'j)GrT\/?-@5)oA^:Cd:sg3THGp>e]ESlDIi:+`7AbCR?fF7Kb_7h(+26<`S.FkZ`DCIbJWr\Xg7A;k:0K,RY"HaJiMRj2[7tT`HjIclcVD)Q&fZ6q)!]G%c4^L&%\P-S<u;\RlAN'3T5*R]Co'gMcAn5J6;H_nX^*LWbJ*nm/p7K2b<+eqmcAD,G".2[fGrkBlGnInr"BV@Wf^$7s=ZCmVB-pVkX]Bm)@*qV"_+F_R'hMSR.ZC$XYDFOMMe(dtX2)1]8=S6Wm6R1/rpF8nMMP<oe,m&G;-TpjF3)p)<-U1Dj#KA7":a7f^nETokiXP`):D;ojW-\HpiBNKg7m8PQNZA"^gONIt\V*<oe*Zh7k]e72n[%dH?aFDus>MCZi7b&ln(]m!e'l7(+_=BH7LJRMtiV!j3,&\idT%0DQukDuV$nBTj^=X>BTOuK#CJCF_,j1dcT,OpD!m+K._X##+[9^Ti%b^%0sM9pS)9;,OGq2jglhbe0Hpo'lUT6TH'M5cSmZq'9FhiqX5^SraF9@KkIM0F!0+8"[[M@.>1A[C'CUkcAE7!o>\<fU+-lG4T1Nh3Hh^#lW/+SI7_ipgZL5oY4(80="n3r)@dEhFLW*$Z$p[O+ha`C$Q`DDWk@U6a)#3\&rkQ$+X\<D\T/e(aAu;O/r5,CS<ll25b*NK>3=*Q,I+I!T[P/eO2;@MD:Kq!ZY'KCe*SINCXgW7bITJkm>B>s4\FgYHkZn+$/<>/Y3I7khL7h)SeiTD!9K]TbNOO"TXBkOm*UnBC1%R`#_BQcF5lW3>o+S.95]PoQ@h&9>&,pRfL_3KWo2eqar"l.W/#e^a2VrOhOq:OOnR^P(tGhh"/ZL&lsYK@WcQQI%h6I@efi2PJ&C4_8fF`s138i*BP*,$/(/7pH8CY_4?l(D-NpBtR7\CbVFUckI>L25d@lTK*+#h8J#[i&Z0tV1\)Gh2ET,:"_EtaK1dK(m-H".KkEXWS-N$;k0tpVcoYcC%okShJl*HR50FH#RjM*PojU?l7rdi>:;Hj1ts:9S[N')'j3)d-&3@%HIAn8/$E"^,1u<;p@(e>Bthl6%5u5e;mpgpqkLUrph\^F9:G7n(%(=X0;XQIIc'nNmuEjf?E]em>5_.N@R:G7"b4<V:H/?)'7Z%]GGA"VXs#'r:8*4MTnM8#-8T'[KiG__*+CR>dp2<:`jX.[Ei!!_%$(d/4h.MCVVQq'YC1(i\C)ru&KBdQL=87&7BNLmDTN8QYZMbNeHn",'DCU%*b<)0A8A@!DFcB(eKBi+*&-(p31Bmm4;`O/]dUC_%lnV;bLRL^BLkFnH0mRiM<^\(?4V:uE5kNSN(pTGp5O)Q%"*i*c.U.EEpbR$89\kGo7eNDN>='JReb1\C]Y\s>TQbQ;%V(W1;h;HA0E?bE@k,tJq!NqIu*<7j!/+6O*P9(!atW6:i\HS+go8&YTqiicPCLYJl)QJ9*`G*2,9u&eZ^B52bKZk\VpP)b6tHOd'FZ.Yn-.6LeQ':UTeMDes7#,%ZJ+h`koXHeX\CB8tmhWADE9Q!6d5G4O:T6P_;Ufj,$fm%5G;DLt54]8IQF0[&)-(0WEE\cM"7^5`dG,0f]t^QpZG^`spkAkW`(N7ZmdUc$#Kahr`p#Me.2.m`UK)DoWs\d;R+$Gn#FIe^3pao#rrKlY\$[jMoOB@f,'amq>^S)N@OQW!+"IV>4Qq7!u4io8TA[N$:MNT,'T+i+AC7A;QMj#6mH<(.t2KlV1\YEAL2[f/M>eaWgE0Hg\G)[R`)GD-]M6X6,\qY6f'-@?@J),:Yj%Au!QnjmVgtG@P8Ucfq9:9NWaup5j?W=qP:#aIBR7S_dMqG6pGrI.YV1^F\p^K"TKY'oBT+^F\s#:agrbD9o>e2:pT6.<`7*(L\?&*<"01?l\'_Qe=aZpd:o:RAn?LE1#h/%[YdbGotrNWJf0%[p@HtBp^&HNO*?<NV**`V7%@cJi5pPimZAifm*G"*6%>@0Xo6J54J9OA(c<@oc29G4SKg4*AY>?IY^]3R5iX5Z&CrfS8gfE7dBV]$\u507nEe]g-l"<,>,?TKM!0e,@_AiM;Zd#a]Vdt6[G9+7Uiq$DI"nDJOV1d1LoE\G'_?%[XWJPQ8^ZN/;`Dh'H3,GQgg6;!_NR;`UIpo2G&:*dG9*R4PWJcCe\(Z#mi%NbAOp="WF)DSZ[#!9BgWa'a6%gisWHa/X'J_2RU@ULk?qn6oU&c35EIA#S$sG0VNuc0bOJ[jd<q$jI$SL_'lY/e2AG['",_L4;C8G9oNN*l-aG/Zs+bCe1*Dl^&D4(DV[=qpFXZrW7a7hlcYkG-tf]oG_.<TXa9ZiD6([e4ESDF2_?`kRKi3G4CVh>\(2+7]T"A5\1FS9&=RGEUf0%BXY4^tNp?<#-b1'(7B2S><\_,kWs<0Ts"CiB47)f&U%oN=a77`o6lMmMF0[m`_[b[gHE&N+Z'&<8MBh65SDfiG'SAc^0_Fb`h1AY$cC>"^5`RCDlBsRK#ss=7PHCn%MZ'q7rDt^/NhZQj8hT##@EpC?AJ0KUm9!mjIJ.1ZqU"QAVrR6#qArWt>WWn5S0e/)HFUneb'BW2CR?<"N810,k:5r#)PV%F%(iah0eeJF?$,!u9GTV\NXfuGQbk.oWQgj6.e"SDH%3*FA3.">MRCCi.(C]l/:H=A<*G[p'/@(_-6VlM3idQTdX`L?0%X61dSV>U]m=uFpI'3#T8Q#%Gr!PTl=6t?M];Ym/6a3QS@jd<mc;\4.Rl5$jg;_dI-IjR89.pk8<Y_'i;7cL?2:`[Ok2NF2)e`LaPMqIaUm>)<&s"j9ONDN3oV*::+t?H@@QQWD"6-ih7F?_&;aonK6LL,j8S=T=-t%._m>?;/?JW]2aYr$_Wo+"'OLfHQ$Rm.e,Ifk.sFJ.1AK*hGNJOKc+j\Kb"U[[lSEB5OI:YJAqFP?BYItYrJDO,7Z"n9YWHnE/b0&#s2]!R-I+)p2+^D=qdTt*.\ro(J!8cZ@E8QKgO)^48)Xmhos?FP0%nL:3\tD:Ns'@(M-18r+#+6OdDW[a)g/R$lR4M5Mhsjfpi=OpTqG.@s1)VVTf.^)7`<6HMCt"R^\"^JjE:6G5A;Ac'Q9]<P<(-WIeJgo#9bl[-Lmba4ERC'_Ft\(8c0h/Y\@m8,?':iru^Bilq;PcfRN$f!AX"-&-iWmLGA/bBQd&SDAJ?sGB.s$plKPZPWt4jFYXs`qG.Ik#<c.Z)@_-Y1>s;-MklE]feE55*SmS4:WF,Xo("`K;&YJ*BL,AJm3<TIlP9F\E>`T3jYJi+.sa@GNL\4.P6P(:m*bEmN$PD@(hSufF%d.i@h^#Jj'/*EQ@88iG_B@U",.VSE2/V^[*q29YA.ucleDE^\D4:-eCD03'.Y;UBgl2@kWRGkWo_DLC_k3./^3f%'>?,Dh2Y_&]/M=n!4AeW*3dIFK_!:`k@R8l_^^lrAVScjI5Du\[D(XA/pEVm`%2]]aZXL1D6enGlaR@;79IC-;O&mnr[$MAr/;?uRdIk-msnb_]Pi)11R^-CA4'gOM$\3B4J,/WAA.Gfk+OULa2aZ5.G!9Y^$8YfND?B,Ok]7eKH(oXlu.8kW*G:gG&H@RbSUWR"@#H[\S?8-0I(c;_6NT3ZO.e@l13FF?/)WHAZ<#m;e?KE)(r)Jj>&[m3#NZjm\]RIXI6A*br26]`[>!(9o/e/C4'F>Ou+_P%.Md"R=`AE395(VH^4gr9l`hL$1fotR?+"Mn87V^e2TM<N?6eBA/P7%HR(VVo+H\=F\N>Xl+Vd#e?(;Y4Z?*GSs6-8f(c-Z?7mQe-;k@Pb?A`O:Tmk=B27rS'9ub]3T92I'5-Mj&6O>&%`7sidasE`XCf4jKU[9C=63Zg5ioWt=j5s2K!BbdD%U?qD?J>XioX#G&Ur!ZR@AKU:q4\H>&%r\-U"a\:>/O79/O&BFjB5E6k-Ec)27l-3*0jgYRq%iAu(;Mg:3=!;N5ZKHR!sfd&lfj1-p^]?YCnp&<9/;e<<EHSbAR'5u%#DiOG8c'GjH'4sej-1U[E+=/U?tP<R,/(QJ/7nkE_eeRh9T-S1Nq<FeA_:f-uB2b(L7cW`2_&(o?rc<G.j$)Z<3`NiBX)?NW-QM/35Q=4BQe]7IX:N"X,8PLSJR54PP)&l8m)fjo>9*np0lOj"@oI%@5b'=74aB:mW*FtQlmC9sD"q2)P.%MXR[lGEp&iaM19u>N0p5,tRMuoW_p@%U(\f@SFkYj>PAo"H"]fMp7Xq+6#/S6GP3&5B[5j6D?E:.V#&$6-14EC%A>nUeF>V7J$aedRt&fk8_b,oQOGW>q[P(Fg8:3o8F$?Z]6\3N##lWTOm"C=KfD*5CT-rF0R+H&l5)k-+%8MI9;R<+VDA?U%^/R[bqm<($MpR)W%$Hobn,]u2SiP"oLXkjj48B$LN2Y_9q[]Z\<?au2?KedL@?=JI0)V(Rr(h'>I'sEsPd?UKnN*pSD[YM3;r^*I5L1dbNOEnY/LGR$9729Sr/^9t:dq,nm!7ZT(NOBMAXC3>iX:roX-O*eMY#Z-]'kjpO"c41;[%Y`9Au$V&h20d])62k!6[%:]-,;#LE+,i3<]8Tn6Uf91J8e>*/W1l:gL[59:+LI(ZOoT-_u^(*6?=:QLk&Ue9Ceu5&`_-8fh<fu,Gd;t@$\I*Bm/4[T6D"T7rt[f`u_u9bs-FKNK2&e4U<(*jCp6)\j;aEQ+<$*`$QU[fFVXKC.ap'pN>*tU!Q5\K<^6"Y>C.H:luZ,=]+H-2T'>uE.kU/O'$@'WA9f9B/3b=`8uEcLY#M^2<o@SA'9X]X.(h:>JU.`O0U)'UX6\QEYKEWN#Tl9JW2<$1u/S;?(X/T@V_r;jC(X'DA3u,an(%jOQ^R;o^^V#@9npTOB;ph>O^.0i\@b@23l]`'=CQ%6o*i^et3ag1fZK3gFeV,dWEQ]'"L&.MbVXR`7puuQ+UorXlIDaW(Z#l6:hJ;,g#QQ/&3f!Psu:Vb4c],E`kKs*_@$6apMCM0Qd"@eBlGqC[h.JE;Mh7\&]TDmF4d,"0J36--l`6He[&f+VqV]adV`2K1q"kV36RFEKB01@s._B\uOUe+4pHdd4(;kmY77a@k&Hl?V/KN2p(+Mb3bb.iO`\BqY0JB=m$^NOXs)SJuYK0P\S,fg.Z367IYWR9?t5^h>$BoX42rbG?cR./uNSkMD-`0*W5XDiIZl]UD&9uPNXqZhq/`$6iVr=Nm7A5I-:bo72%pWGF>,R!T(fQIM'^7Nq/WRN6Ll%<%h\*2&./d)ra7De$8t&UIpe.NJWWo8GBbLSD+FWZg0@FEEj:sd`u1dh1$Mp%6g?W1m#jG[4q?@&j*#LWg<B!n9=J/lkB"q(bWrk7*T4!Z3a%O&N!*+,VQsLb=j'8.gPUA.(0c&Era:=>BJo/hl#97de$UriZImeY!"VCk8coRgOZpsT=CNt[#q^]A9+\MaXF2S?a52qD6,9Bcac99fBDVij,nJg5K(s"Lh%2*p)t"pYJ(H3Z&o.n)JG##5?7tB)gM]p=)lB96=cF_Iq*!aIX`Gn?ab5%i3p:!6oP5O845GCEM+tUlGJHKI6DIGiZ%#Won.`H*-Ef]kA?KdH?WNB5(;V=^r_N^`Q:(ce@2a0^W+FLZGGrMkQ<]H,8As@Ha=I[CLk)M,mKq.!_aO;@W1[<>??'PHp$D8KIoN-L"@M7DDmgPS.m9&GkCE5M"Tk<TriO<*qn@m"I5=EPVB4'G\TiPqIOXcahtY<4LWBkY5-1b\pce:hLh:6iAY.^Cd]0II:M\[qWM>s26su:q2Q(6M`2!cHVO[`a(BEP(*uUka)*JF4>2`\>NPb1^+mEM06N2\`WZV:9[f2gP_cWJD3+RA^(Pj2a!GV.q)Kd4QS.lA(=pd&#?&bYG[[1k+el"C>^orOli)2bk;W)-'[mo;K@H?0_6io=^Td^?\DIEg*ML8f9b"DE=@6`sHo*-akhcR)-B]12ego2CgZG+2dqS'L7HDBg)VE<a:n5@BCTJ\<g+7IZ8;PM4:3$c:dG$XRXd"6geTuPX->5AK*+kCB8R73'JW[P3#Y@c>h-O:L+2)BMZ(?[@Rs^Mb&i+i]LFd3hH:f,3Is&[JWS)7Afaoi)N\`C#F<9<s26^9WS#k\j%q<QqP),?W:F3BND$H7g*]H-`=Z]gcH>E:+)`f.3+e&Cs'1@L+&;^Z\i`j&H#[DoRr`?fkenYHSHhP%V;5q+HJaVFKI>frrhQ*DGn&k/5#4bLVS(VPc@5^C<Wchukc]E!7ias1Y'>$:HYOoV23k8I!X)>O;3H64qLBWT<9Rq9l3K)egB=I.jlsOP4[_b(l1k_?Sjp?[[%b`73dKsKMM-[So`u7kG':kr40dsB!/F23XoNcIEMnd_Fc7=T(A4d=&3roW#Dj==G#%;,srss$bX\rlci-_O?(kh+-2R?$o(qkUD'dT^0Eg>p.O"@1X/EdX7JYfB`,EmE\B\f$3<L@N*1kjfl*ug3fX?H*HAO5RFoX=l9Af.C.B[()jdJB^&JkTZTEoOs3S0'`]Hio&/*o2mlI4m_GI3jlY^R7FY)-!ZK's`pA^<62b!eftnXo@M[2/X^7\/_*m05_1Y`6)=t5+,U.-=iFSR]TQB:S^B7$kOh[.QO!,0N,[oJTQ/Q#/dM+7h]=IeASZrfPXRuNOT6*7;9UAK!jH27"$=1c'j1lD@%T]oeC0M%3\SG[bKc(_t<qLViHV,MT!f#V]_38ad`ogGWLJ?1sfWTloDG0%f:,4TO;Y>[CIeoOOjJ_TK>'`Lb^d*ghC"L)d0F^Nhu[:\#_QY4Dhj9GuM0F6(r0h2?RfuD=Eb?)Hrp(3'FgWk2%ua]jA9^)@!7KDGC`omafhHZ0ML[K3<().!!7eX0C)#_$T6K^1Ud.j7Y&nE?"8b_:i%:d)7_*-4lRHC2);VVpAk/I93e*7CCqB0]1i(+`!f"*oiZ[GIVT*bkTXG`iD0<A(7,-o=(@7;Fc^'Z(1M`[&/K[Cp54Yk%i@A#[4.DB&2(TI.!3!j:Mic@`JM-N#YiQ#C(_Ur;:j!T6@R#-@(`,E5)gd<mjo[P(4o-)!'N0!3s[%I`kQGj<30/F.s%31Ttk#3,+hVZgo0EB7VA$iucQ4$[!$5C"l"<&;;E1QR,%&4Pr'0q>C3i';6Q=;O!?6_3/6-"&IY2la!%.fj'f/-'2Ag6:iFp7TS3]9X.ZN1:CD+FOq-J?FIPK,aq$A>qEs-OuHfO+H'7\7;F)5#p6jMTUE]OYsV<r56$r&r[,n_9]%?DQG%a\4tbn$OdL4*H\EMhV,A"lSfI%W(P&t_aFY<\6tbT[IgkknNs5XR`0t/)aAaId`%f?rhu1RLBKI1q2_EXQ421Z/[o1/Rb\"OE*`O&DG-cO`TTN1hd+Vl?SoZ-BKrm#RCqr,Pq#<EdH9C;6p!1G[M=HUg;P\+lUq#/RHn6s*gTsO%QVi>+GP^+@^?`'U+%a"rS(??jRKPOe'^aC.Lk87;qcoTQSt9"=S]S%HXu[A0C:,,*%CRT93ABU_X]Y9THV:isB#-Q5(;(.^E07nIP7>ag(O?s%Th7d@G.rU!+*1!T],"5rE6@>"@p=-<OCbu)MAAKW_Im@H4SNcO/?m@)XT_S$A_,Tu,<^'`/@:kN2,i^)'6ASgD51L]N%6,O#/0VS1+c8>ZZBF.A>J;Y+MmR!<csiS@`..I7MrOh2'Bu+o,.mMQcOB^.k0g3??PJPAq!0+j!-`?;gh9KmWD@I[k7p`V:'5G[7f?\/P;)af\!t#7aQ5s&T)@ND9#G5>NMR#48=`uC;*BB,mg9p8*6,YU,d)$XgTc0/sb/@G'1Jk/8haR.uPfuIVFK*[hu*.:5?_?Yl)r*VRSak_B?'D;P'E`A'S/^Z`_-b$O,/n">bs8binZ!%/O&[@j77-[8cIR1;]1N7gBZ1H0fuuTA,Ssc3_P?2iDE%rg5=VQpVeA&@&Y,oIek0rD?,TgrC7/qGTHtVO$/+kHrJWNY-M;*,<3[@i5<j*hG3U/!6#k$86uW$F)q75iH*HcQMqJZXYod2E'0L2SkRAS#pCdP$2[6Tca.pD_B<M/<;7iS2#rHip0Q)H/1":i24QKeYCV-'4)^U&0"X;[`6dY?BNDp]2U$*_UShuM6%&S#f7d_D<bt`D^[50)f\;([<-&,!]HLJS&uBM;fa/Tee<^*nN+<=#(E+MM5ac4A,L=?@bK`5er7JUqV?`l/ooHenlGajOqj;HmS97JYiV7X^MiQ+$DPnCLAQFfk%tshAB/kCMK?Xq!aHH\\u#Vn80#YXo#=hoe6d(/WbfU^B*hd)7t43%(U,*CdZJHsc)&q#eY0@bB!;ub6[_'6EhQP,%Y4KD(sfZ:@p_D$":8n"kJ+pmD2qoIOq>J6M54%0L!6'`!;PpO0leH-m34JN9IRju-4L:SD&i)lNeP$kXglmnJA@#Z:P<3#f<Q`>[uibW#9Ca62Z;,*3Q-6h?0k!FA>.7CB!or=nMok#m,0[X`g2n9S\T-=L.;Xf8JA0,r%bPY5T<&YUDItDn)'?tE1`m%MDrG9Dj[@K4[,KMCjCDWSK+;945il38fj-5X:>?S1"lVahF01rm!urtL"N@n;B5-l==,QS4g0mDDh*$&hpV<eAB_\1\^M<oUu6ntP)%5hq[9qL^PQ[!6p.N:94K\M*(h6)Z?nKq\<q%DF7W_*e802T14pK*CkL/Qa7jG!4(o*sm=:`uRSe<#P:F*#EtBDeB;A+[EU^AB,S/-V',7r-$V-J+=l%]Dq^H.0pKrYM+Y])d%)P`F@1TmR'Z^Cq]k#[0#]<mnndSZjluW%\)?ZHD"c#iB.7/HZWeZB]`$e*/l5]RABa'7%VLJQ3jdiNE2qiUq\`Bg0G(Q3br-TDl;2f+$NGK9;I!KE(UYs)71R:R!5j%"/9=eO_C0o-#f."m)2OJ"mhiR+8C)uM*0(=%MG2G\B8F,kQ&2hh4T<C=TT5Ei)hY<W\J'i<@$aH2Od!VE'/f]a0gP>@NbV>8@>cS[VfiN#*5Ln!g%2oPcr-N`d`#a:SEZ`S;Gs;A!3dh6?XhZ))[>jH[k?K7OgIGIb8?T0O6**qs3,*2ojpu&To0-^L@d`uFphCRC9B0>hguU:<[j'(#B]A*,-Vbl4Ccc4Qm:VL3p?!]tb_3l<1E2$%&;S6-:[%*(G;1g)lJE;[NG]m<P*$%e0E,-9LY["qQG>f^o+,.K>@nV'[OIA!*/XaX`hY#_$!9gI^?1J/'i/Nf*j_h9H]'Ge:I@gT0OjR9.CfQaJb:nc\G*L\7<6_"Jo\^F&n#N:AY*qPTi2.;m'%r&Uth5p*[53lFdLkK<TI1D4A$95CZ>bRgZY]R+:OP]47pMg%I0J1fPij-iJiRs+Ol3dOQQs[bYrSDd6bN^BHlP)&XBVUc,-p'fg;XaqB&UU+n%?KRlAE-.Re%oh(0b:AeB!,CbX8I]'fH@D[*^k4u2-1-BKpt!?u2+`*psV*t]f<M`ocDUIhigZ.eEo25eOE(p:.00Gmi2BnTZ9A(lJ<gM$(B\O[4o=YS3VA!o\fKZJdd>Y-K*/n0e%f%2M`^(eGZMOZ#gLCZgP+$>2`e)4rbRjJ`alRUG'e:@oQLKQqGN1.Q$#-f"]BK@gqA=o(L,(bI]2pWg)(l#7Pdd&)U!h_5ZR@K-CBl+^pQjZLhgEr&gL(#jgKWlXPD%mh!m1**_IT#d.3R#FQ,A]3bEW^aFhG\Z.0QsB(2?R`O,`$,C@gqD$(./jn)l[a8>j_\P\V@Bk!i)\J5Y3r-,lD"4"FGdM(>KD`nMpTnIWL-KD4.j3)BFb_[WDCS(YD&cjD>`O6k7mc6K6"U6bm`^mZiUr[f;1U<uZ.K9!11)V[VjsGd!j)Be:LLi=K_K#2rWIT!R$ZN.S;L5%cW0?:A;U*YD)oj,SDSJqj9TZsRKuNG7&49[s6O5&Q)D;H$eBnoBX?QY`XEBo$__I5n^l8O5_T:*CH!#1.V3:;Sj<"-0DqR6)U*:&Au[Et&j25,D>T>q'hkQtMA0Xc\=S.c(:LFJor^mL&gr(H"i*6s1d%&<Pj*;hK`A`pfA1;)9h2p6RJOKLUH/](W1b,,!C)IjnWD-@[3V,<,jimEnOLepSm^M4op)`KaECa0P8Jr&SG6U/eF;VZUBK0Q&M2)(eWX\Sf;B0?S*J]Po&u@1+T*]\bNi7l7e/Q$>!8?"?^OM\S$l7qUV<eCB=D&b-L[ih3ICFt#6<Ihu2&amL7KFm59JRa?8P-f-P`fr9oL/VTsQW1C+Mc:"-/q))Y=Y&GBpFT,EAHY@.[9UZ%"*P"ogN'2(R;Z]5g.mlM<6%qLU1c-Ed,@0f/qmY'\d?PlSH7*e7@j]VF,_cpK9k-bRR$#oNH!rn]D8qu:F\K3fXV?_%lV,]KhXNq\Qb@Mrj+u+ug'qgB+;*^6Nh9+\I+U3*^Q9BJ:cotbP>EOcRADC$O>5cp8uA)5d=bqrS/g)ud[:?KB`g-TRip&re>eS<&TBIZOD.S1P2Yub:2u#gEEdd+JZ7(D_k`l8R!'+WY5`7gfO`mipr2DF=0^TJ@%F-?IM/sh>1ri8.B50N9Bef*2Xko!CKKDcAi.Zekmksoce$^^I"N/_HoMe,Y1LfSE\('&:%?rdV/hUedg4C3`F!2\dc>PuR@uKsmhu[:Mi`jBo&SCA:jaUUb.['C75,]!Ir1LGP;cY8T_S^`:+[f,$l11%$P/_\6d/mHaQc!L*908H#eL;q2OMB;ps4,:^>kVqC\p>%F`j0:]Q:?q>E\gYa_bYUSiMl1c;W_a*^QRaImNIG*@:Ssn5T.qk2(@V\<'%1E9>H8E/gp^&E7LjF@0GW.g29\U0pSW_99S\O@9\3PGjLK6liS&B..O%6GcF8q_mHb>2Qj#2!gF%NR'c_cT?CLEc*;^Oo9p)-L[jFP'`[0Uc=d51*,+`@=1Y066(!f,Dh6`52>t:i@sB;d*s?g`u9n;[)ZSHD4,A?D00X\EY$P.*-tLHC"W%59#a/.MOuKO::"^STTFX>G#eRsptm)&UZ5>IrJ$rRoD-(kDe=R'NLMUIHeY*Ja3<.U4s:p6N5$?=>i.rG+.Z4"ce7^@]CIRD0[AOOT?ZR9GlrD8[9^7)A4j!%gqA/*XA5GL^!H"Pr_sR:)2q6GRYeEt0^mn()uVmJauP2kO/I9`lW:\Ehmra</n=g*4*ge8_@k@/LN>CrOMG\30Tmj#ZfXeC>_>9#m7PaCkNUmh41q0>?0g9cWE\h-P7GZE#[&Fq*RkVF+g2bpl!7)aDX5=WdcJ(.\S7*XD`k>R1<kkT&S0Rk9U(cXb4]Z=U?.]T=%^5?5I@khAdJH_?fJ=$d=>Y$G#<n062&mf+n>Pm^;p*S".(4J>524!&;3SDc0BJ,A%S`R8>RM`V3H[_:8OoEZjCVJ3fMrNM;&c<?hS-BJPA`["Ma1FLc7Kqa7>k]GMk->N>(`GN&DeX14$[<RO2\D>T>4P-2G!'6f%V5:b>E)9\!YlXX:n2R7b\?fL1g0&s:#1kOKf4@?guujA$8I&uP'hr4-W\.2""LS4:9R48&%tE]-.Pg^p6hO.+^<EQ;l*,jq,>*RPEXAfX+q1&D*;m%2Nu9;S'ZcnMMaN/^D(4<Rq/fci41Qr8.TE)!"ooKd)cD%6XfCatM2C7cZEVYI757o*O6r8IT>5_R'&&C+tdKPip.0sI9Jkm8RFZHpU7"^u\YY`u-]%V&SGf01jVT-)gQ&$Wq>e8.me.)m!Irl8H*OF)Z(rR.C$o96C?5k6hcrY+[B%3"4Oa<#.mN5R&Oa/Iir0ODH)il"iH*^>DWjt7`kOCE[,k9p2_5NoD#([1)OX#i5bO--3DZ1C&$+h<T*mIS6$G8\U2+78^H_%I',NX.I*i,J-$%h*9IAfCsXbuWNOlu(bApeeLj<6B1Fh430Hf^67%DrkM*pLj?]]_h(\U/p.:jkC?VCu4ZYkDFD&^%ld;SJ(L#l-Ii'J%D4U:+;RH2UGq=@fI)pAIm^O;$^O&Hm1&W<Hbo3@%*f>R$eH$>^i^sNQCBk:Ybqif,4t*ks1>c2ib]PI1CVkW%=<]Q>qb"dG?H8/mk^*2[q&TNIJPjr/^AtQ]dpnpEcoIppfo[O^'Ebm`@`SJgqKGU3c:#%KBL2c1Ul-XM4f9+61O;4:Jn>Gs*3ULUb$Fs/>p(1%"pp`dIJ$SDWj1p^$`*nS^Y4.=9Xr^Ri@1?,M-u178Z0qN&fma4b/D+fA-?.7seU^H:Gk6@Q0_'J0mOOZtJa(q=+nCk34/@j=eSTQ4%hN3Nrj%LDT9$'Qqf_,OGb1fuJK<doD%]4Pnk3g*7sgU`gZerQa*Nk1j*I:)/c+#Dfmf3Ngf`:<-FPqMA?f+?2qC*\Wl#!a[CdlcPH1J8O9(,1MI"TM^(S,JjtoR%`,L7UV*K_b8rdX:N$p072HGO+^bj"Be-#Q5RiQ]mXNr;VgKe(aP4>in6Yn_9YDEht\c#r:JH(,!36BDbGC_NXTg)U)hUa[$L7LZIL)$Pj=ZVJChZ7Mq`MmHAT5>eYTfHO3BXij%ihI8n^dE$$1\lFMk&?cG7#>m'>%_Z*9,ELe6n^eW"dGKtV-9HS`"A7t6k^:N\,[e,K!^Y(_!rJ9tul*mDXnk)cd53(,S]kt$(7JY<Fo6Cc2g$n3MELV'D1[sVV3(bgm[kIBh5.0m_^>I>uiP*IPn;dj:T@qMRn+V"Ol^sj@0*&dL%c0-fo%EH?'jk$ONI=$SmJQk+rtI3WVE#.RnZ7cbWo'#`,KmO(@l)0G7+1^I]1(LNb<E+)oBr<5d<cd)o);s$Y,=FS^=lH7.ECYrZL<-cjaJ1'I]VsRB6VZnRIHUnHa.L7Y!4Z(r;HC`^<Ml<4/8VJd'QtZaEjGCerOd0rs@`tk]%0jPf6J0^0>e/Hk3]iT7:dAR-aXtJPcm`K\qaS+G8*oR`W3;eNB;R^bH"g3['$-e7s>)a"q7f]Z[THooM(jK?)=0<E`8U!qPB%=t*>K-ggfGS,;[Pri]DG3UJ!hB5p3J++s(CZL0Yj4hQ4r2L;!^c\JC?;q=.NIo\RW2LM^lr5O2R^Y@g-l%bnepS)Z/ie+`iq`YNdg;d!qYM"Efj5(lF54I(oLYrlAF?5EE7^L'Ea>P[.a"3-ZHo?8OUosCh+o-c>rZ>;:IatYF0^nMnK:_6(s*+'1np^PP:[\1IID6O\g:JD,6[\(95<%hQrj1YW1ES&ohkTk(%GYLFNd<ktVUjHSSf,cDPXIa3lT9uZM=!6Kh\#$)?]4Du5NoFUr+M^8e[TaI],gaUT19q]HOU&Y:,Xc:!d\QlT$<mrb^R<8Do1K*P!G"BR41ALof-jXUNq40S#bqk4RpQLro92-H?@IQYqeSbceKP91Kd&XOnEm4E?O+ZDOM<XPJtsSGjT?Ws*CAEI]J?NQZZ5D`Qc')ODt/]4o.(g*,IO>QCb*(D7d>r;6sXf)6[;d0#3Qo\j)NZs7Z/7rSQ5snm@]0HEdJ(CV-&oI($d#2>-)]nZT]9h&Ouqr%U"QqW2@Fgh@NS=RLd,ZZa5%d.6spJB***]_HoQmE<mND14g.^##k?Ie1t=b=fA)D2N_#k:lk&pjUfN?Sb`fc;/0Cph=XfA?Yna`D_fVoR?5:T[a2&[!$GP$bK[h20>rQ?#5h<rASXD%%ts<6,8ETKN=0?L7oFr%CX=e$%kML0d^Es).Ne986V\&N(ZK_8;7NK>(KA'X_j^\_@@na\/$cA3Y&qK@#H71"<iONpGDs9L;)7*)]3LbBVgS$\L"2`V,bm\JMdX7Ch::$.aWW.*i&A8ldm-3k%M(^A(K2j[Vj(t`9bVXPsGHP(==^9^#9@;OL,kt\*NsAT2[tObNmL<WVC)6+)X+6pfZ\(VMBrs><I\$rh"CIPJVQkq"hM(Jb?!7aH+*so]s9!o(D_N0,o?8Do]+))=N%OnX#_h1#pZhak>+s3G!?)m['19JU^Do8bD>K?f%"5CUIDb."mHpT;V>Srgu,6Mniq71c$1J56'*8_Rk.BLO/Cbk<?#5MIWbt>J:'a`cB`^<ub]R8E3:SmGg',=7ju<-1%)34h41q@HYttkBEEAorg$`0Al!f\+J/-^YSg:/,tXEo6(%Mn!5W#T+>1NolbD&Fo&9S-/J,N\#UU;]X7L9o.!Dl[fs)5*r!*l4RKrXD>&<;=<CE%8*KdjrH:J,p)n>V*=an^Q6ER6(';D8r#i1<[79OS=QISY/AWg_R5,JUJf)G%+CN!@UJOQ:C-WI]5R91o<Yj3u"u-nD@>08@llKb8C)/*t$F)ouPgLniT[mkXW2d5oBXYfGfa%e?EO=@Vd8D;j'Q'O5h@:aLnkqTn@?!#c%#Mn'!JqD>ZPsY]<5Cp-Lr.PT7UL$bfhGil+sTl[#ick+&mV85[cahVgND<*.D4uUSZ_0^+HD/P/jQ52JT[>fPD^iBFPK??1h/A^i).C[<R_l8)B]bN=@S+hItRnNQkT7EX5"enoeiup8;O?D(fDFL/UK]XOSdWL4C@>5r6!?pmA.KKs+f]^>nIoV"i@a%gqMJYQIprdh#-OgbUg"Y60f&+3fF1"+?;`<es?Y#1`rqfK-)lD5ac:26,S"!'<X]\(pfYSPA`Sr:Mo!-/>)Z^p;jU-&Wc,([T?gVdsulIoIi8OfsP__e36i:'?Bq8+0(K[O`>Yt+=%^A\9'AT*9o.,E<[]o/L8$<\iR=ZB4$Zhi@j'nbM@8\@)WTPlE]*CrI)BQ1@I$9^WBX1B7Bm5m[r"#9pFgmZUqcq!;7bX-lRnIdNhPc%#bniKO@Y*aDX:5ZA1o))$H"'Z]O6\dp1]:6V4Nggp&CM:cH)Y3FM(S&5*'u&ck=X9P5XR=@%ma![9*MQB>^B+poLsK\.JC[tHbu+.`:bDL`][h(/n`5%/kk*5I\\/m_JA.FbQ+fsTO?-XE%sLH$9U:("`[g6jJD6.uX^mWGIt7"M]cN!<rBfHDdGGr3@^JMHSiHp<<(/+3#(7eJS#6Hh.BQ2I7ImpogHcFGOW0fO=m[):VTb=\0$m3'*?ZTiu)^#8aq?0/YleZQ>LTmd[=Kfs5]nnF9Zi0$YWP"Bghnf-2@l(*4u%NDCE_]sl-#9lL\WJ`%D@\k-Vcq1!TDOaAm^Dq0am?Gnk)oiXA;_HZFd>B^#&1[u+(aKnPdaqoDQWg5UEMN!pHOToBf3E4Fm9i/nI80\!fE)*i9["o$K;GD3NZj@'DDEuqP]"piql-Mp5lK1+,N<.-_$o*J7OXXo$q:T*e8M\-S03C`O>i%N%$f&&cV)I(jJ>aK1;2:SCi"c772uL98ZRII;b;s&rk'AYkf&^dE24Um#cfEnCkRcW4P)Z$:DARZH(2\@NhLMD1Ee6c%(;Zc-ZG&<]K(jhV4bj%@@.mJJJqt1ds+TE,U8'nK,#;J:o=Cq:lVs%!h\/.ZrTl</jY>-S9>@MgGUIK/":*3PDm)C7#lQ/XHY5_)_`Lni_@?3N$:`^9^'l^UsKE#WiuoSL7E6cKqU9.9T)_&,Bk%>CLgYD1m1FF"uMknNB!(nNW<'GfcoLUXS?i=8MG"<NN"6O&[IKE*+T+kEA6QA!7SgKTJ<@d+c@"gKJGf@kWZXqJ=l!%+7;YXqeq+"l*K]<q0u?Bs5AZBIl:N+ZhM6$lM]-,IEh7:+8'[bq8p>]>;tjc_^/(>mWYSJ1"\_#HKnZN-^S:Tp5VjZ\q6"1%ZJt$>M=9rnVqRFLW_&Y@4'#/P!ufP(O),0"uLtH5<;#PF__l)m9nJJ`28pe;B\@8%>9NQ%`u1&KoLoM6#40Ii'ehk,S8APNj1?2Q)6!E;H^]5MJ?u[V\@Zu`6$N0:E^E",q2/Jm_XIi)uj&:K?mrT0u!B/inSBk_\+PO><XVr*-pP8Zek>ISdT+b$q_-DR6tB8E=RNC)Ua[PBaUU-OQ9Tq<+*/])pAPdh(<%"+'+6]4[4_XBfNnf%;0=g!Le>S'a'@f@r;Zjm*RX,mZ</5:A6;Q7,u3jR(QYU<)\$&+d$9N+UJ:9<',4]e%!iDW4Q](qD)Ccc/io>/VP)aLae36j+jae5)=Qk7Zq%/&4MgO:uZeWrgd%H;HY9*j&FMo3AkajkD=d7%[LN"%bhp^5ut1EeB>KP\_Djk,&kcEnN3.Q`hX@JOs%A.6^J:EPE,+6m1!#<5n.la>'*.u&P=:.o#<Rf]U-&nBno.K3SpJY\QhVhld>[Unp8%HM1KeBY;Xtr5jVAHl#NuL4+f+)X`iKL@9JHZRF>*Ib&aB6U6"c@rp"G=8s:XMbNPY<57`pIk_R?%r!rYtZ:XIJiIdum0+YpR$_fL_fkuSkQ>99,;n$H-<T9`(F<f[.n\X-0Je"rb,r_:-5AeZ(rWc0L3i_mpPnWE=S__ckea'k1-?IQ"MX$^%EP&pQg%[[RfuK-eGM8s"`-'(N.^drB4cDNPnZ9q&e%TiiZH.it8;J'bE2B`QCY:X;ET:=TmM^-3GgS=<"a+9m\/h$-[\Ha?QEB!t1r6<G;V(tY"0Li&]TDUonfsO(,-((eRu]/(*oDe5W`.LNLY<EE#;qdHa2<KP]:"VR_)Cs]/XLGkCLbDQRMn5_[LCI2OpeZEjRHd$YuZ?E/J(RGV:ZtpbA_d0f/3JHnkfm_PQE*X8A7rL`Q6s]g,o]o!rq7?"Ker**p3tfFB7kKHLCHs4W]!=X[q6]d20UhgkEHVB+50H-E"fn,q+RkNM,>'5BQ[aBp$#>'k!5qPu.CZ]]OuIVB<m"ZO!R)j(>[r9l<hr'PZ81%+tEP/h$]22Ci2&H=GFogW%S'l#+sCW&obUZS<^=rY[,j^#St7b:-j0GWo%6Hi9bq(tNgbn%([0[+N3q7*@95[/9!i62gf0F+Dpc0TVphR,rO8[T$s!NMFN`2hN1co<r[UoRLJ,0fBXee(AJS#/HMY[)nZUY^MMG8X_LK'W*0^3-suD;EEAb?oed&s2n(#g2r@+7QuWVs%6V[V4?59:])Ka>r0p#G;F<3S:ZQRLG!SR"0EbZ<hg]rF6"&34+f+#^!T.WH,_,dc<h\qpMt!qgi]SGYUJSP_)Fd/6ROHRKK<X?aK'Bu!D6s]a!>i]O_psiB)d$bZa#0'-Wo1W"\%3M+UOm'3QQuJA5=6>eu+;4qVg[EXU7IBGMW/!>;1_MpPA]*YeeP;92oXf@m$c#oL@MNZY14Q/Ot!NDn*gG9,#rMg!"R)m$hXn`g]i#SARfil/f(O1lZ&/+WOe:=BWC0B-t&R9u'FeZ,W`nK^?5=eOi'lC#kb=?V^9,6QPiXQY&]c7;V5XSGig?Q4]fBD0%/^Ud]qN&$%-Lp,1NC&!&%"Vd8Otkh';j-_^WJh"qh[R&BJ'X'[$YHBVsC\uaC7]nY0u@e^A)_[Fo3<=0eWU-Lu8Ebg2M-As%<9ZP_X\DTAECCP@2_RT62X*'<L3MEoYeZ!.p.*it@.hU%On&/g9E=ql!mk?lZHhuAj'.rV5MgI6^-+I<#RaUmTa01V.^s+pacqr[2]>(0#q*(k:Eu4%(427lo(B7gG+[[?[CMpJ2;Cl4ipJG!*fQ$(Wqm-iUqd@jm(/F%jjqg-T)%j"N9!p3Nh7e@D+6D$ul1T%h/DXO(-R7\4@6JTLoAb`Y.JhT1DMm[jEIr['nn2`_47K%iIVpqaK&+sOi2<WW[5!AB]/eW_K176l%>FRY(87QjZ7T+k3KN[1)7;235*SJ;g*;RYA]7\e_)G9sc"ft0q=<*;bur^q%QsMJ:e%,%iq3cQB,?`GM;,KLpoUZu8bHd6caRLACUG\[h1TRe$X8VZ:h6%H!cPOf?:#WH0/PL?e$-h2f(%ER5i6+uCkJPQrC3?r1k$9=dQV6E-kF="d(og$BfDe40RV.g$s\)ii3CC:1#X$/VSaf9R<fjTMRQJ3n)59#CgAe+]54m<B#Q$[AlrSr`Gre),lF>X1,j%?H$$>O,4P2)>#A8*m-BiqCq&1^D7Hb:i^cokL*C'QVHf<1YBG$B"O9\9-C*9N$4:map3p*AAO>KMFmnO2gc""/<O7hA7mW:!<<:J=b+2t5F,iW8ld;S'_R>q=2Ef04\j^;\Hn&eXUlRn:8CC@Z4R8VWX.`t>nA^JPGZ'8M<ZlRIZX9>8i^noL0+MD:k_CD@577d/a42>(I.UdH)CnIQ^_#b-E,b1KLC*ZQZ`Yb8H-RL\(uqq8/,O_^BfsUr=1L=Y,!D+0SS95EWE/e0.j@i\:3og`W]-lM2Vjp!cIZ]`^QRetegk:'a_#p<SV47kdS=UQ!T/i69\6<Q2c@3ZD:0-DHh:2eb*_+WIcG>V2H;AQf\*@IHmnkH[g<skWCnqj/[IhaEHMAPX1r6-npN(<.G74:]?0R8;DqDK:e?g56f":G(tX2"U6j)nJuL&uGp61`3o;S9erSF&^>(V,[-9!kmSL9=P4U>QZK8uOr,8+1[sVra"--4DY3<!r+jR/q41S)r;q?-:UD_%hT6-JbI,M9:dl=QhkkLj9W;e=bc[F[h.pLM,qq$.d>:MO@I<Kk2[*%3)$(#hg%SISR4HYN-DZcj2l&tTS[Ane:k;o(f`>Ml!<Q3eA;Wk<&^F@>$he/^LB1Bau>B*3r:L4mR=o?Tt@jT?CMYQ'S663\Cc7k$C1@iq8-aut3Z'bmU>3iOE'CaF,j>f@!i%0uVAX;=rZ_G/rWp:^XXuRB[-#UqK,V*(\1/ZA%2do@b>7"JFnsq0"=.K\VQ'K)]%Cf,qV7,L.FG/hbF05Dja\?AJWO+IL/aG%WHm<aW,4VgHKW[`&P'Mj<RXKGQ\scd:S[\6`<jT1ILka?)EfsHl2dG=3iUH9tknIaSfbu`uh5W$3X+JKLm4s$Vg%`mF4M9DVk37'X4g]93"_mqL"jX/*;Uc<LVYJ2c6TO[cCJ<i9lE9HU]Xg8mMe@XqM%lB;S<gaV0uTZL4r2nimJ)lBZM6:[>k[Q6XE:VfZ)1W>Ho0_!AZf*34je"$b&^,s\Jssb1t5Q+XLUYKCTtasrc^]"S&>lI/@pEo:Vq6ER*OSFc/C.N:\h[upK8j=jROq5ItPJ-WfK%)HlO=.WV5sO+(0m4IoIiR,_eD330[o7\GGlfmeE91ImmGqNRR@JT3cHKjj,4^@OeQUapXAQ(oF+_"uXfP1o?Wk-lQ<5K3t_N<Hbm+[qRhT!Q:F%PB'N$GqJFf$-IG62]\3N2War;+C@e?Mc;HMG_bI1Dt(5HNp[t`o%WHfRs<u6&t<0AFq4IuE['<.\j;Tr>O8f,_2E*m*pN.![s9dQZ``HQ[cSS'0)chmc\9u0Z,<eD6Z.+j2FY7%+DXt-fd<t?j`",$(.53(FtGP`m&'Zl,J)XWD)$fCT#k)2erjdmf0tpUMYl$ch(;gtpt#7N;Wo[KGpuj"IFVH=poS#uK!og2N2;9dMtYlFeBN3er,Otc7l7jH6HsM*iI2QdpgNc^qJJ&m3'fDdA*MYuM3r8h0UD@[6mBo85q:c?LD8(]&+$Y,Uq1e(btF0H0CZHB+6V5N^e'pOg?]'WZYc\]2rT($]FtjfSAVOgj;k#3*GKGV[>0WEoI4KgPiju2,7e#Sn<MWo>G"c)[>pdL]4RE"^#a5K&s^pjM*+r(SnaL9e[oh.gV2INZd18:39)GZ;Y!`lh6XAZ6?J]>Jp=XRH_8Ip=^[\<HLAe,E@aQr\RBTsO8<[,,D&r[$N!C^oBh"12F"l3YV1s/i<Kun+E6Io:AVE+B9&72/<SeE2WYgO,[!Glk2tAo]W=G5I?C+Z^)K^Fme:'V;W]Vl:VuJ*/\bK*0G]X!6MJ92,X0NNDS8$INPiN]cQ"qmgRD(]GIQC.Jc^B;m(R'D=5aj-H(h*41:@Qo6QArZS\D_64jrFCM;Mo`4mlS^4RcUbn=7$i3Hi+NktUq[>%+hZFGI#F3?.VNDYnC5:MoiD@];to&C'!(N)lD['[&NBPJ5<t3F:[QM[7!0^=u:l2+Oo_'SkW4\mDA([N4#o(uLHg5#R:P*!iri;VpR#D8RhLOt7!<pK^n$lDHU&U?er(9h0\ogAS3HqL$o7kJsEAEq%ks/+]l_WZ:HnBsdLMpjNjrAOg&Dh@qdg-\B[c<_j[gF(BNhIBGN4kAqGrkHVidG2md6bSM3Qqa3?'A%Lelp#NU[e'Ue2XKQIpK>i]1(+&B0qeqLTfXB),m#]qGC=G69oB3`t.a-T6K+`Y+ALSI:n<D&aM98rr,0<W8G'%:.$:.U]M:6\@HE%)OqH.dLN;[:^ISn=bqI_M%6jZ?\he]2(Rp<<?adT+i/TH.HXR#QNPeRlu\bO+F]URC!&2=9P3IMnT*)Pbj#-QMrpUTFa)0AVLWcOZjam$q,(;l?QMq7Z9Q:H>R>8@-[K3N+OCO:*Kl,Y-+M2ml8GKbb/<BK1fi1G6[S@h;F.U<3kWI18Cl"i:Y*m.PWb:q+ofAC^Qo``oU5HS:RG[o'JV13QX/\0kK6s9:94mOeJooV*$gn82b<jZn])nke,loZ#1p#\3'-sQ0E$,=j^B\`Mn-rY]*lM/qQW[OlDfFjJMZ/&FdjF^50`h+$RmcC&MD_b<d>%S:2@tCh\r2lWT^>uaTh&gg-e7lGs4?";=5?BY)Sf@<saj54T\/sHe/1eW/6G&q*@n_uB*>jH]G!"@=do,o&lJ(O*>Ka((C!LTCRjW"FaKj32IL%jj[DNVE1TN&M&.WAo`(\!$I4Omen"Fm;ODR78c1(H?Cj$`J=TTaBG:7=@/uk7>PH.7>-VZCVLhMo!co]H)Mrn*s0;g0B?-]TOk,6R2=??i:9Tq]=*6uc57YKDCM:9Th4Wq!OB,m]lPjWth9*s";QnH"gfC&:!T-LN`m`C6ugOr=Z^P?G6(rprR!_o[&IL8@t_Q/W=+u_R"O:W]hZ&^=f.0Ul]0hTUrBr-RM(t'JKhC_LBU=W\Ok3UVe"ReEO)akNkhH5$KQNq^0ZqjDnrcFf7E1GZ1M7q?g(q_#j6SjRbQi$>k>Htf$*0XJM@I"p2.f)=D@"]dcc+2F$R\clJ';R+$pE:>O3cWVq52uH-5eSu6`g`4D5<i6sAg=Dr8##._<Mjp,Th,'q**ih69SS55M<11<@UOQ^0cg2!pCFokPNoFW@Dfg'3(%pF&7dL'e#B%;R\87E/4R\UcTL=#KrVEjdEra)=jN*jDn@9!8P]]b_<1F@\)fd*e$lA-nC^HN&\ecT.Br(9NO@HNY7FT?F2b\LB'NO:Ee:Af+[u.)&*Pg+3A1O_.-rs)?u:283b$][`i9M1Ji`=n'XWE=p^]h1)Pe\($@t=Q7mOdj%BIu5OQ3',GWr6^QXTfdfZ*_(i;X!Ap8Q9aE\D6LaL"%flOpSm:J8;f^rZ3E+7C0uYO*aC&t/If$$p\(&*jaE1BKId-)*WNA'!iZN+d>4F,&F(S5?5Z4:Tmq#XGN$A8RF+M3]ZRd]Eo9,Q=c!6XCi!ApFT9Tqr"H_YX"q?gmf%GiBCnA%DMXgcll)g^r5eLjhmPl+J&pOIO\5H1)]q"R-4>"R5;42;7o?#Z:V[bl28eJqF=2"*Y2@K3t*ghT3Ht=1EJ+gtN1\VC9f*68*YE:I=&WY6#"O]HGST1,_kTTKR<8$\ijCp(5c3+/4IU;tRj5L:B`VA0MNO5+/D)C9kW,))DBlSf&)k&BD$j#K>==MhKth]DYP7gH[`Ij@-?H22H:R-PN&]o%PA?K9HU<CAdF?PkcuoYV#\M+0W+?%-]*[\E\fY&X/ll&U(+Og04+b>Pu(dH2jo%bNDEnE;.T9#BUW07o[^WQS4;J6JFU4b0P)elJPZ@)*fpaGbjTQMZ>p2d!6='Kqmoe91RICSV+KSQb/=+dI=Tcm($e?P"0HPZ:%9%l?IBigsJTCdRE_I,l#d>XcDu?LpbLZ"7TA7h88MRF(Th?cF$-sAhiBT#>uW/"r`P2@MbqD/nN?gQ-man+e*)uBZ6pB?H6bPek;3eYngUqApWsr\Cnhbk^D<paV'<k>ThQ&84-Lk1IhnZ?&qC:831CKO.ptF=N6Y#i?39!cFpR9Tuo,6]#\bq5M`,:MQnrSDB-2bTV24_r,$QYGU@0](sf!&&C8p9SN`*pb\]@$:E*!MY7M!F=*YdHnG^%1=T)(\+(bHB_F7(+C\XdU<E(D:`gTN-C<b5AZ]Q*QGg*_16sB&ilBtTH[%Y[_hDT61D>Kc*EagoBLD]WVp0Dk#aeWei;a*Zja=Q?T;LU9HfXe3RcL>NhrFnI]p_O,/(BKI1%O=*D1M'Nq3.olF)-IAB@A:Mc%2KB#11LT&6:nC$E(c$)H$EUF0'h>o1J\OoHtR?>$j%dQil#/,>k;l1Or0b(3tX#g$lOh\.TX-#!foKH/8cFT.9KmdDXkQ%,ka<]k2X370&ki":t&6g9?L>:#R&;&4@?to+Gb2o`XTY+)_J4[I\2W)o2Z.'VX/j#L]i]]kF)P0J]^LK:0>*6@iKu+@#['&`_ND=dSHJ5/gS*iNb!%jdAAiZAn^")V&7eJbt['eT;KdG>8!hLY]2gi9[U=m6s\J3@k3.S5l9?ZerY"7,/`.U[6B6aZm+Dlk"q:aL`1ImH=JjsB5b*/[3[G4!_o2R1DsGYe5"_[l'+PX?@B6/GfD1a):<mG@:EEj/nE//6FCX1Y`#[$q*j?]QVZ<JL>Spo(CEitA33u:J?mcfjip.a(/oa-hCZWUQ9'td,SuZf[)HCn/O(FH5\lQ@25][GrNDBR*'+rm3*Qh#q2r%aCYr,A^2&bs?u9Fr*(1)O=r<t3E9@.c(50Q2S3(f4)X#o#Id`iMNk=RZTa'3)ZQol_&q&KRA[B.pnk28I%lCHXS'daD*8k>7A>+kHjOQ0W%Kis&]l$D]LB/E.;93q@%rJb:dQFaH0;[(29-fD9pJi)+#3[-M4:O;c6:XC6"d586\F*uNs)ZN3gRiCJNJ1+i\#JX"$.]T`HgpJB6XG*nOOf,aVl(J.RaEino59`T;Z9iSk!c?r;aQ3CHP'R2UWb(7JWhk<(n.\R1Goe>6s23C8M_q<$9kWF)iD[tOt:FGF]5aN`k:'2-Rk3UF)D+0n;-b+OBkS.K,`79jqGoiE]G`Ap]i+7*R:&)]Sh'jFU!)FFV7[o`NcXZp5\IA8(jFghSPB'kmS0?jc8\r;T*`LENg7&(UPpjXsd]B@D%/_3KS7Pbj*@WK0q.G@@as&GuRbddadBXAiF6mUEh`8@s-rmF.jS_]9:O^A]-oZq;!>-cfd98@m"[]H/trSkl+)SQkB7'Zb"_ZW4<DRR1s2W;Mn0k6Fj7hgn!9;3fuULl/R3lDcbj_rug@tm=4Ju5L#ogY:hifHq$AneWL-o[n(kK*S0;Xj:P2L-@gUqIIK.$H3<lVg`h=L:)`g1lL,.d\F@$p@c0Q*r'#BWm;Ge6il<bi>?db9@65SWj7pb64PlHURN'tGIbF>YOn6_DD.?bKj(ZNtirS;1+iQ7?P+h^)!&g3&f=dBQmfI]=&s%ibn<>cl0]+T2n%_QTP_NZY,E,6g=36_h9\[V4'JC1NF,ePrJo,-aKXR4WrO]Ni")m:TlZ:CQ9?D`_2L2a@SI8n,Ua2pX\.9\/S8HrpRGXK;c3)2Fl.eHef$`(]9"OP#c&J)-N:E\r^+N;ne%`9;mr^<Ybb6rA)N&mb[VC^n,O>HH37skD4$eV71#aC>nD8UP-G[HPWJl9KA/#[uACqk%*R?V4["t3nfcZN_?SE!7Wq/ud\UT.%#hV>tH?KQ3g+:dm*a2I"6STi3Y&.);A@tflnk=V*1@aCQGT$\VQQsqdKp*dhNfePh.Nd%k!otJVJd_:m;f6s3;,&jU(3[f[7X!d.#-O)N'i>cpG%g6h<^d.6`^L`rgrRRXpXc5Rea)#L^4)f2@[M9N*$I30c*^JB;'1b>)5S$Eo'9p/<eH>LWo9OHG7TFB,Z(7takb56F]T>'(S""rJKDXW^[0gR!FaCk<.p%:>7J]2Or0i?Bha64/gFaPj;kfcb2n]'r/V>ZKk!.Oc[(<%083SVON'dP+a&E)I%$(?"s-X`+q5E1YrM/5ZoM"AG%6oL1Sif27AB0o(Q$FH=,>%gRtKUkq1Pr!"6Moj`!:i9mrb?mk!:"XF&S3gQcOjR6W[1t%H+#fML%U"LCk-@d<Vq.4j1$=GK3qcSJS72=a,tGEsoM?6Y#c0mie+3U#cjl'L5'W9)ucQlEj;m*Lb@?!)9+!#fJ%E5X.d*k0_ED`@0"&WjbbH4\XZ@q=Wq`UU3Te"mIB,'#QX`-QHp(8sN=%iM/j;H$@@WK8e%1,\!++1C?Lo0G/%\%o#ulG\Gq/IQrlnSt0MpOg2-pS`h)AZURG!)%5iM0o_n&7(LblaUntkX2HhqPmm.47T)8E4QsOf3d5(-B]7:9@EJ$)!a:49clViDG=`8g9ZLpXCDdA%_]HMr7F^T;lX\4mLkC^(=Mg>H?[Smbc5sYmlt%&eDnS$1\u'9e0'0Kr#Hk_#*^*[IPfYaI5>G\[S#3Os,%H3:S$<B\D3^U@PT+2FYX$6WSTinL!uJC"DUTt[#IMOKlpkai@VekP0S(-V-HQd7[<gLu8-D=ipPc1)*!/ZcdYXhR(P)DQ:>T1'p82?p;B7@HIYg4$,R\dF^7\f5d!#_K5^#KtL3*_p];G>76Daj[B5MbVdi1(@Q%IRC2sqkE,`F07=W*d,fqm)aU%F[je0et*'(&>=;Wh,)h^^T1JZqgW#*g7e-DSWcB)4bP_F2jmPE,I(5@.bT7+,q'Qe/,Be9u?s*FP:s\S`AgRh]n]V_lNIB`cY&3J-&X*X>7jk0]f9nX#HEBn4*2'F':+<>,Bi"lgq2e'p5i#]b]li7O?9bLE+(XqFV+YD1Yq,(a[#2g"u1Bu)c(1Sbp3HP1:LNN(-AOIC:LHO0tB3Q]4:j>RM^?j@k_H,i!97M-t4)ogKDH!]Ppfs.#nWn6]o6p_+"5jsS6Y(_ZW:MJup_\mfpN@&/(j@9mS79<Mb+I((TOU&i^_alo2CiuB\?7*d&lMs)]T%UgbH4U2*-]BS%+HF@O_:O6]G]X`Y^+p33H+r(.JFeJd\8H4KcHVf)k=D-P`J@%j9>OK$l51s*^?tA/!H<T)%V1AE/abUnk7#RKQ:\EE#"F!:(^!kZ34km60[m77bet<9iKC@80s^0el1q6dWjRt+rDpj@3:^@W18WR^*A`R`orLclhgFq-2RcPodW]d[YeUk6B&I$LSaMhW\EOaZn;2PB1ps5&1._TrBH>EhHs(HnS[4"(=i.NpL9V[6Tq(d]Rg=2Q1fJdrgEo#_^AD]d.AgFZ<C]ZV_HPNsbeaD"N<9Q8[40l;I#YQ]+@qYiU@#KnKJkcdY/:*.07L:D)8QD8EDd$Yp+3d9!EX]<dTY$s\"8anGKEJCeaegnj;!J]mNVf7r#Q=RYXa,2rc9i<NcWA2I'Ct]B$A,(0r3^+Ce8A$kp<fQ-KJgSgh/%iCH)aMLN&WUjTZ9o.4@nb6GjoW.QM;)?o9aeVK@MPdX."=3On^6f"r;m:j8fY$u=Fm\9^NWJ5X7_$_<=_MAcXBG>C.S87!,Q';?J"0-ojG(D5U=`on`Zi9oJHG#!IVLLEK:Tq14fV?G'V0j]o/',3`%g.2DZKJ)/:H/6T&"7Ja"a??pXCmR[$?m+FbSf79BB4l&N--jRN/09sG"K2m7o0WXl5r^,O-pZl@4>c-j=>gf^4g<aTlHH/0`t"2<1cIFNEJL=EXn;L"@$ittF=*`$4(?]B!ZShfa`+m`G#:j:+r$[$fDKNrqrmtsSfGQg\PDlE[N?meCQmf=Gt$"9W([U:pmAkPFEk7Bh\LFo5$'eA@!-YBVNm?J;Z@,;"K96uG6u.X!SBQ@iALmY_r9_HIM*n+c,81uVoAY@!5-)hgEG:oNRA9C@&4;;lU*Vn&A`Z1UlW/>ENd7d#H!,g<NQ!gOBc&J<pa8)(E>>X^/pT1UE6as<&ur%9t<+)G9%t]3Tl?o]4XV>8i.R-qAi1_!+r@!\.HFahrk"$qL<_MrnjuIqlB\dV3*AdYO[StF8i"><^.,`db7aT;6K8&rH_[sS8J6_"TQ7=`?0I=?I$=imHuRnrk*bgD9"[g%T.7sKr)R$+jO^%r7C2YIcq^bl]Ra^jFIlh)F-fhYIj0l9r&/FGK+XDJjB;lT8cZ`D-"6QNjJ8n45"pPm[?Pc7[4UKcjP(c*P(LKF5GWB8#l`--+h(WL'*YA&:^#7D%Wt\GNF*TY<Q`Diu7O$("+_h""HoBe=Dei"Wsd8lIYfSce:nVpNCLl'"@F!br[(R&HCYVqkf#&"DR?4f.;\VQDV]l/M\P_%[6UT5K:qccg'2WRL,0X0>"O-j78fqN9gH`n7:20*K_NT*/Hk=oK$ZH`8$WKSJeE5KM6:$)XA2(g+o?$?eaft^516/'L"L)*iHnYiJqO<.7&"sTaubiRZf\\CA[F9_82ZD9QZ#ibt2S`'YDDRi]nB^fa!0<h:Ljt7VEK3SRAk?k5,]O@j*I@5*(W/Q^X2/[*Y\,4JLB.<g)f"h^O^U":T5n+6$$kqS"#b4oW0#H#SU<@u2ub0Tm.!PamVJg+8l[d;Rj!9R\)Knls8k9;%DNHG"#O)./"!+hAd7s#r+B?JljG->3Ds+.iQEO5u!<oD8"s)S*5FX=%@8+aT[0*48@en=5D*eXnecl._J[EXn)d[uo.$c[VkMeW'R:rK1m>^T'GOr+@PM]D)h]l0<JCms,UFh0h/M\UqTF-A[&HkTXY4R&W<aH\\f@ce\ER@D@$$m:LdmM3arZqUhFQrW\G]D5ApL.&d&Wr@F6nrZr`KFXJF>kss4%rNS5ppjjgbPcJ<j_sVOAHTNh@gZS#foC@OQMGlqphD&rU*5GmY4MN/ZqRW3l;fB+jHX/DRlCAmC]4SZ"C6@e4pi)__SEa.[5)3M2IJeH6Ih'>f*29Xej218BIhH,77E+kiCbb[R3/tD"NA/<m>&`o-.6j\#hbZP1Su8d$:IOaBO3c*E:6dp3)X96s1]d+BrMW%r"(]33]qCk@l:o%RWUFc?DTq>o%h^]a1MeFAhdmuToH0!Pr#b.dm!'k!`9LOFd<kcD<@/2YeXQ*6Y?Vk"rGa)2Z>WDRUgBc.Gtqip[G^ahL<XJ=jmBUKdd&LE9>3EiKP4A_N"OO6FU3a5jYP9<*60$tite_-P0H>=[RFagq@(J6]/TE!0Mh/Mk'+"ZAb#iGL6k^(L3&@88TY/997@2=L(giJ%fJ\TqkBqS_i#EMS&`I;?s(D(/`!eQYSJPdBi(f/ZS:8Y*8?=h0:V'$SfT/0QU@LoW`;8?o!MZoSUIraKJN_m[2pcI]2d'+ZM;W>'C>gB)TI0k<4:LTEtm7o98/(Fn^BU$S2TPQbEnm%MjIPp&Z(Y#1Bg!%\RM:@J5kI[7$>>AB@/L<9b"ou0M].Dm%$oGbtC.k-_o%b34+00gZN.VnZmU3OHQpk?BAr>Xi*Z6bEqfB5OmspB=;A8&os`Z>"ps>Y_aEj@%b8"SKufgf,Dsi!GC\@+iIuJbn'M@[_2?ni:&K^-?SV[4c'#nFIKRX0[e6V$A8+lN6]AUC;@:TMB-PGGVKIN-Zo5hH*#F6Smr(\Z<:kec<Xuk=7O5/3GbF&[@I\iFFNZ=8k[6XZ/+qlid5!0pX<NZe9dKb]73ASV!cK=,)4$/%rIVrfV$]]n`,]!jC6MrT_X'Bg=Nh)lc!tQ8bD8T]A_U@JEo2XD'A,/;"PB'M$YT$P$!RT4tp8RLe:OYl!(I&S[hp*j.QokIFOKZI=pd<3OBY>8r3kdDk3,XCYp/.V1u\j.R:X1E;X$(IqueRc7X@Ac6/<RB&lGB;p(0l--?hU4E2,b8'0W"-0RR]b&[3I;thDg`5f%(Jl-36ReE?cGpGlW#<*?dD4OA_OR22>_Y@jNCAW;5>-=l*[7X/pbA!)4V(i<AJUY%#;bH#r%l0N2P#!LPX%h")^BU5;qY3R;deE"FI>eK'3cB4*$4SM^/no48<r^:mUEIg$U0l,T+l1W?:D3*8Eoh/'5-@cXqX]+$^3ClCmSOt^m8TC,&``8DA"JISLt>ktoo%\Jc@`LWn[RQDF8/NbdL_3,LZ^KaTg]QUqOPeV(0lLt6c5gUCYs_ST/CaT^<Zl#Y9sI.ZKY5-gY9t.+I,Sd*q?aSmC-ar^,Xb-=.A"7>e:847^^t-ir%W?7r;/4OTH,DmR]#(dmVLqj/8GpB"RYQUr@MQLNN-,D0FGY/B$Y19>Z0>QtH"&*S%TjZ=@n?kr`9qN:VJOXG'E5>s[4^h!o]l/8SkJ`aZk%+4*o+1g=MQ$YZ\@f+K#2EiQ'OSVuZFcVf[U(unCTq-20/^"U&rA_)f7,.5FpiFFn@VJLobgc^LP<:Pq[,8iO/-AJboQ&&FrB0t<CJF(RP/>F'Y^^mC/):+1_>!bj/65\pC'm&P7+XR[inh)i21g?0@]OAS6mIoV3o-r+'f[,tDJi>-X&.N(]g@JJ*q&ls"^Qn:C+@Bgn`).;C88NSu(8Hj1lak.L8EUV;[&8UpSat1C[V`0;/i-2'#J1[CL6$I%F/Qa>cVr,bX:`f8$BQL="W<?pL()[_Gf1gG2Md-?.;4)fY1dqA%+$#j0)W9BPs+U@>@\UWC;'VZ5+"'f3a/P,cT?BghRR3+Gf>&<")*+FYm2]#[Lh6++T`c^ADV[.$RUNRgS$Ta#to8YK^r^bgcg]9*Lhl7"38gl&0,i5)Z2Vm3ZO-uNNir@*DYL8=7==AodK<\48X5eH%n8[f/7W%@ON'X\hYE9VQ4r?BiRA+3r'jNI_j4'o!E;D`gK2ih5/kpL::`C<iuos&]Z`"&iuG*Tc@!\4+m8!EeNiNo;a;1R"9_TH-sZZpRUZMb1E8mdQMC"DU,p(L*I:XWScE<\d+\B@[<]@(jC3cl%t:CkrErbG96_+WoKt'A$#!2dqacJ?HV@]R)L\k'XkbZ8+$VnY=cf`%m1q_2pkr9ZIFVoQd#ib9ThXa$&1c^qA&"219V@7(>SM*_;3r:i<>Acg$Gm],ikH,FnXkE/JM$Q2r0Fe"JWS,e&s)X_-'<(DMC%tORq?@l;*lPMB4\DZH%-7d&J'gmI;BPY.6$D$X5-n@n8TmD2#+<$:Dd!8OC^?2+Q[jHcmn.-sMK%IGLoeSk.L)3S``&<$A9[UiU#aUG3bs2;%gb2Y+D#olt<HoD-+MRu,2RrJ0nTiBN&WZ,:B\+hZh_rLPYqPRjA2I+h(o87LsA?KC*/q0BDo"i"C3Z+JB'H4J6k4(*.U#_sFG`uk.WW&qUTf^ZcOn290%VsK^*csF`t`--,Y^)_01of8.5e+@*V,fM_Dn%?/t36gF_=oGh@+D:9gI:j9WH_1&Xr-f07cblS`'.8-nl;"8M#.)Te#Pb?-5Nomm,8^'I&;DlMMu/B=1mt6:-JOe#8rEHs2!t%hqgA*_D&J0R5p0))2Z<HV+oPVQ4QNUZMtbq"R.6hdG/sjk=sf#lk+eb&Xs<i,J`;0(>3nGJU^ujX(6NaD4#u!KP5*PGG_(E)@??jh'-7K@0]]CW7jd<7P"H>?c3kVe71`>4%K=a1?AO"k*!1'tBnJJ`B8GE?1n!<o4!;Ba"1!TB'$Z0g:KtN0Yqn./%C[?)'(NJp"*$$8EJ\uY@RPq`@T/^LU9Ke)6)>MpQ6<T4EY(:.'NbJT6(l6N+W+r+0OX3@g5A>@6*sI>+rDKF!uP(=!S!i8CeBBkcn@C;h)qLaFT0(.9JI1G\W[KOEb=.`/rR1q]'^mch*D1d]peZ>j`c&qMome(:\ODtU)gHknNct4j-%*;%oNLm@U^00&$-+Q5WT\!J5Gto;5&6*3E6I!fnAqGokFMe(d"Wh/DrH^38gOZ*W0CYk^ksf['#!Y@3_1s#9ug#P:p9,HD?'T;lb^t(GZ_MKaNhp%[(aOK\Vj[3>dH%Zi=0`qaVt>#h^GaGLLO?ilABl@.)7$/&[5b">6Ud'3.6L;lE=[Nj<t%O,_^YHGSH)Fc[*[X_0(>)@R*A!Tl]q<2&+Meeb/L!D%(VM):D=*midWPrg6"M?8j<J21*[80-V`Z3H=kTh6X704nlSV?A?r"-%]^<-EorKQf>iBid*YUsu<-h$WNTVhCrZJ9$:HJsYHrG8#3]?-m*_OiFUc8l5Qt@EL&[YoH";7E0EWLk[C`9!J@a*\e>-8cU`/,K8P$nAPju2(I[;F,C\!/UA:sm5#6'g-uoBV_s;bfQI_h'q%J5[K:MnB'aG_U&7!)c.ipp;BP0bISq.LpR)(i%L;;B_p>jT)-9=SM>mt]q6ijkRLPm1g:lC8Aen(X!0QWVNY,SPR^cORZuk#Aq3jfg.at!fDA6d`FPb!2n/Scho=#(lW,F#%OWMS-#1VK32k7?bE(8SP)S/!b.2%AiFrblnoDS4Go6d1^kp,$_Rh!=u\Ej#RHo^Z$cGYr"lfA6nm^>'\Pu>_rHUh$-pcYbP:eLqT+U[VHN^Gm!-]];q5uCL:K`e\!(bl/QaemFG"s^nE$AZi)h(*S:4:PL-4k?gPFDKdV1FqGB9Jp7GjuF*"WqH#_mPrEAX_0$f*'URKaGCkAF=N&;3tRL8#QtDF>f_J4PE8Ah`55(hCZ7OhT>.Q[0_EjBcVrTS_Jkhc;Ul]YfOr"BKuH9RI'p8?/@2p6IJ(c%f!/YpffZRcD/qokjS=sApVjS*jNu%%_^^]CjC+HI,f74"dd7Bu\W'c+Sc,&7GFb$j=?N[/PoD.g_!4;FT,*QZ^M5o&1;Oi[J,,FNj;2dqDKZu;J9GL;M`CLoIm]NBPR[Plp!/"`Xj+J(RIR*bA"KE'ZHctl<8%UN[pr::S.`osZ/'&qoCJ<mb'omsfX5Y^p]LNAn3<^TpEojrk+nE7oWWfF?eD"+rl%94piX,&+qni+!eZbtK2W&2qDa(-0;oEWdV?%0$?H0=I_d?3(:*sC@Cuo4$p>%%$^FK;FOEq4gd[C#RK#fC%960@[m[L3m7q'%PM=R@W:U$E'SHB-rjW^A'T,]9I\5]1,a(Y&,e]>k,VK*/,_(ilr!`q,#Qq"ilDC+b(8.<Da(PDFTDHFjK#4/^AO=MH0fStE>Sf[:hQKfU0`CNcjl2NL`=2`bo``t#LPVYAc7OrmQ.j5;3g7tsH(Klog5?N(5l[QjcrIUbTM2TQ`36&TaZ/m?dR(j3S^1I!@]cno/0GF]6kZ:*#]u7;%amc?3`O!@i57>ZD3aZkT+]XURf.kJk+j)lX9F4rTWKM*SpWC(.TT=CJP2%%;8rnEWUT;"7`Sdn*D08/8ul&)jR!uJBFDIfRY64'NX`et^)E+!Q42/o66R)<"%*t:_GKI\'+BdD#LImP.FEg/rXpJ&\n!WQ[c'0VdrW-V@ijW(j=+%+#Y=iSSpnhXJa\m[hV$d"h$UP\e3ZG1FOJnEM/A2Z,%GhGR5VX^@+_r`EWTL0JDI(C7c<K-Xf*=:lDPtak98])I,KHDW)779e,u-==6fK>jEuL?:tVunnEqp17/]mV![9/01MjprW2R'@Pgj_[U$/XuXl&GL.:h/pY/u6?fKMbo!jSGBgBVT;2B[Dp`+T51(k[O>!Ro3q9#j:Dqb46s1"ERQ%2o,*BsEm^;L!b]GhGbmcld4!Q_KAn76jf%rgeNbZb5r:I8AuKEgF`T1:$j+bDdI%B;7!%Zml<WkO%gg'2Q?/&%b0clj9)g\SGtb<&J'4lqCu'F5fg!YG<1YNI]Gh!=b<$QCkk)Ilbjh8AZ?sd#1>Nii%noMInb3+sR7h07VH`]"MIt>n)OAY[,#R!;?@uqWCogNst#g?31[i6BU,>S9?OU'-tkIhgaJ?%"_fcX3'##]X(.sMZ^bL*7AWYUmji+%A"1WSalXQCdIfEhb__e:rb^!3(#1e6aT<,+Z+stEP^9jL'J:s%DdDJdna,]c0/VQA/]DOL;:>Y*&6/:h9XZ@`o`O/aOIGYA<,YPJBX5PP97,2/$$,uEmTSc6\J%W;?YX!R5#?P0m<1pepI_<Nt40_bSTpL%*m)7*l!8rStAft5rX_/:SMa#!f2R(P7j])8Q=D9<Ac(lAY`;T/?$99N1Z%&43@4Icq-G<Y(V)6N$BM-Tl;l@9?JC=UD\gpJtTGGT)(:-',cQV[#,E"[2>>>eOG1rZN:t!*2A2-39[AT-?[*R*0GQM(;FGRYLi<j-ts>smbPdKRI(SArJ/\:nDeB=))b+AFE2W"V(N=6B71=KW<bq]bT7%1-ppG2\1',uWiC'kj.<5SDo(GC`&]nhcA-;D&<>=cmB.C&iP1F>9Ilk3FEoBuG/q3.Zp().[/.Ug8/(_o,R>[q>r[Q^p_ek)l2@5@_=M&0kOCdAh>Z1l&'rRh-b&P[i;c_?IKZgKk6V5"^B5"-h5'eq_q=kF%<u^,j7X\[RHsX4!,t@pdKm%m<&fHL7/J7P0d>r<%g`2L5:@SqTq;S6f3cJcjTL[&aK+;be54eG:@AG$"6;o3G8\ZAK#P#\XG9X\&-4h>!cp`uA-a+G!Q"cM?%LoN/`"W1h+7pe5iTaB*lIPJ:QZ2$0LRerKq$^srbDS$4NiNMO,ent7/^R[LMg\;H[n">ijj%>VROnGL'].]AIC$Ip34LF^K]mVfAQ,&Yk@?EHAOun5n/hBbj[5m"\ukrW@6F$h^]h8jiU.?ia9.dGBS$D^`VStLds]1LBTa*6^FB>Nj^<3:!lEr!$Hb8^.7qT_K/*3o^%%IpT`0k^8*I/MVpUR-ZbS:a0184%t"H5$*T(M(a'@n%n*.F%8hV:qA_-\cfKbnc"l0l%#;lho$B%5nFPfO->pC7`s'[sePMB-7oFG@$ETTH7ak`UYs&eo[?KUQGe3r.ERmBc^JqqEE4qg5bg:N=G/VcTbeZ"SboW0:d?9Ze:'f-Warbm:`!5"U8-m(T_tX+p7C&EP\e8J^fQPoaAkNCM=(lR`LIK"#03%CR$A+]Y$V5ka%(-3]!CZoi7)ia],o%mHd:_*/Z*8$cnR=Y4lOs*G@*[ql7jKL[=(Xr$)"'@iDG,0]9;/sBVB,eHMX$6;?5]3>RUCKUVss]PpSms3OjCAkmC#?.&'W-Sj1duHV!=`Re(X"<8$<r-&ftZDf/B)%qc/\4#So9TN1nQRbub">0K@;I+H,#/+&Y@31s+gJgqr[uqL0(#^st":EALHo'9oe+8_fX]\7:Hni>)-@_3!ja8/B@(1t?*T+R5Q)mDK&raTDf>YV)@0g%s"SJOk9?5[E=_9mALk&3#8NnC1gm5&I[?N;9]:X=F?R$I`U>=QdE@1o)2mk57=PO#WBpP[F+)!k,@'VIOIMWkr&Lb>`',/:f6",PqFd=\pV@21;"On'f&KoH0@#q>DWCd=KLc(;IfHmQVrS*TDL!m3+k@#nfL^-bB5j,?%#on?KLH0k$KRGAlZd?dphiic+i_jD6"61#HFCc8AF3CmK:P'UB%8##XWI+Zi5s_UM1Oa6FTeDM-KaIp'J#BsQ=$kQo*=PDo;Gac-Z1arAs"cqqK@'`EXA\.nVT$o`8J+*P][!WnS[0].f#*MPU*5UeXlmUsma$FG"5VJ[fba*enr@>9_`*oQJ/go-sHUNsq\9jrT.OTe-]c0,":l1LZM@jg"F%UQrUOKV*&X`m=#!H"F"-hC4(\)PRA+6XlueCf!nDgBg2h3rP:gV0Ge/-J0CTOY"/85TqN9LTq0mer8pK<2$co).$,,[JG5n2pLYem`'^(FK[+s%WP]fBi?-rpT83ltRQj@OX5Br#-k*A=Zr`Kb.+V@Fg=&:^0DC*+h'\J:D5tj<6f&U/Zt?RAc#@eeEk6o`nr:?_Il:qKn/,U?qhCM8MjCq=f(("08d,Ih"@',$:EVp;%1*HeX+\aSES-=4f^]jl_S!ml\*90LI#-!/)m?N"Q?jN.=,hB^C&1pX.<J/f>Pajr'K4-mC2Z%7I->`'6LNIj:i4+X?ja+$ZEuA\f7Rq,lbQmlSF7=@NDJIKdn#_nmQFhWmJ3*1&4,d>T34G6A>@J/,Zs8!3^,4jBX56=IO@,E1WuaUhm#H]O;N]k0gn+-Ko+)`YVg#<(bhgYEue!@\$JnL*[`,@[c&S_DgE-Ie?WMe6_G;%=`N8^jK&mHhe`g8,*r2*)rAQGK$`W$&gufG]04^UA!*BORocpi=jeMopgb3<g2r9ho<T\0e/Z7)R)R=\pAuTuDCa_+s@&,Z8i0k5@;4PG^_$Ni)nFN>M:7-m^Jp.>4f4-/%:BC#ku/+E/VnU&_1s+Zi@_jLq,%o8\XYJbSR,T6]_m\'T#&c"u.q+:q&UhhD-giY)7ekHJI=NT,'#V$mJPKT]iUr;JuVqFBWuo$4r?.1T$F1et]&`[.#UR]m"3%4<,cg@FKf5NbJYm64sla=m68"m9:?Cp)/]cU6i9]g;>h0KeChXrf:fm<iFbS``c3672Vs6s,7f9a)WCLG1/GIe1B\HY`l3&js%F#@Fk8Ue)Kp4nmINo^3_p\6!\.Qok,NFK6D1?KSqUSc6UL\a28R>sa8PI.rCTGo+]]#82q4\uc1PS#Y>sZ1ms;#HfdrKq_[V2"O6IPn"Lc0P(cC_['\e&)A78j-WQsb>W]+TRB%?H8-6BZH+!rEYuj-UG>+7=rlAPq=Hh3P^_jP!=8n-2Ng/T]26\McFA*m-a2`<nVQoB,(aD,'p<t%6<p;\T4!ucaSNYkYZ98a7#W6a82LQ=DbO0,&3adA,?><ENUbXTL.\<?%]G`N&L\/u5eL%`5/"aF.I'^jl2f(Nq65XTbSYET:ZP+bp;=,u7MWut#=FfD#L"5V\`@RU#OF0);qKk%$!<53At'7f9Hj`Be>kn?&hHd\7,_XBB9on,E8\5k:oqa$"763m6O)BFpUd77G^BsBW6k9s'g9CK)GpA#])+8g5hB$u=YJ%t4[7.dq>WKa#\WH7hK#BPg..PK(dR?]1kM5?!d4Bi]2lQIaNRG-2\Au/8%oRI7u5fJG(J?Ilb3],5j%49[%_@JV%Y)gN[(8!b(/CV;hp<QCgZ'PV<'fPMnF_#1OtYiLYV4u]?ZTmoXFF`+pitq*J>PP$rI:4=lpP+1Di?Z@7W3tp1Q&dLc-@X04VZZKiQWSY,5g>F=mZHZQePCE(i]%d`q:l:8m*>c;KB^V^au#=f55]Occri1aChS!fQq``-,S(^'DZ8$7Zc7C1fn\d>.W\Rg$YBLIrS)R)<Kpdqjo>MIaR8R%gCop'CDQj+6em05D5<g($usDM\T05FA-D8%LTS#<F)5EB&/+,(--l:NR:8#mse#+c2ps.5m/A7AEFX/B20G)N7dXN,)=*Q![4.*$BECB?Yi7rrj81q<a)=TuVT^qt%:*,'aY^,V[X57GkrdfCY"mJKH`Xrcp[<%`m;PZk&^)TaE32W;;p$=G;#]R*o)a\QEgT4SpM.1h>;qaff^c2MsjI_'2lC]BhhBKc4@;?pJ?M=<6=BcSp8_C%j]EA[,''KCtIRE8"o/Q)"^_+Jf?uA7W[)A;5_(dfqMr,5pXn=`_%k)J0GZLsnc>70`E(nb=/2COM!;!_3M,c<q4=TJs[,=k+]!#-L,2R">k4LqBf#kWeYZTjclJY/mbQob.9i)W'AsR\ftfCnC.Vf\ms]Cc2]Ch<LRZRGCJd(WuVod7u5i;9gV\a1?IWZS(S*Ci,qb/SJL%@0L"\\B+\.\^jNEY7Aokm\K0L_Ahf1#S/7$#(FSPP[DpHM0g\cY=SZu-B(0G1FZVlc7lPnZ/`3_2ln6q75dNLZ7N&X,D/Z0jp3:%Uc5%&"Bo4#0f;s_d]s-BX0B(^'.EbBB"32]s+>-B4a.5X`:fMk<ZqcqV7ZHDr%S*CAXmPE<rn`@`k@u]Yof-@m[3b/F72g$SWA/cOms!KGe>gWdNST)CcE[b<Co_pP"6jd[q@Z/+k/PEQM5dVOn?cos'Bo)2#VdnYR<i&(.a%*,^,NU0#W'26-BMR:UcIjRNS>VK/ps'.`@AV3$mQT5gT&0N2L7%Y</<l6.Ab`H9&B@?21qm^H1erd^]im@::9pUgki0;;;!'b8X11oC'rmXKK.YY@KJ1%,sr9&-sJB@P@3%94PD_FM,rc62k#(#sl."0:#e/a3V,CE6r]9$GisGJan@:L1IZdOF\RCL)W$(D"i,>phX^Q3FU7?JJpR-F0*tl?X!'ho's+6k_BT746CE$jA&tf"-+;e+9Ln""F>33nS;Xh&-p9"Zfco.75I3u9H%c-o]]@MD)4%3Fd<I@*-tk!3R)!ABg!L3"T?$P\N"D7@lET(p=%9]mb+r2>[<cDU%T_s<bY<2FWUI=9@u]Fkgr*L%u7@=[Ith&f)$pVEPdjUa2r:[C+IPE,gIs/?,!V4Ad/aML6?+c7t`cuFud)1e__=3T^,A0<M$QpfW"Ob^Lq&1k3)43V0T\bT^ECiSFn[HfZ9f!gj/$'q*4->5*^<;0E!G^QQ+I<VdE\`)C4'TIG'0HU-S'gT^#?(M^uek*S(<c_2RgNO4EWJ=Ksb%/HgDfa6#WtYu#YLfa[^TNTI*^O?u7r]u=aHU^aR<dM=f#d**LCFrWsXNr#C5[s@.<8#F);(!c3$T):O=:S0RhXr9jX`14dW"7%!d@q?a&"IO9bKG[bUT4-l]BN=cZe4^KKaU'3Yoe:^@+*/.1.JOPqq@Di39DnBK:Z'S0L2`I]$W2.Y(n,@f,umpW$3';BU7r[h5Dgt$;=23)]F@)oR)#'K[/D)YnGR="I3^eeW;-j(`''%j,g;X1@"=jG5h]`Fa,:KKQt_BdZTA0G)EXN/K*I5#=p/s.Tq.ZB6SS?jkP^k";:)Slc"6hmFqI"p&kNZI&^qf4*j15;A,"qrPPqhJQpbS$[#f+Z@DL[Cr?5lUg%`60M@&^aP/'UprHXs.BR-bRGEkEj:?L:3THFMnln4hhLS,SQ;#>J/h>YhTT\t%GNES_@XP&6+oX9KaKXfkV0H(i3ZT&8Y2eZh+]nUBm6]'BM'EU[U_d0V8RDh&mWni2B&Z4T%Lep3uPd(Xb)%J_7_Jr6X@PCr,Ihpj-7u*>MH%^k@+OES7";7@JR]e$TTu2C#893QlKpbj4\\g[ikJP>i5fl@T[.k[5b@:JPfAPP&=J!\Xin2@9XM;Uc>8[Q#Wbb!!]RRhl"*mTGBXkVO+s58VIPB-qjF-],CE"2!W>d]QC7<+"<4+'?ZYZMr[^rlr:ZmDP4gJWu5S?rqr,H<VhE;$5L\F_`Abt"lLM4=k<B7Ye85ef4"N8*8[VPYOkG-Z)b)!*fhW*aRTT<RIA6_b2Q@j1G2cc*Y@7OI81(pP`D.k[O^)tX`(s_V>cGlLpVU"cX-:c.O&?_6_C#`U3gh<!qH0dF0Ni+YY*ST.d"+Foq?oS3j'21+8*?C(HZ.m09SSJ0Y`RN@C/7V*%&Cc:Gjrq1I>I"f$$=V:EB<XmVFd(%XV+s=0+bVDdjHLq"(>0srU#R)*^gQ`R,Fb&WrpNL:a)@o_@iKXW@TOsW,c[#lkt4bl)r,59bsu0'!W]Y3dtYntfU,Pl5flcL?D6"Ve%RXM65_#DO[>%X\8>rqBVb#_L"s&SdJf*b+OXa"F`^flZ/?NT92%e[YIp;r><s_,p=7KL5qG?^K&e+8Tm*3,-5I@kNkTsBi:_18lLd1BhTn0oF1<8W0T[Q5_F,#%_K+>U'6@b=*bied4Xsr\gdt'GW%#-,ZlCeQ5-Tq`l@p^?2W)XPk(sdq'KB)Ej,OTD%gMI&%a+!DSe%R5Zel+R#W97\kODiqqsnC%WE.5BbUspMcNih.1q1HTUN,`+Wq[to52Q.X&u/0m@(j5>k]:nfA;lpS9qHkT5en8NV3EeX@W,Sl\p$^ll9aI^jQs)X!lB411QE8-a8Sgd>ruMaa@\Jg=*rQ+We;ZdW.n&Bo[MTQ\K&_Em!5d&%HP>FLGs37*.Z$$:3^I7<G<MVah;0I1!&!1:ulg(&5b"17Ifoac6K!*+9BRRi%W?T]L-]g":T?tKOge5)*5.e4Hkl)-*,,n^r+qF*n9$a3t?!nHT#8JRN]_acu;_i%KY5G;%!E`#u-h.i_]d!Z55Ni=(Q_.gmgOdAF+Vm)SN9\UOaTiFD0*%86pf4kNMOB6eE(2b4t)08X.%.J\E&im7R5?S#6qn,)F^7*a2us-$)Pf73HSVd=]A*7'MrHSF[Z-l!ukoQg?&Q*M"aDfoU`U:-%"A1TT,IZ^'BAN/0e32n]pgAai)q&IcR[%'Z1U(`d!mE@HKI2[RJ)1nqC'-`p'g+OCo2_>h(:Ps[Nu&T6T<C`MP))201kZ_U'D]-,fe3p?5O;A>(U'p__8']56IJ\i84QRNtgO++g\2It744eu<0W^pg!>76ZaKY$@s&2;M6VLh8'R$(aNUa/qRU"CondIBAm6',It&MP6faC='?33lVJ!IKl:\/eE;HkX0Z]nTC=>*tOnK>LAl*^L>re?T1>*W2F_A+uHT6UMfL".0670G,QF4^R^iXR4*PG:b`cn_*&J*o$ioL,a3'Ag-/;mJ&M+&>'t?lXjb9noAQ,GhH3"`4]h@]GX2[GRaslOi2DW88b!WUMr0n5?JR'*0!M,Ar3g#X<\,8o(GqK_fkPnj0Qe@[]/*R#mhDW>1&m=9BuClFS4i%=.,S0,[(]H?GbhAk!>/9U`gsUodRuJ^V6mO5pkjuGiL;'<E3TbYcg)#&e\K`4!!FrO,+#B@8G/A*.<,'OgfIgc=Z_oh:XrkK*Io.'+kfg*\R=He!`Ku`ZcDO\9JNsX2(XYS`%C7'M-T*s%#>OE=%aHq>poU%?Z1^]P[r_XP_1`*O[iW@EC?$c0/Jh!_lm%>Bo+h_ehK)IqER(6\iHuOY7oQEK=2.i,9!Y1O+2Q=ko+HWmOp:fkEBhF0I*U_Es?O`\:Dd+Y]CA9dQ)B?t,3p4NH*7fKgboHp+1=BW*7ZK_*S'@W8LnfJ#2ifK9<^P"[DdFRBRQln^%0_M!%;k5^$ToKS&ZBX)<Nb,W!kl9u$37L*EOQf;'+-K=VN3Lfoi.d@^Y=D)LsEsO+V^psmEDn,PTBK.]?!c/W0L=4Kr<5HT/Q*^!N__TF+Uh+;.CI@-7NAYAY]Y>a%O,K$M;Il<]C/MY<ZsF+5G=hlO-#Q^83ZFM^9.?MA\(rqek0K4t!ki-nHC-p-LCc[<I5_("4.^nng3`l\`p)s\$&RX_r(q53r0bLg?fk?<n+@[h)EKa^:.`eU3Q\#F:s:PQm5%-Xjf\Ocgf6ge)K+Jh<(-H,oq$G3`Ve`Le.b.sM.qP[LgQ/Ee#o%D4Ok?Ia2*a>kVefP[2AS1^PB93ZlDU05D+90LA#"u&SS.OI:%4(\c`Fq4AY/;d\bjEi/<h^CdLAm2BV`mkKg?(R[\5A_rXC0kq''T'oB:Rj2Y>O"b6t!;Oba[msgA9B2=`c_A(HaYZ3r>WC$k]#p6?TPQ;cf=qIDh`WZE?6q%h4-g,Rlq[guiR#?N>%p,c_H*)J8/o,dLU^t+f-6L_8&g'aI,+s2KUS,(aDPu\Q%PS'>"RrfBaF(Uhm@^0q?a!popL"3'g,i8#6u,1lO9[ZOj?9Lj`b)gJ85r'Od+sInDt`/E#5I+U"g#SE].uLM,rUk1+gZE&#PMVb5Q_$,9BDs^@>"k4Ops*t%-UY=fZ>][QSQS](_L/B'"#V)+C'IK\$E/FR$jY3jA-,S[!go-%Kg^U,^P36]Hp'G=r"c?3LT6Hb[S@.4?jB6%:gAXpiO@$_%9W>eESMkd?$N-(jjpS;(P?K5XYG;PB:$aM%&,F_1*;h3ctt0f%bug!UqES/..f*jUUdF&#oH`Z^PXq4m3:O"=4=+I_po&!Z@Y]kceNI_9ft=^JhUlO7UN!8C@rA6pkf[ZsqV#b?F8?E[u1b7CA$(/Q>q#WD+;(`i.Wl(9t+eXACZ?Li>lb82*9,;u>l#5S$RO7=N@O.]*`;EC\40:#fp&cu;]oL56DZ_9.lk"YHC'1'L';K1+r#Sqn<ZHg:DjVd[s3X"]E8[R1aB(6e0A":^Y>gB9JY%ZhqBY3#Y5Q&#K1+i@\T^Y@hbP"9'h'EZV-j-Z1KD@q1+++s^RnN79mGjLP@62Sk]J.)U3:;)BNd!`ddnst=4YpjbX;Z5Lq05Qq!ZK#$"B3"i?T&W=`)=B:MW6>5hoNu`df/+1`8CAe;YG^?Sog\-a=[<W6T@G3=LZK^t+t/3,NN\Ghe#4%+?+o/@YQaDT`40DUI,Ys]2IIKIAOYU.$jOWnZiR]:/g70FTMXF!J:jJdAop39lP-^V;QV't6.g[iha-FGrth#gnirdK+j6i+49dm?"UG>'kPP2@HcSMq_AH8riU&e*EmrtTH`f<KeDY$6]Hr;nbPL9eK[Mh>b+oB#,3,[NI/QULn6%/"4^""F\0K20LZd2bTjQGJh6XSi!n)o<clp12oMd),m\K]R^G;CoPn4TsP"@t]O,)I1M;2NjK4%5NFj^XGOVZq:o.RmC^R15rj,FLu@)-1WCCoQY*5h(2;C6r.^2[t(MdmDXP>&*UR\Wj^8?e&SU')$l!]$P_9cPf@<W!Ot5sohe:I+K'KFVI9LZD+$s%hnBh%1UH-9bK>'-Ve!J`-g;km*rVqk\dOK'ihjrrD+8'NA3S]'VN)gMW6FgSo,,SO6&F7mhO7DI1EuA%P:sf[C!3,(cp2`>`8rKSdX'(dUG87M(eTClk$I!,ZX$+!&02\J++i+ohbAV,:o>8jHIF!Ruf.QS*2',e93e&kq!bfE`9jJHPQUT95P+&L7MWi/..;+J-87]2@LBMGX4.phL>N]"eknStI=$[`J4ti(mn[P:r:<%oDL3!Jq$!EGGPu+?o"L#'nW2%!d5"58XX:+lr_4`#f7-RVYTsC0N)'_+K.&%jd[e+mB*ji*lipTmqgY#j`2%bWp(MaT""`"Ebgu,+ul34tfl_>jG\H/VtZr_96CgOMh6+AfAUKpBqc(57.Ve8VN!$cMc<,=>MUYF1J^COl216MtC^_5eG$I<=HSoeDUlU<ABGHK5%V.6l^e<P'A0rg]Pp]#!F)'eZPft+@*aM+OT<irsr6M/soiY[qT<iH\Z:)1EU5LO+4==Z0^*-O,,85q`tf^P_?u,O[/HtqQQ**Y\]&BZLq,Wlk-lZgA+nrXc17^L@IbgbImD-k*m;D40)4bCA>^R!?WF5UjJ9M1S@[crpbF+hmkO9:JT4i!rqtE?gRl<U;$V:8g``g^LK87c>,3mke%A42+<u'%L9ECU5.#-+`,!3:r\?K1.ebq)<mb9[\aUVrlCfQQ.@)dU,4@J(V?lPl.@3o?%@'-Rt75D/UqP*hiP2n-KmETmb^>0IC=R0)$SY`-LjOtMO%/el?K"4G;N&Q*0!:D('&gH#LhO^nY3@-SN(s7-,+==Zo!XrGr@HNa(F1#h\5V2fY%n#U-&?,fJA^tifr#p9dhQ`O15'c)b+7r86HJ,j1d]V1/1WVX$E*6dq6`UJlQIdgn2<3%`tuHn;[5=#dYj2\_Y/SkqS_j*eq]h[fqhtD%fZ*CnKd?o8fZTpUbJTLB?!%0^(TS5lS4+oEU1k*AXZ]2j]e+olBTfOqHBcNFrG;XS?,_Df&rX;G]_BZr/$0a(sn81D`+"hpuBIR(DR2aC5^;H71JcOf?\$GjmA4G]g]DD;fkS7qb%JbW2Z3P45fF%<X-Do`!hT9/aurHUVO>;']>b+!E!6cJ/0l0T-pZ70OOb^mZ.#G<%$bZ*q4K-0X+K1D>>ST-6B]B\KZQ2:Q6R4.esJBbO135gP[+>DV1+SjsG[KWtf.<HoK%OP,l?g4"\NaECu38k*,j/8RA`oTf]sXtNbbOrn":L%ENkm.^$;Ri$K(P_l&&WVC<i/u-L=jaS_dK.*O35shr1E@7buXDpn6#i!*=2TXKgV:-=+Sg?=<DY^qqqj6%/%/Od?UjI3"QU4u26^t_?'&7;BGDL@g/-B?,NA2S)q$'uXis&Il)=;MZ;UhEL6Dt$aPE9,2EV306O:`L<nKE`;8p(,S=Lj&oTG`njQOd[@k!p<U3RL5HG')d89d<4N,Z3SF'802#=c.Su'[fUk-UY]\2%q-ikLai,<XK*G!:5N,S0Ud#X=/-c3,agL>A-LB5:$$9&n4pb.ZnLhJ;uli<H"1^efnV6_Kp@i0Ka*'Sq-lbgGGSXniX1,Glo^Z4Ehg$d`[l$'k3`0I9fTTB;hEPqDi`s[`lss@]K]Qe:Q:1in60M-Z7\<Ak$9gJIESPc3OV_(+YC^!#\6A-lN.F69PM$L`Y$Q",`7pC('E\=p`BNLV\?3hp)pK3WuV33u,E<deRI8&@o12D_0*Ac4j,`1NN[.lnBLE&gS_H7PLBM6*7K*]2GM_H\M7N>r'Nm1Sflb5a+l0f@3gDX>O[;p@[]OB.kmb)o_`qM4LQ&&I5`+-[4-?9Mn<YG,M\3W:^j1MNLg@YCP1O]IRjM3'nCJ6[Wahcr=E=T_npRAM$c!\T;0$oYqh^iJ^(-K3:q<cb:,PMrj,&0j@ui[s&8EmIAt:pH[:B+X4'UOfG?u4hi4/-P6R8cTB*_D,R>^;OeG8N^S$q<\W->R9Tl)XXtD?`&_N@8":>KB/%\C>]Q^gL-6\GQ;NpO!mind7I;cB+A]8)ktpY-b]VU.E-=<$3-Wr/V:dik!ZlXR,AGmsEb(9$'KSf_LqA5Z6]HfHL56^F>Tfk@jER]rBjR(XEk5sS6&[gdQ!O)/0=q4'PcVY/3%S\C`^'_3ja2=OPD;VuN0*f?6Bu#q(_q6:I]?4QJeLSII>'rQqF7N$]:*\S<c8eVS=OdAIfS\0#pAksp]%CW8n_Z`6?`C5Att4$M2GfE59D$/O2/E.+@M`*2PdkcSK3KR6L1l`drt:cC3`L4moLqU--DdN08<Te+!aCWGN<"Qan\qRbr@&l'6LlRO'Xi<m'S(+G0QLi[\?`\dZn5:EXk<64lX"f!K[DDVKUmcW5`CH@#-%>f3tc2l\k#q;t<NHT4"Yl$1gY6r*J(K[WhLmFfQl8Y?_Vd'WY!BR`u1gM9p"R&n`)`6>WE18Vr]ca6`?BGib+tGs6er7gG1JL[#gF5q#^CJ.jar&I`/H`9jpK.*ZUM\P46*ZU9P:F/oY8%EhFD#<l$L*6SmSb/)7f]tu8T9H=\]:n"<q$ma%_=bDgn>%WkhQU$fT7Ps.f-lWpAe1St=WM2C0#Jg*H#(D"6nIW.UB.b#(r<[fdJIeR1qS)&!Ku,RcqcUj/q9`?t[5D:AYW+>j%@7oT(HtY]lrV(91b'('63P&\;iEn$NJhWOm2Iq2<iYrl*2na6kfl(NK8<pW!4<EOl#SQ,`s*8X0PKN\K>?!n(sL,SOP82CKfYMNgQB6Vq66OKL_06G>FI>2E=*/d6]Ntu9%+#KRU=FB',nGZrZ/-CCE1e#+V&HAX;VcM+Y-&alXiOI+#aTO'H_dMmlq>hTX-.9GEOb:6&gjZKGr>Iq<tAD07-+l[c\84fc63q6[@8uAhY+?:iG(/0b*jO^s>4"k6\k6'542!'C$`A3IHB3d8f:/X@saI"8uS;<MZQ&#S;Y+ljX[7R@"aj#^_f^jP]cR_g(:A_,Hlq[:>4pk^t#1RW3p*9[lI==ffgT0tK<@&8/CEFh$Era@(V*c*aDp?d?PVI9^",2!d3^Air)?-TL=%Bo]/BB"5\aC458>r&BVHS8qlKNd,p65t-gPLh=]=@Te\QCJ=/l7H!FP9;T/:X"\B0#6rl/7B]D4p6;k8^,ZgQjfGGa>(--D;dpWASBG\r":pdOH6F.BLZZf7LKaf)C*W$g=jVdJ,-P!(MLK=J[5eXXbDM18jLPoN7[DVpJpBPQrOcpAa5o!P:JCpNK><3DQ6sLZE'WfK?*dA[5h)KdM5\fe>&lNCRl_%;];K/8p^dYRODhYj&]<_sR-=!<n3!(.7Y?DK:KP'i]spnc9am-n!uSW-*a'\TN(^LXCqTQ>mk#200tS[Ihi,Ei$K8VcMFA[+#a*0\e.9I+65+Y=cbQsKf:"(Nj`]>)[)>.Zh\IXA%Nq?#eFIc7-^KHJ<pD@So)9fKX*FBR3(Sn$iF&5i"5e&BH-+tErWFLP+;CboK8<D=1aOUq5_=]aTMY^I5.\,:4Ln[e1R!WL;Z#B$BYn-,/+D1IGg48d6ZWaeYU6>Z&iO@$!iFPn^[?N&e0&SlM;i]Dn>\CK-&kBgdAYbV@bON*bVh23'-Xa:aJdWBM0-or/6cYlRMhnFZ;`/.'L=G"=H&4a7$Xj3Ai/(iM]3qYAYRj)6m]QF6S!d"SHTEb3#W'2^g\THh"5fh>=roBl6!Cs&VIUpZlE1Kn"GR=_+1:Jd6,W$W%k(2U)6]gX;KP(6.Z3,N[]f^?6hmR,!IiY,6B/X]+*,DJ_c,q<lQQ;R6<JYG`37TD7'fX/>5^3VH2e)A1O!R+?-8G6)bOJ@pSU4#g7Z"PFY^XJ#M)TCPK8b3C/CXf708.>"^3\E`s@`0Ye1u]hgL`<;-X?.$B/fKplSM."[=S+I4*gp']LuOa1AoA!Gn?85OSd(pSE'n'H:RqVpua#4*$9"Cbb]\PsQE*$t,OT_Z%`*ZjDo45'#Q?1YiIf#3u7lR;(k<X]Du]s"jcXbR[3I@@tS<Usa'";[(B2e_UVE^V``F$*"-I=dcN;MG[$*-:`M3Q_1>kMr25;hZCb90>/14S^<&qTrR`);X!:[Hd="EN"Lh;m4F$%>q^2l9oLW[1qjm\n!b'%2c@`*&Mj_)V'g:7Kk##\O!F_IU.6^n8F(=h0-F!DX(l5\1I/,P43C.)bmS:321&"Wb5^uCq\e:Cfjs.:.)b=oJ8J8*/?juKRMjm=ec>g`tY:c`5BW$<&;1NP%tNLCl:nS2[q-lcr#CP%LAS9TK#!OEI%.N`R@UBi\`kNK4>!=%1NS*.Bmn=8:ek.[BE(jMIfM_)Af`ZiWINLp/E%rm!!*XHUu":9:a`_rPhWg5V;Q#oCkD\mWXpb<?6LXG//L=hC%d6"moSt$O[cA4^2_M`Nk\jS-JL0cm@@(Q&&sc6/hE-Ga\FP_p&=+-f);T>n2b"^JfFC*h9$m#JU$jHX^Ze'\Me2k&dQgd."8jH[^;m7mXMt1$%X;dUTe-nNo^5e/S`A/d`e#7QKgB^clX@c\_V(LZ^i:Am]gIq)u8"Br#5kYc,pc0Old^(rOqQUTLV0l<$3W(gTD<+>p4$?]3?@;B7_G+k8R=X5uaAa>%"C)6#JSfD9d4)AuJfAC'fqCjQFTo^oCe\X^8N7Z\q)Bru#7Of7#/YIX==:3Xu`>KbQqXE-"bA@X42G-bASPJ523/fE77f,X9/_Rmm\FS+;66)^$?$>r6Y,2fiY,sWY+l,=(Y0jg3fKYIiHC@V1(<SkfWB^IqQbij+d;A6Yd3S;RB$MRfTpOkVO9J7Vb:G0Zp!i?8Lc=kmW&Lce^Bm*n&_`-)PFM]gb`U,>!_=2'G)k*/#A=/#Q^rd_$9-b[m'[O7$-SAPY$"1Ph#;n\?g+@?32e't=E:4%!BN-,pX&(Z-_m)@b2J]c-]OeW+no-?HBSA&Q4,:SH6!Q54d8anWOK99TaCJU`@Gc]Cd*SF)N"gKjS^]DC'>8B%arXa4]*K\qfoBR&8:_4T'dSaTjXgSa_QlZPOT%`jWG]$..q<&??.@@q:BVO]$efJ8VQ=s=G&j$c`o'>pI(7".]D4Lnp=8K@5qgJK%9cs%U7Z/*-#phk3Q"dWo&j2*WLQP6cmIX+*+%Td/9+-F_Fp+cFI6REE84h9Coa-sKYql%XpW8,&#do6"-/85@Zs[N<RKEWQ9]/i$tL=ZC/AZp/*"jADTmZ,,ID#MG9`^)d%V*1/s@:H1Ud],KVb4-7SWG*5;C.N<B^!KaQ8pgb%AT.OIU16<5<@_gf'#UDW0`;TUk44ET1oVU9@ltqYAa/4;F(3A9h&&l=An#YL:Sf>0#\6qi-FdKt(-mLWat5gXM!jf]CsTgBes][t*E*(I=_q)"MisX2,[E=53l8$/PHVbC/r6^rYq\`9E%rOlG;\oLs(>1Z5qj!bl+:T),nNbV\'&o,u*p7E7j^:fQ7\bggN7UN_)G_j:t!3lNnXGdhSC*Op4!=XHM#aDMQN<(0k/_elDk]/EGsU=bdml6S2F73`;9$).K/78IDrZkTbP-/2"q*SJg/DC;KG,DL&Wkrd4FlWRki7f&g[h59_G^GWHC:WgL"`[@)&^aJ)44Rb/%F>3W5r:'2"[9?<fC*olNWOO7^/9<$mAp3,k[!#ZiK8:j(.uk$<gFntLe;-F&WrRJ+8oF!mY^usYV.e6GChUt,QTLJ=Y6PQ!K/u8s3neA$gh9j;(eYX'MA59Je<:!a(<@(?d#oC\\[mC9Rbc^s!lKhR3:oU@]2<OnO*8f@(DN(N574ks.'1!n@;4J`H?YiPnDma&4ksPJH02`9<_[\7jW+ofW"c/B6QB%7'QU:47^%Ns./7D_r"#D&G.ak]W?43Vng<jJ[toQc1uRaad<BqGY!g)94(d>CI:3-\BYiVT3iF=cNP1.a&;rka7ia;mabPn9.lF>3bA`ID:jCf[>jFL!`E9X`7'R`bV#iBlOOVJlO;md/eUb.]Lcep&iP+5)QADO^^+G<fmLa1X,+^^_l++ORnE+-!6X*b)#t&PMY![NTlQ3Us<7I?[#:#_BaQ>Ch.0]pV1M-eOTRj2,RX1XV>8m]G]#gb;BuL)@*Va*LdobOYe%0&p3XD7+FOMD1O!_EAa#up=6dF])G%X]V\t`]Q3)R<J6oL/sP,AAnQp[nD]/sR:,RqY!*73_&!64rI[!uOT#-nl(H)&\N*kDp([U>(]C%L$*nSmpYiNQ9BZkaP]&d'SE0LDPr"2B36HJ:IsI'Jq17b"`%mI&n28LZde.(7+TYR1dn@!Std.UZni%MhH%2D%[0.oD7Y1;t+LIQdn0#+HQKT3Rh:2e"nBZe:+MS(CuD,.&8!@[:?I_bmt?iZ#)72bun`p;1<lRYRb`#-6t3QKG`TS"r+Sn$uaOBON!#9MULegbOJmo%'th\YbCr(QN"_^-kB=:DdMo(M/\uY2-A?UgZ[rkAN^K]Kr6Dk<r;ZCd_N_e44+bSS#4=F;:rhR7^hN1_+H8l<`5:i=&(?*8*oT802"Q>m-n*Z@b`J*&))_hc*-Qh5`H\YY$R:f,-L!(r_p[Yld?fb3Di'0U#P5N^@10L&nUE3,JlnpS0i-(G5m8N=k9'fP7C+$ne)l2OGVF]31rRc:0fo>Nsu$F*4?/[$;+8csW/KhPh,Z>%Vao+e245P?eD'A>-500I1lf5o'Vlf6S26fuGW#n)!.![F[-p!0"eh?L3bMOA)1+fe^k]M?<t)330U%GV2GojXmj/l&Z41@V(trUnEIK%4!;7,49@?2U:6\:!O0CF)IN&V1QK7ooP>J@-e5%G]%1(J\e\'"'bu=fe0oC$.u0f]n6['"mEah_E\BPs&g9/:Y3Z":-,!>apPEg3Y%?nFkhSN!$6>+o,7O^HfuG<PsFL65AF)h:8&SZ,U,c(&>E]MMA^\J^(k+^gGD7mQ_I18'"4+>p`29Z#"*ta8@pAH[J;22)QMN:`*L$nK3,N%'$bkpZWfdA-1=Yoi,"LIkO6"DT&/L7(Lm"a%J`L)8sHVoNoe4P4-(L$6UOT2<bh_3,k,p4R^:&a@2#W5`gZ)%4fb$XCE^kB!EVu$Fp&q-6dr2@Vb"C25[Hj7_;#&=@k6*lcZ;2LJ-`(?,Xt<m_?WshW"Ot">ppU*RCT[LR,JN/E<.ZCO?3s@[ljJ%)#AD+!f43+0oLs'H9rqs'1U@`6/W6=)?E5q_6Ee:r4n0d8J2Z(+o6>=)C.Y&qd*r\r*XlI'<$]]WKqUS=u7GgM6QFI>C\*i^$I'R=LFgC+X,bo\bA/W9-)Xq`EtEo!G!82`0ibPB?ue!n$HS:I*g#MQumHpG?ap&='fq@o^V?a^3o1.1n1Jg;+/b6JNFaM6:R.o*dBf+S9,G]TVU$#HVjSnUWm8B=Z6Z^]P/BG_QQF/8lU(/qFMAZ4NKUDJd$F)rM,Gq4ujAoT3p14&B<VfMF]"Xb\1CH<[VNdL7BTc4Fg3SGTG9dCf\cTXBC8on\fk/e>m>o%?kRY2$RPZYo0Xf/;$EdMBL,H>pD2Fpl?nF\9;aWZ&eD[hJ?k>&l_I9L(s*pr"+f^BnqZo[UDVt5\@>1$*t#Z/2Rts5YUT_Z%f];_K'h([_t\:iBVpu0+V0-jTEW'cE+;[D7\i\='aRI6^I(_GB,"_&FQ]XR28IW*a7lF`ieXN\o=%G8n@eSGZBeccJ5\E^&NLd;anbH$#$9a;"ZX<)VZ"t,MtY0@=HGNa$;S*\Uf)anRNfkY5<a]8>d@>PWJ]MeO6f"9=2<$"gf&WnEbaj@;<4W>aVH]2.BXiXuDB>B@V@c4oT=rPaOB%ldDt8a-X]R^g`,V\:iRmNTm8E'9>M570sShf`Edm4<LTkc)`$lh%[Q11b;':,q$JQg)jidH%ioWLtMiuBqRf1W\an6'So[[P^YI<pR]4DinP-NmNA7@#fnJ6(ZrQ19LgZs`&:Y>`W[]ZG@qLC8KMnM@0?<-6,hYR@94Fa"',L3MK>\sb=FAt<m2b_*hXl&Nq0X+_DZ<gU,/3$pYlRs'DT*-V,'2jMF(nd;C"Vl2C>)qQmf*o4',1'$]t!<;`r=oD,AY"DhG;kgi5:\PBFP_%^t$9@V@Xpl.*>caJ&eo!M_3;&l$HCii_cZ_i<%hVAk*6[L#Xi>gk!:NSm/;S]lE/nj**@)TQ7?S/jai-CLB3F^n7h*73qZ<@_Mc"q(pB4;_,X)R9@k.-PjZO9/Rl)@P/2W@oLoJ@a)S/416D-[)Cr\iI>s1k`lu"%!kJ#7rg\p^sln"@Srk(dCKS/o>u7U%Y*BCfg47Ql7GOl,T(5OeHk7;ZL>=gV$Xcd]EcfjM%7?04PC,"N;&m0kFFQ1G3*AhR"%F$5*9YJk.<3kRY2Maf?J;YG%TTNVo,]SUF*N/n-08.qOicgba"J4tiHOoP.Yqp?`P.?+bYGEc"@$QSTgGLhLG\#9#^Dk9,^DAL+9o*@T,MQr`4)[+%"lW-8A:Mf&`&]$JZko&"=,DF--QWb/&a5`Li@(e`+-_6hS?<&74K210E`@Dt3@NJuZ:>`oo/\UfrF[.\'1)&;5CbW4N1-Kupp`nUcK*'.c.XslK,*h,'\cD/YC/0lh<cB]K2Bsl6H8!BcQCWeS/*HLjB1E0j\Cr3$)@1`cq`c=.BK9kq-2cpH(@G$^5Jc"E.!Q`'G\?Vl@,U.hH&I);_i*WWPi(/t/Gt?J?HOQ2FC"8W+0J+NVJVZ]CW%gDj(BGs_-%ZVWEX.tF6Yj^SdL$lr`sMjK*\^3?6qWKHe"nfE"t'\<'r>"ELnU+<&s+_O?;e2s1,d-R32q+*@l%:6*DT5T@JIGg3])D`L4h<U[4P$GD(VKj<gI,2L^Jm:6'A7/M=3Y6U!qX)+EJ[2>kO_.:PpKH-'<lE2]PpkS:a$ONCV&R_UFrLLaNJ[5pKHg!Nr5Q_V9fDHBV%4FhUc@bP$%`f`s\=i:#p^fR7H]Nr:@f9hPFYOUEP%EJe)*PeQ]0TCC&:XZ&^u.G@59?&*A9r_>!tnUQYd=Qj+e)o'Kdd3CTqIi3!Ys2.i11jHd!$KBd;Be")[<(.J4]J_lN:G+S+U=EB^"MqSIEDGU%oT:!_rZs'3.sBRo@.O7jIOWQgUT8mbpG1[^[*I7Pp]VCUO3r]g@'BM@:kEnr,KO>%N>)`ATR]Q[&`TF/ZPB!5IZJ5o?h^^4(jQ4]jC4TTp?nkkY3aT>Fl!buZFoNr0pq*&>MOHPf\9VWR5o1^IV;0[3/-"!H#;8l.bu!A_s*'[3joijRYURo3rm9f9CtY$)U+Ra%q0fd)bje3OHn1:.t?&;;HrPt>B:2Hl)g>BSS`M)/9MLm0ca&jd[HG\[Lt$=JN=K,5D*&qlo];^VdBQ;l,44S-S78d^t\P?ScfWCi=WgIg%/aB<AKC.WJi[<9d9G$>8%YaH=5((2Ps7]auS+X1-?NSL;`*][7i8DRiD*&dncm[T;$KmC\nkSXeaR$:'.`h;KV7tCm-66aD&!94:e,a9@3,%R?@,=-"Zj%G[`JfNkdd38d!6V>^iJ=i0%GhXtg:u[WdW'X>CJLYJ%W<@km#)8E\"qpV>-k6hh1+F!2*CrOA>;9=01oi0s/XY4j1t'd-g<*QeD&JWY;%a9MKLCb%W(IRCQ$8A?/-,a(9):l,KIET,$>Q@;0SN6<751DA&2B7[+Xo]L6"t"3i!oA=F#TC?d+T8eG3e.0"#+P_&N+2k[%nLLnILDn_ai)\KiEDWlJgLR7qcpE)H4,T@3f*;<gAY:R4WHb"J]<d%)b\5?<D`nO\[8hfBmGAk;+;oD-f^fYa7]ph^IfqfU@Ym*j:1F:UmZ=`$WkR!-[2?%M%u<GCH7F.&FFJInt4Z0HLetB@]63I)&fUrAp3Yo!oHJkV2Mk#E,]0g(\9C7qP9-HL&)Vf'Ts1DfNZ*%PW6ue$Wk])IJ8^r+4)3CUA_-K]<0bdh:C%=@b=9I']eC^ZtUZAt$t\W$%C8"C*<AHc)6"r3t,X)g/t*r#B7:(u6)TLl&sb.6a-Jbf9c3F=0FI=sc-`MlujPn0^A)oe^.Q1uAQi7qk"?)PqCec!WQ)2D.9%\`aV(F!h0OCc2Sld7ac?OGP8S'KQX2-]s:65S;@W\mDtiim3ql79)6TL(GLT8#ls-o5d6[j\h3a?pt2rN4.c+J.K4DA<a"^e;)k'An5%#:F&lUYI+t28\FT"JXXRr,=HLJ*[c<l$/'L=6IHL;C7X[][*HY>?o1eTmX4AKVP$6Bie;RtRt0m%H^700DDl`-)o2$Hh=MYRj[CU`64a]YLnBD>-:$"O,6JHr.W#lVU(f;MUrZJQ^G_9l-oTF\20c9$P@f#DZ^#QFgTKB<fe151;2-\AN/^RK,n0B,r!c@H&!MD+XTsm0bW@GR7[<Io4441!/64r)!Q4*>i,K^Qok[[)-SP@Z!39.S$UJN03'rG31g$SMQk4Y9_YG7TK)?ERnee$HNmIO]2O`2e/Z]f0*?JXNc^=u.lqM^Y(_LJ3#P%W?mQ67FI]k9]22E5f/S(ibr9T^d0L&^V%"ga:P(_ja',WM7aC,i<WuPb)4ZJEaZG4<A'klQpPu`pu&OGZCObhn`&M\lZ8.m8%DVQX6"u=$(%NSQ&ZM$lp0/Y(-'<Ns'@p::>7_J&q@2hc\)NU;&,E[q"=jt%7Mpuf^R8IckX[%'hI2SK:2GTk[$h!8eW(k^^&He1GdUPYg3a>-c=tHZY<4%NqWM&fj;e`_s_;13T\S!KdhP>)+$chhll>mGfZa6EcM5I$8nqsdV);%f"(uG4HfAl+3KQ5T$aPA!"&>KAmRn.TUYbYc=_8aV,0>6Y*1m6459c1p/:m+/-f]=T%Eu',qd!EN!`qTkWZ.1GM2i?k5&eTRNp^8<(i$kf8Xb`0r1tIfDKgT#f+":AO2Oc7Um5gp.E#]g+"buI`)+$t@AK83R)]l&,1M364<^g/$DeLRh3nt1"E"(=MAO9:2&F6^@/XWTuqrPZs>4*&li\-:BA4!I$egt`:i-R8a,A*Ve#T-Nm#3Z;:p0l.R[*u28Am/H4oS8ZLR'0f3\IJo#('7/pP!X)ImSOU]<(#QSi9AsY+kl5S?8lae=a;@[JIkgX:KY[Leg2/L\W8K+^@*kn/F\6.\>/X6"L)KXK>3aG7n)ZY;dIt>:Br0pRZRBZS9T\-pr@E$LMTF&ChMTs,V#`DLM+5ij?7ZaYHe<HO=1hI44Bl2*>^G^DYQkoLs(@2A/CNlDk\404GUcnQQXDCW[K!A/FUJW87o,'^s!3C*#U44-$\1AdnHT`?*7"=7S#eOL_>MHVrEVD_md-=G2=7S9t+sR<Y4sAY^U$$\P=L>0HP?tbULUg#/"FgY.IQ"(gPr#6mG9t$/2@L0eoQF2=kRK8&>,X&/6MU@<],S7\qH]ghWeSG;Y:]+9^b7\X3Rd%1/+A6g&!J$`Of^%#`WU)%Vr:WQX@+7O8$k0EF(FS5b)@FR\4\J,2.oSR/C4A1>6"WW=!bX=Qeh,sW#/"*M';0o+[D&[j7kCWZl%/Zk]Z^dOU"[T7<\+[EC^`C\HB=u<9d-m9OIRLY?>1Vb,FhX)K-&fh@qUp\fVr>1c=9?m*2&)'*&-L#N<FP\A[*U&]B2]0T$35,SJ*s9/O#WESbD7NQfOL^_mY!?No#\9#>IJf]+cRW1ghp#Fpk2D;p\0k3M)2</6r34PB0SgZuMZNu'2H(@r46E;^?]Rot<+EF]G`:_qV#_"?D5Y<1$_.[f#5ZqC1d5%dd"k%Y6oblGNI\F6J-pc&5@_usi>/qS!Ea8<6")\e.&"2#=Xj<e5;%/&Vaj76,U?2Rn*CV;Y,b#@#Aq$ggEYT'l'G,%HiKeq@LOXMrE13$jTQ;#@74D<&bGr"(<A;8Mepf;S7*J,HgQ&c6S^rb"UCi0hO\\YRIeM%WeGQI^%hCWjPu206^!Y=6BNX61KCm]*&p45$CqHBa\q>j#-t5S0GeY?Rm]=hle(K!-XH#soT^3__&u_lVAL"i55bY5H\u9d4+M;O%o_!Y7/C=fTEkN.q@JOQ&lCSUj<q.8a-^1D\qu2B&V_@-aR"j_mlqJh:YnJRgqi8H1E-t)LJ+j`/d0"@+$6\<AC*d^9?s/XR*iO!8G:9-8LSdNRGj\!A$O7I!Q&1Q_j]S,3UFKk0+U93QV&a+@M>q$+DD`T_f]7.D/GmFn34SG$(QkD;a=T?<"\g](YW92c$QkJ/gOm8Lc$&!#8kZQHa(MB(l\Z+iWd)BWf1%6B3f\A0=BtkY?(@Cf4PUb,BKR=qMO%Uo@I;-:!9#),?-sSmU`YcNX!stL1F4T+5tEdh\16Vl:.$PCebQhb1@QKVUB'kW?>0qQ`N.])M3u<]GcrtUM)O),KehQ")BA@Q-,DVFot_ECOEu#OJSarJ9E36&s+qMF&gLhl#l/innm%`>`/&>PZd<6?7tDh%dV..Q#fc"Z%h#&/r3#G[kuMIV(Dd?m**Tk5iJe"a=53Pemh1F=<PKi#a5<g+c:=WS[G1dUNE"3Ou72]X<L,fh3Umh(ppS[jkP[3$77L!akf!A>,Sl!8G+k:YbL_Y06hhNZl/N4bcjtG=\FKW.N9&$2T3D%RN6thW@E!ZfX>8YMZSLIL''k170/)XOAQp'YRG=c+F[-K?KdZ1Tr*\tW0ZsDV_C2aqht[W?_n55Ib6'I+^,X()?=/uBUOTCJlerWqZ.V&#lrW#M$F\l@PgKPX:!GoJKVi\5`&6&3?s3>@^)pQJf#sA$ET8^?kP12^hFh*RQ)JmI/n3rS_<W&bR`,f8@3X:Xq'XcaSZ]k;Zf7(m0YM'M3\b]\hK*YMRYJXQBJ+9oW8*];RV+X0poni.qmKg$XBoe/TS.`^[`fB`lg(7r\hY("m'%GnHY,HJq?U(pcCT"P3VG0(+)184t4pQkrYat2?82_'f%%b#?$(5OsNK[hDgHbg,-lk'7ne2Or?UD?j?tiJCKHe,Kr#5VMHE%aV-*'8aI(ifZ(ai#K)W8^KJ[5f+[$<_bbG9S.;Q!+*mPXUA3Mkcf$ntSR$Ar""X_8Y?oLV7mApi4Lm-`L'%+/b7SpFJ;b+kkN<f"9crtfC_K#C][U'61<Gb_b-/M+G"U4Q8lA\JPVk5N6T!J[+I+e4B$+\I5-'VM9JH(LB4a\%#jIaicNHMi[s.H3Ze)#iU)qj?[>o*e2PED,BqOgp-H'htXu>79A;4q/>"+W0"PG[oh6knWPuo@7."J\"<-g5C:8LG^0T^i"Dh?Ao6G`+_&&l7`TThs.HkVRY_0lgV\;"H@EDT"dl^dY(GooZ__?j,;L/C(oM&98=N+&W]/86>nPIC-]&^ABK0-8k^qJj_N+sPYu4`b]moknC>7cf_$fJX]^doH:l*P/E1j9Y[@FTU$l(GdX(k[TQ(HXOgR?qOMW>p(EMqKP#7#rb3-@ASTOQij3Gl^WXkP#XYF'>-=e>e6?m'^M:nk5`j]TJ/MYTW,3'@Q#\[Ao-$jP9^d;9-[W58B<\l;3A<2gD,mP)JkW@7&1Bqb![BuW.lL65_"MPdL+A%PR"bu*bcIGh:P?;RKnY`b&ETF;Ck@t67Y[(9!Co$,6"tr1-gmC^]<:mJ5bYFnKS26?D9i^&Q40J8d+#900&V114mu)JrOC[#Hi^5HK0_SU:D9[kSuq*:nJFW=#M*f,7"lL#LZ'(J;L&mA!r/%P80q@RaT#*>[23['7_)dDS/GC)Fl0QoGkerQ=qZp->=-2'ZICHB[`kG!)2Tq+<1OYL*&`k!r5IQW,s2Hm5SVhAFM19T$aihScELPoO#;kK?,u$E%IA/ofK\2e`Q:-*$R8dpMVjC.]#Hb!BeoT4>lN6X]D/o[Kln+C'U]Y'=ctE^LW,*;^)KC)1KY(269b_>"1^N!.L9g0d!/37`3%FbXjNU/(]C-IX>nHW,AeOHCqc_k99*IKdGi]8V`=BQ<L\]h2\VZ4V@!L8.BAE9/3G'Y,0&0DLo"$D4F,aW<),+i8&:BmL@7'lZ2L#qm#=ca=T"ApB8W0gY>>fVq,SaKK9dUPR+^jJk6Vr7gO=o%7ELaUGOUpMV>BfE62Ce%2]6RN1.2:[`*-o"7,jYd/QrCEpnV\m-s>=@IUN;),n[O+\GJ%"Qcj),P=ZhoJqLp'Ob+gFc_"k`saVBf7ma@a\o'2+X*HPi&2U,k!CJ4?sj1iKFS3CZk0Kg6br'XHX!8a#Mtl0jaZCU*n,[2o9t7X,*V."kY'<MKR%Q^U"V["<%$\*QB,$jm($^I!,e$ukajJCP8F]rbV9G-g"??`IX)(f;W<$O9)VN2!0V>dbs"!o-Eq-h.k]\I:&V8*E[/lSRB4VHVILiAUNb1"N+Z>!C(h^&"oOnSMih5dZ0,"jXq$V'S4&P!qN0@RjYl,8.3)6:I.9GGbr4E`gq/1a#dcPa;b;;f,mF^6Wa]M%>b\;s-";5EiuXbg7Na#h8.dO1MJO1tIAnM@<eeD#"es>!_6OGCCA"F7)!N*s*jel"`"@n.jHY[HMQnh4fiD`;-k2[><1*=BH@)Sq"8E?3R:'WO0\J3'@:mKg^cZ[3a$anYRU/*t]p.:BWj&Y=_>qmO9;5VU6\?Ua.6S_K#Di\JULL32k']7D9Cli]>=1]Mr;,j^c1Op;6NV[kb$Yp7WcN5iF&r`<>YA1Q+d-1.,hjm$mSqS1<&An<d!lG24N)3[jIJUd)H.]UT&J?c3dZuKipQ^I'D0-R!Y1g]2q!,ePYs=5iW61Or0dY8/`](m&O),=8((s;:1'UShJN0pDf\3i^1$2eAnD1<'Y'YRgMW9bpOB`I+Qfheaur,@ht<`0*[![3f7<rVA7Om*X:l;BaZq^+jk4i^W_'/>174oB@;))S+rF!U`t=X<@3C&\7YVM16q!SS,)?IhmLlZ,_4p_c@[Seq7U3(:-b!ps`<\o>Q!=OgKL;[j_ZL3Ni7_qG7_hE#)Q2?7PdD3p7Zi6BFCo-XJ;G]`eg=$W6%_3-7&[sWYZs:=jA&6UR3Phd84G=g,,c$B#?6gE:sH3k+p]J!legKh;R`ZNY@d%fL:T1hG9O[jb#gVEC(X_S@BkYm%Z)A8ck>W"fLZ<A*4s/bV("Jl4W_T"?8A%$aD%V!Um<C"3A>=/3^((K'AJK%^GYL9+2ELO3Y<"@E8D_KdUKh(XE-h`*g.R<b^hIl%49aW=g>?6BpGla@iO)28eYm,19+B,P=-YYgcn;IF1RS%Pa8OTJLoLHr9#J"4S<Mq[6"YmK?>l20BYVf?!FNDZlL?GD5c9FO?:1Xm9M<3LLjJ8.G'.&n_f2o&=c;ZTh-q+5rX`%cLMSO0uZVo[4GO[Y!ts#=kHT0YM(c!]R,!KU1R=Bdac/A,'9(cqSM#,$M^880L6s!!5_/*+Ws$<84Z8_'@eHqn-<>4V*J3LfH+GJ7*ZUemZ+Y2n$@oQb/sCnoC=],";6j^;eZk61iO$JMi.^5_`asd0U[N*OP=GVBtrGK>XTZ:+VFBh'cV!%3l]o,2#ND@.V^caV=ChO$+ILL%F%D*/KHiD"-K^Z][hVYU,UZl=033IF5)nBXrBpn)hpp.bTZfLE5-DM9cKLcR;"2ifS3KBL-KJ2ntFA4)LNUnCY3q<\.<TjO3KNs?&10pC-CNd[6oN$!`,2$dSP9T4CK5iI@[-dW&6[)@11!a.OJ4,>_fec[025Y.8%NLB*tr.,UW#f9mC7GS>49eNhe?_9^((WX7aDH+s]g4H35ki$3TVQT_;;c63ISt"8;,XZ.68*NZr5K=9Npjm0U:ik(J<Lq],MNIB:#N>3DO2A=M?+\W9r>0Yq,#OWk3.Xkd`DN&%bMW/UehUag9_\AD`:2Sh?[g#1<K"JAHtJUX]pS.,\9N**GdP1MBai^,n`doGZt,m<5i-;3eEPI-aH+#*XR=hgZs\rmZok&iu`UP#ZZ<d3nW,O/RpIjk\;,Y%H*>>fX"QX.Z=\:6CFLlYs/1%+c!J5@#?<;=-ok/1W"'=U/2fnBGpilZCb/#stpa'+)JRn829*9s@--DDVL<(;5l'F>'m'C6nP;8U+tb01K3&]NI5JR".H/C>f)GhY2'0N2<VC$<>qIj5qL#h(i?+e?&AcH<*Z4kAS:))aiJ1S1;PI[aH_^VjaTGYiA^n0+;Ld+2nX%_*A'ggQ%-9LH@F2")8$&^L]Jfs&lfCJA#;:Z#"K).`M&K+e9E^l[u-".D?-]E`9>rq%IQJ.2?RoB(NIU%m**d0rIk64].jg[=&8*3!%p7!TTPW#H"_5!Ha^bs`-$7^hpE07R@`4,sm@jE]lhN`"tO]aOnf(.be_((*=4dRX7tm-G)8e)kR3g[&PpiK6T3FFifu]!CAPJsp+(0VsL47gRJ/'>E1+jLXKHH#2O`gDuLW?hU]#TB&5?NZ(FGp')mH)2=N/TJO)31CViYr,]Vh4e'>ni$b&HfFW";=,dgh">O\-T41:(Nc1TeEi.)`\6Pt(,b9VL%".l6Rq3`u#*\645`UFiQ$\fV?kZ3bFUU[p:g&<IFHIPO*I%I.=(DS&%Dks#Pjs;IY`tppmK%iAdY1V\[scIa^D]r?UTq&_L;Bl+GtqE&J_Y\CFks%LJsrQm6(gU<[C4lCn6P\@!@Ae9D]T6!&e0L(,b"=#7"SC&`MmY^J`iAVQuX_ti[.CJqB(u]>#Bu(UbLhM1MjnC*SB,dGM$q5QT"=u'mEC=E(#PJ]!$P2F)j2o9@KJr]AZS[6VpBOW-?C=8eWURdOCPmGXgM1CN::8$:Y:e=Hs4i%'V.=LDhV,BLX-Whb-4sTVd6jIN,t;hYc@D?.3IK"X<^/<F43:K!Bhl+rg8>hfk?VK<D4=V7SI8qs,CJC`\-o@UHtY6kY#P-9$Y4,nV@>.&4TOho+p=^TH^HPMgX(s)7Z^_#rLnHS$q1KS/^&H3`tk6/C.H)8:bt(<.Ldg_]>gB8q$4;"I+\TGg7)gq;bgGRu#8f!8$bIUNS[3F/mtDd]?*3;6je;,3M$[Y(05d@*a*K5;qi1\T4SRMIF:o#:4<lM$M1V4^DiM4'c"lU'Gnl[/R.EP`^kBQhE7,&9QN$s125479\A?nO.!0Mi$3A<oX#:oS\E=<K94#`D)p(Y7M@Ajj24J6sck/aj#cXAK,4#gnUiomtW::EfNg&kZP8-GkuaO4kf)rXZh"q6n*:H^oEi>$JmC5bT`A7eiN<^ULZ&fIUm*gjl:d]uQ#dFZULVX*.X8?.bV`2XW,:A*?'Xi8\<V@lDT^#Ipk#VUIquWnTG]@;,eP>oGqG(8q?qBNl@8$9%,,6lBBt)Jj3t+oCXTRc/poj_20s"=.iO6l<_b1<_<i:r<]6^6)pL2$Y:WL6%16Y^.R9S_Veo'[b3RT,ZQ%#oKT8Z\lT+$:tfKdibHj+j*6Bc1/Y<%*flUeo@t"XZ5Nf^C:AZ9e:7%L4G)C+h,D3i3O]E?fp6UCLFVs3a>m&BcCPLr+&ce&i@TI%d0$X_W&-eKg[!BZZfl9C'YrDTUAiKG&TekJf#c/K'I(3Uc)<]-)h<?3h)-2#$X_;Lc!c&d$r\AP$1_N916#tCF72g;bLoNe$iC21RsksCd@b5&R6RnT@PdVNYd]&)3HbE#171u&B(ZJW&DG.*&X4A;-<pN<.MKeRjdbU.Mr?uE,Z$;,DKtKH6CjSL>7%t$l_^fP85"]jRI3O`7='>&HP?LdR\V"Qo0mPnWc!\dY8VPKct:_7;F5:[KC?A8;p5WO<fnlBTY-q)NQ627>?*A\e[eYEMcFLU"q$O=^@LBeke*%gT#$iTf1KKC)kuJPAOk61.Yi-UJ,/%)Lg;oORU40>D!j6*5372/0D<c!ug1h;]$Ar!Og+tI*U%?Y9Z1?:4V(3A5O<RLLIE,20MNKVB4JgT4oa]KFY7dL^=g;pD`o`8XKg22pe<]1t6t2gGEZf3l]N\\fO4mB0%JFY90uXdnQKH+Z25!K-rZO$9!Hk*gZ#R(mO-&fh`VamGjYn8OsJ&-KHi*8-`3c@V$u$7OEp#,/G6Ob)F1GWX5F+_</NddgaL<2='RrMY2f4H5\0kbA=\9M[%?=NVcHc5<fbI$Zl1qg[<&@o7?[YG$$b0UEXSL'#,U3(:uSelL)!U.YR]GI8n$Kai^X7H5dAa6V]4'.GO<?P9^DGJoX>FD";sU[1*Hu-P"(r#g$$>riAQG@\utTj2-Je.]@%P:Dpd7>!fTI$-1ndVTNQ`OX4f,6R3#:G7;0<6>6umA$JMDB5.gcBO9c%G2W-u`%rFD:cJ/1"0q&Ye9]$I4t&OMWsu9YM8Pg:DoN!6\MOS4"H[$p&QI0$p]4;6bJqR"QmJp0:+&[Hkas']cB$/?ksRor6]dXoP`t1k<&hA$A!UuG7][fS@q%=RF1Q!/Wag_/06Ar&!I.cWjAal-1;ZOk7[kAQUP/Un(-)\ZVT?8RHV.]Phhm2kg85;?^:c<,D,a7&Mc7%P/fNGo_Oj[`:O)ctJL@N^LBUC9F<1]*-F"-,=<A,Y8f(nb"n>F+8Bj\a-t58+=Q!l0#`(/b6j(_EX[mbsb@4>,)OcK#L)h*3KIK21>(kHO91$lg6QecAV3P;OJfnKQ91OuKAiZ=-V@9aG%bhPY+i^)72Ond&JIH)+%"Q=7:6S4@$)CHAOHU86mNREYRk-5h#Rl?-+<r-W..J"jga*d_=72'4r73tE^]XbV#)TU[D6[P-V'_qDUhW;rLbgPlgHqXYZrCk+Rr"P8MNsL%P>*I$=`''gAMkcA9bPE;H,+l>4<-+Mj,GLog)^A%Yk7,/%KTLs%-K<Z,RP_mP6h:a+Tc0a=8KY;Ba"A"Nb<jUr(V=AiB)RF"MY"je4deZC>e>L@.'jP1r4u][`k?Y!(4,$#m^*b8%VkRlRP:COsYc]-&G,h8qpJ:"`..Ijiq#;/#K2G??YHU6VZpPFAUB96EPVAWYBXN/6[cP;XXFTC129hs*"f`0FWL4^dpPS6b,$#$.8gp;;VAm!7\Me2f=9t=16nenfKe5?%0`6lZ>%mn]K$JBj"?5N=%+:k4e:*iDN,Z7$*'\M>6QKNshuLNq_!IfeAcZLG_3D\tm4@?Y%^5ljndmqTFI?#Il_FHfA9^XWC+]9BcIPL\k'k#n>$dUJTNDOKH)QG[S7p+l'3@c372*<<4j,DE6-tAt&R"1N#;a-$KA^5=[,q'-(6,hr=63g<WcIFj:IS*./F'N+LKcZ*o:lP%q.Y=!M,+9;>e8@k^&igU@eb0T=>-)DfDCDV-mC1#SCpDZbAG7!pX*qaMM:?H+GF$\ml+=jqtc6*Om(&]u8&99sK)5_4eSA`8Iu@WhX`L`#Oj0(RlC/dQ;^\8;5i4G'[H(bf=!A26Li8d'0&_4hY'6#oiQ<%C9A6kq0cW_dqX(#BN!`:j/Y1-[5"hU.t<Ud^A2E0C0^.N[donI*0;bmRF-k6d%U)>P/)\Qn&[?kDW(dLch&ll]h,_'_b^</F01U>m80+G0gJ@cFVDZ8Of_849Kr!A&AeZ.T1ASa^h^EKul2Pd=8%E5BV<M1F#`@+?U$$Q?;p%#YBZZ9&ER\>@<+EE,>f2FO#7XTW@Hb[;?E@,\mqg,ER`j@orJ_Ee@:*JXY2$YWp5i5C_;"C_bP'@,?=og$q_P@A",CN^"!'E%Up@HB^4iGUe2YXfT:IKuSg.eX^-/m,S/)/0PnYhs`MH%ou</:1bV-m*^GJ3\r$r"NCn]q]BC?ioBC+[+lYMpL]`U6e(`[k*54lW,=X>:)G*XSIf"9RU7^N9>pno$?1j_PP6l`'ciU7puM3TillcmgY^M4JpeT<^K-.4m2J]f5Tf%#9LVE670V)C1,fdKQ3!);IWuq5<<GOKCF.185W)fha#K0dF7=Yqpc.u$K@(QEpf<PR'8p_p\`![c2(+$rBpXX5FI%=@5o<@-+kKs.FjJTW:h30,ctj)Y7"^&o"3(nlgVV5S1sT%1L.0-*-,,3N`*A!Y$bn+N9#s49&gjqJVTZZ$3Mq;Je27#JC0b/\?Lge6-0:&9R,8@Bn>t)+:X`ESM;GqNFbS7"#]kFIPq#c+Qn/;\PKE&oq@$Q9,%du_[dIB.GbZu62G8ZKHOV`DMF%/TnW%:,lgmL]_$.b%>k8QVt]JLY2f6>Sq.)$73mtPCh1Pc@nLH,9i09G-0jp7[0g]9.A?O?0.l36H!<m<R&Lr]1X>,LQOLbW1rbA=0u7*!73%8:Af?8R0f0e&:Z1@:k^rj\+G'n2em^7'RN&ZQHpSMXoWTE`#BCk7g[t_8Efg#65)>&Gp"\O^1<bJH&/0,sq%r)M.%q_<6'AEiT'+B`:[_=I%[,N$+&WA8Q47UReWL=j4\/+5)PVds5J>ac?YIH%eDJ#2h,R=_8*$R)9fcm"MRu-Lq/lG1:M=dnfnXS)F[Y)J+G'(c\>)<.W-T#+Qm='%1F:H]Vinf.)]3T+?.8,$)+d(9(]]/><G2SFBF'8XNP\2aI8CnQC`)FH9me78+WdNT!MhZ,E4Clc`)3%8\3SJM9*WLsKlM[^,mMaiVcY,]Wan&>jTE."o+pnN'nh6\l=^9M[PpPj/E9o"Af[h+-B-O08!Kb9NL0hQBL7Og(`86gE?NBa4XGQn!87d%J;4uY`1[(27gIk4AOHE,"\qsg>`A,=($L5WeUe).OFWK+&kKWbTIWtr&G`ujdr$hS%\ajCl42cMO^YcuW>\;OSiuP84M/uOU`'Ch!Sml[p(/BUDJrf'"GdP:DFL4"g7F#`ma;,+h[E)&6KcOuo@BQ$?u,3dK:f[+El0!D(>(HS)H+LF&8"T<`\hp=_@?2lVC2$Yeg<S^1kCf_2s>CVA=k'1+?qR_Mm7eDGKJQ6U`H3:BOY(S8;kiZ3$5!DY=/P&*j[L)#:cXm[B,N&Z53dD4sbcT%C1keGPh'/2Kpe?!6A).?pPfG-_=^>KKoZ1&EF76mFL#.,c_^"\Z/9We!t5N(#rSdMjC(*F`$GV,3,t15FXH3!&-g7L1JFu0K<LW-<csL3(f@E/!Q/!8.c1sM$,s!6XU,,f[nL./nu1(Td^J)(LI*MigAg`(8[]2#hk/,&09^R=25q_coM(Doc>-iZ1(0;q4_hY798Ua4#ie*S;s<nHseDW,ZQY3M6pS.iYXUpN#'5P/`;#i;qA_$rHP)=0R8@(ObNo(@%.gB\V2nm*"bBIAs8&-bfl9-2+/sfZDJhnZ*Ts%\^`Nu@bJ*sBh"5lc*dG"TGj<q6X/\EdgUIU[.6A*LX9B.<X;)W"jjgOf[0U>49=IBqVVirgE-F^=@OQ8BE4kHJ;CuWlM;T9OG]>gOV:9-d*?qWMQXm2o=GE2Vc[mK`X0?U)5faq$h]ZI;HSB?YLXn"*s`0\"Om<*lCac%on1$HdZhlFLWkg9)p05,S)CeqRJ9Bh5l!)a$ptM*O3brDm*E\TYl1?2ZJ`h?&kN<1o?JCb:V&.ZNJ(kW+_`c#F&&r0I@FW/g6sW#r&ddd%!I!_rpHTTp-\2KKXg-hPM$$WJG=XJ^bXMJ(QS(n1bZ6]6/1\7D=VXs<(!pc`2u^h#A3g^M4X&KQJgM3*5ICGdcRS,q\1B%E9TJbk,,Re258q`N='kBjm\]SF>TS:.Kbpk$*#6q^nOJU3TP!=-T1/0_%!e;lNY5b"[@lVfZ;M"5['sd,BUKZaMYVg):]iE\46[K\MD+fW\7t92Oi7%LASL'C[elm9#nEV2G^cV55Se7iA"$/"2_L4VF1LBcA)fGScnP2N^Nq?h1R+7jc,t=ZP0plOiD&*E+[p;)"G()+f0/>kSiMb?,D0S6g6p]B+r\/f#^2c`['3K-GtLF+`LWdW#`_lf?AO1jhG]Im<kT<:*XaPH5q^7@8Jj?Hl*HN\erKD,%oEh'8;2!U=44gXF%:0C"#c>bXqfOqnBHVA#tW(ihK)s-$I;EV]\JT:/\&@9['5_)@/I_!9rCKT1,fp4qN2D:fG%UoVa:X@^.`sV*&4o#7EjH>kR]0Ws`Y3S?;lM7?1/Y>t^)o/+X&PJ!sTsWpS*A2s5)9%UINFG>+#:;*d2W'51p"JD@D<(!.ANVE"-;RM#`h.7:)'CX7b#%nA*@e^o_:=?pMPK6].hEk)Z4QodlCh@:D#9Q_X`8A<dqQstauRAZS1[?,/D[.&Aaf$=c5>B9e:T'-_")Ju=ZE+o)-rPP@$dX\$C<DYD$2g2Rk<82m`jVJ1PMj0t'k$/WaD@!8S(0DAs#kjR*1:=16)0$+OX0f9e2\7KPZIr;Cs'mi>Y8Ub,rpR1Cl.MbNMo:@"SFg[dqi'G]a>%>U+:1=F,'et>;@h:D%rR7Rr@CjhLuF4T0c:aZZJQ,q.XJ"'1pSgMM5XGQel7VB"gu:3HY(KYNeU3J_<7lNk_&kU+.40Y4q0^u/),R[4?'<!Z0f>S&FRtBC%NQ[[s8YWQ,Xm\,2,TLq)Poh)=;@u.+1d)%HHiGn+f6V8=YlRVCH0YK90Yq6(&7gmT6d>KOGE/G+&A:V_$=6NZMYjSr*jAq]@<gE"7O71O8H+)fE<g+mSf9%=LNmdZXSqXh(%N&85$6m%kUk-Dt6i4$pu-p[B3U'-`olC0RW#dJ7C%*)e!Y&igXu%1r6fa6!:VFOL9nX3j2abV1FG5e("+748V,\hQJ.O$[djdk"$\aZho4h9T9ZS@6JV(q(O?h2^1QmQ5<u]hhu>`.aom&O4>Pd)]f4Vo"CE*4>6!jl.+!bNh_:<!tCJ4MnauM/m<0&d:e-SsW$R@[!Z7$Ns(clG!*e$9K;cG7lZhcl59lmP'q/I(i&Nd->!mJC/aYD.Pn(lEPF;`"T1A22>$!!>T#I++]fAM.G@#?u#aP]5p=&+<h*#`aH`(K,jFJak@NN<l<US_;SpA`t9/%J'n)j[J?Tfq+.#f+EI3r//oI<h0Q*nQ]*'TRmt3/:HS1acsaC*1s1@Vk,K.cQ?bbGcknU33]2`7Uk12QSj:p<ho=]0]eP*Q9-SgM^m(6s+uFpEq=Nk""M0?nh-.U7icpj3ljk@*0SCQ;.G1Mp@V1-Rfkpe`6P>M,8-+Yu<a*^teC(("8HqLXP>IYV8SDZ<&YCu$s*X5'<R:p-&1<EMJ3WRBVTiG@B*JJ:Q^0EIbCd"ZYLp:2+5_i]r#t&\1.XrHqhT#qL+\^R?10a^k31\)jf+Af@>m1(8)!W!m3Qn`%`35H"1:bG&*HE\K\<)(*$qZ-'ZJ1eF@N#G#&HYk'>2;cJ]=DpMO+""'6KR5:)&%??\[U]kp[*2@MZ@NE06*dSE47_Y^SsO0Y>o0R'@8K)f7L)3uYkj/c@_5@Vjt;(.:'J0bJsPJun30U@OT',!e'*iHGT(TrgJ+]=>E0D2(*?ki8e)1C2p[RI$dZ1S#9s$1LT=UKF!Qpu]VVWO])<'-&,T'e3uBph.LmpH1@sRO`]85u-^tOV*ruK&-hC"B=N\1g'u!MLh`@TICkGau1jD#T>YV?2.nIVJ2#.(?39`&DiRC2^8M"[9<Z1\X9[*#[o&M=:T>U#Xf@P8<d&]3/c&jnAP"O^+'&NQML'nmk!FdAtZ$RPEO"#^i_F_K3Qo)%1H`K4UR[_nC2:lDcbIk`EGR`*,aEqPT/8.3>bFT9rZ9;C6CI]*!"\$U00<e1c]%)@+bl9;g#@D`mZ>%5up=j=-HpT]WU8N,3iJcO'Zt,Y(n>L8t)lF'h2'!dUNX+X'6NW@NBaXkH1i/T%UG<8]eT#:(K-?>aU3<E'];RnZ&O&R>fV?4dRrYV[#'EH]VfZOH2lhB(]B6)&4![ZUPkEJ"<YZAccFmM:Vr0N=]mJb)AnQ;duRA@SDMaE+5mcedTLg%bb"nUaC)eL:+ot(+"j*Yn]/T2;/Nb""`uAg-]M(i6^jhPVn-Z64pgg)[P)93$'j\_[.-ZEm.6sG72WSgO-6iS1S9A9\cGq#0/*'\0*1%CF&Q'%Z>-W(lMO"0LCaf&S_OCNX.72AK&5h&J"c'8Cis)5a+ND)A<^JN3IZ+*1G*>%;;/k)b:flLoJ)i*"[W3BHm-EhcMKS]nkEPXYbs6=L\sOB[X+5JIEKPK+ZHre073*(l">)^nCj%-B'&9W4;I_)[=np,'uj`Bepla1e&B3\+ac^H*j4LYt#@!(lAWPb6:\cL7OTq!.T@5nPM"24>m'hgf[(?6Qi?dRRV-4Os#o3TY(&l.WHI+]@4E?q%#^m[/FUVO'hHr0&.r\gE7`HGaL6]r:Ba=D!(*P"5pA!7%dAlOG>!G8G<N[&Kd6.6lPedk[Y9H%+%^%CB<'/X;GYID2I3Q%LaOlA(m1MD#2P>%Tu9C,EXlc&I@>"a/HLDFr1XH+WT8&1g8u2go']%X-dh0DS8AH+s8RI^7:]g5#@FM^@@Y%j8c8mhR@"9mLLS2L*3VR&J?Y5Ui*a(H&\>ji6(N<IOAZ=A_;rB(\FZQ6gOt-*#3s^@Z!^Yf7Ioq+iNbJVk8'D>3l6hP"0F[U*sg_cgR\4_eD6u\B[IoTi+3MGR'AeFYK)r/H-s[dOc.glYa>6I(Of8V(Eh0W@^L/*OeLs<@O*"VH8/1nuAjtL)e^%cP.IFJ(+(rlgjjl-n1iU7[Z"lECd`sGqVe-O+B[:Ah9`1#db#h4:R4U&oB>NS])$S-@VZm38G1'TPKY#.G=k@T8!BTr:"ho%)gE)Ek.Ocn"]?br\qa(8YEV;7O\X2.h,5di<!Pe6=aN(e2h8P#BgM<^W<58d0i3X3CHQi)@"sh36MRLa5f#l=82#_9Njf#L\=n\7%NIK^BPCKQmSKRH!2DIC=UKR]fE89f9`%02iBskn[E+f`C>HN@G*0h\QWE<qK,\=R_%AQGKV#NgJC`]GB\A]$;``$0JUp,@@S!Dc+8^>oe[W)9Y-KbJrg%M8fGZ&<rsKf8=IBG`iuZ]+i!a4T*^TpRB^9mE$CXA#Mt"tpAb4,3?ii;.d,8YZ7]kQ8;nZ,@##u'M[)XA"L&cB"lcO"jZj*5J5m%:$J65JMAe;ZXXG/9_JDk&1_BjV;\XDD$ZiiirP2&[TX#&S_hTZsJ!Bk^'/82^63ucd2kefRF:PgOeuLWe6ZA/cM'8^sC@U<O&Q_bC&,HP\+KnK7/e(V/JNHfA?.f_KI/9iiJN]mOM4mlGEl:cf/Oi8<9rs=/XK4-kM?Y4nO9uj*4<IhI1OR8#`s!D!UjtoMf2@HYAT3VDU9*"i8kD+I8k4$AcJC-T=_,%[':K.p.1qq_:b]CpE,H(R$3UJOJ\\l<\Yt6[G`X=OLkWRer_@]olq.FC`(^CiN"-gNJRY#m6Kg>[gLSqd+,FpJ)l1=S7=P/m^1r`9!XmeE00At!o_S7k;rrHd,&g7dO\K)^Yp"7_@;%WQ!Q6j^A7;5*H)GD'+l9*5]#VTu+c7lA0[O6eBdRmW<eEZr'o^BsX@THB8.,c.&s[uh@@$LERGG#HBXFC][cch-^Te8^e!>ohI3eX`j]srlQFY-Wj"jq=UI384nSWiADdfNr-J<8fm(V\>.)G`1Z=1o;f+-VE?M'fW4u!@I*#GZdlbmh';tHnYUAJFg9,gQFVK)'n@UI)H&ME<iT?ha$KK"ns&0NMlo:3Yhm0?Rc=q:l\LV4fs#MRIk^3$cNTs@B%3o$OYgQSYs=dLHo4SroDe?;i0+7O\HUVB!4*L0gZ.ks'PWU]cXkAstSq6!N.jk#Wfg`q4fA`b*iUbhc)Dd%)b4K#(CSF7.i/$O4Al9k3U=u7qG4#]7gJbNFoYGjhVV9Vq$E-:;gi)Q<c9?=5?WH,0X^NY%ioNO%m,W4361Gu?_a'I3:eA@AIQYM*ej5*`MoM6ZTS<J(7H%Ff)-8!s3hl6@p6M_]g#rWlf/Mm*Ik\jWFFITnS/I.Zr<DDdP:QXL?A8=m0WSSLHp%CX<?'QUEHU\4;e;%YZbVU#JhDt=in5GG(2@m<]]XR3.Z"o%4:7`k@>jNI7m8aIn8jsp`OS.-PW,c6^)g<jg1f9[\UDTdqZV+DK>hFg0K,`m3'MlA_/u>]hpm1T-f-H1'Oe,f,N#Y"i1NFV+;th,\:mWkZT$[JucCDLi:-.tk1;;'AEID/%&9lZ:>qGW7P0o@tFO6_hb)]l3/G]Oc>uC!ZE+)#BQuX2_Njts^YKV:T,/A,'30V$p*HM(dP<02i8j'V&kX\BgX5(+ee`8&A4D+:PE["9efN73L,Ur+)'D61"\"`?1\pZ<I:,VC*V3XHhk_Ym'*,=8EXud$-+X34MnI`K#A8:qFAIJsb93C%mWA4u:G&llpD^:[(i&QP7X.VN'5geoGR6%3PJt4^'[_jO)YLg`QkBWh[[#r7+P/M\jS3r="8_Di37(ctT`%KrkV]1cD500/H%V]"""AiPon(Nb#$-p^T`Jk$<$+.eT-W45:X_<7Ggm2enMp"pP5;!1$kr/CG'0>Hk]sOWrLrcMYbab7.Lr,R6U);8e/8&FJ3"SltmSqtR<8$2A(S7r!N__$$jr<(G]^rt@<Rorpgj1]f8J(4ammc/].GNpi`U-NY`t*=O?KEAKa+j[]Z.^jH=\`Un'X3f;)q5RaLj'MC]%t-PH/,^`[GTd-R%E,.M)Al0\/K&jV?`8i#^<C,\uZI+MB#;'-bt6d]<Z>\G.]j'C!Pd=6#-j*)WHp`]9O"F`dZaHRCX67=a=*_WHp3"%jP=6,qg*tc?Y"2Us$P*A.<QQECTd[R-+@V^sbncjsM7<d!1$Skn_S4Q"<\;iAHSF0-sA-K7G\6_V15m#e:q-,XV<(\]DWcfi^1?-m!(*YTp,$R=O,fP&62b<@uZ1h9$^iUO1p;V0Wqf^;80V@DR'lLCW(/MnFs)W*0P(J<<[bd\XpmR@LPK^+i#2'9+m*!AGD,26K+7<6\>b0EDM?_;9(7dh/nIE(QKS*-qkSZl%4e,RFX1'#:fha%(n$D1-dsMbE.!s$)oTS<'1@BK`9QA>)qdRi,Kl]88BAX%S:e%N_BKT69=\.`uY:EUNb4pnj$2fNj3F:nf9Mq@7_(_^5JN`"+_eVrr)57Ma%N#5UJ>*kHinbBZ3f]VQ&k-92A+IpN%-=_ketZA8eSm62Q?PXf/kNmUi)jURE#glU'E*[M=r6Aa[2S;46dEQ7>0DlYg$)qa$T4=bcW485H,$q#jOn)9X@Rnf<LC@/uD`+pQNaZ,K4!QCPqXE"Q]o'+>S7f(Xd#c4.-cM1hnioa:nc1VX#*[pC^,8hQ9<QYH"LFa;&7YLH&RTk&Hldl<4d`u9pI`5(03s0_lfXm5n_<(k?#D9d3Bp5GN\a1R%.A2*MGBH?ed8<W8dmqu!>iN,L[MBF7ZERM;E]3?#SZ(I6%F'p1acU,JoXPFmb8(3"pJZVT=Tn`VTjW6%l*f;M47V@q8\Y.`lIusA>Q2Q@UYL<'PYn=`,)kbMlD(S:E"hI9/.=+!5A[ghl^.+eZ^\a'k$R,E2W$N`HTp>VKka-N>cKNh#TiISJ>0lIBsrse=cCTD_cgT=0[Tp7;O@prm]K=@Fks?@>W1Y[F*-0*c%qT-@:<pOPV>PR,"sO\8cbBb(KNnVO*3/])a"4h6KO^V=D*08%#lfC_8JE*mu<"<2.:b`]Z+@u2QPuiD+.?<!#27RdKC-0%$D%B%"uEM+tns'b8d_5-E>/9TagqMpl?$kQ;U;,?1$g<Lj@Tj:'?c`Y*A>0P\[H"7tR4A]X)dE]'m6nR7c^ccVB$S=.\kbenM+Ga*$oEl8.,&3EH8=P%'GnQU@`uRcuHjV)";Tf'Y\Em6upA0H_$<0r%#Obebona<FG(.gdUM5\)XgMD7(5?t(Q51'?X?J&-l,n<+?HTA+?u%o(]@"Kh2dPhfn.4J68;</;sWIV/#e!cCS`OfJdGRFKuXDf2`,AsCN\$I+-$rsH)Kc1"u*[>$f>`7AKfR@DKpLt+uU3=2Z=2_e#f`6,D")(TSUgE?h7<9I3UN&)7]JZ[A(=*.$cX02ZGQ^r3LS`b3-aS;)k.Q#\5!sUU2A29%.!>+(0*q$Suk.<9XhRd&*OO$rO2E/pb9QCS'q'^']`nMDpA;R2"elq<<.hip,18BTgX_=II/D'Oe=N_!C+M!@k&,2MClJhtE5'k$,?9NQd8:r5=gSmAZhIaJ#I7mGtJUgE+0m5N<kV+Ce\XX^:AZ&Mt@8f[%ZmN*nc(cYK@$*uTdME*EL,?1S-/=[k,0[L[FiEJ1l`TQW=%%>u3\L\(ME@t"VeUK7GEX>KBa(oj9=)jSS?ldnX1@T,")YL=ALafOesJj6QaN2-gMudaFK%SWguQgM::/diCtfCRZrg"+E**O,D`,"/1q$9!'5!b(/@?%+o.V6j2TGiq[/nr:!+^.!KFKi/Q\DY\[5_EM1.'HdK,E#Y!6!ebK^]0Q<(+Ys0WU?NVQ<Er,:&tug`oOt?qDKbeuEji6a]"AhW)+0?ZdNn9ju(,6p@F(!0BbpmmH*Q3+_<h-[AsKaEB:mNC6/3MFJd(Z32@JRhDB'<+LQq.^,2amEm(!EZX7]quK/%f57<7DXmXLVNG5M';.lM9aIq&2;9I8%qqAl-'o9ui>ksEoaO32KEZs"ZB\s`Q>2Yf<V&.sQe/>BQU>5-PtZs;*M@%dnsbI:b`YX6=+J.%Lk??*#E()c==EN$^K].uPAaf<dg/&;o0C`g-[@0Z/KiL"-=)!;hX*_iq:RA(%E]$B=Z<?.Z!&Yp'Nir=Ut]TA;bK^k'U#1Y`2$<]Ue1eMBV:t7cmX)DE-e!m5Fh4<e'`G$'0j(8"8-JDrat2nHuMWt)Kp"-OJ+IjfY2@s/ck9GU.+RCf>)&12O!!-Af7/k!o]kJSg&_0GId+pR]e#]Lk_Z*MBSF,a1$M7TMFDNEs:TOLfi4A:$2M3'PqIXO(JKEjOs-6hr=0bF*3^Gn%?oRk+:3-a;mNc]C/U(E?S0d'SA.l'SS:<9,:PCM,7jk0D#ijH@`TUmk2fuO:TIHb"@<D$P:0/i2K+A1sY=C_?E6K9.1XqbW#t7WaJC4d/pc!K0.Eq)#_Sh[LOskj$hO42062&2hA2Lir+%BLEcemE\rBq#\8ZD%?g"Qi0L^>G0\i#%3uUd*%P0GOu@)5Wd9Fp.%:KZ#tc1LBGj>LEF*m;Vdq+d-n=8*/O9T7nBF"EbX%u($63?;7nP?COQ=JsQ.Vbr$o]^K2kaWQ15J87H"XC8<9t?]1BBLd\\@#L<#(-/'8RXlm>p(3YL)rn:7;k3U^/]9erJKDWrE)>f]aRo_$ng93lCZE!bG=Oe%Aif=D#?;?pnBjDO3nVlM#N(DRao<&$ZO3B][.A72kJb\!CMrTs30*JsBG7:A!1I*P+qq+cd-tU[=)]#TFt=(p5G2HD?W9*JnRN(cJkQUDrTObqN^FLFe_lN"m9tc;$aeg-b92pa24T9TJ4Zj@0Hl^foo@n3%$`@q0lXQ=7V,)hG!fK"<+X'#f%LaD`+>Qn`C^<GI+FFTuA40Sge=[YGIPf:cIGfiOABk@Th4l!1ma;8KN"1+d&#ECt7f[90BU9W:Ga+A6+Z=aiH<IkhKD^I>L%$WGP4km:e-V$@n,&*HMRAlLjGq@I#,*rc\T_'EkVLU;[>0o25<_ZD]Q#L6q:Euj)WR.:o.^q"Klk1b1'2!Y5VBd0/$>-[V#3YWFJ6%D6.Q>2c+)h;6L+fhDL&(Bb-G/J=">_/Q?I9\&Pn.3Pn!bm4_p13qQ.)n[J`RIR)fe,-t6_sl]m9i)hrFp9#R<RV^F>*;R*Z`fJHC?'DC/BO.IYCsp,\l$LdH#'24GojZKCVe3`&c?.etDp$m4g:IVjNnj3?Kg8*bU=jg?hkHQUb(33l5i$LrMf?UH,rkRr"4m'<TG6:oE&K@`QYX_p(o$/+:Gr8hi4HXf]"-2nPGV9Sb<Hh%[?<@#K,cfQTDeD?(^4ih^aFH9)\#6O5Y5&BmoT>SaqhZuF(r,!CQTMFG,n=eL1<FH\DTOMON"[[H+[M;tXjU)R\J3Q>Yr#1S@-X#dLnCIRQF>"6W9#H4St2JVKkMk3jc=S<@h8H.k19V[s5RA@Y(,e3$tJ12Fq_\c&X#CaW+_CidP-;:D/V+4K@a'6@(Q;enF@CBiN6A-P_]k!Ki*P%Z!_Jp-?M#oC4kQ:fl$40QVBpih'+5NTl;kr\Qn0&pHJ`"$(e_ENPGnN\hbYquG)<+WTd$"L;/DO/!:^@B)d7mS^3ooP2oAT'f`q>EI(T1Zq,13bEh82j1PT/_qXqrF;+ZPA`<YTSA8N=rpB51n_#;&,O@g(3b;HupmJ55VBPVo@8f&TB+3WkDb(gqq\`0$GK1(YTr_$4-'iD!MhD'IaPAF/_l-t4-oE&'=.<n\B"[3U\Z/_i%=+f>GiFH\EfX#-jE.l-5/G@i`s$Q4Fsgc@,L:j3[eCjF5OiSBT]PV1@pZ7d=^>gJnBg?j58e4[@'B;Wcb;tlVgTp%Ej/K6qU4JtTX_jAMeVW"4!*#S_^$EHft-V@'WG')U,=dpUei,*6r`O_JYq*lVh,30q?;3*%16t8mD0W\Aa2A[RQ@E+CK.Von0_7jBtD$"kOj;1PS.!+"!bo74a<@0:!C6FaL>c<h%<0h5/9,loJ=?_S*I;p8YJ]gZ#;e=Od6&rH=#!cQQ`M'+18gH731#nudA5qZ@iR5$'Or3f-f3TtLktEg:,>Z#o*hM<LrLPh.WJs8JhfN@a4:pLN)hut"U7Tm41+`2^EZ92j".]aYmH8/`AeCmoAh9l;g;U$j)W$-1"1%>ScL1G]%o*1c!gW'=Dh+WEB+dnihi@<\dR<ib0r2sJBX2#)*#/[2c!fQ]X'EX+T![:hX*h&rRUP$WTgjg,$&=gV<#uFL>\f%i_?5EX?'rhb<?OS0b>_rjL=4#l%;\s3.MR\9Lo1@c'@:-#CWA/H2Z]]Y$O%oX.%=:cPZMqK5d"Q0%MDtID6e6L7&7?Tf#IdCV%)l<$C6'_,Uh7/C2@6h'&sfL:tg&3i;82Fq-)VNQJR^(0p.(R:D8NC(>"l)1iks[Ad*iC79q\ulI+/MMO"W?;ZhXW14\%IfFk"oP)eg"UYluf>pbNZj&p!4lcn.NRX-g;dEU)j7tI"Qd[P8F+u$mP9H[d$&H\+jS3fFR[_8RZ9"6>%(*]$oQlRYn>1OIbPo:#%GGWJ(7[`JQN/$`EZ2uYb%KeXFOg@J:X]Ql1'ri7YB[9h:N,AcX_[QhZ&fV&OM+BQSViNG-6\D?Xc$nr>9AM\h%`u6AJ-/;>/WaZ6^c=h<<T_ZPM3Ljs?%IXa=t/5o:-0)UY2Or#.,;%^7Qk&Q2Io'q(i"^,\F0NBYQi80E"Fr27P@Wm,"ra(O<'n-0uEAf"d9.l6K)tsN'bC"/ek//\4hqKPArmA+I[mu)23XOZ#_,QNepf9qS$I((I*0[TYoA>BnoQ=RZ0c>(FSV8*>cc'G<Vd*oA5.NKL-dg@4$Mdi;cZGQV@Ip2I6DnA(qk:ZQT$7=a^'#h0(HJ2*c)r!sW)#1<K:tr/Z[J*L_/o78_r1k9:<KHU$?;rjsVFS_3#4%McOnLIYbk5pj:6OOt9$!;77<R<I6e"/^BaOMY*S`o:HDm<[7DabRT9&j;Bd)pm%2.`/G;1\NN2g(n:Bo=VYZEL`[?c#)n&O'bT0G7f/"0N61N9k96S#]`b76c-<]C(CSt'/8HdcQgI7]mU>jgu9=m:6TXPVk%QZ,E*"+F21?H\d7]V-AHG8kVeoa;>bnPT_^".[j6m5bCmr.6b"urG)%l3*q8pF0a`c56;M5mliK96n]<q4BcYiW.9&t2@#P:d`#g5a]SBo4W#c"205>nP)+@/c3(4O=5@;(j%b"NGS/@]8"%4:d?*^A(>pG60gF5gT8ID2E)6AeJO\iqSY<6sjQ9Z?bKP#A"0N1BBP#)StB_DEWAe1)IS)9dC4Rk$CS@"jClP([fe7V\i#Bhe6&gTdp%R3.r9<YVrNe2OD*1>F1OWeSArB$;R=KHd]Le3AAh*!Y9%>LghPJQ5Oi0c]K3;*QPW)+N@D%QE1Oq=q5Tjm43`4ZQtMaL$59OV15Hk\q8A5F+.&#Z2RWG?NT$Pa6N@>5V\N'A7n6K-m+_X?A5YW;f6&7.rs!f3itX6)qU&B(gY0+oK"@T]#@Y/s##8op)k9)KI*Rr.G-&JZmSRB-^h'J7!T)NiMU]IT^E'2Slu6jW5%M8@ok":B@s63lE*Yi\8<?N!J&$'68'F\?*WkLB3P+[_pql`)'Cc_ge)7;r;42;="%KD]2u!X'YD*0YGM_q"95p6[XBAtL1$G3;5KmF:of^5'!7N'2'%kiF(U_J6$;QZ5$>>#r'hH0:35RZAK$Y"a_a<2=Yk0ki1I(aV##;'^\.-7MoFaOgn,dhX&s(f&P1CF+!."JGh<A))Ej[UNbK^TO":]V5j0`hmOXZb9m3!ni.%[c;]33d.^Jo6"62,(DKg,c$k=?&*X1du]!r%1%?O,5@U[TMgHk]hcQ*>FP`SB\5(rh.(CsQ,6n+iR3,"/7QUeSn;*J.YXLR$kEinY_q-.U-sGI=t8lp9H4@ne0OBa4(io,Uk21PIFAOlYY?k:5^'OJG[baM#GJ5B2T&?17PT<N'SQg,[Q6/f,=(:q9bfEL=t#0"M)J<rZn`5L5T#U3mDI,<*=Pt0(/%ZSf_Y>]:uEMc!t@H@J^"`EUF:Z;U/`L-<6Zc:g+sY#M&(Y7!eIq>fN3:157ZOGj6?=/p@S('k\lZjP@:ebV2qOBm/gcWR8HAP%Fmk0(7ZkD<<[Hr4#t^_ifrdtK@CCR5#;hA69rF#&qfh?lj)qPHpSL`HPE0&5^A`ISV&8^qI+JqeXA0dj*4Ij3$)CknbB[KRrd;-7TF]k<KsiVEO5>lcC\qo>J(h4_7H+-2^Xb=#PI$6GdlsR>dX7<-:U<RG&nm40npSN2blXW#gj)*jJ.YOQF'Hl+"D$(2TMa2a8)-[U:<-%lT!ip8/b!&L2V-;k8%49RrgX<mLIuS)H<lU;M#O]NNFX6,@u@g?ADjX66B^HlXKZ-?HI0+.'+;,hOJtIG_1'Wh#lj.]6ai4kT=rt:Nu8(UFk/CKL`q'fcnkW%YQ\R\dBSo4@7,?!Pr,-&pa3`431q=*QImGh*BMi/c'J`9bM:Zf#'n+>3&-W)4ChuUe1i(@g.3=f\G.6KHcC7oj);uZ%e&G;t)_kBf7/'\RgR%D2+]$5[/4)<Y'\,M=:,4n(q-`rBF$Z3s.>qGnEbGmk#%4VrT5X3X;ldifOuRnpWms@XOe3?,-Kn#1/SX655Vk2V8IoCKb87aMe1do/p-W_^9oU-"Ybq+dgZE@4m.G-?<#j"!o]*_D0JHUjfkIOS&cu#!/L_'YpI[bl8-^A]*-YQ^A[T:Z`0c]@?<>8&7ReaqUNQ66ns\,=><0&8\5`s#]K&mQ`mr'5(^1$&=SQP`dFu+cqNeW?=cE&O%XO4"hc\GUNJm1nLi>/ulU"D=HFT'D\P2cL'/&`K!o$10,>RFrH3;qG2!`J2mb6*J4-$;uE_Pi#X;'r7F%PYLN@B#Cp4N=m$<3e-cupYGHdBd>-)N0`I)-'CUA55dJA4BQ9g"J8Sur2=mhc^WaaC)=`Y+3\b2:/28n#,6916_[))E#Wr&V9]On$G#CMCAns6n!C[Q;M>\fXC^VWL+kR+GpPg7mW[N6l>#7gW.8=iVWXMRa)CU8P`%WmqJVmmcdL%.o'Dj(V@1;,^S."F4+!3"^Dp\d@LX"sB*IE3.;b[At<2\_FcuNYTjiGl=Ul^`_PE81)6REB]#F:?L>t"P+09^shfCAq<=5El$+o-7tjmuN>d([4.B#Y,18X>TSdRt3[?`pCD2V[W"cRt=]\TCOtR_>hP)Y5iPJQ2uL*Cq%MR@"MG$2MK9@@h1)5^r'',&F(/NEWNH=P2,-(:B&H75JDM>"uH@9oU[$%5R_1_Q6)IMGYWc!?sc2bNV@tc_QMu9a35sk`e86JEZHc(a\Fi$IF2%MW#kKEsi7?JsT:JS44-gnd1J1q1qEr#36WBo9qpi.m+FK0[A>%9'4d#;++B"@D7pCAqHpU,%M&]8Jkm)P8RtaUJ:euR;8t2`)0[,Y-RAiX#2Z^dqttOAW7/TCNTe[TkQ?jeMWUC[+NK2e66W>>FIE`;RO\R:fn#DE"#2;<A9)6,/[j)%7Z/1?eHeO=<*KN&G5qUO/Xis.dqn_'+Gj-9ndY-1(Mb`$>dUJ-FnVY8EkD?M:FH0b]%B@$8d>&n@H6.TGm@/`Ph[*X/Tsd.K/A.-0U:i2&iOqm%.][YRJ6Yh04P%Q2A3V)4=-lYS]Or;3_V&2c3aepAH2ae$1rGB!H.D2]\7j&V=a_CRkBMWq89<)VrXTGi&LmXh0<bf9jLaJYYii`?thB9KFAW!q7@:D*VJ\;d4ttr4mEiT(ihQ4&dfJJ[Fa\0USZt-KK3Oh[TZXQ2Q""r9J^.U*.>n$pJ?G/8;*2KkMhF$*XtoCAkbK2JAr^f?\jl\[es*SJ3&h^k?n%m]mWQmLS(:#]Vh\`>u:U25@?hY@kalGR*?,_C2(^rQVn^^:-rb<Ygq.AdcNF_26X)o"X52\j%.)V4ApQ!j)\d.G<(b&\KtALnZZ"6'.LbR5@\$_7+YTpIk(ZVEel3fAL'5&E73*bd$_]mPd$m/^"![m?eRrZY!s2elM6&j2i,mI#/]JAk5/_J+N>_h<k4As'PO#QiCFlf`1^GL\sC7I/g8EI\6MIs5Wa$qu=S4s763)p4(]oq]l)Inc-f409?)smf12es,[0Jr`=U0s"F?njo/WKs7^I-IPtU0#_E<Y#o!&rIs:MmL?l>5%0'_>C06Ss_#3JINmt_>;%^*+]5JeAS-GQ9b]4`>/oCPpHt?"NTo\GC)8YfPX4YT^G7frm;R?m1Y+lSY@"AP!r^>]`OHN1Rl!''5J?A40$Qmh>o%^G6`LHmud;4q4HVV6#.A8f@Y_<%$TaA.qV"d$c*en=(QpqKmB2*/8&QQi4#$kt'jCqf;2VT3kQ.i%&n:&^L^,At\/BIrPljP&V<7ChBqa+ZS-2V76)[M\a5lrhG?)@ji_]P2L@(m(gM#Y[/Je_[/ep6#"R&KB3@GcLU^X9KfL`.?;>La_dFaB7kHr=%Om%`O<2h_UWfQ4amWc\7ueB0\X#c^Di(ta>mC,chD,@g<J2%pB<.Y;@[L2t&5bZV:X!4E,[(c?nFnAIQ;f+:fp,^^jKa?h"1&GDSH,Bgtr5U9i3C]E->Xe;<b!MYd"#"5JT>A=eUMTrN^hZ3NWg\RmNrcb!I"kTrhe*]6c]rmjp<g@tt5hi&@@_5XF=2YO!mhuE+AiAfKmc*>`<7jRChf#oS]g;[OBR:_:Qcp&9RWO<L1U3th?'6*n"//FCN>c?@=j5CLioB"bUP?)tg_sK,eLhYRL2qABc6G'<2FaVfbLmm9^&<4kB6tF=Y`Cd$6A(+Ai>clQ*+8rE+pA5i$6:;I(",("FM5Kti7okQ"J>'K-*V&X,"=PKg]V:^6^TXA)Ve*rX5E.4isp?PNZZ$MagcSU7:p?=;IKZHF@6'G-rPr@#XL4DYTYP!6jdo#\-IPCMA2acN[+R%;nki0!<7;<5ED1X`"4XO*CsOdl-&Sk!5>K8O"R;3!*Xj0qIOG&5d/6PjV.TqPQR0`J[E$V<,6FP$Ad%]ai7?IW7HL#P;*tf^QnEO5Q$T>ebcXfa<q&&/:ZdmHpXR2`dAW")K[ZGrll1;&,WINm/Ja8RK$c(MdmU0=BhuUkP-a!VLQ<P^D*1:b-_RJj3[OlW=djoAEW`Rs2$Ru.0!j"k8\\`41_kZNJNN-B[LmIVP?l3(ZBW!aQo=#aP#%Ql0AJ%e?lZ^!FM?>hfg?<<)L<J*dbJBh=f_`qA3N+?fD%R?bgIIT>"\'Dom>jL5JEpr[2[9B]8\a)mY_dUE0&Bn4*3%gs36G'"HohHeg8;U+hQZ&H"_=%"Cde6i2Ki#QMcuO\QT93P\61!!
+# ===>END WOOF<===
--- a/wscript Thu Jul 19 13:17:35 2007 +0200
+++ b/wscript Fri Sep 28 11:59:46 2007 +0100
@@ -1,13 +1,14 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import os
import sys
import shlex
import shutil
+import types
+import optparse
+import os.path
import Params
import Object
import pproc as subprocess
-import optparse
Params.g_autoconfig = 1
@@ -19,9 +20,9 @@
srcdir = '.'
blddir = 'build'
-def dist_hook(srcdir, blddir):
- shutil.rmtree("doc/html")
- shutil.rmtree("doc/latex")
+def dist_hook():
+ shutil.rmtree("doc/html", True)
+ shutil.rmtree("doc/latex", True)
def set_options(opt):
@@ -36,7 +37,7 @@
opt.add_option('-d', '--debug-level',
action='callback',
- type=str, dest='debug_level', default='debug',
+ type="string", dest='debug_level', default='ultradebug',
help=('Specify the debug level, does nothing if CFLAGS is set'
' in the environment. [Allowed Values: debug, optimized].'
' WARNING: this option only has effect '
@@ -65,8 +66,14 @@
dest='doxygen')
opt.add_option('--run',
- help=('Run a locally built program'),
+ help=('Run a locally built program; argument can be a program name,'
+ ' or a command starting with the program name.'),
type="string", default='', dest='run')
+ opt.add_option('--command-template',
+ help=('Template of the command used to run the program given by --run;'
+ ' 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('--shell',
help=('Run a shell with an environment suitably modified to run locally built programs'),
@@ -78,8 +85,7 @@
def configure(conf):
- if not conf.check_tool('compiler_cxx'):
- Params.fatal("No suitable compiler found")
+ conf.check_tool('compiler_cxx')
# create the second environment, set the variant and set its name
variant_env = conf.env.copy()
@@ -89,6 +95,8 @@
else:
variant_name = debug_level
+ variant_env['INCLUDEDIR'] = os.path.join(variant_env['PREFIX'], 'include')
+
if Params.g_options.enable_gcov:
variant_name += '-gcov'
variant_env.append_value('CCFLAGS', '-fprofile-arcs')
@@ -105,12 +113,30 @@
variant_env.append_value('CXXDEFINES', 'RUN_SELF_TESTS')
- if os.path.basename(conf.env['CXX']).startswith("g++"):
- variant_env.append_value('CXXFLAGS', ['-Wall', '-Werror'])
+ if (os.path.basename(conf.env['CXX']).startswith("g++")
+ and 'CXXFLAGS' not in os.environ):
+ variant_env.append_value('CXXFLAGS', ['-Werror'])
if 'debug' in Params.g_options.debug_level.lower():
variant_env.append_value('CXXDEFINES', 'NS3_DEBUG_ENABLE')
variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
+ variant_env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE')
+
+ ## In optimized builds we still want debugging symbols, e.g. for
+ ## profiling, and at least partially usable stack traces.
+ if ('optimized' in Params.g_options.debug_level.lower()
+ and 'CXXFLAGS' not in os.environ):
+ for flag in variant_env['CXXFLAGS_DEBUG']:
+ ## this probably doesn't work for MSVC
+ if flag.startswith('-g'):
+ variant_env.append_value('CXXFLAGS', flag)
+
+ ## in optimized builds, replace -O2 with -O3
+ if 'optimized' in Params.g_options.debug_level.lower():
+ lst = variant_env['CXXFLAGS']
+ for i, flag in enumerate(lst):
+ if flag == '-O2':
+ lst[i] = '-O3'
if sys.platform == 'win32':
if os.path.basename(conf.env['CXX']).startswith("g++"):
@@ -119,22 +145,43 @@
conf.sub_config('src')
+def create_ns3_program(bld, name, dependencies=('simulator',)):
+ program = bld.create_obj('cpp', 'program')
+ program.name = name
+ program.target = program.name
+ program.uselib_local = 'ns3'
+ return program
+
+
def build(bld):
+ print "Entering directory `%s/build'" % Params.g_build.m_curdirnode.abspath()
+ Params.g_cwd_launch = Params.g_build.m_curdirnode.abspath()
+
+ bld.create_ns3_program = types.MethodType(create_ns3_program, bld)
+
variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT']
variant_env = bld.env_of_name(variant_name)
bld.m_allenvs['default'] = variant_env # switch to the active variant
- if Params.g_options.run:
- run_program(Params.g_options.run)
- return
- elif Params.g_options.shell:
+ if Params.g_options.shell:
run_shell()
- return
+ raise SystemExit(0)
+
+ if Params.g_options.doxygen:
+ doxygen()
+ raise SystemExit(0)
+
+ check_shell()
# process subfolders from here
bld.add_subdirs('src')
- bld.add_subdirs('samples utils examples')
+ bld.add_subdirs('samples utils examples tutorial')
+ ## Create a single ns3 library containing all modules
+ lib = bld.create_obj('cpp', 'shlib')
+ lib.name = 'ns3'
+ lib.target = 'ns3'
+ lib.add_objects = list(bld.env_of_name('default')['NS3_MODULES'])
def shutdown():
#import UnitTest
@@ -151,64 +198,127 @@
if Params.g_options.lcov_report:
lcov_report()
- if Params.g_options.doxygen:
- doxygen()
+ if Params.g_options.run:
+ run_program(Params.g_options.run, Params.g_options.command_template)
+ raise SystemExit(0)
+
+ if Params.g_options.command_template:
+ Params.fatal("Option --command-template requires the option --run to be given")
-def _find_program(program_name):
+def _find_program(program_name, env):
+ launch_dir = os.path.abspath(Params.g_cwd_launch)
+ found_programs = []
for obj in Object.g_allobjs:
+ if obj.m_type != 'program' or not obj.target:
+ continue
+
+ ## filter out programs not in the subtree starting at the launch dir
+ if not (obj.path.abspath().startswith(launch_dir)
+ or obj.path.abspath(env).startswith(launch_dir)):
+ continue
+
+ found_programs.append(obj.target)
if obj.target == program_name:
return obj
- raise ValueError("progam '%s' not found" % (program_name,))
+ raise ValueError("program '%s' not found; available programs are: %r"
+ % (program_name, found_programs))
-def _run_argv(argv):
+def _run_argv(argv, os_env=None):
env = Params.g_build.env_of_name('default')
if sys.platform == 'linux2':
pathvar = 'LD_LIBRARY_PATH'
- pathsep = ':'
elif sys.platform == 'darwin':
pathvar = 'DYLD_LIBRARY_PATH'
- pathsep = ':'
elif sys.platform == 'win32':
pathvar = 'PATH'
- pathsep = ';'
elif sys.platform == 'cygwin':
pathvar = 'PATH'
- pathsep = ':'
else:
Params.warning(("Don't know how to configure "
"dynamic library path for the platform '%s'") % (sys.platform,))
pathvar = None
- pathsep = None
- os_env = dict(os.environ)
+ proc_env = dict(os.environ)
+ if os_env is not None:
+ proc_env.update(os_env)
+
if pathvar is not None:
- if pathvar in os_env:
- os_env[pathvar] = pathsep.join([os_env[pathvar]] + list(env['NS3_MODULE_PATH']))
+ if pathvar in proc_env:
+ proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']) + [proc_env[pathvar]])
else:
- os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH']))
+ proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']))
- retval = subprocess.Popen(argv, env=os_env).wait()
+ retval = subprocess.Popen(argv, env=proc_env).wait()
if retval:
- raise SystemExit(retval)
+ Params.fatal("Command %s exited with code %i" % (argv, retval))
-def run_program(program_string):
+def run_program(program_string, command_template=None):
+ """
+ if command_template is not None, then program_string == program
+ name and argv is given by command_template with %s replaced by the
+ full path to the program. Else, program_string is interpreted as
+ a shell command with first name being the program name.
+ """
env = Params.g_build.env_of_name('default')
- argv = shlex.split(program_string)
- program_name = argv[0]
+
+ if command_template is None:
+ argv = shlex.split(program_string)
+ program_name = argv[0]
+
+ try:
+ program_obj = _find_program(program_name, env)
+ except ValueError, ex:
+ Params.fatal(str(ex))
+
+ try:
+ program_node, = program_obj.m_linktask.m_outputs
+ except AttributeError:
+ Params.fatal("%s does not appear to be a program" % (program_name,))
+
+ execvec = [program_node.abspath(env)] + argv[1:]
+ else:
+
+ program_name = program_string
+ try:
+ program_obj = _find_program(program_name, env)
+ except ValueError, ex:
+ Params.fatal(str(ex))
+ try:
+ program_node, = program_obj.m_linktask.m_outputs
+ except AttributeError:
+ Params.fatal("%s does not appear to be a program" % (program_name,))
+
+ execvec = shlex.split(command_template % (program_node.abspath(env),))
+
+
+ former_cwd = os.getcwd()
+ os.chdir(Params.g_cwd_launch)
try:
- program_obj = _find_program(program_name)
- except ValueError:
- Params.fatal("progam '%s' not found" % (program_name,))
+ retval = _run_argv(execvec)
+ finally:
+ os.chdir(former_cwd)
+
+ return retval
- try:
- program_node, = program_obj.m_linktask.m_outputs
- except AttributeError:
- Params.fatal("%s does not appear to be a program" % (program_name,))
-
- execvec = [program_node.abspath(env)] + argv[1:]
- return _run_argv(execvec)
+def check_shell():
+ if 'NS3_MODULE_PATH' not in os.environ:
+ return
+ env = Params.g_build.env_of_name('default')
+ correct_modpath = os.pathsep.join(env['NS3_MODULE_PATH'])
+ found_modpath = os.environ['NS3_MODULE_PATH']
+ if found_modpath != correct_modpath:
+ msg = ("Detected shell (waf --shell) with incorrect configuration\n"
+ "=========================================================\n"
+ "Possible reasons for this problem:\n"
+ " 1. You switched to another ns-3 tree from inside this shell\n"
+ " 2. You switched ns-3 debug level (waf configure --debug)\n"
+ " 3. You modified the list of built ns-3 modules\n"
+ "You should correct this situation before running any program. Possible solutions:\n"
+ " 1. Exit this shell, and start a new one\n"
+ " 2. Run a new nested shell")
+ Params.fatal(msg)
def run_shell():
@@ -216,7 +326,9 @@
shell = os.environ.get("COMSPEC", "cmd.exe")
else:
shell = os.environ.get("SHELL", "/bin/sh")
- _run_argv([shell])
+
+ env = Params.g_build.env_of_name('default')
+ _run_argv([shell], {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])})
def doxygen():