--- a/.hgtags Fri May 30 15:31:50 2008 -0400
+++ b/.hgtags Wed Jun 04 17:19:32 2008 -0400
@@ -12,3 +12,4 @@
b5bf2588cde2f1273b1095cc5c83a0c272e55370 release ns-3.0.10
ee5e1da76ecc52337f097cd90ebb50a3d49ec541 release-3.0.11
b17f2928291eec5bf5b1c59a4a5fd583f704ac40 release ns-3.0.12
+79dba133b5f8a2d6f6f678a22e8519bc155e6a4e release ns-3.0.13
--- a/RELEASE_NOTES Fri May 30 15:31:50 2008 -0400
+++ b/RELEASE_NOTES Wed Jun 04 17:19:32 2008 -0400
@@ -3,6 +3,26 @@
This file contains ns-3 release notes (most recent releases first).
+Release 3.0.13 (2008/06/02)
+========================
+- point to point links generate ppp pcap traces
+- point to point links support asymmetrical data rates.
+- generate doxygen documentation for all attributes and trace sources
+- add ConfigStore and GtkConfigStore to contrib module
+- socket API now support tx and rx buffers: implemented for UDP and TCP
+- ARP cache now supports per-entry pending queues
+- lots of bugfixes and implementation and API cleanups
+
+Warning: among API changes in this release, Application::Start and
+Application::Stop now interprets the time argument as a relative
+instead of absolute simulation time, to align with how Simulator::Schedule
+behaves. Any code that calls these APIs in the middle of the simulation
+will need to be adapted.
+
+The API of Simulator::StopAt (time) has also changed. Now it is
+called Simulator::Stop (time), and takes a relative time, instead of
+absolute.
+
Release 3.0.12 (2008/04/07)
========================
- Add Attribute support to the TypeId metadata system and add
--- a/VERSION Fri May 30 15:31:50 2008 -0400
+++ b/VERSION Wed Jun 04 17:19:32 2008 -0400
@@ -1,1 +1,1 @@
-3.0.12
+3.0.13
--- a/doc/modules Fri May 30 15:31:50 2008 -0400
+++ b/doc/modules Wed Jun 04 17:19:32 2008 -0400
@@ -13,7 +13,7 @@
* - a Functor class: ns3::Callback
* - an os-independent interface to get access to the elapsed wall clock time: ns3::SystemWallClockMs
* - a class to register regression tests with the test manager: ns3::Test and ns3::TestManager
- * - debugging facilities: \ref logging, \ref assert, \ref error
+ * - debugging facilities: \ref logging, \ref assert
* - \ref randomvariable
* - a base class for objects which need to support per-instance "attributes" and
* trace sources: ns3::ObjectBase
@@ -24,7 +24,7 @@
* in a simulation: ns3::Config.
*
* @defgroup common Common
- * The "core" module contains:
+ * The "common" 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
@@ -62,4 +62,4 @@
* @brief Constants you can change
*
* @defgroup contrib Contrib
- */
\ No newline at end of file
+ */
--- a/doc/release_steps.txt Fri May 30 15:31:50 2008 -0400
+++ b/doc/release_steps.txt Wed Jun 04 17:19:32 2008 -0400
@@ -6,7 +6,7 @@
- revise and check in RELEASE_NOTES
- update and check in VERSION to the latest release number
- confirm that Doxygen builds cleanly and without warnings
- (./waf --doxygen), and check in any necessary changes
+ (./waf check; ./waf --doxygen), and check in any necessary changes
2. ./waf configure; ./waf dist
- this will create a ns-3.0.x.tar.bz2 tarball
- this will also create a ns-3.0.x-ref-traces.tar.bz2 tarball
@@ -23,7 +23,7 @@
6. Run the regression tests on the new release and update the reference traces
- ./waf --regression
- ./waf --valgrind --regression (for valgrind version)
- - There should be no regressions at this time
+ - There should be no regression errors at this time
- tag ns-3-dev-ref-traces with "release ns-3.0.X"
hg tag "release ns-3.0.x"
hg push
--- a/doc/tutorial/Makefile Fri May 30 15:31:50 2008 -0400
+++ b/doc/tutorial/Makefile Wed Jun 04 17:19:32 2008 -0400
@@ -2,13 +2,21 @@
TEXI2PDF = texi2dvi --pdf
EPSTOPDF = epstopdf
TGIF = tgif
+DIA = dia
CONVERT = convert
CSS = --css-include=tutorial.css
SPLIT = --split section
-TGIF_SOURCES = helpers.obj
+DIA_SOURCES = buffer.dia pp.dia dumbbell.dia star.dia sockets-overview.dia
+TGIF_SOURCES = packet.obj helpers.obj
+
+DIA_EPS = ${DIA_SOURCES:.dia=.eps}
+DIA_PNG = ${DIA_SOURCES:.dia=.png}
+DIA_PDF = ${DIA_SOURCES:.dia=.pdf}
+
TGIF_EPS = ${TGIF_SOURCES:.obj=.eps}
-TGIF_PNG = ${TGIF_SOURCES:.obj=.eps}
+TGIF_PNG = ${TGIF_SOURCES:.obj=.png}
+TGIF_PDF = ${TGIF_SOURCES:.obj=.pdf}
all: images html split-html pdf
@@ -17,8 +25,11 @@
# buffer may be needed (xorg-x11-server-Xvfb) to provide a "fake"
# display
images:
+ cd figures/; $(DIA) -t png $(DIA_SOURCES)
+ cd figures/; $(DIA) -t eps $(DIA_SOURCES)
+ cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);)
+ cd figures/; $(TGIF) -print -png $(TGIF_SOURCES)
cd figures/; $(TGIF) -print -eps $(TGIF_SOURCES)
- cd figures/; $(TGIF) -print -png $(TGIF_SOURCES)
cd figures/; $(foreach FILE,$(TGIF_EPS),$(EPSTOPDF) $(FILE);)
html: images
@@ -30,5 +41,9 @@
pdf: images
$(TEXI2PDF) tutorial.texi
-clean:
+figures-clean:
+ cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF)
+ cd figures/; rm -rf $(TGIF_EPS); rm -rf $(TGIF_PNG); rm -rf $(TGIF_PDF)
+
+clean: figures-clean
rm -rf tutorial.aux tutorial.cp tutorial.cps tutorial.fn tutorial.ky tutorial.pg tutorial.tp tutorial.vr tutorial.toc tutorial.log tutorial.pdf tutorial.html tutorial/
Binary file doc/tutorial/dumbbell.png has changed
--- a/doc/tutorial/figures/README Fri May 30 15:31:50 2008 -0400
+++ b/doc/tutorial/figures/README Wed Jun 04 17:19:32 2008 -0400
@@ -1,8 +1,17 @@
Please write image files in a vector graphics format, when possible, and
generate the .png and .pdf versions on the fly (see ../Makefile).
-Recommended tools are dia, tgif, and xfig. Store the .dia, .obj, or .fig
-versions in mercurial, but not the .png or .pdfs.
+Currently supported tools are dia and tgif. xfig could be added similarly
+if someone wants to add it. The main requirement for adding another format
+is that the tool to edit it is freely available and that a cron script can
+autogenerate the pdf and png from the figure source.
+
+Store the .dia, or .obj versions in mercurial, but not the .png or .pdfs.
+If the figure is not available in a vector graphics format, store both
+a .png and a .pdf version in this directory.
+
+If you add a source (.dia, .obj) file here, remember to add it to
+the list of figure sources in the Makefile in the directory above
Note: tgif can convert from .obj to .pdf, but the pdf that results takes
up a whole page. Instead, we convert to an intermediate .eps step, and
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/figures/buffer.dia Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,1623 @@
+<?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"/>
+ </dia:attribute>
+ <dia:attribute name="fitto">
+ <dia:boolean val="false"/>
+ </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="5,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="4.95,-17.05;8.05,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="5,-17"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Count#</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,-15.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="O1">
+ <dia:attribute name="obj_pos">
+ <dia:point val="8,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.95,-17.05;11.05,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="8,-17"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Size#</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="9.5,-15.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="10.825,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="10.775,-17.05;15.225,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="10.825,-17"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4.3499999999999996"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Initial Start#</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,-15.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="15,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="14.95,-17.05;19.05,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="15,-17"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Dirty Start#</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="17,-15.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="O4">
+ <dia:attribute name="obj_pos">
+ <dia:point val="22.925,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="22.875,-17.05;29.1,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="22.925,-17"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="6.1249999999999964"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#90ee90"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </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>#Unused Area#</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="25.9875,-15.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="O5">
+ <dia:attribute name="obj_pos">
+ <dia:point val="19,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="18.95,-17.05;23.05,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="19,-17"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Dirty Size#</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="21,-15.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="O6">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17,-15"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="16.93,-15.3378;29.4316,-14.6622"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="17,-15"/>
+ <dia:point val="20,-11"/>
+ <dia:point val="26.0375,-11"/>
+ <dia:point val="29,-15"/>
+ </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="O9" connection="11"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O7">
+ <dia:attribute name="obj_pos">
+ <dia:point val="21,-15"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="20.93,-15.3378;42.4316,-14.6622"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="21,-15"/>
+ <dia:point val="24,-11"/>
+ <dia:point val="39.0375,-11"/>
+ <dia:point val="42,-15"/>
+ </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="O5" connection="13"/>
+ <dia:connection handle="3" to="O9" connection="15"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O8">
+ <dia:attribute name="obj_pos">
+ <dia:point val="9.5,-15"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="9.4309,-15.4359;48.4563,-9.59687"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="9.5,-15"/>
+ <dia:point val="23.5,-6"/>
+ <dia:point val="41.125,-10"/>
+ <dia:point val="48.125,-15"/>
+ </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="O1" connection="13"/>
+ <dia:connection handle="3" to="O14" connection="15"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O9">
+ <dia:attribute name="obj_pos">
+ <dia:point val="29,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="28.95,-17.05;42.05,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="29,-17"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="13"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </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>#Dirty Area#</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="35.5,-15.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="O10">
+ <dia:attribute name="obj_pos">
+ <dia:point val="13,-15"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="12.9296,-15.34;40.43,-11.1632"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="13,-15"/>
+ <dia:point val="18,-9"/>
+ <dia:point val="37,-11"/>
+ <dia:point val="40,-15"/>
+ </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="O2" connection="13"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O11">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40,-22"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="30.9298,-29.0702;40.0702,-21.9298"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="40,-22"/>
+ <dia:point val="31,-29"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O13" connection="11"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O12">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40,-22"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="39.9293,-29.0707;47.0707,-21.9293"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="40,-22"/>
+ <dia:point val="47,-29"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O13" connection="15"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O13">
+ <dia:attribute name="obj_pos">
+ <dia:point val="31,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="30.95,-31.05;47.05,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="31,-31"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="16"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Virtual Zero Area#</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="39,-29.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="O14">
+ <dia:attribute name="obj_pos">
+ <dia:point val="42,-17"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="41.95,-17.05;48.175,-14.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="42,-17"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="6.1249999999999964"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#90ee90"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </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>#Unused Area#</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="45.0625,-15.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:group>
+ <dia:object type="Flowchart - Box" version="0" id="O15">
+ <dia:attribute name="obj_pos">
+ <dia:point val="5,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="4.95,-31.05;9.05,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="5,-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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Data#</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,-29.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="O16">
+ <dia:attribute name="obj_pos">
+ <dia:point val="9,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="8.95,-31.05;15.15,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="9,-31"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="6.1000000000000014"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Zero Area Size#</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="12.05,-29.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="O17">
+ <dia:attribute name="obj_pos">
+ <dia:point val="15,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="14.95,-31.05;21.05,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="15,-31"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Used start#</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="18,-29.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="O18">
+ <dia:attribute name="obj_pos">
+ <dia:point val="21,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="20.95,-31.05;26.05,-28.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="21,-31"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Used Size#</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="23.5,-29.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:group>
+ <dia:group>
+ <dia:object type="Flowchart - Box" version="0" id="O19">
+ <dia:attribute name="obj_pos">
+ <dia:point val="5,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="4.95,-2.05;9.05,0.05"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="5,-2"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Data#</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,-0.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="9,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="8.95,-2.05;15.15,0.05"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="9,-2"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="6.1000000000000014"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Zero Area Size#</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="12.05,-0.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="15,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="14.95,-2.05;21.05,0.05"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="15,-2"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Used start#</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="18,-0.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="21,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="20.95,-2.05;26.05,0.05"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="21,-2"/>
+ </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="padding">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Used Size#</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="23.5,-0.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:group>
+ <dia:object type="Standard - Line" version="0" id="O23">
+ <dia:attribute name="obj_pos">
+ <dia:point val="7,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="4.49821,-15.1254;7.05702,-1.94298"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="7,-2"/>
+ <dia:point val="5,-15"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </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="O19" connection="2"/>
+ <dia:connection handle="1" to="O0" connection="11"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O24">
+ <dia:attribute name="obj_pos">
+ <dia:point val="7,-29"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="4.49858,-29.0575;7.05754,-16.8685"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="7,-29"/>
+ <dia:point val="5,-17"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </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="O15" connection="13"/>
+ <dia:connection handle="1" to="O0" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O25">
+ <dia:attribute name="obj_pos">
+ <dia:point val="12.05,-31"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="11.9915,-34.0955;39.3889,-30.6111"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="12.05,-31"/>
+ <dia:point val="13,-36"/>
+ <dia:point val="36,-34"/>
+ <dia:point val="39,-31"/>
+ </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="O16" connection="2"/>
+ <dia:connection handle="3" to="O13" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O26">
+ <dia:attribute name="obj_pos">
+ <dia:point val="18,-29"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="17.9318,-29.0682;33.2055,-21.5098"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="18,-29"/>
+ <dia:point val="22,-22"/>
+ <dia:point val="30,-23"/>
+ <dia:point val="33,-22"/>
+ </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="O17" connection="13"/>
+ <dia:connection handle="3" to="O28" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O27">
+ <dia:attribute name="obj_pos">
+ <dia:point val="24,-29"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="23.9293,-29.0707;41.5,-21.95"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="24,-29"/>
+ <dia:point val="28,-25"/>
+ <dia:point val="41,-27"/>
+ <dia:point val="41,-22"/>
+ </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="3" to="O28" connection="4"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O28">
+ <dia:attribute name="obj_pos">
+ <dia:point val="33,-22"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="32.95,-22.05;41.05,-19.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="33,-22"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="8"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2"/>
+ </dia:attribute>
+ <dia:attribute name="inner_color">
+ <dia:color val="#1e90ff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </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>#Used#</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="37,-20.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="O29">
+ <dia:attribute name="obj_pos">
+ <dia:point val="35,-8"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.95,-8.05;42.05,-5.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="35,-8"/>
+ </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="#1e90ff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </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>#Used#</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="38.5,-6.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="O30">
+ <dia:attribute name="obj_pos">
+ <dia:point val="12.05,0"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="11.9807,-0.294111;39.3576,4.18349"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="12.05,0"/>
+ <dia:point val="16,6"/>
+ <dia:point val="36,5"/>
+ <dia:point val="38.9,0"/>
+ </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="O20" connection="13"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O31">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40,-6"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="32.9318,-6.06822;40.0682,-1.93178"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="40,-6"/>
+ <dia:point val="33,-2"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O33" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O32">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40,-6"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="39.9329,-6.06708;42.0671,-1.93292"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="40,-6"/>
+ <dia:point val="42,-2"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O33" connection="4"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Flowchart - Box" version="0" id="O33">
+ <dia:attribute name="obj_pos">
+ <dia:point val="33,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="32.95,-2.05;42.05,0.05"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="33,-2"/>
+ </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="show_background">
+ <dia:boolean val="true"/>
+ </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>#Virtual Zero Area#</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="37.5,-0.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="18,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="17.9343,-7.50205;35.1202,-1.93435"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="18,-2"/>
+ <dia:point val="25,-5"/>
+ <dia:point val="28,-6"/>
+ <dia:point val="35,-7"/>
+ </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="O21" connection="2"/>
+ <dia:connection handle="3" to="O29" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - BezierLine" version="0" id="O35">
+ <dia:attribute name="obj_pos">
+ <dia:point val="23.5,-2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="23.4296,-8.86763;42.2683,-1.92958"/>
+ </dia:attribute>
+ <dia:attribute name="bez_points">
+ <dia:point val="23.5,-2"/>
+ <dia:point val="26,-5"/>
+ <dia:point val="36,-11"/>
+ <dia:point val="42,-8"/>
+ </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="O22" connection="2"/>
+ <dia:connection handle="3" to="O29" connection="4"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O36">
+ <dia:attribute name="obj_pos">
+ <dia:point val="33,-20"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="32.95,-20.05;33.05,-16.95"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="33,-20"/>
+ <dia:point val="33,-17"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O28" connection="11"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O37">
+ <dia:attribute name="obj_pos">
+ <dia:point val="41,-20"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="40.95,-20.05;41.05,-16.95"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="41,-20"/>
+ <dia:point val="41,-17"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O28" connection="15"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O38">
+ <dia:attribute name="obj_pos">
+ <dia:point val="35,-15"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.95,-15.05;35.05,-7.95"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="35,-15"/>
+ <dia:point val="35,-8"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O29" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O39">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40,-22"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="39.95,-22.05;40.05,-5.95"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="40,-22"/>
+ <dia:point val="40,-6"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O40">
+ <dia:attribute name="obj_pos">
+ <dia:point val="42,-15"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="41.95,-15.05;42.05,-7.95"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="42,-15"/>
+ <dia:point val="42,-8"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O9" connection="15"/>
+ <dia:connection handle="1" to="O29" connection="4"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O41">
+ <dia:attribute name="obj_pos">
+ <dia:point val="5,1"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="5,0.175;7.125,1.55"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Buffer#</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="5,1"/>
+ </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:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O42">
+ <dia:attribute name="obj_pos">
+ <dia:point val="6,-14"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="6,-14.825;9.825,-13.45"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#BufferData#</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,-14"/>
+ </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:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O43">
+ <dia:attribute name="obj_pos">
+ <dia:point val="5,-32"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="5,-32.825;7.125,-31.45"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#Buffer#</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="5,-32"/>
+ </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:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ </dia:layer>
+</dia:diagram>
Binary file doc/tutorial/figures/dumbbell.dia has changed
Binary file doc/tutorial/figures/oneobj.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/figures/packet.obj Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,227 @@
+%TGIF 4.1.43-QPL
+state(0,37,100.000,0,64,0,32,0,9,1,1,1,0,0,0,1,0,'Courier-Bold',1,103680,0,3,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0).
+%
+% @(#)$Header$
+% %W%
+%
+unit("1 pixel/pixel").
+color_info(11,65535,0,[
+ "magenta", 65535, 0, 65535, 65535, 0, 65535, 1,
+ "red", 65535, 0, 0, 65535, 0, 0, 1,
+ "green", 0, 65535, 0, 0, 65535, 0, 1,
+ "blue", 0, 0, 65535, 0, 0, 65535, 1,
+ "yellow", 65535, 65535, 0, 65535, 65535, 0, 1,
+ "pink", 65535, 49344, 52171, 65535, 49344, 52171, 1,
+ "cyan", 0, 65535, 65535, 0, 65535, 65535, 1,
+ "CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1,
+ "white", 65535, 65535, 65535, 65535, 65535, 65535, 1,
+ "black", 0, 0, 0, 0, 0, 0, 1,
+ "DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1
+]).
+script_frac("0.6").
+fg_bg_colors('black','white').
+dont_reencode("FFDingbests:ZapfDingbats").
+page(1,"",1,'').
+box('black','',32,48,240,256,0,3,1,0,0,0,0,0,0,'3',0,[
+]).
+text('black',64,10,1,0,1,121,28,3,22,6,0,0,0,0,2,121,28,0,0,"",0,0,0,0,32,'',[
+minilines(121,28,0,0,0,0,0,[
+mini_line(121,22,6,0,0,0,[
+str_block(0,121,22,6,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,138240,121,22,6,0,0,0,0,0,0,0,
+ "class Packet")])
+])
+])]).
+text('black',416,100,1,0,1,116,28,15,22,6,0,0,0,0,2,116,28,0,0,"",0,0,0,0,122,'',[
+minilines(116,28,0,0,0,0,0,[
+mini_line(116,22,6,0,0,0,[
+str_block(0,116,22,6,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,138240,116,22,6,0,0,0,0,0,0,0,
+ "class Buffer")])
+])
+])]).
+text('black',48,178,4,0,1,83,69,32,14,4,0,0,0,0,2,83,69,0,0,"",0,0,0,0,192,'',[
+minilines(83,69,0,0,0,0,0,[
+mini_line(80,14,4,0,0,0,[
+str_block(0,80,14,4,0,-1,0,0,0,[
+str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0,
+ "private data:")])
+]),
+mini_line(59,14,3,0,0,0,[
+str_block(0,59,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,59,14,3,0,0,0,0,0,0,0,
+ "- unique id")])
+]),
+mini_line(83,14,3,0,0,0,[
+str_block(0,83,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,83,14,3,0,0,0,0,0,0,0,
+ "- Buffer object")])
+]),
+mini_line(76,14,3,0,0,0,[
+str_block(0,76,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,76,14,3,0,0,0,0,0,0,0,
+ "- Tags object")])
+])
+])]).
+text('black',112,288,1,0,1,103,28,82,22,6,0,0,0,0,2,103,28,0,0,"",0,0,0,0,310,'',[
+minilines(103,28,0,0,0,0,0,[
+mini_line(103,22,6,0,0,0,[
+str_block(0,103,22,6,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,138240,103,22,6,0,-1,0,0,0,0,0,
+ "class Tags")])
+])
+])]).
+text('black',48,50,5,0,1,175,86,176,14,4,0,0,0,0,2,175,86,0,0,"",0,0,0,0,64,'',[
+minilines(175,86,0,0,0,0,0,[
+mini_line(105,14,4,0,0,0,[
+str_block(0,105,14,4,0,-1,0,0,0,[
+str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0,
+ "public functions:")])
+]),
+mini_line(80,14,3,0,0,0,[
+str_block(0,80,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,80,14,3,0,-1,0,0,0,0,0,
+ "- constructors")])
+]),
+mini_line(175,14,3,0,0,0,[
+str_block(0,175,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,175,14,3,0,-1,0,0,0,0,0,
+ "- add/remove/peek at Headers")])
+]),
+mini_line(155,14,3,0,0,0,[
+str_block(0,155,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,155,14,3,0,-1,0,0,0,0,0,
+ "- add/remove/peek at Tags")])
+]),
+mini_line(88,14,3,0,0,0,[
+str_block(0,88,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,88,14,3,0,0,0,0,0,0,0,
+ "- fragmentation")])
+])
+])]).
+box('black','',384,144,614,352,0,3,1,245,0,0,0,0,0,'3',0,[
+]).
+text('black',400,274,4,0,1,204,69,246,14,4,0,0,0,0,2,204,69,0,0,"",0,0,0,0,288,'',[
+minilines(204,69,0,0,0,0,0,[
+mini_line(80,14,4,0,0,0,[
+str_block(0,80,14,4,0,-1,0,0,0,[
+str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0,
+ "private data:")])
+]),
+mini_line(193,14,3,0,0,0,[
+str_block(0,193,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,193,14,3,0,0,0,0,0,0,0,
+ "- struct BufferData, a dynamically")])
+]),
+mini_line(160,14,3,0,0,0,[
+str_block(0,160,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,160,14,3,0,0,0,0,0,0,0,
+ "varying byte buffer to which")])
+]),
+mini_line(204,14,3,0,0,0,[
+str_block(0,204,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,204,14,3,0,0,0,0,0,0,0,
+ "data can be prepended or appended")])
+])
+])]).
+text('black',400,146,5,0,1,188,86,247,14,4,0,0,0,0,2,188,86,0,0,"",0,0,0,0,160,'',[
+minilines(188,86,0,0,0,0,0,[
+mini_line(105,14,4,0,0,0,[
+str_block(0,105,14,4,0,-1,0,0,0,[
+str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0,
+ "public functions:")])
+]),
+mini_line(172,14,3,0,0,0,[
+str_block(0,172,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,172,14,3,0,0,0,0,0,0,0,
+ "- Iterators to move byte buffer")])
+]),
+mini_line(171,14,3,0,0,0,[
+str_block(0,171,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,171,14,3,0,0,0,0,0,0,0,
+ "pointers forward or backward")])
+]),
+mini_line(188,14,3,0,0,0,[
+str_block(0,188,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,188,14,3,0,0,0,0,0,0,0,
+ "- functions to read and write data")])
+]),
+mini_line(132,14,3,0,0,0,[
+str_block(0,132,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,132,14,3,0,-1,0,0,0,0,0,
+ "of various sized chunks")])
+])
+])]).
+box('black','',96,324,304,532,0,3,1,264,0,0,0,0,0,'3',0,[
+]).
+text('black',112,454,4,0,1,167,69,265,14,4,0,0,0,0,2,167,69,0,0,"",0,0,0,0,468,'',[
+minilines(167,69,0,0,0,0,0,[
+mini_line(80,14,4,0,0,0,[
+str_block(0,80,14,4,0,-1,0,0,0,[
+str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0,
+ "private data:")])
+]),
+mini_line(167,14,3,0,0,0,[
+str_block(0,167,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,167,14,3,0,0,0,0,0,0,0,
+ "- singly linked-list of TagData")])
+]),
+mini_line(158,14,3,0,0,0,[
+str_block(0,158,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,158,14,3,0,0,0,0,0,0,0,
+ "structures, with a reference")])
+]),
+mini_line(32,14,3,0,0,0,[
+str_block(0,32,14,3,0,0,0,0,0,[
+str_seg('black','Times-Roman',0,80640,32,14,3,0,0,0,0,0,0,0,
+ "count")])
+])
+])]).
+text('black',112,326,5,0,1,155,86,266,14,4,0,0,0,0,2,155,86,0,0,"",0,0,0,0,340,'',[
+minilines(155,86,0,0,0,0,0,[
+mini_line(105,14,4,0,0,0,[
+str_block(0,105,14,4,0,-1,0,0,0,[
+str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0,
+ "public functions:")])
+]),
+mini_line(80,14,3,0,0,0,[
+str_block(0,80,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,80,14,3,0,-1,0,0,0,0,0,
+ "- constructors")])
+]),
+mini_line(155,14,3,0,0,0,[
+str_block(0,155,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,155,14,3,0,-1,0,0,0,0,0,
+ "- templates to add, remove,")])
+]),
+mini_line(148,14,3,0,0,0,[
+str_block(0,148,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,148,14,3,0,-1,0,0,0,0,0,
+ "or peek at Tags of various")])
+]),
+mini_line(31,14,3,0,0,0,[
+str_block(0,31,14,3,0,-1,0,0,0,[
+str_seg('black','Times-Roman',0,80640,31,14,3,0,-1,0,0,0,0,0,
+ "types")])
+])
+])]).
+poly('black','',2,[
+ 59,245,96,320],0,2,1,272,0,0,3,0,0,0,0,'2',0,0,
+ "0","",[
+ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
+]).
+poly('black','',2,[
+ 123,246,288,320],0,2,1,280,0,0,3,0,0,0,0,'2',0,0,
+ "0","",[
+ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
+]).
+poly('black','',2,[
+ 141,219,379,147],0,2,1,286,0,0,3,0,0,0,0,'2',0,0,
+ "0","",[
+ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
+]).
+poly('black','',2,[
+ 132,226,375,335],0,2,1,287,0,0,3,0,0,0,0,'2',0,0,
+ "0","",[
+ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
+]).
Binary file doc/tutorial/figures/pp.dia has changed
Binary file doc/tutorial/figures/sockets-overview.dia has changed
Binary file doc/tutorial/figures/star.dia has changed
Binary file doc/tutorial/figures/threeobj.png has changed
Binary file doc/tutorial/oneobj.png has changed
--- a/doc/tutorial/other.texi Fri May 30 15:31:50 2008 -0400
+++ b/doc/tutorial/other.texi Wed Jun 04 17:19:32 2008 -0400
@@ -34,7 +34,7 @@
you old-timers) cable. This topology is shown below.
@sp 1
-@center @image{pp,,,,png}
+@center @image{figures/pp,,,,png}
@cindex CreateObject
@cindex InternetNode
@@ -173,7 +173,7 @@
that implements a simple star network as seen below.
@sp 1
-@center @image{star,,,,png}
+@center @image{figures/star,,,,png}
In order to create a star network, we need to be able to instantiate some
number (greater than one) of net devices on a node. In the name of simplicity
@@ -506,7 +506,7 @@
The following is a representation of the topology.
@sp 1
-@center @image{dumbbell,,,,png}
+@center @image{figures/dumbbell,,,,png}
We have provided a file that constructs this dumbbell network and creates
enough data flowing across the choke point that some packets will be dropped.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/packets.texi Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,620 @@
+@node ns-3 Packets
+@chapter ns-3 Packets
+
+The design of the Packet framework of @emph{ns} was heavily guided by a few
+important use-cases:
+@itemize @bullet
+@item avoid changing the core of the simulator to introduce
+new types of packet headers or trailers
+@item maximize the ease of integration with real-world code
+and systems
+@item make it easy to support fragmentation, defragmentation,
+and, concatenation which are important, especially in wireless systems.
+@item make memory management of this object efficient
+@item allow actual application data or dummy application bytes for
+emulated applications
+@end itemize
+
+@emph{ns} Packet objects contain a buffer of bytes: protocol headers and
+trailers are serialized in this buffer of bytes using user-provided
+serialization and deserialization routines. The content of this byte
+buffer is expected to match bit-for-bit the content of a real packet on
+a real network implementing the protocol of interest.
+
+Fragmentation and defragmentation are quite natural to implement within
+this context: since we have a buffer of real bytes, we can split it in
+multiple fragments and re-assemble these fragments. We expect that this
+choice will make it really easy to wrap our Packet data structure within
+Linux-style skb or BSD-style mbuf to integrate real-world kernel code in
+the simulator. We also expect that performing a real-time plug of the
+simulator to a real-world network will be easy.
+
+Because we understand that simulation developers often wish to store in
+packet objects data which is not found in the real packets (such as
+timestamps or any kind of similar in-band data), the @emph{ns} Packet class
+can also store extra per-packet "Tags" which are 16 bytes blobs of data.
+Any Packet can store any number of unique Tags, each of which is
+uniquely identified by its C++ type. These tags make it easy to attach
+per-model data to a packet without having to patch the main Packet
+class or Packet facilities.
+
+Memory management of Packet objects is entirely automatic and extremely
+efficient: memory for the application-level payload can be modelized by
+a virtual buffer of zero-filled bytes for which memory is never allocated
+unless explicitely requested by the user or unless the packet is fragmented.
+Furthermore, copying, adding, and, removing headers or trailers to a packet
+has been optimized to be virtually free through a technique known as
+Copy On Write.
+
+Packets (messages) are fundamental objects in the simulator and
+their design is important from a performance and resource management
+perspective. There
+are various ways to design the simulation packet, and tradeoffs
+among the different approaches. In particular, there is a
+tension between ease-of-use, performance, and safe interface
+design.
+
+There are a few requirements on this object design:
+@itemize @bullet
+@item Creation, management, and deletion of this object
+should be as simple as possible, while avoiding the
+chance for memory leaks and/or heap corruption;
+@item Packets should support serialization and deserialization
+so that network emulation is supported;
+@item Packets should support fragmentation and concatenation
+(multiple packets in a data link frame), especially for wireless
+support;
+@item It should be natural for packets to carry actual application
+data, or if there is only an emulated application and there is
+no need to carry dummy bytes, smaller packets could be used with
+just the headers and a record of the payload size, but not actual
+application bytes, conveyed in the simulated packet.
+@item Packets should facilitate BSD-like operations on mbufs, for
+support of ported operating system stacks.
+@item Additional side-information should be supported, such as
+a tag for cross-layer information.
+@end itemize
+
+@section Packet design overview
+
+Unlike @emph{ns-2}, in which Packet objects contain a buffer of C++
+structures corresponding to protocol headers, each network packet in
+@emph{ns-3} contains a byte Buffer and a list of Tags:
+@itemize @bullet
+@item The byte buffer stores the serialized content of the chunks
+added to a packet. The serialized representation of these chunks 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.
+Packets can also be created with an arbitrary zero-filled payload
+for which no real memory is allocated.
+@item The list of tags stores an arbitrarily large set of arbitrary
+user-provided data structures in the packet. Each Tag is uniquely
+identified by its type; only one instance of each
+type of data structure is allowed in a list of tags. These tags typically
+contain per-packet cross-layer information or flow identifiers (i.e.,
+things that you wouldn't find in the bits on the wire). Each tag
+stored in the tag list can be at most 16 bytes.
+Trying to attach bigger data structures will trigger
+crashes at runtime. The 16 byte limit is a modifiable compilation
+constant.
+@end itemize
+
+@float Figure,fig:packets
+@caption{Implementation overview of Packet class.}
+@image{figures/packet}
+@end float
+
+Figure @ref{fig:packets} is a high-level overview of the Packet
+implementation; more detail on the byte Buffer implementation
+is provided later in Figure @ref{fig:buffer}.
+In \nsthree, the Packet byte buffer is analogous to a Linux skbuff
+or BSD mbuf; it is a serialized representation of the actual
+data in the packet. The tag list is a container for extra
+items useful for simulation convenience; if a Packet is converted
+to an emulated packet and put over an actual network, the tags
+are stripped off and the byte buffer is copied directly
+into a real packet.
+
+The Packet class has value semantics: it can be freely copied around,
+allocated on the stack, and passed to functions as arguments. Whenever
+an instance is copied, the full underlying data is not copied; it
+has ``copy-on-write'' (COW) semantics. Packet instances can be passed
+by value to function arguments without any performance hit.
+
+The fundamental classes for adding to and removing from the byte
+buffer are @code{class Header} and @code{class Trailer}.
+Headers are more common but the below discussion also largely applies to
+protocols using trailers. Every protocol header that needs to
+be inserted and removed from a Packet instance should derive from
+the abstract Header base class and implement the private pure
+virtual methods listed below:
+@itemize @bullet
+@item @code{ns3::Header::SerializeTo()}
+@item @code{ns3::Header::DeserializeFrom()}
+@item @code{ns3::Header::GetSerializedSize()}
+@item @code{ns3::Header::PrintTo()}
+@end itemize
+Basically, the first three functions are used to serialize and deserialize
+protocol control information to/from a Buffer. For example,
+one may define @code{class TCPHeader : public Header}. The
+TCPHeader object will typically consist of some private data
+(like a sequence number) and public interface access functions
+(such as checking the bounds of an input). But the underlying
+representation of the TCPHeader in a Packet Buffer is 20 serialized
+bytes (plus TCP options). The TCPHeader::SerializeTo() function would
+therefore be designed to write these 20 bytes properly into
+the packet, in network byte order. The last function is used
+to define how the Header object prints itself onto an output stream.
+
+Similarly, user-defined Tags can be appended to the packet.
+Unlike Headers, Tags are not serialized into a contiguous buffer
+but are stored in an array. By default, Tags are limited to 16 bytes in
+size. Tags can be flexibly defined to be any type, but there
+can only be one instance of any particular object type in
+the Tags buffer at any time. The implementation makes use
+of templates to generate the proper set of Add(), Remove(),
+and Peek() functions for each Tag type.
+
+@section Packet interface
+
+The public member functions of a Packet object are as follows:
+
+@subsection Constructors
+@verbatim
+ /**
+ * Create an empty packet with a new uid (as returned
+ * by getUid).
+ */
+ Packet ();
+ /**
+ * Create a packet with a zero-filled payload.
+ * The memory necessary for the payload is not allocated:
+ * it will be allocated at any later point if you attempt
+ * to fragment this packet or to access the zero-filled
+ * bytes. The packet is allocated with a new uid (as
+ * returned by getUid).
+ *
+ * \param size the size of the zero-filled payload
+ */
+ Packet (uint32_t size);
+@end verbatim
+
+@subsection Adding and removing Buffer data
+The below code is reproduced for Header class only; similar functions
+exist for Trailers.
+@verbatim
+ /**
+ * Add header to this packet. This method invokes the
+ * ns3::Header::serializeTo method to request the header to serialize
+ * itself in the packet buffer.
+ *
+ * \param header a reference to the header to add to this packet.
+ */
+ void Add (Header const &header);
+ /**
+ * Deserialize header from this packet. This method invokes the
+ * ns3::Header::deserializeFrom method to request the header to deserialize
+ * itself from the packet buffer. This method does not remove
+ * the data from the buffer. It merely reads it.
+ *
+ * \param header a reference to the header to deserialize from the buffer
+ */
+ void Peek (Header &header);
+ /**
+ * Remove a deserialized header from the internal buffer.
+ * This method removes the bytes read by Packet::peek from
+ * the packet buffer.
+ *
+ * \param header a reference to the header to remove from the internal buffer.
+ */
+ void Remove (Header const &header);
+ /**
+ * Add trailer to this packet. This method invokes the
+ * ns3::Trailer::serializeTo method to request the trailer to serialize
+ * itself in the packet buffer.
+ *
+ * \param trailer a reference to the trailer to add to this packet.
+ */
+@end verbatim
+
+@subsection Adding and removing Tags
+@verbatim
+ /**
+ * 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.
+ *
+ * \param tag a pointer to the tag to attach to this packet.
+ */
+ template <typename T>
+ void AddTag (T const &tag);
+ /**
+ * Remove a tag from this packet. The data stored internally
+ * for this tag is copied in the input tag if an instance
+ * of this tag type is present in the internal buffer. If this
+ * tag type is not present, the input tag is not modified.
+ *
+ * This operation can be potentially slow and might trigger
+ * unexpectedly large memory allocations. It is thus
+ * usually a better idea to create a copy of this packet,
+ * and invoke removeAllTags on the copy to remove all
+ * tags rather than remove the tags one by one from a packet.
+ *
+ * \param tag a pointer to the tag to remove from this packet
+ * \returns true if an instance of this tag type is stored
+ * in this packet, false otherwise.
+ */
+ template <typename T>
+ bool RemoveTag (T &tag);
+ /**
+ * Copy a tag stored internally to the input tag. If no instance
+ * of this tag is present internally, the input tag is not modified.
+ *
+ * \param tag a pointer to the tag to read from this packet
+ * \returns true if an instance of this tag type is stored
+ * in this packet, false otherwise.
+ */
+ template <typename T>
+ bool PeekTag (T &tag) const;
+ /**
+ * Remove all the tags stored in this packet. This operation is
+ * much much faster than invoking removeTag n times.
+ */
+ void RemoveAllTags (void);
+@end verbatim
+
+@subsection Fragmentation
+@verbatim
+ /**
+ * Create a new packet which contains a fragment of the original
+ * packet. The returned packet shares the same uid as this packet.
+ *
+ * \param start offset from start of packet to start of fragment to create
+ * \param length length of fragment to create
+ * \returns a fragment of the original packet
+ */
+ Packet CreateFragment (uint32_t start, uint32_t length) const;
+
+ /**
+ * Concatenate the input packet at the end of the current
+ * packet. This does not alter the uid of either packet.
+ *
+ * \param packet packet to concatenate
+ */
+ void addAtEnd (Packet packet);
+
+ /oncatenate the input packet at the end of the current
+ * packet. This does not alter the uid of either packet.
+ *
+ * \param packet packet to concatenate
+ */
+ void AddAtEnd (Packet packet);
+ /**
+ * Concatenate the fragment of the input packet identified
+ * by the offset and size parameters at the end of the current
+ * packet. This does not alter the uid of either packet.
+ *
+ * \param packet to concatenate
+ * \param offset offset of fragment to copy from the start of the input packet
+ * \param size size of fragment of input packet to copy.
+ */
+ void AddAtEnd (Packet packet, uint32_t offset, uint32_t size);
+ /**
+ * Remove size bytes from the end of the current packet
+ * It is safe to remove more bytes that what is present in
+ * the packet.
+ *
+ * \param size number of bytes from remove
+ */
+ void RemoveAtEnd (uint32_t size);
+ /**
+ * Remove size bytes from the start of the current packet.
+ * It is safe to remove more bytes that what is present in
+ * the packet.
+ *
+ * \param size number of bytes from remove
+ */
+ void RemoveAtStart (uint32_t size);
+@end verbatim
+
+@subsection Miscellaneous
+@verbatim
+ /**
+ * \returns the size in bytes of the packet (including the zero-filled
+ * initial payload)
+ */
+ uint32_t GetSize (void) const;
+ /**
+ * If you try to change the content of the buffer
+ * returned by this method, you will die.
+ *
+ * \returns a pointer to the internal buffer of the packet.
+ */
+ uint8_t const *PeekData (void) const;
+ /**
+ * A packet is allocated a new uid when it is created
+ * empty or with zero-filled payload.
+ *
+ * \returns an integer identifier which uniquely
+ * identifies this packet.
+ */
+ uint32_t GetUid (void) const;
+@end verbatim
+
+@section Using Headers
+@emph{walk through an example of adding a UDP header}
+
+@section Using Tags
+@emph{walk through an example of adding a flow ID}
+
+@section Using Fragmentation
+@emph{walk through an example of link-layer fragmentation/reassembly}
+
+@section Sample program
+The below sample program (from @code{ns3/samples/main-packet.cc}) illustrates
+some use of the Packet, Header, and Tag classes.
+
+@verbatim
+/* -*- Mode:C++; c-basic-offset:4; tab-width:4; 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 void 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);
+}
+void
+MyHeader::DeserializeFrom (Buffer::Iterator start)
+{
+ // deserialize from head of buffer
+ m_data = start.ReadNtohU16 ();
+}
+
+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.Peek (my);
+ p.Remove (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.Add (my);
+ struct MyTag myTag;
+ myTag.m_streamId = 5;
+ p.AddTag (myTag);
+ Receive (p);
+ return 0;
+}
+@end verbatim
+
+@section Implementation details
+
+@subsection Private member variables
+
+A Packet object's interface provides access to some private
+data:
+@verbatim
+ Buffer m_buffer;
+ Tags m_tags;
+ uint32_t m_uid;
+ static uint32_t m_global_uid;
+@end verbatim
+Each Packet has a Buffer and a Tags object, and a 32-bit unique ID (m\_uid).
+A static member variable keeps track of the UIDs allocated. Note
+that real network packets do not have a UID; the UID is therefore an
+instance of data that normally would be stored as a Tag in the packet.
+However, it was felt that a UID is a special case that is so often
+used in simulations that it would be more convenient to store it
+in a member variable.
+
+@subsection Buffer implementation
+
+Class Buffer represents a buffer of bytes. Its size is
+automatically adjusted to hold any data prepended
+or appended by the user. Its implementation is optimized
+to ensure that the number of buffer resizes is minimized,
+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.
+
+Authors of new Header or Trailer classes need to know the public
+API of the Buffer class. (add summary here)
+
+The byte buffer is implemented as follows:
+@verbatim
+ 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];
+ };
+ struct BufferData *m_data;
+ uint32_t m_zeroAreaSize;
+ uint32_t m_start;
+ uint32_t m_size;
+@end verbatim
+
+@itemize @bullet
+@item @code{BufferData::m_count}: reference count for BufferData structure
+@item @code{BufferData::m_size}: size of data buffer stored in BufferData structure
+@item @code{BufferData::m_initialStart}: offset from start of data buffer where data was first inserted
+@item @code{BufferData::m_dirtyStart}: offset from start of buffer where every Buffer which holds a reference to this BufferData instance have written data so far
+@item @code{BufferData::m_dirtySize}: size of area where data has been written so far
+@item @code{BufferData::m_data}: pointer to data buffer
+@item @code{Buffer::m_zeroAreaSize}: size of zero area which extends before @code{m_initialStart}
+@item @code{Buffer::m_start}: offset from start of buffer to area used by this buffer
+@item @code{Buffer::m_size}: size of area used by this Buffer in its BufferData structure
+@end itemize
+
+@float Figure,fig:buffer
+@caption{Implementation overview of a packet's byte Buffer.}
+@image{figures/buffer,15cm}
+@end float
+
+This data structure is summarized in Figure @ref{fig:buffer}.
+Each Buffer holds a pointer to an instance of a BufferData. Most
+Buffers should be able to share the same underlying BufferData and
+thus simply increase the BufferData's reference count. If they have to
+change the content of a BufferData inside the Dirty Area, and if the
+reference count is not one, they first create a copy of the BufferData and
+then complete their state-changing operation.
+
+@subsection Tags implementation
+Tags are implemented by a single pointer which points to the start of a
+linked list ofTagData data structures. Each TagData structure points
+to the next TagData in the list (its next pointer contains zero to
+indicate the end of the linked list). Each TagData contains an integer
+unique id which identifies the type of the tag stored in the TagData.
+@verbatim
+struct TagData {
+ struct TagData *m_next;
+ uint32_t m_id;
+ uint32_t m_count;
+ uint8_t m_data[Tags::SIZE];
+};
+class Tags {
+ struct TagData *m_next;
+};
+@end verbatim
+
+Adding a tag is a matter of inserting a new TagData at the head of
+the linked list. Looking at a tag requires you to find the relevant
+TagData in the linked list and copy its data into the user data
+structure. Removing a tag and updating the content of a tag
+requires a deep copy of the linked list before performing this operation.
+On the other hand, copying a Packet and its tags is a matter of
+copying the TagData head pointer and incrementing its reference count.
+
+Tags are found by the unique mapping betweent the Tag type and
+its underlying id. This is why at most one instance of any Tag
+can be stored in a packet. The mapping between Tag type and
+underlying id is performed by a registration as follows:
+@verbatim
+/* A sample Tag implementation
+ */
+struct MyTag {
+ uint16_t m_streamId;
+};
+@end verbatim
+
+@emph{add description of TagRegistration for printing}
+
+@subsection Memory management
+
+@emph{Describe free list.}
+
+@emph{Describe dataless vs. data-full packets.}
+
+@subsection Copy-on-write semantics
+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). This design feature
+and aspects of the public interface borrows from the packet design
+of the Georgia Tech Network Simulator.
+This implementation of COW uses a customized reference counting
+smart pointer class.
+
+What COW 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'' and must therefore invoke
+a true copy.
+
+Dirty operations:
+@itemize @bullet
+@item Packet::RemoveTag()
+@item Packet::Add()
+@item both versions of ns3::Packet::AddAtEnd()
+@end itemize
+
+Non-dirty operations:
+@itemize @bullet
+@item Packet::AddTag()
+@item Packet::RemoveAllTags()
+@item Packet::PeekTag()
+@item Packet::Peek()
+@item Packet::Remove()
+@item Packet::CreateFragment()
+@item Packet::RemoveAtStart()
+@item Packet::RemoveAtEnd()
+@end itemize
+
+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.
+
Binary file doc/tutorial/pp.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/sockets.texi Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,243 @@
+@node Sockets APIs
+@chapter Sockets APIs
+
+The @uref{http://en.wikipedia.org/wiki/Berkeley_sockets,,sockets API}
+is a long-standing API used by user-space applications to access
+network services in the kernel. A ``socket'' is an abstraction, like
+a Unix file handle, that allows applications to connect to other
+Internet hosts and exchange reliable byte streams and unreliable
+datagrams, among other services.
+
+ns-3 provides two types of sockets APIs, and it is important to
+understand the differences between them. The first is a @emph{native}
+ns-3 API, while the second uses the services of the native API to
+provide a @uref{http://en.wikipedia.org/wiki/POSIX,,POSIX-like}
+API as part of an overall application process. Both APIs strive
+to be close to the typical sockets API that application writers
+on Unix systems are accustomed to, but the POSIX variant is much
+closer to a real system's sockets API.
+
+@section ns-3 sockets API
+
+The native sockets API for ns-3 provides an interface to various
+types of transport protocols (TCP, UDP) as well as to packet sockets
+and, in the future, Netlink-like sockets. However, users are cautioned
+to understand that the semantics are @strong{not} the exact same as
+one finds in a real system (for an API which is very much aligned
+to real systems, see the next section).
+
+@code{class ns3::Socket} is defined in @code{src/node/socket.cc,h}.
+Readers will note that many public member functions are aligned
+with real sockets function calls, and all other things being equal,
+we have tried to align with a Posix sockets API. However, note that:
+
+@itemize @bullet
+@item ns-3 applications handle a smart pointer to a Socket object, not
+a file descriptor;
+@item there is no notion of synchronous API or a ``blocking'' API;
+in fact, the model for interaction between application and socket is
+one of asynchronous I/O, which is not typically found in real systems
+(more on this below);
+@item the C-style socket address structures are not used;
+@item the API is not a complete sockets API, such as supporting
+all socket options or all function variants;
+@item many calls use @code{ns3::Packet} class to transfer data
+between application and socket. This may seem a little funny to
+people to pass ``Packets'' across a stream socket API, but think
+of these packets as just fancy byte buffers at this level (more
+on this also below).
+@end itemize
+
+@subsection Basic operation and calls
+
+@float Figure,fig:sockets-overview
+@caption{Implementation overview of native sockets API}
+@image{figures/sockets-overview, 10cm}
+@end float
+
+@subsubsection Creating sockets
+
+An application that wants to use sockets must first create one.
+On real systems, this is accomplished by calling socket():
+@verbatim
+ int
+ socket(int domain, int type, int protocol);
+@end verbatim
+which creates a socket in the system and returns an integer descriptor.
+
+In ns-3, we have no equivalent of a system call at the lower layers,
+so we adopt the following model. There are certain @emph{factory}
+objects that can create sockets. Each factory is capable of creating
+one type of socket, and if sockets of a particular type are able to
+be created on a given node, then a factory that can create such sockets
+must be aggregated to the Node.
+@verbatim
+ static Ptr<Socket> CreateSocket (Ptr<Node> node, TypeId tid);
+@end verbatim
+Examples of TypeIds to pass to this method are @code{TcpSocketFactory},
+@code{PacketSocketFactory}, and @code{UdpSocketFactory}.
+
+This method returns a smart pointer to a Socket object. Here is an
+example:
+@verbatim
+ Ptr<Node> n0;
+ // Do some stuff to build up the Node's internet stack
+ Ptr<Socket> localSocket = Socket::CreateSocket (n0, TcpSocketFactory::GetTypeId ());
+@end verbatim
+
+In some ns-3 code, sockets will not be explicitly created by user's
+main programs, if an ns-3 application does it. For instance, for
+@code{class ns3::OnOffApplication}, the function @code{StartApplication()}
+performs the socket creation, and the application holds the socket
+pointer.
+
+@subsubsection Using sockets
+
+Below is a typical sequence of socket calls for a TCP client in a
+real implementation:
+@itemize @bullet
+@item @code{sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);}
+@item @code{bind(sock, ...);}
+@item @code{connect(sock, ...);}
+@item @code{send(sock, ...);}
+@item @code{recv(sock, ...);}
+@item @code{close(sock);}
+@end itemize
+
+There are analogs to all of these calls in ns-3, but we will focus on
+two aspects here. First, most usage of sockets in real systems
+requires a way to manage I/O between the application and kernel.
+These models include @emph{blocking sockets}, @emph{signal-based I/O},
+and @emph{non-blocking sockets} with polling. In ns-3, we make use
+of the callback mechanisms to support a fourth mode, which is
+analogous to POSIX @emph{asynchronous I/O}.
+
+In this model, on the sending side, if the @code{send()} call were to
+fail because of insufficient buffers, the application suspends the
+sending of more data until a function registered at the
+@code{SetSendCallback()} callback is invoked. An application can
+also ask the socket how much space is available by calling
+@code{GetTxAvailable ()}. A typical sequence of events for
+sending data (ignoring connection setup) might be:
+
+@itemize @bullet
+@item @code{SetSendCallback (MakeCallback(&HandleSendCallback));}
+@item @code{Send ();}
+@item @code{Send ();}
+@item ...
+@item @code{// Send fails because buffer is full}
+@item (wait until HandleSendCallback() is called)
+@item (HandleSendCallback() is called by socket, since space now available)
+@item @code{Send (); // Start sending again}
+@end itemize
+
+Similarly, on the receive side, the socket user does not block on
+a call to @code{recv()}. Instead, the application sets a callback
+with @code{SetRecvCallback ()} in which the socket will notify the
+application when (and how much) there is data to be read, and
+the application then calls @code{Recv()} to read the data until
+no more can be read.
+
+@subsection Packet vs. buffer variants
+
+There are two basic variants of @code{Send()} and @code{Recv()} supported:
+@verbatim
+ virtual int Send (Ptr<Packet> p) = 0;
+ int Send (const uint8_t* buf, uint32_t size);
+
+ Ptr<Packet> Recv (void);
+ int Recv (uint8_t* buf, uint32_t size);
+@end verbatim
+
+The non-Packet variants are left for legacy API reasons. When calling
+the raw buffer variant of @code{Send()}, the buffer is immediately
+written into a Packet and the @code{Send (Ptr<Packet> p)} is invoked.
+
+Users may find it semantically odd to pass a Packet to a stream socket
+such as TCP. However, do not let the name bother you; think of
+@code{ns3::Packet} to be a fancy byte buffer. There are a few reasons why
+the Packet variants are more likely to be preferred in ns-3:
+
+@itemize @bullet
+@item Users can use the Tags facility of packets to, for example, encode
+a flow ID or other helper data.
+@item Users can exploit the copy-on-write implementation to avoid
+memory copies (on the receive side, the conversion back to a
+@code{uint8_t* buf} may sometimes incur an additional copy).
+@item Use of Packet is more aligned with the rest of the ns-3 API
+@end itemize
+
+@subsection Sending dummy data
+
+Sometimes, users want the simulator to just pretend that there is an
+actual data payload in the packet (e.g. to calculate transmission delay)
+but do not want to actually produce or consume the data. This is
+straightforward to support in ns-3; have applications call
+@code{Create<Packet> (size);} instead of @code{Create<Packet> (buffer, size);}.
+Similarly, passing in a zero to the pointer argument in the raw buffer
+variants has the same effect. Note that, if some subsequent code tries
+to read the Packet data buffer, the fake buffer will be converted to
+a real (zero'ed) buffer on the spot, and the efficiency will be lost there.
+
+@subsection Socket options
+
+@emph{to be completed}
+
+@subsection Socket errno
+
+@emph{to be completed}
+
+@subsection Example programs
+
+@emph{to be completed}
+
+@section POSIX-like sockets API
+
+@emph{this capability is under development and is scheduled for
+inclusion in August 2008 timeframe; see the repository
+http://code.nsnam.org/mathieu/ns-3-simu for details}
+
+The below is excerpted from Mathieu's post to ns-developers list
+on April 4, 2008.
+
+"To summarize, the goal is that the full posix/socket API is defined in
+src/process/simu.h: each posix type and function is re-defined there
+with a simu_ or SIMU_ prefix to avoid ugly name clashes and collisions
+(feel free to come up with a better prefix).
+
+Each process is created with a call to ProcessManager::Create and is
+attached to that ProcessManager instance. So, if the ProcessManager
+(which is aggregated to a Node in src/helper/process-helper.cc) is
+killed when the simulation ends, the system will automatically reclaim
+all the resources of each process associated to each manager. The same
+happens when an application "exits" from its main function.
+
+The example application defines two posix "processes": the function
+ClientProgram creates a udp socket on the localhost port 2000 and the
+function ServerProgram creates a udp socket on the localhost port 2000.
+The code does not work right now because I did not get the details of
+simu_read right yet but, I do plan to make this work at some point.
+
+I really think that this approach is worthwhile for many reasons, a few
+of which are outlined below:
+@itemize @bullet
+@item makes porting real world application code _much_ easier
+
+@item makes write applications for new users much easier because they can
+read the bsd socket api reference and documentation and write code
+directly.
+
+@item can be used to write applications which work in both simulation and
+in the real world at the same time. To do this, all you have to do is
+write your application to use the simu_ API, and, then, you can chose at
+compile-time which implementation of that API you want to use: you can
+pick one implementation which forwards all calls to the system BSD
+socket API or another one which forwards all calls to the attached
+ProcessManager. Arguably, I did not implement the version which forwards
+to system BSD sockets but, that should be pretty trivial.
+@end itemize
+
+So, anyway, comments about the overall API would be welcome. Students
+interested in the gsoc project for real-world code integration should
+consider looking at this also."
+
Binary file doc/tutorial/star.png has changed
Binary file doc/tutorial/threeobj.png has changed
--- a/doc/tutorial/tutorial.texi Fri May 30 15:31:50 2008 -0400
+++ b/doc/tutorial/tutorial.texi Wed Jun 04 17:19:32 2008 -0400
@@ -93,9 +93,12 @@
Part 4: Creating New or Revised Topologies
* Helper Functions::
* Other-network-topologies::
-Part 5: Extending ns-3
+Part 5: Key ns-3 objects and systems
+* ns-3 Packets::
* ns-3 Callbacks::
+* Sockets APIs::
* ns-3 routing overview::
+Part 6: Extending ns-3
* Nonlinear-Thinking::
* Summary::
* Object-Model::
@@ -111,8 +114,10 @@
@include attributes.texi
@include statistics.texi
@include helpers.texi
+@include packets.texi
@include callbacks.texi
-@include output.texi
+@include sockets.texi
+@c @include output.texi
@include routing.texi
@c @include other.texi
@include troubleshoot.texi
--- a/examples/csma-packet-socket.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/csma-packet-socket.cc Wed Jun 04 17:19:32 2008 -0400
@@ -38,9 +38,6 @@
#include "ns3/node-module.h"
#include "ns3/helper-module.h"
-#include "ns3/ascii-trace.h"
-#include "ns3/pcap-trace.h"
-
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample");
@@ -105,9 +102,9 @@
// 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 ();
+ std::ofstream os;
+ os.open ("csma-packet-socket.tr");
+ csma.EnableAsciiAll (os);
NS_LOG_INFO ("Run Simulation.");
Simulator::Run ();
--- a/examples/mixed-global-routing.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/mixed-global-routing.cc Wed Jun 04 17:19:32 2008 -0400
@@ -40,8 +40,6 @@
#include "ns3/simulator-module.h"
#include "ns3/node-module.h"
#include "ns3/helper-module.h"
-#include "ns3/ascii-trace.h"
-#include "ns3/pcap-trace.h"
#include "ns3/global-route-manager.h"
using namespace ns3;
@@ -73,13 +71,13 @@
// We create the channels first without any IP addressing information
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
- p2p.SetChannelParameter ("BitRate", StringValue ("5Mbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
NetDeviceContainer d0d2 = p2p.Install (n0n2);
NetDeviceContainer d1d2 = p2p.Install (n1n2);
- p2p.SetChannelParameter ("BitRate", StringValue ("1500kbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
NetDeviceContainer d5d6 = p2p.Install (n5n6);
--- a/examples/mixed-wireless.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/mixed-wireless.cc Wed Jun 04 17:19:32 2008 -0400
@@ -159,8 +159,12 @@
MobilityHelper mobility;
Ptr<ListPositionAllocator> positionAlloc =
CreateObject<ListPositionAllocator> ();
- positionAlloc->Add (Vector (0.0, 0.0, 0.0));
- positionAlloc->Add (Vector (5.0, 0.0, 0.0));
+ double x = 0.0;
+ for (uint32_t i = 0; i < backboneNodes; ++i)
+ {
+ positionAlloc->Add (Vector (x, 0.0, 0.0));
+ x += 5.0;
+ }
mobility.SetPositionAllocator (positionAlloc);
mobility.SetMobilityModel ("ns3::RandomDirection2dMobilityModel",
"Bounds", RectangleValue (Rectangle (0, 1000, 0, 1000)),
@@ -268,7 +272,6 @@
{
subnetAlloc->Add (Vector (0.0, j, 0.0));
}
- mobility.EnableNotifier ();
mobility.PushReferenceMobilityModel (backbone.Get (i));
mobility.SetPositionAllocator (subnetAlloc);
mobility.SetMobilityModel ("ns3::RandomDirection2dMobilityModel",
@@ -329,14 +332,13 @@
//
// Let's set up some ns-2-like ascii traces, using another helper class
//
- // Look at nodes 11, 13 only
- // XXX todo
- // asciiTrace.TraceQueues ("/NodeList/11|13/DeviceList/0");
- // asciiTrace.TraceNetDeviceRx ("/NodeList/11|13/DeviceList/0");
std::ofstream ascii;
ascii.open ("mixed-wireless.tr");
WifiHelper::EnableAsciiAll (ascii);
CsmaHelper::EnableAsciiAll (ascii);
+ // Look at nodes 11, 13 only
+ //WifiHelper::EnableAscii (ascii, 11, 0);
+ //WifiHelper::EnableAscii (ascii, 13, 0);
// Let's do a pcap trace on the backbone devices
WifiHelper::EnablePcap ("mixed-wireless", backboneDevices);
@@ -344,10 +346,11 @@
CsmaHelper::EnablePcap ("mixed-wireless", appSink->GetId (), 0);
#ifdef ENABLE_FOR_TRACING_EXAMPLE
- Config::Connect ("/NodeList/*/$MobilityModelNotifier/CourseChange",
+ Config::Connect ("/NodeList/*/$MobilityModel/CourseChange",
MakeCallback (&CourseChangeCallback));
#endif
+
///////////////////////////////////////////////////////////////////////////
// //
// Run simulation //
@@ -355,7 +358,7 @@
///////////////////////////////////////////////////////////////////////////
NS_LOG_INFO ("Run Simulation.");
- Simulator::StopAt (Seconds (stopTime));
+ Simulator::Stop (Seconds (stopTime));
Simulator::Run ();
Simulator::Destroy ();
}
--- a/examples/simple-alternate-routing.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/simple-alternate-routing.cc Wed Jun 04 17:19:32 2008 -0400
@@ -97,13 +97,13 @@
// We create the channels first without any IP addressing information
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
- p2p.SetChannelParameter ("BitRate", StringValue ("5Mbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
NetDeviceContainer d0d2 = p2p.Install (n0n2);
NetDeviceContainer d1d2 = p2p.Install (n1n2);
- p2p.SetChannelParameter ("BitRate", StringValue ("1500kbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
NetDeviceContainer d3d2 = p2p.Install (n3n2);
--- a/examples/simple-error-model.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/simple-error-model.cc Wed Jun 04 17:19:32 2008 -0400
@@ -92,13 +92,13 @@
// We create the channels first without any IP addressing information
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
- p2p.SetChannelParameter ("BitRate", DataRateValue (DataRate (5000000)));
+ p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate (5000000)));
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
NetDeviceContainer d0d2 = p2p.Install (n0n2);
NetDeviceContainer d1d2 = p2p.Install (n1n2);
- p2p.SetChannelParameter ("BitRate", DataRateValue (DataRate (1500000)));
+ p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate (1500000)));
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds (10)));
NetDeviceContainer d3d2 = p2p.Install (n3n2);
--- a/examples/simple-global-routing.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/simple-global-routing.cc Wed Jun 04 17:19:32 2008 -0400
@@ -92,13 +92,13 @@
// We create the channels first without any IP addressing information
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
- p2p.SetChannelParameter ("BitRate", StringValue ("5Mbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
NetDeviceContainer d0d2 = p2p.Install (n0n2);
NetDeviceContainer d1d2 = p2p.Install (n1n2);
- p2p.SetChannelParameter ("BitRate", StringValue ("1500kbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
NetDeviceContainer d3d2 = p2p.Install (n3n2);
--- a/examples/simple-point-to-point-olsr.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/simple-point-to-point-olsr.cc Wed Jun 04 17:19:32 2008 -0400
@@ -93,11 +93,11 @@
// We create the channels first without any IP addressing information
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
- p2p.SetChannelParameter ("BitRate", StringValue ("5Mbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
NetDeviceContainer nd02 = p2p.Install (n02);
NetDeviceContainer nd12 = p2p.Install (n12);
- p2p.SetChannelParameter ("BitRate", StringValue ("1500kbps"));
+ p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
NetDeviceContainer nd32 = p2p.Install (n32);
NetDeviceContainer nd34 = p2p.Install (n34);
@@ -161,7 +161,7 @@
PointToPointHelper::EnablePcapAll ("simple-point-to-point-olsr");
PointToPointHelper::EnableAsciiAll (ascii);
- Simulator::StopAt (Seconds (30));
+ Simulator::Stop (Seconds (30));
NS_LOG_INFO ("Run Simulation.");
Simulator::Run ();
--- a/examples/tcp-large-transfer.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/tcp-large-transfer.cc Wed Jun 04 17:19:32 2008 -0400
@@ -111,7 +111,7 @@
// We create the channels first without any IP addressing information
PointToPointHelper p2p;
- p2p.SetChannelParameter ("BitRate", DataRateValue (DataRate(100000)));
+ p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate(10000000)));
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds(10)));
NetDeviceContainer dev0 = p2p.Install (c0);
NetDeviceContainer dev1 = p2p.Install (c1);
@@ -165,7 +165,7 @@
PointToPointHelper::EnablePcapAll ("tcp-large-transfer");
- Simulator::StopAt (Seconds(100));
+ Simulator::Stop (Seconds(1000));
Simulator::Run ();
Simulator::Destroy ();
}
--- a/examples/wifi-adhoc.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/wifi-adhoc.cc Wed Jun 04 17:19:32 2008 -0400
@@ -102,7 +102,7 @@
Ptr<Socket>
Experiment::SetupPacketReceive (Ptr<Node> node)
{
- TypeId tid = TypeId::LookupByName ("ns3::PacketSocket");
+ TypeId tid = TypeId::LookupByName ("ns3::PacketSocketFactory");
Ptr<Socket> sink = Socket::CreateSocket (node, tid);
sink->Bind ();
sink->SetRecvCallback (MakeCallback (&Experiment::ReceivePacket, this));
@@ -136,7 +136,7 @@
socket.SetPhysicalAddress (devices.Get (1)->GetAddress ());
socket.SetProtocol (1);
- OnOffHelper onoff ("ns3::PacketSocket", Address (socket));
+ OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket));
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (250)));
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
onoff.SetAttribute ("DataRate", DataRateValue (DataRate (60000000)));
--- a/examples/wifi-ap.cc Fri May 30 15:31:50 2008 -0400
+++ b/examples/wifi-ap.cc Wed Jun 04 17:19:32 2008 -0400
@@ -162,7 +162,7 @@
socket.SetPhysicalAddress (staDevs.Get (1)->GetAddress ());
socket.SetProtocol (1);
- OnOffHelper onoff ("ns3::PacketSocket", Address (socket));
+ OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket));
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (42)));
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
@@ -170,7 +170,7 @@
apps.Start (Seconds (0.5));
apps.Stop (Seconds (43.0));
- Simulator::StopAt (Seconds (44.0));
+ Simulator::Stop (Seconds (44.0));
Config::Connect ("/NodeList/*/DeviceList/*/Tx", MakeCallback (&DevTxTrace));
Config::Connect ("/NodeList/*/DeviceList/*/Rx", MakeCallback (&DevRxTrace));
--- a/samples/main-packet-tag.cc Fri May 30 15:31:50 2008 -0400
+++ b/samples/main-packet-tag.cc Wed Jun 04 17:19:32 2008 -0400
@@ -19,6 +19,7 @@
*/
#include "ns3/tag.h"
#include "ns3/packet.h"
+#include "ns3/uinteger.h"
#include <iostream>
using namespace ns3;
@@ -27,22 +28,12 @@
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);
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
// these are our accessors to our tag structure
void SetSimpleValue (uint8_t value);
@@ -51,53 +42,46 @@
uint8_t m_simpleValue;
};
-MyTag::MyTag ()
-{}
-MyTag::MyTag (const MyTag &other)
- : m_simpleValue (other.m_simpleValue)
-{}
-MyTag::~MyTag ()
-{}
+TypeId
+MyTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::MyTag")
+ .SetParent<Tag> ()
+ .AddConstructor<MyTag> ()
+ .AddAttribute ("SimpleValue",
+ "A simple value",
+ EmptyAttributeValue (),
+ MakeUintegerAccessor (&MyTag::GetSimpleValue),
+ MakeUintegerChecker<uint8_t> ())
+ ;
+ return tid;
+}
+TypeId
+MyTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
uint32_t
-MyTag::GetUid (void)
+MyTag::GetSerializedSize (void) const
+{
+ return 1;
+}
+void
+MyTag::Serialize (TagBuffer i) const
{
- // we input a unique string to AllocateUid
- // to avoid name collisions.
- static uint32_t uid = AllocateUid<MyTag> ("MyTag.tests.nsnam.org");
- return uid;
+ i.WriteU8 (m_simpleValue);
+}
+void
+MyTag::Deserialize (TagBuffer i)
+{
+ m_simpleValue = i.ReadU8 ();
}
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;
+ os << "v=" << (uint32_t)m_simpleValue;
}
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;
@@ -116,7 +100,7 @@
tag.SetSimpleValue (0x56);
// store the tag in a packet.
- Ptr<Packet> p = Create<Packet> ();
+ Ptr<Packet> p = Create<Packet> (100);
p->AddTag (tag);
// create a copy of the packet
@@ -124,7 +108,7 @@
// read the tag from the packet copy
MyTag tagCopy;
- p->PeekTag (tagCopy);
+ p->FindFirstMatchingTag (tagCopy);
// the copy and the original are the same !
NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
--- a/samples/main-random-topology.cc Fri May 30 15:31:50 2008 -0400
+++ b/samples/main-random-topology.cc Wed Jun 04 17:19:32 2008 -0400
@@ -25,7 +25,6 @@
c.Create (10000);
MobilityHelper mobility;
- mobility.EnableNotifier ();
mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator",
"X", StringValue ("100.0"),
"Y", StringValue ("100.0"),
@@ -36,7 +35,7 @@
Config::Connect ("/NodeList/*/$ns3::MobilityModelNotifier/CourseChange",
MakeCallback (&CourseChange));
- Simulator::StopAt (Seconds (100.0));
+ Simulator::Stop (Seconds (100.0));
Simulator::Run ();
--- a/samples/main-random-walk.cc Fri May 30 15:31:50 2008 -0400
+++ b/samples/main-random-walk.cc Wed Jun 04 17:19:32 2008 -0400
@@ -8,7 +8,7 @@
using namespace ns3;
static void
-CourseChange (ns3::TraceContext const&, Ptr<const MobilityModel> mobility)
+CourseChange (std::string foo, Ptr<const MobilityModel> mobility)
{
Vector pos = mobility->GetPosition ();
Vector vel = mobility->GetVelocity ();
@@ -22,7 +22,7 @@
Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Mode", StringValue ("Time"));
Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Time", StringValue ("2s"));
Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Speed", StringValue ("Constant:1.0"));
- Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Bounds", StringValue ("0:200:0:100"));
+ Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Bounds", StringValue ("0|200|0|200"));
CommandLine cmd;
cmd.Parse (argc, argv);
@@ -31,7 +31,6 @@
c.Create (100);
MobilityHelper mobility;
- mobility.EnableNotifier ();
mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator",
"X", StringValue ("100.0"),
"Y", StringValue ("100.0"),
@@ -40,12 +39,12 @@
"Mode", StringValue ("Time"),
"Time", StringValue ("2s"),
"Speed", StringValue ("Constant:1.0"),
- "Bounds", StringValue ("0:200:0:100"));
+ "Bounds", StringValue ("0|200|0|200"));
mobility.InstallAll ();
- Config::Connect ("/NodeList/*/$ns3::MobilityModelNotifier/CourseChange",
+ Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
MakeCallback (&CourseChange));
- Simulator::StopAt (Seconds (100.0));
+ Simulator::Stop (Seconds (100.0));
Simulator::Run ();
--- a/src/applications/packet-sink/packet-sink.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/applications/packet-sink/packet-sink.cc Wed Jun 04 17:19:32 2008 -0400
@@ -106,10 +106,11 @@
while (packet = socket->Recv ())
{
SocketRxAddressTag tag;
- bool found = packet->PeekTag (tag);
+ bool found;
+ found = packet->FindFirstMatchingTag (tag);
NS_ASSERT (found);
Address from = tag.GetAddress ();
- packet->RemoveTag (tag);
+ // XXX packet->RemoveTag (tag);
if (InetSocketAddress::IsMatchingType (from))
{
InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
--- a/src/applications/udp-echo/udp-echo-client.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/applications/udp-echo/udp-echo-client.cc Wed Jun 04 17:19:32 2008 -0400
@@ -93,7 +93,7 @@
{
NS_LOG_FUNCTION_NOARGS ();
- if (!m_socket)
+ if (m_socket == 0)
{
TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
m_socket = Socket::CreateSocket (GetNode(), tid);
@@ -111,7 +111,7 @@
{
NS_LOG_FUNCTION_NOARGS ();
- if (!m_socket)
+ if (m_socket != 0)
{
m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket> > ());
}
@@ -153,10 +153,11 @@
while (packet = socket->Recv ())
{
SocketRxAddressTag tag;
- bool found = packet->PeekTag (tag);
+ bool found;
+ found = packet->FindFirstMatchingTag (tag);
NS_ASSERT (found);
Address from = tag.GetAddress ();
- packet->RemoveTag (tag);
+ // XXX packet->RemoveTag (tag);
if (InetSocketAddress::IsMatchingType (from))
{
InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
--- a/src/applications/udp-echo/udp-echo-server.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/applications/udp-echo/udp-echo-server.cc Wed Jun 04 17:19:32 2008 -0400
@@ -69,7 +69,7 @@
{
NS_LOG_FUNCTION_NOARGS ();
- if (!m_socket)
+ if (m_socket == 0)
{
TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
m_socket = Socket::CreateSocket (GetNode(), tid);
@@ -85,7 +85,7 @@
{
NS_LOG_FUNCTION_NOARGS ();
- if (!m_socket)
+ if (m_socket != 0)
{
m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket> > ());
}
@@ -98,10 +98,11 @@
while (packet = socket->Recv ())
{
SocketRxAddressTag tag;
- bool found = packet->PeekTag (tag);
+ bool found;
+ found = packet->FindFirstMatchingTag (tag);
NS_ASSERT (found);
Address from = tag.GetAddress ();
- packet->RemoveTag (tag);
+ // XXX packet->RemoveTag (tag);
if (InetSocketAddress::IsMatchingType (from))
{
InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
--- a/src/common/buffer.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/common/buffer.cc Wed Jun 04 17:19:32 2008 -0400
@@ -203,11 +203,13 @@
Buffer::Buffer ()
{
+ NS_LOG_FUNCTION (this);
Initialize (0);
}
Buffer::Buffer (uint32_t dataSize)
{
+ NS_LOG_FUNCTION (this << dataSize);
Initialize (dataSize);
}
@@ -225,17 +227,21 @@
m_start <= m_data->m_size &&
m_zeroAreaStart <= m_data->m_size;
- NS_ASSERT (offsetsOk);
- NS_ASSERT (dirtyOk);
- NS_ASSERT (internalSizeOk);
-
- return m_data->m_count > 0 && offsetsOk && dirtyOk &&
- internalSizeOk;
+ bool ok = m_data->m_count > 0 && offsetsOk && dirtyOk && internalSizeOk;
+ if (!ok)
+ {
+ LOG_INTERNAL_STATE ("check " << this <<
+ ", " << (offsetsOk?"true":"false") <<
+ ", " << (dirtyOk?"true":"false") <<
+ ", " << (internalSizeOk?"true":"false") << " ");
+ }
+ return ok;
}
void
Buffer::Initialize (uint32_t zeroSize)
{
+ NS_LOG_FUNCTION (this << zeroSize);
m_data = Buffer::Create (0);
#ifdef BUFFER_HEURISTICS
m_start = std::min (m_data->m_size, g_recommendedStart);
@@ -261,6 +267,7 @@
m_start (o.m_start),
m_end (o.m_end)
{
+ NS_LOG_FUNCTION (this << &o);
m_data->m_count++;
NS_ASSERT (CheckInternalState ());
}
@@ -268,6 +275,7 @@
Buffer &
Buffer::operator = (Buffer const&o)
{
+ NS_LOG_FUNCTION (this << &o);
NS_ASSERT (CheckInternalState ());
if (m_data != o.m_data)
{
@@ -294,6 +302,8 @@
Buffer::~Buffer ()
{
+ NS_LOG_FUNCTION (this);
+ NS_ASSERT (CheckInternalState ());
HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart));
m_data->m_count--;
if (m_data->m_count == 0)
@@ -333,9 +343,11 @@
return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
}
-void
+bool
Buffer::AddAtStart (uint32_t start)
{
+ NS_LOG_FUNCTION (this << start);
+ bool dirty;
NS_ASSERT (CheckInternalState ());
bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
if (m_start >= start && !isDirty)
@@ -347,31 +359,13 @@
*/
NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
m_start -= start;
+ dirty = m_start > m_data->m_dirtyStart;
+ // update dirty area
+ m_data->m_dirtyStart = m_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 ());
@@ -383,23 +377,30 @@
m_data = newData;
int32_t delta = start - m_start;
- m_start = 0;
+ m_start += delta;
m_zeroAreaStart += delta;
m_zeroAreaEnd += delta;
m_end += delta;
+ m_start -= start;
+
+ // update dirty area
+ m_data->m_dirtyStart = m_start;
+ m_data->m_dirtyEnd = m_end;
+
+ dirty = true;
HEURISTICS (g_nAddRealloc++);
}
HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
- // update dirty area
- m_data->m_dirtyStart = m_start;
- m_data->m_dirtyEnd = m_end;
LOG_INTERNAL_STATE ("add start=" << start << ", ");
NS_ASSERT (CheckInternalState ());
+ return dirty;
}
-void
+bool
Buffer::AddAtEnd (uint32_t end)
{
+ NS_LOG_FUNCTION (this << end);
+ bool dirty;
NS_ASSERT (CheckInternalState ());
bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
@@ -411,26 +412,13 @@
*/
NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
m_end += end;
+ // update dirty area.
+ m_data->m_dirtyEnd = m_end;
+
+ dirty = m_end < m_data->m_dirtyEnd;
HEURISTICS (g_nAddNoRealloc++);
}
-#if 0
- // this is an optimization
- else if (GetInternalEnd () + end > m_data->m_size)
- {
- 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::Recycle (m_data);
- }
- m_data = newData;
-
- m_end += end;
- HEURISTICS (g_nAddRealloc++);
- }
-#endif
else
{
uint32_t newSize = GetInternalSize () + end;
@@ -443,28 +431,35 @@
}
m_data = newData;
+ int32_t delta = -m_start;
+ m_zeroAreaStart += delta;
+ m_zeroAreaEnd += delta;
+ m_end += delta;
+ m_start += delta;
+ m_end += end;
- m_zeroAreaStart -= m_start;
- m_zeroAreaEnd -= m_start;
- m_end -= m_start;
- m_start = 0;
+ // update dirty area
+ m_data->m_dirtyStart = m_start;
+ m_data->m_dirtyEnd = m_end;
- m_end += end;
+ dirty = true;
HEURISTICS (g_nAddRealloc++);
}
HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
- // update dirty area
- m_data->m_dirtyStart = m_start;
- m_data->m_dirtyEnd = m_end;
LOG_INTERNAL_STATE ("add end=" << end << ", ");
NS_ASSERT (CheckInternalState ());
+
+ return dirty;
}
-void
+void
Buffer::AddAtEnd (const Buffer &o)
{
- if (m_end == m_zeroAreaEnd &&
+ NS_LOG_FUNCTION (this << &o);
+ if (m_data->m_count == 1 &&
+ m_end == m_zeroAreaEnd &&
+ m_end == m_data->m_dirtyEnd &&
o.m_start == o.m_zeroAreaStart &&
o.m_zeroAreaEnd - o.m_zeroAreaStart > 0)
{
@@ -476,6 +471,7 @@
uint32_t zeroSize = o.m_zeroAreaEnd - o.m_zeroAreaStart;
m_zeroAreaEnd += zeroSize;
m_end = m_zeroAreaEnd;
+ m_data->m_dirtyEnd = m_zeroAreaEnd;
uint32_t endData = o.m_end - o.m_zeroAreaEnd;
AddAtEnd (endData);
Buffer::Iterator dst = End ();
@@ -483,8 +479,10 @@
Buffer::Iterator src = o.End ();
src.Prev (endData);
dst.Write (src, o.End ());
+ NS_ASSERT (CheckInternalState ());
return;
}
+
Buffer dst = CreateFullCopy ();
Buffer src = o.CreateFullCopy ();
@@ -493,11 +491,13 @@
destStart.Prev (src.GetSize ());
destStart.Write (src.Begin (), src.End ());
*this = dst;
+ NS_ASSERT (CheckInternalState ());
}
void
Buffer::RemoveAtStart (uint32_t start)
{
+ NS_LOG_FUNCTION (this << start);
NS_ASSERT (CheckInternalState ());
uint32_t newStart = m_start + start;
if (newStart <= m_zeroAreaStart)
@@ -542,6 +542,7 @@
void
Buffer::RemoveAtEnd (uint32_t end)
{
+ NS_LOG_FUNCTION (this << end);
NS_ASSERT (CheckInternalState ());
uint32_t newEnd = m_end - std::min (end, m_end - m_start);
if (newEnd > m_zeroAreaEnd)
@@ -577,6 +578,7 @@
Buffer
Buffer::CreateFragment (uint32_t start, uint32_t length) const
{
+ NS_LOG_FUNCTION (this << start << length);
NS_ASSERT (CheckInternalState ());
Buffer tmp = *this;
tmp.RemoveAtStart (start);
@@ -588,6 +590,7 @@
Buffer
Buffer::CreateFullCopy (void) const
{
+ NS_LOG_FUNCTION (this);
NS_ASSERT (CheckInternalState ());
if (m_zeroAreaEnd - m_zeroAreaStart != 0)
{
@@ -602,12 +605,25 @@
Buffer::Iterator i = tmp.End ();
i.Prev (dataEnd);
i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
+ NS_ASSERT (tmp.CheckInternalState ());
return tmp;
}
NS_ASSERT (CheckInternalState ());
return *this;
}
+int32_t
+Buffer::GetCurrentStartOffset (void) const
+{
+ return m_start;
+}
+int32_t
+Buffer::GetCurrentEndOffset (void) const
+{
+ return m_end;
+}
+
+
void
Buffer::TransformIntoRealBuffer (void) const
{
--- a/src/common/buffer.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/buffer.h Wed Jun 04 17:19:32 2008 -0400
@@ -36,6 +36,8 @@
namespace ns3 {
/**
+ * \ingroup packet
+ *
* \brief automatically resized byte buffer
*
* This represents a buffer of bytes. Its size is
@@ -392,6 +394,7 @@
/**
* \param start size to reserve
+ * \returns true if the buffer needed resizing, false otherwise.
*
* Add bytes at the start of the Buffer. The
* content of these bytes is undefined but debugging
@@ -399,9 +402,10 @@
* Any call to this method invalidates any Iterator
* pointing to this Buffer.
*/
- void AddAtStart (uint32_t start);
+ bool AddAtStart (uint32_t start);
/**
* \param end size to reserve
+ * \returns true if the buffer needed resizing, false otherwise.
*
* Add bytes at the end of the Buffer. The
* content of these bytes is undefined but debugging
@@ -409,8 +413,15 @@
* Any call to this method invalidates any Iterator
* pointing to this Buffer.
*/
- void AddAtEnd (uint32_t end);
+ bool AddAtEnd (uint32_t end);
+ /**
+ * \param o the buffer to append to the end of this buffer.
+ *
+ * Add bytes at the end of the Buffer.
+ * Any call to this method invalidates any Iterator
+ * pointing to this Buffer.
+ */
void AddAtEnd (const Buffer &o);
/**
* \param start size to remove
@@ -451,6 +462,9 @@
Buffer CreateFullCopy (void) const;
+ int32_t GetCurrentStartOffset (void) const;
+ int32_t GetCurrentEndOffset (void) const;
+
Buffer (Buffer const &o);
Buffer &operator = (Buffer const &o);
Buffer ();
--- a/src/common/chunk.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/chunk.h Wed Jun 04 17:19:32 2008 -0400
@@ -6,6 +6,11 @@
namespace ns3 {
+/**
+ * \ingroup packet
+ *
+ * \brief abstract base class for ns3::Header and ns3::Trailer
+ */
class Chunk : public ObjectBase
{
public:
--- a/src/common/data-rate.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/data-rate.h Wed Jun 04 17:19:32 2008 -0400
@@ -31,6 +31,11 @@
namespace ns3 {
/**
+ * \ingroup common
+ * \defgroup datarate Data Rate
+ */
+/**
+ * \ingroup datarate
* \brief Class for representing data rates
*
* Allows for natural and familiar use of data rates. Allows construction
@@ -80,7 +85,6 @@
*/
uint64_t GetBitRate() const;
- ATTRIBUTE_HELPER_HEADER_1 (DataRate);
private:
uint64_t m_bps;
static uint64_t Parse(const std::string);
@@ -94,7 +98,7 @@
* \brief hold objects of type ns3::DataRate
*/
-ATTRIBUTE_HELPER_HEADER_2 (DataRate);
+ATTRIBUTE_HELPER_HEADER (DataRate);
/**
* \param lhs
--- a/src/common/data-writer.cc Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 "data-writer.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include "ns3/assert.h"
-#include <string.h>
-#include <list>
-
-#define noTRACE_DATA_WRITER 1
-
-#ifdef TRACE_DATA_WRITER
-#include <iostream>
-# define TRACE(x) \
-std::cout << "DATA WRITER TRACE " << this << " " << x << std::endl;
-#else /* TRACE_DATA_WRITER */
-# define TRACE(format,...)
-#endif /* TRACE_DATA_WRITER */
-
-#define BUFFER_SIZE (4096)
-
-
-namespace ns3 {
-
-class DataWriterPrivate {
-public:
- DataWriterPrivate ();
- ~DataWriterPrivate ();
-
- void open (char const *filename);
- void write (uint8_t *buffer, uint32_t size);
-private:
- uint8_t m_data[BUFFER_SIZE];
- uint32_t m_current;
- int m_fd;
-};
-
-DataWriterPrivate::DataWriterPrivate ()
- : m_current (0)
-{}
-DataWriterPrivate::~DataWriterPrivate ()
-{
- ::Write (m_fd, m_data, m_current);
- ::Close (m_fd);
-}
-
-
-void
-DataWriterPrivate::Open (char const *filename)
-{
- m_fd = ::Open (filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
- NS_ASSERT (m_fd != -1);
-}
-
-#ifndef min
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif /* min */
-
-void
-DataWriterPrivate::Write (uint8_t *buffer, uint32_t size)
-{
- while (size > 0)
- {
- uint32_t toCopy = min (BUFFER_SIZE - m_current, size);
- memcpy (m_data + m_current, buffer, toCopy);
- size -= toCopy;
- m_current += toCopy;
- buffer += toCopy;
- if (m_current == BUFFER_SIZE)
- {
- ssize_t written = 0;
- written = ::Write (m_fd, m_data, BUFFER_SIZE);
- NS_ASSERT (written == BUFFER_SIZE);
- m_current = 0;
- }
- }
-}
-
-DataWriter::DataWriter ()
- : m_priv (new DataWriterPrivate ())
-{}
-DataWriter::~DataWriter ()
-{
- delete m_priv;
- m_priv = 0;
-}
-
-void
-DataWriter::Open (char const *filename)
-{
- m_priv->Open (filename);
-}
-void
-DataWriter::Write (uint8_t *buffer, uint32_t size)
-{
- m_priv->Write (buffer, size);
-}
-
-}; // namespace
--- a/src/common/data-writer.h Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 DATA_WRITER_H
-#define DATA_WRITER_H
-
-#include <stdint.h>
-
-namespace ns3 {
-
-class DataWriterPrivate;
-
-class DataWriter {
-public:
- DataWriter ();
- ~DataWriter ();
-
- void open (char const *filename);
- void write (uint8_t *buffer, uint32_t size);
-private:
- DataWriterPrivate *m_priv;
-};
-
-}; //namespace ns3
-
-#endif /* DATA_WRITER_H */
--- a/src/common/error-model.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/error-model.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,6 +30,11 @@
class Packet;
/**
+ * \ingroup common
+ * \defgroup errormodel Error Model
+ */
+/**
+ * \ingroup errormodel
* \brief General error model that can be used to corrupt packets
*
* This object is used to flag packets as being lost/errored or not.
--- a/src/common/header.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/header.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,13 +28,13 @@
namespace ns3 {
/**
+ * \ingroup packet
+ *
* \brief Protocol header serialization and deserialization.
*
* Every Protocol header which needs to be inserted or removed
* 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.
+ * implement the pure virtual methods defined here.
*
* 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
--- a/src/common/packet-metadata-test.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/common/packet-metadata-test.cc Wed Jun 04 17:19:32 2008 -0400
@@ -28,44 +28,74 @@
#include "packet.h"
#include "packet-metadata.h"
-namespace ns3 {
+using namespace ns3;
+
+namespace {
+
+class HistoryHeaderBase : public Header
+{
+public:
+ static TypeId GetTypeId (void);
+ HistoryHeaderBase ();
+ bool IsOk (void) const;
+protected:
+ void ReportError (void);
+private:
+ bool m_ok;
+};
+
+TypeId
+HistoryHeaderBase::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::HistoryHeaderBase")
+ .SetParent<Header> ()
+ ;
+ return tid;
+}
+
+HistoryHeaderBase::HistoryHeaderBase ()
+ : m_ok (true)
+{}
+
+bool
+HistoryHeaderBase::IsOk (void) const
+{
+ return m_ok;
+}
+void
+HistoryHeaderBase::ReportError (void)
+{
+ m_ok = false;
+}
+
template <int N>
-class HistoryHeader : public Header
+class HistoryHeader : public HistoryHeaderBase
{
public:
HistoryHeader ();
- bool IsOk (void) const;
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual void Print (std::ostream &os) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
-private:
- bool m_ok;
};
template <int N>
HistoryHeader<N>::HistoryHeader ()
- : m_ok (false)
+ : HistoryHeaderBase ()
{}
template <int N>
-bool
-HistoryHeader<N>::IsOk (void) const
-{
- return m_ok;
-}
-
-template <int N>
TypeId
HistoryHeader<N>::GetTypeId (void)
{
std::ostringstream oss;
oss << "ns3::HistoryHeader<"<<N<<">";
static TypeId tid = TypeId (oss.str ().c_str ())
- .SetParent<Header> ()
+ .SetParent<HistoryHeaderBase> ()
+ .AddConstructor<HistoryHeader<N> > ()
;
return tid;
}
@@ -98,19 +128,53 @@
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;
+ ReportError ();
}
}
return N;
}
+class HistoryTrailerBase : public Trailer
+{
+public:
+ static TypeId GetTypeId (void);
+ HistoryTrailerBase ();
+ bool IsOk (void) const;
+protected:
+ void ReportError (void);
+private:
+ bool m_ok;
+};
+
+TypeId
+HistoryTrailerBase::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::HistoryTrailerBase")
+ .SetParent<Trailer> ()
+ ;
+ return tid;
+}
+HistoryTrailerBase::HistoryTrailerBase ()
+ : m_ok (true)
+{}
+bool
+HistoryTrailerBase::IsOk (void) const
+{
+ return m_ok;
+}
+void
+HistoryTrailerBase::ReportError (void)
+{
+ m_ok = false;
+}
+
+
template <int N>
-class HistoryTrailer : public Trailer
+class HistoryTrailer : public HistoryTrailerBase
{
public:
HistoryTrailer ();
@@ -128,24 +192,17 @@
template <int N>
HistoryTrailer<N>::HistoryTrailer ()
- : m_ok (false)
{}
template <int N>
-bool
-HistoryTrailer<N>::IsOk (void) const
-{
- return m_ok;
-}
-
-template <int N>
TypeId
HistoryTrailer<N>::GetTypeId (void)
{
std::ostringstream oss;
oss << "ns3::HistoryTrailer<"<<N<<">";
static TypeId tid = TypeId (oss.str ().c_str ())
- .SetParent<Trailer> ()
+ .SetParent<HistoryTrailerBase> ()
+ .AddConstructor<HistoryTrailer<N> > ()
;
return tid;
}
@@ -179,18 +236,21 @@
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;
+ ReportError ();
}
}
return N;
}
+}
+
+namespace ns3 {
+
class PacketMetadataTest : public Test {
@@ -228,6 +288,43 @@
while (k.HasNext ())
{
struct PacketMetadata::Item item = k.Next ();
+ if (item.isFragment || item.type == PacketMetadata::Item::PAYLOAD)
+ {
+ got.push_back (item.currentSize);
+ continue;
+ }
+ if (item.type == PacketMetadata::Item::HEADER)
+ {
+ Callback<ObjectBase *> constructor = item.tid.GetConstructor ();
+ HistoryHeaderBase *header = dynamic_cast<HistoryHeaderBase *> (constructor ());
+ if (header == 0)
+ {
+ goto error;
+ }
+ header->Deserialize (item.current);
+ if (!header->IsOk ())
+ {
+ delete header;
+ goto error;
+ }
+ delete header;
+ }
+ else if (item.type == PacketMetadata::Item::TRAILER)
+ {
+ Callback<ObjectBase *> constructor = item.tid.GetConstructor ();
+ HistoryTrailerBase *trailer = dynamic_cast<HistoryTrailerBase *> (constructor ());
+ if (trailer == 0)
+ {
+ goto error;
+ }
+ trailer->Deserialize (item.current);
+ if (!trailer->IsOk ())
+ {
+ delete trailer;
+ goto error;
+ }
+ delete trailer;
+ }
got.push_back (item.currentSize);
}
@@ -285,7 +382,7 @@
if (!CheckHistory (p, __FILE__, \
__LINE__, __VA_ARGS__)) \
{ \
- ok = false; \
+ result = false; \
} \
Buffer buffer; \
buffer = p->Serialize (); \
@@ -294,7 +391,7 @@
if (!CheckHistory (otherPacket, __FILE__, \
__LINE__, __VA_ARGS__)) \
{ \
- ok = false; \
+ result = false; \
} \
}
@@ -309,7 +406,7 @@
bool
PacketMetadataTest::RunTests (void)
{
- bool ok = true;
+ bool result = true;
PacketMetadata::Enable ();
@@ -607,7 +704,55 @@
p = Create<Packet> (16383);
p = Create<Packet> (16384);
- return ok;
+
+ // bug 179.
+ p = Create<Packet> (40);
+ p2 = p->CreateFragment (5, 5);
+ p3 = p->CreateFragment (10, 30);
+ ADD_HEADER (p2, 8);
+ ADD_HEADER (p3, 8);
+ REM_HEADER (p2, 8);
+ REM_HEADER (p3, 8);
+ p2->AddAtEnd (p3);
+
+
+ p = Create<Packet> (1000);
+ ADD_HEADER (p, 10);
+ ADD_TRAILER (p, 5);
+ p1 = p->Copy ();
+ ADD_HEADER (p1, 20);
+ REM_HEADER (p1, 20);
+ REM_TRAILER (p1, 5);
+ NS_TEST_ASSERT_EQUAL (p->GetSize (), 1015);
+
+
+ p = Create<Packet> (1510);
+ ADD_HEADER (p, 8);
+ ADD_HEADER (p, 25);
+ REM_HEADER (p, 25);
+ ADD_HEADER (p, 1);
+ p1 = p->CreateFragment (0, 1500);
+ p2 = p1->Copy ();
+ ADD_HEADER (p2, 24);
+ NS_TEST_ASSERT_EQUAL (p->GetSize (), 1519);
+
+ p = Create<Packet> (1000);
+ ADD_HEADER (p, 2);
+ ADD_TRAILER (p, 3);
+ p1 = p->Copy ();
+ CHECK_HISTORY (p1, 3, 2, 1000, 3);
+ REM_HEADER (p, 2);
+ ADD_HEADER (p, 1);
+ CHECK_HISTORY (p, 3, 1, 1000, 3);
+ CHECK_HISTORY (p1, 3, 2, 1000, 3);
+
+ p = Create<Packet> (200);
+ ADD_HEADER (p, 24);
+ p1 = p->CreateFragment(0, 100);
+ p2 = p->CreateFragment(100, 100);
+ p1->AddAtEnd (p2);
+
+ return result;
}
static PacketMetadataTest g_packetHistoryTest;
--- a/src/common/packet-metadata.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/common/packet-metadata.cc Wed Jun 04 17:19:32 2008 -0400
@@ -178,100 +178,13 @@
value >>= 8;
buffer[1] = value;
}
-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)
+void
+PacketMetadata::Append32 (uint32_t value, uint8_t *buffer)
{
- 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;
+ buffer[0] = value & 0xff;
+ buffer[1] = (value >> 8) & 0xff;
+ buffer[2] = (value >> 16) & 0xff;
+ buffer[3] = (value >> 24) & 0xff;
}
void
@@ -342,6 +255,7 @@
void
PacketMetadata::UpdateTail (uint16_t written)
{
+ NS_LOG_FUNCTION (this << written);
if (m_head == 0xffff)
{
NS_ASSERT (m_tail == 0xffff);
@@ -368,6 +282,7 @@
void
PacketMetadata::UpdateHead (uint16_t written)
{
+ NS_LOG_FUNCTION (this << written);
if (m_head == 0xffff)
{
NS_ASSERT (m_tail == 0xffff);
@@ -393,33 +308,29 @@
uint16_t
PacketMetadata::AddSmall (const struct PacketMetadata::SmallItem *item)
{
+ NS_LOG_FUNCTION (this << item->next << item->prev << item->typeUid << item->size << item->chunkUid);
NS_ASSERT (m_data != 0);
NS_ASSERT (m_used != item->prev && m_used != item->next);
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
+ uint32_t n = 2 + 2 + typeUidSize + sizeSize + 2;
+ if (m_used + n > m_data->m_size ||
+ (m_head != 0xffff &&
+ m_data->m_count != 1 &&
+ m_used != m_data->m_dirtyEnd))
{
ReserveCopy (n);
- goto restart;
}
+ 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);
return n;
}
@@ -428,76 +339,110 @@
const PacketMetadata::SmallItem *item,
const PacketMetadata::ExtraItem *extraItem)
{
+ NS_LOG_FUNCTION (this << next << prev <<
+ item->next << item->prev << item->typeUid << item->size << item->chunkUid <<
+ extraItem->fragmentStart << extraItem->fragmentEnd << extraItem->packetUid);
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;
+
+ uint32_t typeUidSize = GetUleb128Size (typeUid);
+ uint32_t sizeSize = GetUleb128Size (item->size);
+ uint32_t fragStartSize = GetUleb128Size (extraItem->fragmentStart);
+ uint32_t fragEndSize = GetUleb128Size (extraItem->fragmentEnd);
+ uint32_t n = 2 + 2 + typeUidSize + sizeSize + 2 + fragStartSize + fragEndSize + 4;
- 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;
- }
+ if (m_used + n > m_data->m_size ||
+ (m_head != 0xffff &&
+ m_data->m_count != 1 &&
+ m_used != m_data->m_dirtyEnd))
+ {
+ ReserveCopy (n);
}
- 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;
+ uint8_t *buffer = &m_data->m_data[m_used];
+
+ Append16 (next, buffer);
+ buffer += 2;
+ Append16 (prev, buffer);
+ buffer += 2;
+ AppendValue (typeUid, buffer);
+ buffer += typeUidSize;
+ AppendValue (item->size, buffer);
+ buffer += sizeSize;
+ Append16 (item->chunkUid, buffer);
+ buffer += 2;
+ AppendValue (extraItem->fragmentStart, buffer);
+ buffer += fragStartSize;
+ AppendValue (extraItem->fragmentEnd, buffer);
+ buffer += fragEndSize;
+ Append32 (extraItem->packetUid, buffer);
+
+ return n;
}
+/**
+ * \param item the item data to write
+ * \param extraItem the extra item data to write
+ * \param available the number of bytes which can
+ * be written without having to rewrite the buffer entirely.
+ */
void
PacketMetadata::ReplaceTail (PacketMetadata::SmallItem *item,
PacketMetadata::ExtraItem *extraItem,
uint32_t available)
{
+ NS_LOG_FUNCTION (this <<
+ item->next << item->prev << item->typeUid << item->size << item->chunkUid <<
+ extraItem->fragmentStart << extraItem->fragmentEnd << extraItem->packetUid <<
+ available);
+
NS_ASSERT (m_data != 0);
- if (available >= 14 &&
+ /* If the tail we want to replace is located at the end of the data array,
+ * and if there is extra room at the end of this array, then,
+ * we can try to use that extra space to avoid falling in the slow
+ * path below.
+ */
+ if (m_tail + available == m_used &&
+ m_used == m_data->m_dirtyEnd)
+ {
+ available = m_data->m_size - m_tail;
+ }
+
+ uint32_t typeUid = ((item->typeUid & 0x1) == 0x1)?item->typeUid:item->typeUid+1;
+ uint32_t typeUidSize = GetUleb128Size (typeUid);
+ uint32_t sizeSize = GetUleb128Size (item->size);
+ uint32_t fragStartSize = GetUleb128Size (extraItem->fragmentStart);
+ uint32_t fragEndSize = GetUleb128Size (extraItem->fragmentEnd);
+ uint32_t n = 2 + 2 + typeUidSize + sizeSize + 2 + fragStartSize + fragEndSize + 4;
+
+ if (available >= n &&
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;
- }
+ AppendValue (typeUid, buffer);
+ buffer += typeUidSize;
+ AppendValue (item->size, buffer);
+ buffer += sizeSize;
+ Append16 (item->chunkUid, buffer);
+ buffer += 2;
+ AppendValue (extraItem->fragmentStart, buffer);
+ buffer += fragStartSize;
+ AppendValue (extraItem->fragmentEnd, buffer);
+ buffer += fragEndSize;
+ Append32 (extraItem->packetUid, buffer);
+ m_used = buffer - &m_data->m_data[0];
+ m_data->m_dirtyEnd = m_used;
+ return;
}
+
+ /* Below is the slow path which is hit if the new tail we want
+ * to append is bigger than the previous tail.
+ */
// create a copy of the packet.
PacketMetadata h (m_packetUid, 0);
@@ -510,6 +455,7 @@
uint16_t written = h.AddBig (0xffff, h.m_tail,
&tmpItem, &tmpExtraItem);
h.UpdateTail (written);
+ current = tmpItem.next;
}
// append new tail.
uint16_t written = h.AddBig (0xffff, h.m_tail, item, extraItem);
@@ -518,11 +464,18 @@
*this = h;
}
+/**
+ * \param current the offset we should start reading the data from
+ * \param item pointer to where we should store the data to return to the caller
+ * \param extraItem pointer to where we should store the data to return to the caller
+ * \returns the number of bytes read.
+ */
uint32_t
PacketMetadata::ReadItems (uint16_t current,
struct PacketMetadata::SmallItem *item,
struct PacketMetadata::ExtraItem *extraItem) const
{
+ NS_LOG_FUNCTION (this << current);
const uint8_t *buffer = &m_data->m_data[current];
item->next = buffer[0];
item->next |= (buffer[1]) << 8;
@@ -644,12 +597,12 @@
void
PacketMetadata::DoAddHeader (uint32_t uid, uint32_t size)
{
+ NS_LOG_FUNCTION (this << uid << size);
if (!m_enable)
{
m_metadataSkipped = true;
return;
}
- NS_LOG_FUNCTION ("uid=" << uid << "size=" << size << "");
struct PacketMetadata::SmallItem item;
item.next = m_head;
@@ -665,12 +618,12 @@
PacketMetadata::RemoveHeader (const Header &header, uint32_t size)
{
uint32_t uid = header.GetInstanceTypeId ().GetUid () << 1;
+ NS_LOG_FUNCTION (this << uid << size);
if (!m_enable)
{
m_metadataSkipped = true;
return;
}
- NS_LOG_FUNCTION ("(uid=" << uid << ", size=" << size << ")");
struct PacketMetadata::SmallItem item;
struct PacketMetadata::ExtraItem extraItem;
uint32_t read = ReadItems (m_head, &item, &extraItem);
@@ -703,12 +656,12 @@
PacketMetadata::AddTrailer (const Trailer &trailer, uint32_t size)
{
uint32_t uid = trailer.GetInstanceTypeId ().GetUid () << 1;
+ NS_LOG_FUNCTION (this << uid << size);
if (!m_enable)
{
m_metadataSkipped = true;
return;
}
- NS_LOG_FUNCTION ("(uid=" << uid << ", size=" << size << ")");
struct PacketMetadata::SmallItem item;
item.next = 0xffff;
item.prev = m_tail;
@@ -723,12 +676,12 @@
PacketMetadata::RemoveTrailer (const Trailer &trailer, uint32_t size)
{
uint32_t uid = trailer.GetInstanceTypeId ().GetUid () << 1;
+ NS_LOG_FUNCTION (this << uid << size);
if (!m_enable)
{
m_metadataSkipped = true;
return;
}
- NS_LOG_FUNCTION ("(uid=" << uid << ", size=" << size << ")");
struct PacketMetadata::SmallItem item;
struct PacketMetadata::ExtraItem extraItem;
uint32_t read = ReadItems (m_tail, &item, &extraItem);
@@ -760,6 +713,7 @@
void
PacketMetadata::AddAtEnd (PacketMetadata const&o)
{
+ NS_LOG_FUNCTION (this << &o);
if (!m_enable)
{
m_metadataSkipped = true;
@@ -767,46 +721,52 @@
}
if (m_tail == 0xffff)
{
+ // We have no items so 'AddAtEnd' is
+ // equivalent to self-assignment.
*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)
+ // We read the current tail because we are going to append
+ // after this item.
+ struct PacketMetadata::SmallItem tailItem;
+ PacketMetadata::ExtraItem tailExtraItem;
+ uint32_t tailSize = ReadItems (m_tail, &tailItem, &tailExtraItem);
+
+ uint16_t current;
+ struct PacketMetadata::SmallItem item;
+ PacketMetadata::ExtraItem extraItem;
+ o.ReadItems (o.m_head, &item, &extraItem);
+ if (extraItem.packetUid == tailExtraItem.packetUid &&
+ item.typeUid == tailItem.typeUid &&
+ item.chunkUid == tailItem.chunkUid &&
+ item.size == tailItem.size &&
+ extraItem.fragmentStart == tailExtraItem.fragmentEnd)
{
- lastTailSize = m_data->m_size - m_tail;
+ /* If the previous tail came from the same header as
+ * the next item we want to append to our array, then,
+ * we merge them and attempt to reuse the previous tail's
+ * location.
+ */
+ tailExtraItem.fragmentEnd = extraItem.fragmentEnd;
+ ReplaceTail (&tailItem, &tailExtraItem, tailSize);
+ current = item.next;
+ }
+ else
+ {
+ current = o.m_head;
}
- uint16_t current = o.m_head;
+ /* Now that we have merged our current tail with the head of the
+ * next packet, we just append all items from the next packet
+ * to the current packet.
+ */
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);
- }
+ uint16_t written = AddBig (0xffff, m_tail, &item, &extraItem);
+ UpdateTail (written);
if (current == o.m_tail)
{
break;
@@ -826,6 +786,7 @@
void
PacketMetadata::RemoveAtStart (uint32_t start)
{
+ NS_LOG_FUNCTION (this << start);
if (!m_enable)
{
m_metadataSkipped = true;
@@ -891,6 +852,7 @@
void
PacketMetadata::RemoveAtEnd (uint32_t end)
{
+ NS_LOG_FUNCTION (this << end);
if (!m_enable)
{
m_metadataSkipped = true;
@@ -1069,6 +1031,7 @@
uint32_t
PacketMetadata::GetSerializedSize (void) const
{
+ NS_LOG_FUNCTION (this);
uint32_t totalSize = 0;
totalSize += 4;
if (!m_enable)
@@ -1105,6 +1068,7 @@
void
PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const
{
+ NS_LOG_FUNCTION (this);
uint32_t bytesWritten = 0;
i.WriteU32 (size);
bytesWritten += 4;
@@ -1160,6 +1124,7 @@
uint32_t
PacketMetadata::Deserialize (Buffer::Iterator i)
{
+ NS_LOG_FUNCTION (this);
struct PacketMetadata::SmallItem item;
struct PacketMetadata::ExtraItem extraItem;
uint32_t totalSize = i.ReadU32 ();
--- a/src/common/packet-metadata.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/packet-metadata.h Wed Jun 04 17:19:32 2008 -0400
@@ -36,6 +36,7 @@
/**
* \internal
+ * \ingroup packet
* \brief handle packet metadata about packet headers and trailers
*
* This class is used by the Packet class to record every operation
@@ -249,13 +250,11 @@
uint32_t available);
inline void UpdateHead (uint16_t written);
inline void UpdateTail (uint16_t written);
- uint32_t GetUleb128Size (uint32_t value) const;
+ inline 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 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);
+ inline void Append32 (uint32_t value, uint8_t *buffer);
+ inline 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);
--- a/src/common/packet.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/common/packet.cc Wed Jun 04 17:19:32 2008 -0400
@@ -19,11 +19,63 @@
*/
#include "packet.h"
#include "ns3/assert.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("Packet");
namespace ns3 {
uint32_t Packet::m_globalUid = 0;
+TypeId
+TagIterator::Item::GetTypeId (void) const
+{
+ return m_tid;
+}
+uint32_t
+TagIterator::Item::GetStart (void) const
+{
+ return m_start;
+}
+uint32_t
+TagIterator::Item::GetEnd (void) const
+{
+ return m_end;
+}
+void
+TagIterator::Item::GetTag (Tag &tag) const
+{
+ if (tag.GetInstanceTypeId () != GetTypeId ())
+ {
+ NS_FATAL_ERROR ("The tag you provided is not of the right type.");
+ }
+ tag.Deserialize (m_buffer);
+}
+TagIterator::Item::Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer)
+ : m_tid (tid),
+ m_start (start),
+ m_end (end),
+ m_buffer (buffer)
+{}
+bool
+TagIterator::HasNext (void) const
+{
+ return m_current.HasNext ();
+}
+TagIterator::Item
+TagIterator::Next (void)
+{
+ TagList::Iterator::Item i = m_current.Next ();
+ return TagIterator::Item (i.tid,
+ i.start-m_current.GetOffsetStart (),
+ i.end-m_current.GetOffsetStart (),
+ i.buf);
+}
+TagIterator::TagIterator (TagList::Iterator i)
+ : m_current (i)
+{}
+
+
void
Packet::Ref (void) const
{
@@ -50,7 +102,7 @@
Packet::Packet ()
: m_buffer (),
- m_tags (),
+ m_tagList (),
m_metadata (m_globalUid, 0),
m_refCount (1)
{
@@ -59,7 +111,7 @@
Packet::Packet (const Packet &o)
: m_buffer (o.m_buffer),
- m_tags (o.m_tags),
+ m_tagList (o.m_tagList),
m_metadata (o.m_metadata),
m_refCount (1)
{}
@@ -72,14 +124,14 @@
return *this;
}
m_buffer = o.m_buffer;
- m_tags = o.m_tags;
+ m_tagList = o.m_tagList;
m_metadata = o.m_metadata;
return *this;
}
Packet::Packet (uint32_t size)
: m_buffer (size),
- m_tags (),
+ m_tagList (),
m_metadata (m_globalUid, size),
m_refCount (1)
{
@@ -87,7 +139,7 @@
}
Packet::Packet (uint8_t const*buffer, uint32_t size)
: m_buffer (),
- m_tags (),
+ m_tagList (),
m_metadata (m_globalUid, size),
m_refCount (1)
{
@@ -97,9 +149,9 @@
i.Write (buffer, size);
}
-Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
+Packet::Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata)
: m_buffer (buffer),
- m_tags (tags),
+ m_tagList (tagList),
m_metadata (metadata),
m_refCount (1)
{}
@@ -107,13 +159,14 @@
Ptr<Packet>
Packet::CreateFragment (uint32_t start, uint32_t length) const
{
+ NS_LOG_FUNCTION (this << start << length);
Buffer buffer = m_buffer.CreateFragment (start, length);
NS_ASSERT (m_buffer.GetSize () >= start + length);
uint32_t end = m_buffer.GetSize () - (start + length);
PacketMetadata metadata = m_metadata.CreateFragment (start, end);
// again, call the constructor directly rather than
// through Create because it is private.
- return Ptr<Packet> (new Packet (buffer, m_tags, metadata), false);
+ return Ptr<Packet> (new Packet (buffer, m_tagList, metadata), false);
}
uint32_t
@@ -125,14 +178,22 @@
void
Packet::AddHeader (const Header &header)
{
+ NS_LOG_FUNCTION (this << &header);
uint32_t size = header.GetSerializedSize ();
- m_buffer.AddAtStart (size);
+ uint32_t orgStart = m_buffer.GetCurrentStartOffset ();
+ bool resized = m_buffer.AddAtStart (size);
+ if (resized)
+ {
+ m_tagList.AddAtStart (m_buffer.GetCurrentStartOffset () - orgStart,
+ m_buffer.GetCurrentStartOffset () + size);
+ }
header.Serialize (m_buffer.Begin ());
m_metadata.AddHeader (header, size);
}
uint32_t
Packet::RemoveHeader (Header &header)
{
+ NS_LOG_FUNCTION (this << &header);
uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
m_buffer.RemoveAtStart (deserialized);
m_metadata.RemoveHeader (header, deserialized);
@@ -141,8 +202,15 @@
void
Packet::AddTrailer (const Trailer &trailer)
{
+ NS_LOG_FUNCTION (this << &trailer);
uint32_t size = trailer.GetSerializedSize ();
- m_buffer.AddAtEnd (size);
+ uint32_t orgEnd = m_buffer.GetCurrentEndOffset ();
+ bool resized = m_buffer.AddAtEnd (size);
+ if (resized)
+ {
+ m_tagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd,
+ m_buffer.GetCurrentEndOffset () - size);
+ }
Buffer::Iterator end = m_buffer.End ();
trailer.Serialize (end);
m_metadata.AddTrailer (trailer, size);
@@ -150,6 +218,7 @@
uint32_t
Packet::RemoveTrailer (Trailer &trailer)
{
+ NS_LOG_FUNCTION (this << &trailer);
uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
m_buffer.RemoveAtEnd (deserialized);
m_metadata.RemoveTrailer (trailer, deserialized);
@@ -159,28 +228,43 @@
void
Packet::AddAtEnd (Ptr<const Packet> packet)
{
+ NS_LOG_FUNCTION (this << packet);
+ uint32_t aStart = m_buffer.GetCurrentStartOffset ();
+ uint32_t bEnd = packet->m_buffer.GetCurrentEndOffset ();
m_buffer.AddAtEnd (packet->m_buffer);
- /**
- * XXX: we might need to merge the tag list of the
- * other packet into the current packet.
- */
+ uint32_t appendPrependOffset = m_buffer.GetCurrentEndOffset () - packet->m_buffer.GetSize ();
+ m_tagList.AddAtEnd (m_buffer.GetCurrentStartOffset () - aStart,
+ appendPrependOffset);
+ TagList copy = packet->m_tagList;
+ copy.AddAtStart (m_buffer.GetCurrentEndOffset () - bEnd,
+ appendPrependOffset);
+ m_tagList.Add (copy);
m_metadata.AddAtEnd (packet->m_metadata);
}
void
Packet::AddPaddingAtEnd (uint32_t size)
{
- m_buffer.AddAtEnd (size);
+ NS_LOG_FUNCTION (this << size);
+ uint32_t orgEnd = m_buffer.GetCurrentEndOffset ();
+ bool resized = m_buffer.AddAtEnd (size);
+ if (resized)
+ {
+ m_tagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd,
+ m_buffer.GetCurrentEndOffset () - size);
+ }
m_metadata.AddPaddingAtEnd (size);
}
void
Packet::RemoveAtEnd (uint32_t size)
{
+ NS_LOG_FUNCTION (this << size);
m_buffer.RemoveAtEnd (size);
m_metadata.RemoveAtEnd (size);
}
void
Packet::RemoveAtStart (uint32_t size)
{
+ NS_LOG_FUNCTION (this << size);
m_buffer.RemoveAtStart (size);
m_metadata.RemoveAtStart (size);
}
@@ -188,7 +272,8 @@
void
Packet::RemoveAllTags (void)
{
- m_tags.RemoveAll ();
+ NS_LOG_FUNCTION (this);
+ m_tagList.RemoveAll ();
}
uint8_t const *
@@ -206,7 +291,30 @@
void
Packet::PrintTags (std::ostream &os) const
{
- m_tags.Print (os, " ");
+ TagIterator i = GetTagIterator ();
+ while (i.HasNext ())
+ {
+ TagIterator::Item item = i.Next ();
+ os << item.GetTypeId ().GetName () << " [" << item.GetStart () << "-" << item.GetEnd () << "]";
+ Callback<ObjectBase *> constructor = item.GetTypeId ().GetConstructor ();
+ if (constructor.IsNull ())
+ {
+ if (i.HasNext ())
+ {
+ os << " ";
+ }
+ continue;
+ }
+ Tag *tag = dynamic_cast<Tag *> (constructor ());
+ NS_ASSERT (tag != 0);
+ os << " ";
+ tag->Print (os);
+ if (i.HasNext ())
+ {
+ os << " ";
+ }
+ delete tag;
+ }
}
void
@@ -335,12 +443,14 @@
void
Packet::EnableMetadata (void)
{
+ NS_LOG_FUNCTION_NOARGS ();
PacketMetadata::Enable ();
}
Buffer
Packet::Serialize (void) const
{
+ NS_LOG_FUNCTION (this);
Buffer buffer;
uint32_t reserve;
@@ -350,24 +460,25 @@
m_metadata.Serialize (buffer.Begin (), reserve);
// write tags
- reserve = m_tags.GetSerializedSize ();
- buffer.AddAtStart (reserve);
- m_tags.Serialize (buffer.Begin (), reserve);
+ //XXX
+ //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 ());
+ tmp.AddAtEnd (buffer);
// write byte buffer size.
- buffer.AddAtStart (4);
- buffer.Begin ().WriteU32 (m_buffer.GetSize ());
+ tmp.AddAtStart (4);
+ tmp.Begin ().WriteU32 (m_buffer.GetSize ());
- return buffer;
+ return tmp;
}
void
Packet::Deserialize (Buffer buffer)
{
+ NS_LOG_FUNCTION (this);
Buffer buf = buffer;
// read size
uint32_t packetSize = buf.Begin ().ReadU32 ();
@@ -376,11 +487,13 @@
// read buffer.
buf.RemoveAtEnd (buf.GetSize () - packetSize);
m_buffer = buf;
+ buffer.RemoveAtStart (4 + packetSize);
+
// read tags
- buffer.RemoveAtStart (4 + packetSize);
- uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
- buffer.RemoveAtStart (tagsDeserialized);
+ //XXX
+ //uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
+ //buffer.RemoveAtStart (tagsDeserialized);
// read metadata
uint32_t metadataDeserialized =
@@ -388,6 +501,39 @@
buffer.RemoveAtStart (metadataDeserialized);
}
+void
+Packet::AddTag (const Tag &tag) const
+{
+ NS_LOG_FUNCTION (this << &tag);
+ TagList *list = const_cast<TagList *> (&m_tagList);
+ TagBuffer buffer = list->Add (tag.GetInstanceTypeId (), tag.GetSerializedSize (),
+ m_buffer.GetCurrentStartOffset (),
+ m_buffer.GetCurrentEndOffset ());
+ tag.Serialize (buffer);
+}
+TagIterator
+Packet::GetTagIterator (void) const
+{
+ return TagIterator (m_tagList.Begin (m_buffer.GetCurrentStartOffset (), m_buffer.GetCurrentEndOffset ()));
+}
+
+bool
+Packet::FindFirstMatchingTag (Tag &tag) const
+{
+ TypeId tid = tag.GetInstanceTypeId ();
+ TagIterator i = GetTagIterator ();
+ while (i.HasNext ())
+ {
+ TagIterator::Item item = i.Next ();
+ if (tid == item.GetTypeId ())
+ {
+ item.GetTag (tag);
+ return true;
+ }
+ }
+ return false;
+}
+
std::ostream& operator<< (std::ostream& os, const Packet &packet)
{
packet.Print (os);
@@ -403,24 +549,190 @@
#include "ns3/test.h"
#include <string>
+#include <stdarg.h>
+
+using namespace ns3;
+
+namespace {
+
+class ATestTagBase : public Tag
+{
+public:
+ ATestTagBase () : m_error (false) {}
+ bool m_error;
+};
+
+template <int N>
+class ATestTag : public ATestTagBase
+{
+public:
+ static TypeId GetTypeId (void) {
+ std::ostringstream oss;
+ oss << "anon::ATestTag<" << N << ">";
+ static TypeId tid = TypeId (oss.str ().c_str ())
+ .SetParent<Tag> ()
+ .AddConstructor<ATestTag<N> > ()
+ .HideFromDocumentation ()
+ ;
+ return tid;
+ }
+ virtual TypeId GetInstanceTypeId (void) const {
+ return GetTypeId ();
+ }
+ virtual uint32_t GetSerializedSize (void) const {
+ return N;
+ }
+ virtual void Serialize (TagBuffer buf) const {
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ buf.WriteU8 (N);
+ }
+ }
+ virtual void Deserialize (TagBuffer buf) {
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ uint8_t v = buf.ReadU8 ();
+ if (v != N)
+ {
+ m_error = true;
+ }
+ }
+ }
+ virtual void Print (std::ostream &os) const {
+ os << N;
+ }
+ ATestTag ()
+ : ATestTagBase () {}
+};
+
+class ATestHeaderBase : public Header
+{
+public:
+ ATestHeaderBase () : Header (), m_error (false) {}
+ bool m_error;
+};
+
+template <int N>
+class ATestHeader : public ATestHeaderBase
+{
+public:
+ static TypeId GetTypeId (void) {
+ std::ostringstream oss;
+ oss << "anon::ATestHeader<" << N << ">";
+ static TypeId tid = TypeId (oss.str ().c_str ())
+ .SetParent<Header> ()
+ .AddConstructor<ATestHeader<N> > ()
+ .HideFromDocumentation ()
+ ;
+ return tid;
+ }
+ virtual TypeId GetInstanceTypeId (void) const {
+ return GetTypeId ();
+ }
+ virtual uint32_t GetSerializedSize (void) const {
+ return N;
+ }
+ virtual void Serialize (Buffer::Iterator iter) const {
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ iter.WriteU8 (N);
+ }
+ }
+ virtual uint32_t Deserialize (Buffer::Iterator iter) {
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ uint8_t v = iter.ReadU8 ();
+ if (v != N)
+ {
+ m_error = true;
+ }
+ }
+ return N;
+ }
+ virtual void Print (std::ostream &os) const {
+ }
+ ATestHeader ()
+ : ATestHeaderBase () {}
+
+};
+
+struct Expected
+{
+ Expected (uint32_t n_, uint32_t start_, uint32_t end_)
+ : n (n_), start (start_), end (end_) {}
+
+ uint32_t n;
+ uint32_t start;
+ uint32_t end;
+};
+
+}
+
+#define E(a,b,c) a,b,c
+
+#define CHECK(p, n, ...) \
+ if (!DoCheck (p, __FILE__, __LINE__, n, __VA_ARGS__)) \
+ { \
+ result = false; \
+ }
namespace ns3 {
-class PacketTest: public Test {
+
+class PacketTest: public Test
+{
public:
+ PacketTest ();
virtual bool RunTests (void);
- PacketTest ();
+private:
+ bool DoCheck (Ptr<const Packet> p, const char *file, int line, uint32_t n, ...);
};
PacketTest::PacketTest ()
: Test ("Packet") {}
+bool
+PacketTest::DoCheck (Ptr<const Packet> p, const char *file, int line, uint32_t n, ...)
+{
+ bool result = true;
+ std::vector<struct Expected> expected;
+ va_list ap;
+ va_start (ap, n);
+ for (uint32_t k = 0; k < n; ++k)
+ {
+ uint32_t N = va_arg (ap, uint32_t);
+ uint32_t start = va_arg (ap, uint32_t);
+ uint32_t end = va_arg (ap, uint32_t);
+ expected.push_back (Expected (N, start, end));
+ }
+ va_end (ap);
+
+ TagIterator i = p->GetTagIterator ();
+ uint32_t j = 0;
+ while (i.HasNext () && j < expected.size ())
+ {
+ TagIterator::Item item = i.Next ();
+ struct Expected e = expected[j];
+ std::ostringstream oss;
+ oss << "anon::ATestTag<" << e.n << ">";
+ NS_TEST_ASSERT_EQUAL_FILELINE (item.GetTypeId ().GetName (), oss.str (), file, line);
+ NS_TEST_ASSERT_EQUAL_FILELINE (item.GetStart (), e.start, file, line);
+ NS_TEST_ASSERT_EQUAL_FILELINE (item.GetEnd (), e.end, file, line);
+ ATestTagBase *tag = dynamic_cast<ATestTagBase *> (item.GetTypeId ().GetConstructor () ());
+ NS_TEST_ASSERT (tag != 0);
+ item.GetTag (*tag);
+ NS_TEST_ASSERT (!tag->m_error);
+ delete tag;
+ j++;
+ }
+ return result;
+}
bool
PacketTest::RunTests (void)
{
- bool ok = true;
+ bool result = true;
Ptr<Packet> pkt1 = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello"), 5);
Ptr<Packet> pkt2 = Create<Packet> (reinterpret_cast<const uint8_t*> (" world"), 6);
@@ -428,25 +740,80 @@
packet->AddAtEnd (pkt1);
packet->AddAtEnd (pkt2);
- if (packet->GetSize () != 11)
- {
- Failure () << "expected size 11, got " << packet->GetSize () << std::endl;
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (packet->GetSize (), 11);
std::string msg = std::string (reinterpret_cast<const char *>(packet->PeekData ()),
packet->GetSize ());
- if (msg != "hello world")
- {
- Failure () << "expected 'hello world', got '" << msg << "'" << std::endl;
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (msg, "hello world");
+
+
+ Ptr<const Packet> p = Create<Packet> (1000);
+
+ p->AddTag (ATestTag<1> ());
+ CHECK (p, 1, E (1, 0, 1000));
+ Ptr<const Packet> copy = p->Copy ();
+ CHECK (copy, 1, E (1, 0, 1000));
+
+ p->AddTag (ATestTag<2> ());
+ CHECK (p, 2, E (1, 0, 1000), E(2, 0, 1000));
+ CHECK (copy, 1, E (1, 0, 1000));
+
+ {
+ Packet c0 = *copy;
+ Packet c1 = *copy;
+ c0 = c1;
+ CHECK (&c0, 1, E (1, 0, 1000));
+ CHECK (&c1, 1, E (1, 0, 1000));
+ CHECK (copy, 1, E (1, 0, 1000));
+ c0.AddTag (ATestTag<10> ());
+ CHECK (&c0, 2, E (1, 0, 1000), E (10, 0, 1000));
+ CHECK (&c1, 1, E (1, 0, 1000));
+ CHECK (copy, 1, E (1, 0, 1000));
+ }
- return ok;
+ Ptr<Packet> frag0 = p->CreateFragment (0, 10);
+ Ptr<Packet> frag1 = p->CreateFragment (10, 90);
+ Ptr<const Packet> frag2 = p->CreateFragment (100, 900);
+ frag0->AddTag (ATestTag<3> ());
+ CHECK (frag0, 3, E (1, 0, 10), E(2, 0, 10), E (3, 0, 10));
+ frag1->AddTag (ATestTag<4> ());
+ CHECK (frag1, 3, E (1, 0, 90), E(2, 0, 90), E (4, 0, 90));
+ frag2->AddTag (ATestTag<5> ());
+ CHECK (frag2, 3, E (1, 0, 900), E(2, 0, 900), E (5, 0, 900));
+
+ frag1->AddAtEnd (frag2);
+ CHECK (frag1, 6, E (1, 0, 90), E(2, 0, 90), E (4, 0, 90), E (1, 90, 990), E(2, 90, 990), E (5, 90, 990));
+
+ CHECK (frag0, 3, E (1, 0, 10), E(2, 0, 10), E (3, 0, 10));
+ frag0->AddAtEnd (frag1);
+ CHECK (frag0, 9,
+ E (1, 0, 10), E(2, 0, 10), E (3, 0, 10),
+ E (1, 10, 100), E(2, 10, 100), E (4, 10, 100),
+ E (1, 100, 1000), E(2, 100, 1000), E (5, 100, 1000));
+
+
+ // force caching a buffer of the right size.
+ frag0 = Create<Packet> (1000);
+ frag0->AddHeader (ATestHeader<10> ());
+ frag0 = 0;
+
+ p = Create<Packet> (1000);
+ p->AddTag (ATestTag<20> ());
+ CHECK (p, 1, E (20, 0, 1000));
+ frag0 = p->CreateFragment (10, 90);
+ CHECK (p, 1, E (20, 0, 1000));
+ CHECK (frag0, 1, E (20, 0, 90));
+ p = 0;
+ frag0->AddHeader (ATestHeader<10> ());
+ CHECK (frag0, 1, E (20, 10, 100));
+
+
+
+ return result;
}
-static PacketTest gPacketTest;
+static PacketTest g_packetTest;
}; // namespace ns3
--- a/src/common/packet.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/packet.h Wed Jun 04 17:19:32 2008 -0400
@@ -24,9 +24,9 @@
#include "buffer.h"
#include "header.h"
#include "trailer.h"
-#include "tags.h"
#include "packet-metadata.h"
#include "tag.h"
+#include "tag-list.h"
#include "ns3/callback.h"
#include "ns3/assert.h"
#include "ns3/ptr.h"
@@ -34,9 +34,78 @@
namespace ns3 {
/**
+ * \ingroup common
+ * \defgroup packet Packet
+ */
+
+/**
+ * \ingroup packet
+ * \brief Iterator over the set of tags in a packet
+ *
+ * This is a java-style iterator.
+ */
+class TagIterator
+{
+public:
+ /**
+ * Identifies a tag and a set of bytes within a packet
+ * to which the tag applies.
+ */
+ class Item
+ {
+ public:
+ /**
+ * \returns the ns3::TypeId associated to this tag.
+ */
+ TypeId GetTypeId (void) const;
+ /**
+ * \returns the index of the first byte tagged by this tag.
+ *
+ * The index is an offset from the start of the packet.
+ */
+ uint32_t GetStart (void) const;
+ /**
+ * \returns the index of the last byte tagged by this tag.
+ *
+ * The index is an offset from the start of the packet.
+ */
+ uint32_t GetEnd (void) const;
+ /**
+ * \param tag the user tag to which the data should be copied.
+ *
+ * Read the requested tag and store it in the user-provided
+ * tag instance. This method will crash if the type of the
+ * tag provided by the user does not match the type of
+ * the underlying tag.
+ */
+ void GetTag (Tag &tag) const;
+ private:
+ friend class TagIterator;
+ Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer);
+ TypeId m_tid;
+ uint32_t m_start;
+ uint32_t m_end;
+ TagBuffer m_buffer;
+ };
+ /**
+ * \returns true if calling Next is safe, false otherwise.
+ */
+ bool HasNext (void) const;
+ /**
+ * \returns the next item found and prepare for the next one.
+ */
+ Item Next (void);
+private:
+ friend class Packet;
+ TagIterator (TagList::Iterator i);
+ TagList::Iterator m_current;
+};
+
+/**
+ * \ingroup packet
* \brief network packets
*
- * Each network packet contains a byte buffer, a list of tags, and
+ * Each network packet contains a byte buffer, a set of tags, and
* metadata.
*
* - The byte buffer stores the serialized content of the headers and trailers
@@ -45,13 +114,10 @@
* 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.
- * These tags typically contain per-packet cross-layer information or
- * flow identifiers. Each tag stored in the tag list can be at most
- * 16 bytes big. Trying to attach bigger data structures will trigger
- * crashes at runtime.
+ * - Each tag tags a subset of the bytes in the packet byte buffer with the
+ * information stored in the tag. A classic example of a tag is a FlowIdTag
+ * which contains a flow id: the set of bytes tagged by this tag implicitely
+ * belong to the attached flow id.
*
* - The metadata describes the type of the headers and trailers which
* were serialized in the byte buffer. The maintenance of metadata is
@@ -83,6 +149,8 @@
* by getUid).
*/
Packet ();
+ Packet (const Packet &o);
+ Packet &operator = (const Packet &o);
/**
* Create a packet with a zero-filled payload.
* The memory necessary for the payload is not allocated:
@@ -152,63 +220,6 @@
*/
uint32_t RemoveTrailer (Trailer &trailer);
/**
- * \param tag a pointer to the tag to attach to this packet.
- *
- * 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. The copy constructor of the
- * tag is invoked to copy it into the tag buffer.
- *
- * Note that adding a tag is a const operation which is pretty
- * un-intuitive. The rationale is that the content and behavior of
- * a packet is _not_ changed when a tag is added to a packet: any
- * code which was not aware of the new tag is going to work just
- * the same if the new tag is added. The real reason why adding a
- * tag was made a const operation is to allow a trace sink which gets
- * a packet to tag the packet, even if the packet is const (and most
- * trace sources should use const packets because it would be
- * totally evil to allow a trace sink to modify the content of a
- * packet).
- *
- */
- template <typename T>
- void AddTag (T const &tag) const;
- /**
- * Remove a tag from this packet. The data stored internally
- * for this tag is copied in the input tag if an instance
- * of this tag type is present in the internal buffer. If this
- * tag type is not present, the input tag is not modified.
- *
- * This operation can be potentially slow and might trigger
- * unexpectedly large memory allocations. It is thus
- * usually a better idea to create a copy of this packet,
- * and invoke removeAllTags on the copy to remove all
- * tags rather than remove the tags one by one from a packet.
- *
- * \param tag a pointer to the tag to remove from this packet
- * \returns true if an instance of this tag type is stored
- * in this packet, false otherwise.
- */
- template <typename T>
- bool RemoveTag (T &tag);
- /**
- * 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
- * in this packet, false otherwise.
- */
- template <typename T>
- bool PeekTag (T &tag) const;
- /**
- * Remove all the tags stored in this packet. This operation is
- * much much faster than invoking removeTag n times.
- */
- void RemoveAllTags (void);
- /**
* \param os output stream in which the data should be printed.
*
* Iterate over the tags present in this packet, and
@@ -330,12 +341,47 @@
* a different CPU.
*/
void Deserialize (Buffer buffer);
+
+ /**
+ * \param tag the new tag to add to this packet
+ *
+ * Tag each byte included in this packet with the
+ * new tag.
+ *
+ * Note that adding a tag is a const operation which is pretty
+ * un-intuitive. The rationale is that the content and behavior of
+ * a packet is _not_ changed when a tag is added to a packet: any
+ * code which was not aware of the new tag is going to work just
+ * the same if the new tag is added. The real reason why adding a
+ * tag was made a const operation is to allow a trace sink which gets
+ * a packet to tag the packet, even if the packet is const (and most
+ * trace sources should use const packets because it would be
+ * totally evil to allow a trace sink to modify the content of a
+ * packet).
+ */
+ void AddTag (const Tag &tag) const;
+ /**
+ * \returns an iterator over the set of tags included in this packet.
+ */
+ TagIterator GetTagIterator (void) const;
+ /**
+ * \param tag the tag to search in this packet
+ * \returns true if the requested tag type was found, false otherwise.
+ *
+ * If the requested tag type is found, it is copied in the user's
+ * provided tag instance.
+ */
+ bool FindFirstMatchingTag (Tag &tag) const;
+
+ /**
+ * Remove all the tags stored in this packet.
+ */
+ void RemoveAllTags (void);
+
private:
- Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
- Packet (const Packet &o);
- Packet &operator = (const Packet &o);
+ Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata);
Buffer m_buffer;
- Tags m_tags;
+ TagList m_tagList;
PacketMetadata m_metadata;
mutable uint32_t m_refCount;
static uint32_t m_globalUid;
@@ -357,7 +403,6 @@
* to detect when an operation is "dirty".
*
* Dirty operations:
- * - ns3::Packet::RemoveTag
* - ns3::Packet::AddHeader
* - ns3::Packet::AddTrailer
* - both versions of ns3::Packet::AddAtEnd
@@ -381,42 +426,4 @@
} // namespace ns3
-
-/**************************************************
- Start of implementation of templates defined
- above
- *************************************************/
-
-namespace ns3 {
-
-template <typename T>
-void Packet::AddTag (T const& tag) const
-{
- 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
-
#endif /* PACKET_H */
--- a/src/common/pcap-writer.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/common/pcap-writer.cc Wed Jun 04 17:19:32 2008 -0400
@@ -46,7 +46,12 @@
PcapWriter::~PcapWriter ()
{
+ if (m_writer != 0)
+ {
+ m_writer->close ();
+ }
delete m_writer;
+ m_writer = 0;
}
void
--- a/src/common/pcap-writer.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/pcap-writer.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,8 @@
class Packet;
/**
+ * \ingroup common
+ *
* \brief Pcap output for Packet logger
*
* Log Packets to a file in pcap format which can be
@@ -49,17 +51,35 @@
/**
* Write a pcap header in the output file which specifies
- * that the content of the file will Packets with
+ * that the content of the file will be Packets with
* Ethernet/LLC/SNAP encapsulation. This method should
* be invoked before ns3::PcapWriter::writePacket and after
* ns3::PcapWriter::open.
*/
void WriteEthernetHeader (void);
+ /**
+ * Write a pcap header in the output file which specifies
+ * that the content of the file will be IPv4 Packets. This
+ * method should be invoked before ns3::PcapWriter::WritePacket
+ * and after ns3::PcapWriter::Open.
+ */
void WriteIpHeader (void);
+ /**
+ * Write a pcap header in the output file which specifies
+ * that the content of the file will be 802.11 Packets. This
+ * method should be invoked before ns3::PcapWriter::WritePacket
+ * and after ns3::PcapWriter::Open.
+ */
void WriteWifiHeader (void);
+ /**
+ * Write a pcap header in the output file which specifies
+ * that the content of the file will be ppp Packets. This
+ * method should be invoked before ns3::PcapWriter::WritePacket
+ * and after ns3::PcapWriter::Open.
+ */
void WritePppHeader (void);
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-buffer.cc Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,193 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "tag-buffer.h"
+#include "ns3/assert.h"
+#include <string.h>
+
+namespace ns3 {
+
+#ifndef TAG_BUFFER_USE_INLINE
+
+void
+TagBuffer::WriteU8 (uint8_t v)
+{
+ NS_ASSERT (m_current + 1 <= m_end);
+ *m_current = v;
+ m_current++;
+}
+
+void
+TagBuffer::WriteU16 (uint16_t data)
+{
+ WriteU8 ((data >> 0) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+}
+void
+TagBuffer::WriteU32 (uint32_t data)
+{
+ WriteU8 ((data >> 0) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 16) & 0xff);
+ WriteU8 ((data >> 24) & 0xff);
+}
+
+
+uint8_t
+TagBuffer::ReadU8 (void)
+{
+ NS_ASSERT (m_current + 1 <= m_end);
+ uint8_t v;
+ v = *m_current;
+ m_current++;
+ return v;
+}
+
+uint16_t
+TagBuffer::ReadU16 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint16_t data = byte1;
+ data <<= 8;
+ data |= byte0;
+ return data;
+}
+uint32_t
+TagBuffer::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;
+}
+
+#endif /* TAG_BUFFER_USE_INLINE */
+
+
+void
+TagBuffer::WriteU64 (uint64_t data)
+{
+ WriteU8 ((data >> 0) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 16) & 0xff);
+ WriteU8 ((data >> 24) & 0xff);
+ WriteU8 ((data >> 32) & 0xff);
+ WriteU8 ((data >> 40) & 0xff);
+ WriteU8 ((data >> 48) & 0xff);
+ WriteU8 ((data >> 54) & 0xff);
+}
+void
+TagBuffer::WriteDouble (double v)
+{
+ uint8_t *buf = (uint8_t *)&v;
+ for (uint32_t i = 0; i < sizeof (double); ++i, ++buf)
+ {
+ WriteU8 (*buf);
+ }
+}
+void
+TagBuffer::Write (const uint8_t *buffer, uint32_t size)
+{
+ for (uint32_t i = 0; i < size; ++i, ++buffer)
+ {
+ WriteU8 (*buffer);
+ }
+}
+uint64_t
+TagBuffer::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;
+}
+double
+TagBuffer::ReadDouble (void)
+{
+ double v;
+ uint8_t *buf = (uint8_t *)&v;
+ for (uint32_t i = 0; i < sizeof (double); ++i, ++buf)
+ {
+ *buf = ReadU8 ();
+ }
+ return v;
+}
+void
+TagBuffer::Read (uint8_t *buffer, uint32_t size)
+{
+ for (uint32_t i = 0; i < size; ++i, ++buffer)
+ {
+ *buffer = ReadU8 ();
+ }
+}
+TagBuffer::TagBuffer (uint8_t *start, uint8_t *end)
+ : m_current (start),
+ m_end (end)
+{}
+
+void
+TagBuffer::TrimAtEnd (uint32_t trim)
+{
+ NS_ASSERT (m_current <= (m_end - trim));
+ m_end -= trim;
+}
+
+void
+TagBuffer::CopyFrom (TagBuffer o)
+{
+ NS_ASSERT (o.m_end >= o.m_current);
+ NS_ASSERT (m_end >= m_current);
+ uintptr_t size = o.m_end - o.m_current;
+ NS_ASSERT (size <= (uintptr_t)(m_end - m_current));
+ memcpy (m_current, o.m_current, size);
+ m_current += size;
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-buffer.h Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,219 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAG_BUFFER_H
+#define TAG_BUFFER_H
+
+#include <stdint.h>
+
+#define TAG_BUFFER_USE_INLINE 1
+
+#ifdef TAG_BUFFER_USE_INLINE
+#define TAG_BUFFER_INLINE inline
+#else
+#define TAG_BUFFER_INLINE
+#endif
+
+namespace ns3 {
+
+/**
+ * \ingroup packet
+ *
+ * \brief read and write tag data
+ *
+ * This class allows subclasses of the ns3::Tag base class
+ * to serialize and deserialize their data through a stream-like
+ * API. This class keeps track of the "current" point in the
+ * buffer and advances that "current" point everytime data is
+ * written. The in-memory format of the data written by
+ * this class is unspecified.
+ *
+ * If the user attempts to write more data in the buffer than
+ * he allocated with Tag::GetSerializedSize, he will trigger
+ * an NS_ASSERT error.
+ */
+class TagBuffer
+{
+public:
+ TagBuffer (uint8_t *start, uint8_t *end);
+ void TrimAtEnd (uint32_t trim);
+ void CopyFrom (TagBuffer o);
+
+ /**
+ * \param v the value to write
+ *
+ * Write one byte and advance the "current" point by one.
+ */
+ TAG_BUFFER_INLINE void WriteU8 (uint8_t v);
+ /**
+ * \param v the value to write
+ *
+ * Write two bytes and advance the "current" point by two.
+ */
+ TAG_BUFFER_INLINE void WriteU16 (uint16_t v);
+ /**
+ * \param v the value to write
+ *
+ * Write four bytes and advance the "current" point by four.
+ */
+ TAG_BUFFER_INLINE void WriteU32 (uint32_t v);
+ /**
+ * \param v the value to write
+ *
+ * Write eight bytes and advance the "current" point by eight.
+ */
+ void WriteU64 (uint64_t v);
+ /**
+ * \param v the value to write
+ *
+ * Write a double and advance the "current" point by the size of the
+ * data written.
+ */
+ void WriteDouble (double v);
+ /**
+ * \param buffer a pointer to data to write
+ * \param size the size of the data to write
+ *
+ * Write all the input data and advance the "current" point by the size of the
+ * data written.
+ */
+ void Write (const uint8_t *buffer, uint32_t size);
+ /**
+ * \returns the value read
+ *
+ * Read one byte, advance the "current" point by one,
+ * and return the value read.
+ */
+ TAG_BUFFER_INLINE uint8_t ReadU8 (void);
+ /**
+ * \returns the value read
+ *
+ * Read two bytes, advance the "current" point by two,
+ * and return the value read.
+ */
+ TAG_BUFFER_INLINE uint16_t ReadU16 (void);
+ /**
+ * \returns the value read
+ *
+ * Read four bytes, advance the "current" point by four,
+ * and return the value read.
+ */
+ TAG_BUFFER_INLINE uint32_t ReadU32 (void);
+ /**
+ * \returns the value read
+ *
+ * Read eight bytes, advance the "current" point by eight,
+ * and return the value read.
+ */
+ uint64_t ReadU64 (void);
+ /**
+ * \returns the value read
+ *
+ * Read a double, advance the "current" point by the size
+ * of the data read, and, return the value read.
+ */
+ double ReadDouble (void);
+ /**
+ * \param buffer a pointer to the buffer where data should be
+ * written.
+ * \param size the number of bytes to read.
+ *
+ * Read the number of bytes requested, advance the "current"
+ * point by the number of bytes read, return.
+ */
+ void Read (uint8_t *buffer, uint32_t size);
+private:
+
+ uint8_t *m_current;
+ uint8_t *m_end;
+};
+
+} // namespace ns3
+
+#ifdef TAG_BUFFER_USE_INLINE
+
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+void
+TagBuffer::WriteU8 (uint8_t v)
+{
+ NS_ASSERT (m_current + 1 <= m_end);
+ *m_current = v;
+ m_current++;
+}
+
+void
+TagBuffer::WriteU16 (uint16_t data)
+{
+ WriteU8 ((data >> 0) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+}
+void
+TagBuffer::WriteU32 (uint32_t data)
+{
+ WriteU8 ((data >> 0) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 16) & 0xff);
+ WriteU8 ((data >> 24) & 0xff);
+}
+
+uint8_t
+TagBuffer::ReadU8 (void)
+{
+ NS_ASSERT (m_current + 1 <= m_end);
+ uint8_t v;
+ v = *m_current;
+ m_current++;
+ return v;
+}
+
+uint16_t
+TagBuffer::ReadU16 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint16_t data = byte1;
+ data <<= 8;
+ data |= byte0;
+ return data;
+}
+uint32_t
+TagBuffer::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;
+}
+
+} // namespace ns3
+
+#endif /* TAG_BUFFER_USE_INLINE */
+
+#endif /* TAG_BUFFER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-list.cc Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,392 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "tag-list.h"
+#include <vector>
+
+#define USE_FREE_LIST 1
+#define FREE_LIST_SIZE 1000
+
+namespace ns3 {
+
+struct TagListData {
+ uint32_t size;
+ uint32_t count;
+ uint32_t dirty;
+ uint8_t data[4];
+};
+
+#ifdef USE_FREE_LIST
+static class TagListDataFreeList : public std::vector<struct TagListData *>
+{
+public:
+ ~TagListDataFreeList ();
+} g_freeList;
+static uint32_t g_maxSize = 0;
+
+TagListDataFreeList::~TagListDataFreeList ()
+{
+ for (TagListDataFreeList::iterator i = begin ();
+ i != end (); i++)
+ {
+ uint8_t *buffer = (uint8_t *)(*i);
+ delete [] buffer;
+ }
+}
+#endif /* USE_FREE_LIST */
+
+TagList::Iterator::Item::Item (TagBuffer buf_)
+ : buf (buf_)
+{}
+
+bool
+TagList::Iterator::HasNext (void) const
+{
+ return m_current < m_end;
+}
+struct TagList::Iterator::Item
+TagList::Iterator::Next (void)
+{
+ NS_ASSERT (HasNext ());
+ struct Item item = Item (TagBuffer (m_current+16, m_end));
+ item.tid.SetUid (m_nextTid);
+ item.size = m_nextSize;
+ item.start = m_nextStart;
+ item.end = m_nextEnd;
+ item.start = std::max (item.start, m_offsetStart);
+ item.end = std::min (item.end, m_offsetEnd);
+ m_current += 4 + 4 + 4 + 4 + item.size;
+ item.buf.TrimAtEnd (m_end - m_current);
+ PrepareForNext ();
+ return item;
+}
+void
+TagList::Iterator::PrepareForNext (void)
+{
+ while (m_current < m_end)
+ {
+ TagBuffer buf = TagBuffer (m_current, m_end);
+ m_nextTid = buf.ReadU32 ();
+ m_nextSize = buf.ReadU32 ();
+ m_nextStart = buf.ReadU32 ();
+ m_nextEnd = buf.ReadU32 ();
+ if (m_nextStart > m_offsetEnd || m_nextEnd < m_offsetStart)
+ {
+ m_current += 4 + 4 + 4 + 4 + m_nextSize;
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+TagList::Iterator::Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd)
+ : m_current (start),
+ m_end (end),
+ m_offsetStart (offsetStart),
+ m_offsetEnd (offsetEnd)
+{
+ PrepareForNext ();
+}
+
+uint32_t
+TagList::Iterator::GetOffsetStart (void) const
+{
+ return m_offsetStart;
+}
+
+
+TagList::TagList ()
+ : m_used (0),
+ m_data (0)
+{}
+TagList::TagList (const TagList &o)
+ : m_used (o.m_used),
+ m_data (o.m_data)
+{
+ if (m_data != 0)
+ {
+ m_data->count++;
+ }
+}
+TagList &
+TagList::operator = (const TagList &o)
+{
+ if (this == &o)
+ {
+ return *this;
+ }
+
+ Deallocate (m_data);
+ m_data = o.m_data;
+ m_used = o.m_used;
+ if (m_data != 0)
+ {
+ m_data->count++;
+ }
+ return *this;
+}
+TagList::~TagList ()
+{
+ Deallocate (m_data);
+ m_data = 0;
+ m_used = 0;
+}
+
+TagBuffer
+TagList::Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end)
+{
+ uint32_t spaceNeeded = m_used + bufferSize + 4 + 4 + 4 + 4;
+ NS_ASSERT (m_used <= spaceNeeded);
+ if (m_data == 0)
+ {
+ m_data = Allocate (spaceNeeded);
+ m_used = 0;
+ }
+ else if (m_data->size < spaceNeeded ||
+ (m_data->count != 1 && m_data->dirty != m_used))
+ {
+ struct TagListData *newData = Allocate (spaceNeeded);
+ memcpy (&newData->data, &m_data->data, m_used);
+ Deallocate (m_data);
+ m_data = newData;
+ }
+ TagBuffer tag = TagBuffer (&m_data->data[m_used],
+ &m_data->data[spaceNeeded]);
+ tag.WriteU32 (tid.GetUid ());
+ tag.WriteU32 (bufferSize);
+ tag.WriteU32 (start);
+ tag.WriteU32 (end);
+ m_used = spaceNeeded;
+ m_data->dirty = m_used;
+ return tag;
+}
+
+void
+TagList::Add (const TagList &o)
+{
+ TagList::Iterator i = o.Begin (0, 0xffffffff);
+ while (i.HasNext ())
+ {
+ TagList::Iterator::Item item = i.Next ();
+ TagBuffer buf = Add (item.tid, item.size, item.start, item.end);
+ buf.CopyFrom (item.buf);
+ }
+}
+
+void
+TagList::RemoveAll (void)
+{
+ Deallocate (m_data);
+ m_data = 0;
+ m_used = 0;
+}
+
+TagList::Iterator
+TagList::Begin (uint32_t offsetStart, uint32_t offsetEnd) const
+{
+ if (m_data == 0)
+ {
+ return Iterator (0, 0, offsetStart, offsetEnd);
+ }
+ else
+ {
+ return Iterator (m_data->data, &m_data->data[m_used], offsetStart, offsetEnd);
+ }
+}
+
+bool
+TagList::IsDirtyAtEnd (uint32_t appendOffset)
+{
+ TagList::Iterator i = Begin (0, 0xffffffff);
+ while (i.HasNext ())
+ {
+ TagList::Iterator::Item item = i.Next ();
+ if (item.end > appendOffset)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+TagList::IsDirtyAtStart (uint32_t prependOffset)
+{
+ TagList::Iterator i = Begin (0, 0xffffffff);
+ while (i.HasNext ())
+ {
+ TagList::Iterator::Item item = i.Next ();
+ if (item.start < prependOffset)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+TagList::AddAtEnd (int32_t adjustment, uint32_t appendOffset)
+{
+ if (adjustment == 0 && !IsDirtyAtEnd (appendOffset))
+ {
+ return;
+ }
+ TagList list;
+ TagList::Iterator i = Begin (0, 0xffffffff);
+ while (i.HasNext ())
+ {
+ TagList::Iterator::Item item = i.Next ();
+ item.start += adjustment;
+ item.end += adjustment;
+
+ if (item.start > appendOffset)
+ {
+ continue;
+ }
+ else if (item.start < appendOffset && item.end > appendOffset)
+ {
+ item.end = appendOffset;
+ }
+ else
+ {
+ // nothing to do.
+ }
+ TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
+ buf.CopyFrom (item.buf);
+ }
+ *this = list;
+}
+
+void
+TagList::AddAtStart (int32_t adjustment, uint32_t prependOffset)
+{
+ if (adjustment == 0 && !IsDirtyAtStart (prependOffset))
+ {
+ return;
+ }
+ TagList list;
+ TagList::Iterator i = Begin (0, 0xffffffff);
+ while (i.HasNext ())
+ {
+ TagList::Iterator::Item item = i.Next ();
+ item.start += adjustment;
+ item.end += adjustment;
+
+ if (item.end < prependOffset)
+ {
+ continue;
+ }
+ else if (item.end > prependOffset && item.start < prependOffset)
+ {
+ item.start = prependOffset;
+ }
+ else
+ {
+ // nothing to do.
+ }
+ TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
+ buf.CopyFrom (item.buf);
+ }
+ *this = list;
+}
+
+#ifdef USE_FREE_LIST
+
+struct TagListData *
+TagList::Allocate (uint32_t size)
+{
+ while (!g_freeList.empty ())
+ {
+ struct TagListData *data = g_freeList.back ();
+ g_freeList.pop_back ();
+ NS_ASSERT (data != 0);
+ if (data->size >= size)
+ {
+ data->count = 1;
+ data->dirty = 0;
+ return data;
+ }
+ uint8_t *buffer = (uint8_t *)data;
+ delete [] buffer;
+ }
+ uint8_t *buffer = new uint8_t [std::max (size, g_maxSize) + sizeof (struct TagListData) - 4];
+ struct TagListData *data = (struct TagListData *)buffer;
+ data->count = 1;
+ data->size = size;
+ data->dirty = 0;
+ return data;
+}
+
+void
+TagList::Deallocate (struct TagListData *data)
+{
+ if (data == 0)
+ {
+ return;
+ }
+ g_maxSize = std::max (g_maxSize, data->size);
+ data->count--;
+ if (data->count == 0)
+ {
+ if (g_freeList.size () > FREE_LIST_SIZE ||
+ data->size < g_maxSize)
+ {
+ uint8_t *buffer = (uint8_t *)data;
+ delete [] buffer;
+ }
+ else
+ {
+ g_freeList.push_back (data);
+ }
+ }
+}
+
+#else /* USE_FREE_LIST */
+
+struct TagListData *
+TagList::Allocate (uint32_t size)
+{
+ uint8_t *buffer = new uint8_t [size + sizeof (struct TagListData) - 4];
+ struct TagListData *data = (struct TagListData *)buffer;
+ data->count = 1;
+ data->size = size;
+ data->dirty = 0;
+ return data;
+}
+
+void
+TagList::Deallocate (struct TagListData *data)
+{
+ if (data == 0)
+ {
+ return;
+ }
+ data->count--;
+ if (data->count == 0)
+ {
+ uint8_t *buffer = (uint8_t *)data;
+ delete [] buffer;
+ }
+}
+
+#endif /* USE_FREE_LIST */
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-list.h Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,169 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAG_LIST_H
+#define TAG_LIST_H
+
+#include <stdint.h>
+#include "ns3/type-id.h"
+#include "tag-buffer.h"
+
+namespace ns3 {
+
+struct TagListData;
+
+/**
+ * \ingroup packet
+ *
+ * \brief keep track of the tags stored in a packet.
+ *
+ * This class is mostly private to the Packet implementation and users
+ * should never have to access it directly.
+ *
+ * \internal
+ * The implementation of this class is a bit tricky so, there are a couple
+ * of things to keep in mind here:
+ *
+ * - it stores all tags in a single byte buffer: each tag is stored
+ * as 4 32bit integers (TypeId, tag data size, start, end) followed
+ * by the tag data as generated by Tag::Serialize.
+ *
+ * - the struct TagListData structure which contains the tag byte buffer
+ * is shared and, thus, reference-counted. This data structure is unshared
+ * as-needed to emulate COW semantics.
+ *
+ * - each tag tags a unique set of bytes identified by the pair of offsets
+ * (start,end). These offsets are provided by Buffer::GetCurrentStartOffset
+ * and Buffer::GetCurrentEndOffset which means that they are relative to
+ * the start of the 'virtual byte buffer' as explained in the documentation
+ * for the ns3::Buffer class. Whenever the origin of the offset of the Buffer
+ * instance associated to this TagList instance changes, the Buffer class
+ * reports this to its container Packet class as a bool return value
+ * in Buffer::AddAtStart and Buffer::AddAtEnd. In both cases, when this happens
+ * the Packet class calls TagList::AddAtEnd and TagList::AddAtStart to update
+ * the byte offsets of each tag in the TagList.
+ *
+ * - whenever bytes are removed from the packet byte buffer, the TagList offsets
+ * are never updated because we rely on the fact that they will be updated in
+ * either the next call to Packet::AddHeader or Packet::AddTrailer or when
+ * the user iterates the tag list with Packet::GetTagIterator and
+ * TagIterator::Next.
+ */
+class TagList
+{
+public:
+
+ class Iterator
+ {
+ public:
+ struct Item
+ {
+ TypeId tid;
+ uint32_t size;
+ uint32_t start;
+ uint32_t end;
+ TagBuffer buf;
+ Item (TagBuffer buf);
+ private:
+ friend class TagList;
+ friend class TagList::Iterator;
+ };
+ bool HasNext (void) const;
+ struct TagList::Iterator::Item Next (void);
+ uint32_t GetOffsetStart (void) const;
+ private:
+ friend class TagList;
+ Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd);
+ void PrepareForNext (void);
+ uint8_t *m_current;
+ uint8_t *m_end;
+ uint32_t m_offsetStart;
+ uint32_t m_offsetEnd;
+ uint32_t m_nextTid;
+ uint32_t m_nextSize;
+ uint32_t m_nextStart;
+ uint32_t m_nextEnd;
+ };
+
+ TagList ();
+ TagList (const TagList &o);
+ TagList &operator = (const TagList &o);
+ ~TagList ();
+
+ /**
+ * \param tid the typeid of the tag added
+ * \param bufferSize the size of the tag when its serialization will
+ * be completed. Typically, the return value of Tag::GetSerializedSize
+ * \param start offset which uniquely identifies the first byte tagged by this tag.
+ * \param end offset which uniquely identifies the last byte tagged by this tag.
+ * \returns a buffer which can be used to write the tag data.
+ *
+ *
+ */
+ TagBuffer Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end);
+
+ /**
+ * \param o the other list of tags to aggregate.
+ *
+ * Aggregate the two lists of tags.
+ */
+ void Add (const TagList &o);
+
+ void RemoveAll (void);
+
+ /**
+ * \param offsetStart the offset which uniquely identifies the first data byte
+ * present in the byte buffer associated to this TagList.
+ * \param offsetEnd the offset which uniquely identifies the last data byte
+ * present in the byte buffer associated to this TagList.
+ * \returns an iterator
+ *
+ * The returned iterator will allow you to loop through the set of tags present
+ * in this list: the boundaries of each tag as reported by their start and
+ * end offsets will be included within the input offsetStart and offsetEnd.
+ */
+ TagList::Iterator Begin (uint32_t offsetStart, uint32_t offsetEnd) const;
+
+ /**
+ * Adjust the offsets stored internally by the adjustment delta and
+ * make sure that all offsets are smaller than appendOffset which represents
+ * the location where new bytes have been added to the byte buffer.
+ */
+ void AddAtEnd (int32_t adjustment, uint32_t appendOffset);
+ /**
+ * Adjust the offsets stored internally by the adjustment delta and
+ * make sure that all offsets are bigger than prependOffset which represents
+ * the location where new bytes have been added to the byte buffer.
+ */
+ void AddAtStart (int32_t adjustment, uint32_t prependOffset);
+
+private:
+ bool IsDirtyAtEnd (uint32_t appendOffset);
+ bool IsDirtyAtStart (uint32_t prependOffset);
+
+ struct TagListData *Allocate (uint32_t size);
+ void Deallocate (struct TagListData *data);
+
+ uint16_t m_used;
+ struct TagListData *m_data;
+};
+
+} // namespace ns3
+
+#endif /* TAG_LIST_H */
--- a/src/common/tag-registry.cc Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <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
--- a/src/common/tag-registry.h Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <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.cc Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "tag.h"
+
+namespace ns3 {
+
+TypeId
+Tag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::Tag")
+ .SetParent<ObjectBase> ()
+ ;
+ return tid;
+}
+
+
+} // namespace ns3
--- a/src/common/tag.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/tag.h Wed Jun 04 17:19:32 2008 -0400
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2006 INRIA
+ * Copyright (c) 2008 INRIA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,106 +20,56 @@
#ifndef TAG_H
#define TAG_H
+#include "ns3/object-base.h"
+#include "tag-buffer.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.
+ * \ingroup 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
+ * \brief tag a set of bytes in a packet
*
- * 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
+ * New kinds of tags can be created by subclassing this base class.
*/
-class Tag
+class Tag : public ObjectBase
{
-protected:
+public:
+ static TypeId GetTypeId (void);
+
+ /**
+ * \returns the number of bytes required to serialize the data of the tag.
+ *
+ * This method is typically invoked by Packet::AddTag just prior to calling
+ * Tag::Serialize.
+ */
+ virtual uint32_t GetSerializedSize (void) const = 0;
/**
- * \param name the unique name of the new type of tag
- * \returns a newly-allocated uid
+ * \param i the buffer to write data into.
+ *
+ * Write the content of the tag in the provided tag buffer.
+ * DO NOT attempt to write more bytes than you requested
+ * with Tag::GetSerializedSize.
+ */
+ virtual void Serialize (TagBuffer i) const = 0;
+ /**
+ * \param i the buffer to read data from.
*
- * This method should be used by subclasses to implement
- * their static public GetUid method.
+ * Read the content of the tag from the provided tag buffer.
+ * DO NOT attempt to read more bytes than you wrote with
+ * Tag::Serialize.
*/
- template <typename T>
- static uint32_t AllocateUid (std::string name);
+ virtual void Deserialize (TagBuffer i) = 0;
+
+ /**
+ * \param os the stream to print to
+ *
+ * This method is typically invoked from the Packet::PrintTags method
+ */
+ virtual void Print (std::ostream &os) const = 0;
};
} // 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 Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,529 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "tags.h"
-#include <string.h>
-#include "ns3/fatal-error.h"
-
-namespace ns3 {
-
-#ifdef USE_FREE_LIST
-
-struct Tags::TagData *Tags::gFree = 0;
-uint32_t Tags::gN_free = 0;
-
-struct Tags::TagData *
-Tags::AllocData (void) const
-{
- struct Tags::TagData *retval;
- if (gFree != 0)
- {
- retval = gFree;
- gFree = gFree->m_next;
- gN_free--;
- }
- else
- {
- retval = new struct Tags::TagData ();
- }
- return retval;
-}
-
-void
-Tags::FreeData (struct TagData *data) const
-{
- if (gN_free > 1000)
- {
- delete data;
- return;
- }
- gN_free++;
- data->m_next = gFree;
- data->m_id = 0;
- gFree = data;
-}
-#else
-struct Tags::TagData *
-Tags::AllocData (void) const
-{
- struct Tags::TagData *retval;
- retval = new struct Tags::TagData ();
- return retval;
-}
-
-void
-Tags::FreeData (struct TagData *data) const
-{
- delete data;
-}
-#endif
-
-bool
-Tags::Remove (uint32_t id)
-{
- bool found = false;
- for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
- {
- if (cur->m_id == id)
- {
- found = true;
- }
- }
- if (!found)
- {
- return false;
- }
- struct TagData *start = 0;
- struct TagData **prevNext = &start;
- for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
- {
- if (cur->m_id == id)
- {
- /**
- * XXX
- * Note: I believe that we could optimize this to
- * avoid copying each TagData located after the target id
- * and just link the already-copied list to the next tag.
- */
- continue;
- }
- struct TagData *copy = AllocData ();
- copy->m_id = cur->m_id;
- copy->m_count = 1;
- copy->m_next = 0;
- memcpy (copy->m_data, cur->m_data, Tags::SIZE);
- *prevNext = copy;
- prevNext = ©->m_next;
- }
- *prevNext = 0;
- RemoveAll ();
- m_next = start;
- return true;
-}
-
-void
-Tags::Print (std::ostream &os, std::string separator) const
-{
- for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
- {
- 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
-
-#ifdef RUN_SELF_TESTS
-
-#include "ns3/test.h"
-#include <iomanip>
-#include <iostream>
-
-namespace ns3 {
-
-static bool g_a;
-static bool g_b;
-static bool g_c;
-static bool g_z;
-
-class TagsTest : Test {
-public:
- TagsTest ();
- virtual ~TagsTest ();
- virtual bool RunTests (void);
-};
-
-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;
-};
-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;
-};
-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];
-};
-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];
-};
-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 : 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;
- }
- MySmartTag (const MySmartTag &o)
- {
- //std::cout << "copy" << std::endl;
- }
- ~MySmartTag ()
- {
- //std::cout << "destruct" << std::endl;
- }
- MySmartTag &operator = (const MySmartTag &o)
- {
- //std::cout << "assign" << std::endl;
- return *this;
- }
- 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;}
-};
-
-
-TagsTest::TagsTest ()
- : Test ("Tags")
-{}
-TagsTest::~TagsTest ()
-{}
-
-bool
-TagsTest::RunTests (void)
-{
- bool ok = true;
-
- // build initial tag.
- Tags tags;
- myTagA a;
- a.a = 10;
- tags.Add (a);
- a.a = 0;
- tags.Peek (a);
- if (a.a != 10)
- {
- ok = false;
- }
- g_a = false;
- tags.Print (std::cout, "");
- if (!g_a)
- {
- ok = false;
- }
- myTagB b;
- b.b = 0xff;
- tags.Add (b);
- b.b = 0;
- tags.Peek (b);
- if (b.b != 0xff)
- {
- ok = false;
- }
- g_b = false;
- g_a = false;
- tags.Print (std::cout, "");
- if (!g_a || !g_b)
- {
- ok = false;
- }
- // make sure copy contains copy.
- Tags other = tags;
- g_b = false;
- g_a = false;
- other.Print (std::cout, "");
- if (!g_a || !g_b)
- {
- ok = false;
- }
- g_b = false;
- g_a = false;
- tags.Print (std::cout, "");
- if (!g_a || !g_b)
- {
- ok = false;
- }
- myTagA oA;
- oA.a = 0;
- other.Peek (oA);
- if (oA.a != 10)
- {
- ok = false;
- }
- myTagB oB;
- oB.b = 1;
- other.Peek (oB);
- if (oB.b != 0xff)
- {
- ok = false;
- }
- // remove data.
- other.Remove (oA);
- if (other.Peek (oA))
- {
- ok = false;
- }
- g_b = false;
- g_a = false;
- other.Print (std::cout, "");
- if (g_a || !g_b)
- {
- ok = false;
- }
- if (!tags.Peek (oA))
- {
- ok = false;
- }
- other.Remove (oB);
- if (other.Peek (oB))
- {
- ok = false;
- }
- if (!tags.Peek (oB))
- {
- ok = false;
- }
-
- other = tags;
- Tags another = other;
- myTagC c;
- memset (c.c, 0x66, 16);
- another.Add (c);
- c.c[0] = 0;
- another.Peek (c);
- if (!another.Peek (c))
- {
- ok = false;
- }
- if (tags.Peek (c))
- {
- ok = false;
- }
-
- other = other;
- //other.prettyPrint (std::cout);
-
- //struct myInvalidTag invalid;
- //tags.add (&invalid);
-
- myTagZ tagZ;
- Tags testLastTag;
- tagZ.z = 0;
- testLastTag.Add (tagZ);
- g_z = false;
- testLastTag.Print (std::cout, "");
- if (!g_z)
- {
- ok = false;
- }
-
- MySmartTag smartTag;
- {
- Tags tmp;
- tmp.Add (smartTag);
- tmp.Peek (smartTag);
- 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;
-}
-
-static TagsTest gTagsTest;
-
-
-}; // namespace ns3
-
-#endif /* RUN_SELF_TESTS */
-
--- a/src/common/tags.h Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef TAGS_H
-#define TAGS_H
-
-#include <stdint.h>
-#include <ostream>
-#include <vector>
-#include "buffer.h"
-
-namespace ns3 {
-
-/**
- * \ingroup constants
- * \brief Tag maximum size
- * The maximum size (in bytes) of a Tag is stored
- * in this constant.
- */
-#define TAGS_MAX_SIZE 32
-
-class Tags {
-public:
- inline Tags ();
- inline Tags (Tags const &o);
- inline Tags &operator = (Tags const &o);
- inline ~Tags ();
-
- template <typename T>
- void Add (T const&tag) const;
-
- template <typename T>
- bool Remove (T &tag);
-
- template <typename T>
- bool Peek (T &tag) const;
-
- 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);
-
- enum {
- SIZE = TAGS_MAX_SIZE
- };
-private:
- struct TagData {
- uint8_t m_data[Tags::SIZE];
- struct TagData *m_next;
- uint32_t m_id;
- uint32_t m_count;
- };
-
- bool Remove (uint32_t id);
- struct Tags::TagData *AllocData (void) const;
- void FreeData (struct TagData *data) const;
-
- static struct Tags::TagData *gFree;
- static uint32_t gN_free;
-
- struct TagData *m_next;
-};
-
-} // namespace ns3
-
-
-
-/**************************************************************
- An implementation of the templates defined above
- *************************************************************/
-#include "tag-registry.h"
-#include "tag.h"
-#include "ns3/assert.h"
-#include <string>
-
-namespace ns3 {
-
-template <typename T>
-void
-Tags::Add (T const&tag) const
-{
- 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 != T::GetUid ());
- }
- struct TagData *newStart = AllocData ();
- newStart->m_count = 1;
- newStart->m_next = 0;
- newStart->m_id = T::GetUid ();
- void *buf = &newStart->m_data;
- new (buf) T (tag);
- newStart->m_next = m_next;
- const_cast<Tags *> (this)->m_next = newStart;
-}
-
-template <typename T>
-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);
- if (Peek (tag))
- {
- Remove (T::GetUid ());
- return true;
- }
- else
- {
- return false;
- }
-}
-
-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 == T::GetUid ())
- {
- /* found tag */
- T *data = reinterpret_cast<T *> (&cur->m_data);
- tag = T (*data);
- return true;
- }
- }
- /* no tag found */
- return false;
-}
-
-Tags::Tags ()
- : m_next ()
-{}
-
-Tags::Tags (Tags const &o)
- : m_next (o.m_next)
-{
- if (m_next != 0)
- {
- m_next->m_count++;
- }
-}
-
-Tags &
-Tags::operator = (Tags const &o)
-{
- // self assignment
- if (m_next == o.m_next)
- {
- return *this;
- }
- RemoveAll ();
- m_next = o.m_next;
- if (m_next != 0)
- {
- m_next->m_count++;
- }
- return *this;
-}
-
-Tags::~Tags ()
-{
- RemoveAll ();
-}
-
-void
-Tags::RemoveAll (void)
-{
- struct TagData *prev = 0;
- for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
- {
- cur->m_count--;
- if (cur->m_count > 0)
- {
- break;
- }
- if (prev != 0)
- {
- TagRegistry::Destruct (prev->m_id, prev->m_data);
- FreeData (prev);
- }
- prev = cur;
- }
- if (prev != 0)
- {
- TagRegistry::Destruct (prev->m_id, prev->m_data);
- FreeData (prev);
- }
- m_next = 0;
-}
-
-
-}; // namespace ns3
-
-#endif /* TAGS_H */
--- a/src/common/trailer.h Fri May 30 15:31:50 2008 -0400
+++ b/src/common/trailer.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,13 +29,13 @@
namespace ns3 {
/**
+ * \ingroup packet
+ *
* \brief Protocol trailer serialization and deserialization.
*
* Every Protocol trailer which needs to be inserted or removed
* 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.
+ * implement the pure virtual methods defined here.
*/
class Trailer : public Chunk
{
--- a/src/common/wscript Fri May 30 15:31:50 2008 -0400
+++ b/src/common/wscript Wed Jun 04 17:19:32 2008 -0400
@@ -7,14 +7,15 @@
'packet-metadata.cc',
'packet-metadata-test.cc',
'packet.cc',
- 'tags.cc',
- 'tag-registry.cc',
'chunk.cc',
'header.cc',
'trailer.cc',
'pcap-writer.cc',
'data-rate.cc',
'error-model.cc',
+ 'tag.cc',
+ 'tag-list.cc',
+ 'tag-buffer.cc',
]
headers = bld.create_obj('ns3header')
@@ -24,12 +25,12 @@
'chunk.h',
'header.h',
'trailer.h',
- 'tags.h',
- 'tag-registry.h',
- 'tag.h',
'packet.h',
'packet-metadata.h',
'pcap-writer.h',
'data-rate.h',
'error-model.h',
+ 'tag.h',
+ 'tag-list.h',
+ 'tag-buffer.h',
]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/attribute-iterator.cc Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,274 @@
+#include "attribute-iterator.h"
+#include "ns3/config.h"
+#include "ns3/log.h"
+#include "ns3/pointer.h"
+#include "ns3/object-vector.h"
+#include "ns3/string.h"
+#include <fstream>
+
+
+NS_LOG_COMPONENT_DEFINE ("AttributeIterator");
+
+namespace ns3 {
+
+
+AttributeIterator::AttributeIterator ()
+{}
+
+AttributeIterator::~AttributeIterator ()
+{}
+
+void
+AttributeIterator::Iterate (void)
+{
+ for (uint32_t i = 0; i < Config::GetRootNamespaceObjectN (); ++i)
+ {
+ Ptr<Object> object = Config::GetRootNamespaceObject (i);
+ StartVisitObject (object);
+ DoIterate (object);
+ EndVisitObject ();
+ }
+ NS_ASSERT (m_currentPath.empty ());
+ NS_ASSERT (m_examined.empty ());
+}
+
+bool
+AttributeIterator::IsExamined (Ptr<const Object> object)
+{
+ for (uint32_t i = 0; i < m_examined.size (); ++i)
+ {
+ if (object == m_examined[i])
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+std::string
+AttributeIterator::GetCurrentPath (std::string attr) const
+{
+ std::ostringstream oss;
+ for (uint32_t i = 0; i < m_currentPath.size (); ++i)
+ {
+ oss << "/" << m_currentPath[i];
+ }
+ if (attr != "")
+ {
+ oss << "/" << attr;
+ }
+ return oss.str ();
+}
+
+std::string
+AttributeIterator::GetCurrentPath (void) const
+{
+ std::ostringstream oss;
+ for (uint32_t i = 0; i < m_currentPath.size (); ++i)
+ {
+ oss << "/" << m_currentPath[i];
+ }
+ return oss.str ();
+}
+
+void
+AttributeIterator::DoStartVisitObject (Ptr<Object> object)
+{}
+void
+AttributeIterator::DoEndVisitObject (void)
+{}
+void
+AttributeIterator::DoStartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> item)
+{}
+void
+AttributeIterator::DoEndVisitPointerAttribute (void)
+{}
+void
+AttributeIterator::DoStartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector)
+{}
+void
+AttributeIterator::DoEndVisitArrayAttribute (void)
+{}
+void
+AttributeIterator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item)
+{}
+void
+AttributeIterator::DoEndVisitArrayItem (void)
+{}
+
+void
+AttributeIterator::VisitAttribute (Ptr<Object> object, std::string name)
+{
+ m_currentPath.push_back (name);
+ DoVisitAttribute (object, name);
+ m_currentPath.pop_back ();
+}
+
+void
+AttributeIterator::StartVisitObject (Ptr<Object> object)
+{
+ m_currentPath.push_back ("$" + object->GetInstanceTypeId ().GetName ());
+ DoStartVisitObject (object);
+}
+void
+AttributeIterator::EndVisitObject (void)
+{
+ m_currentPath.pop_back ();
+ DoEndVisitObject ();
+}
+void
+AttributeIterator::StartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> value)
+{
+ m_currentPath.push_back (name);
+ m_currentPath.push_back ("$" + value->GetInstanceTypeId ().GetName ());
+ DoStartVisitPointerAttribute (object, name, value);
+}
+void
+AttributeIterator::EndVisitPointerAttribute (void)
+{
+ m_currentPath.pop_back ();
+ m_currentPath.pop_back ();
+ DoEndVisitPointerAttribute ();
+}
+void
+AttributeIterator::StartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector)
+{
+ m_currentPath.push_back (name);
+ DoStartVisitArrayAttribute (object, name, vector);
+}
+void
+AttributeIterator::EndVisitArrayAttribute (void)
+{
+ m_currentPath.pop_back ();
+ DoEndVisitArrayAttribute ();
+}
+
+void
+AttributeIterator::StartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item)
+{
+ std::ostringstream oss;
+ oss << index;
+ m_currentPath.push_back (oss.str ());
+ m_currentPath.push_back ("$" + item->GetInstanceTypeId ().GetName ());
+ DoStartVisitArrayItem (vector, index, item);
+}
+void
+AttributeIterator::EndVisitArrayItem (void)
+{
+ m_currentPath.pop_back ();
+ m_currentPath.pop_back ();
+ DoEndVisitArrayItem ();
+}
+
+
+void
+AttributeIterator::DoIterate (Ptr<Object> object)
+{
+ if (IsExamined (object))
+ {
+ return;
+ }
+ TypeId tid;
+ for (tid = object->GetInstanceTypeId (); tid.HasParent (); tid = tid.GetParent ())
+ {
+ NS_LOG_DEBUG ("store " << tid.GetName ());
+ for (uint32_t i = 0; i < tid.GetAttributeN (); ++i)
+ {
+ Ptr<const AttributeChecker> checker = tid.GetAttributeChecker (i);
+ const PointerChecker *ptrChecker = dynamic_cast<const PointerChecker *> (PeekPointer (checker));
+ if (ptrChecker != 0)
+ {
+ NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i));
+ PointerValue ptr;
+ object->GetAttribute (tid.GetAttributeName (i), ptr);
+ Ptr<Object> tmp = ptr.Get<Object> ();
+ if (tmp != 0)
+ {
+ StartVisitPointerAttribute (object, tid.GetAttributeName (i), tmp);
+ m_examined.push_back (object);
+ DoIterate (tmp);
+ m_examined.pop_back ();
+ EndVisitPointerAttribute ();
+ }
+ continue;
+ }
+ // attempt to cast to an object vector.
+ const ObjectVectorChecker *vectorChecker = dynamic_cast<const ObjectVectorChecker *> (PeekPointer (checker));
+ if (vectorChecker != 0)
+ {
+ NS_LOG_DEBUG ("vector attribute " << tid.GetAttributeName (i));
+ ObjectVectorValue vector;
+ object->GetAttribute (tid.GetAttributeName (i), vector);
+ StartVisitArrayAttribute (object, tid.GetAttributeName (i), vector);
+ for (uint32_t j = 0; j < vector.GetN (); ++j)
+ {
+ NS_LOG_DEBUG ("vector attribute item " << j);
+ Ptr<Object> tmp = vector.Get (j);
+ StartVisitArrayItem (vector, j, tmp);
+ m_examined.push_back (object);
+ DoIterate (tmp);
+ m_examined.pop_back ();
+ EndVisitArrayItem ();
+ }
+ EndVisitArrayAttribute ();
+ continue;
+ }
+ uint32_t flags = tid.GetAttributeFlags (i);
+ Ptr<const AttributeAccessor> accessor = tid.GetAttributeAccessor (i);
+ if ((flags & TypeId::ATTR_GET) && accessor->HasGetter () &&
+ (flags & TypeId::ATTR_SET) && accessor->HasSetter ())
+ {
+ VisitAttribute (object, tid.GetAttributeName (i));
+ }
+ else
+ {
+ NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (i));
+ }
+ }
+ }
+ Object::AggregateIterator iter = object->GetAggregateIterator ();
+ bool recursiveAggregate = false;
+ while (iter.HasNext ())
+ {
+ Ptr<const Object> tmp = iter.Next ();
+ if (IsExamined (tmp))
+ {
+ recursiveAggregate = true;
+ }
+ }
+ if (!recursiveAggregate)
+ {
+ iter = object->GetAggregateIterator ();
+ while (iter.HasNext ())
+ {
+ Ptr<Object> tmp = const_cast<Object *> (PeekPointer (iter.Next ()));
+ StartVisitObject (tmp);
+ m_examined.push_back (object);
+ DoIterate (tmp);
+ m_examined.pop_back ();
+ EndVisitObject ();
+ }
+ }
+}
+
+TextFileAttributeIterator::TextFileAttributeIterator (std::ostream &os)
+ : m_os (os)
+{}
+void
+TextFileAttributeIterator::DoVisitAttribute (Ptr<Object> object, std::string name)
+{
+ StringValue str;
+ object->GetAttribute (name, str);
+ m_os << GetCurrentPath () << " " << str.Get () << std::endl;
+}
+
+void
+TextFileAttributeIterator::Save (void)
+{
+ Iterate ();
+}
+
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/attribute-iterator.h Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,65 @@
+#ifndef ATTRIBUTE_ITERATOR_H
+#define ATTRIBUTE_ITERATOR_H
+
+#include "ns3/ptr.h"
+#include "ns3/object.h"
+#include <vector>
+
+namespace ns3 {
+
+class ObjectVectorValue;
+
+// This class is used internally by ConfigStore and GtkConfigStore.
+class AttributeIterator
+{
+public:
+ AttributeIterator ();
+ virtual ~AttributeIterator ();
+
+ void Iterate (void);
+protected:
+ std::string GetCurrentPath (void) const;
+private:
+ virtual void DoVisitAttribute (Ptr<Object> object, std::string name) = 0;
+ virtual void DoStartVisitObject (Ptr<Object> object);
+ virtual void DoEndVisitObject (void);
+ virtual void DoStartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> value);
+ virtual void DoEndVisitPointerAttribute (void);
+ virtual void DoStartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector);
+ virtual void DoEndVisitArrayAttribute (void);
+ virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item);
+ virtual void DoEndVisitArrayItem (void);
+
+ void DoIterate (Ptr<Object> object);
+ bool IsExamined (Ptr<const Object> object);
+ std::string GetCurrentPath (std::string attr) const;
+
+ void VisitAttribute (Ptr<Object> object, std::string name);
+ void StartVisitObject (Ptr<Object> object);
+ void EndVisitObject (void);
+ void StartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> value);
+ void EndVisitPointerAttribute (void);
+ void StartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector);
+ void EndVisitArrayAttribute (void);
+ void StartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item);
+ void EndVisitArrayItem (void);
+
+
+ std::vector<Ptr<Object> > m_examined;
+ std::vector<std::string> m_currentPath;
+};
+
+class TextFileAttributeIterator : public AttributeIterator
+{
+public:
+ TextFileAttributeIterator (std::ostream &os);
+ void Save (void);
+private:
+ virtual void DoVisitAttribute (Ptr<Object> object, std::string name);
+ std::ostream &m_os;
+};
+
+
+} // namespace ns3
+
+#endif /* ATTRIBUTE_ITERATOR_H */
--- a/src/contrib/config-store.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/contrib/config-store.cc Wed Jun 04 17:19:32 2008 -0400
@@ -1,9 +1,9 @@
#include "config-store.h"
+#include "attribute-iterator.h"
#include "ns3/string.h"
+#include "ns3/log.h"
+#include "ns3/attribute-list.h"
#include "ns3/config.h"
-#include "ns3/object-vector.h"
-#include "ns3/pointer.h"
-#include "ns3/log.h"
#include <string>
#include <fstream>
#include <iostream>
@@ -54,141 +54,22 @@
while (is.good())
{
is >> path >> value;
- NS_LOG_DEBUG (path << "=" << value);
+ NS_LOG_DEBUG (path << " " << value);
Config::Set (path, StringValue (value));
}
}
void
ConfigStore::StoreTo (std::string filename)
{
+
std::ofstream os;
os.open (filename.c_str (), std::ios::out);
- for (uint32_t i = 0; i < Config::GetRootNamespaceObjectN (); ++i)
- {
- Ptr<Object> object = Config::GetRootNamespaceObject (i);
- Store (os, object);
- }
+ TextFileAttributeIterator iter = TextFileAttributeIterator (os);
+ iter.Save ();
os.close ();
- NS_ASSERT (m_currentPath.empty ());
- NS_ASSERT (m_examined.empty ());
exit (0);
}
-bool
-ConfigStore::IsExamined (Ptr<const Object> object)
-{
- for (uint32_t i = 0; i < m_examined.size (); ++i)
- {
- if (object == m_examined[i])
- {
- return true;
- }
- }
- return false;
-}
-
-std::string
-ConfigStore::GetCurrentPath (std::string attr) const
-{
- std::ostringstream oss;
- for (uint32_t i = 0; i < m_currentPath.size (); ++i)
- {
- oss << "/" << m_currentPath[i];
- }
- oss << "/" << attr;
- return oss.str ();
-}
-
-void
-ConfigStore::Store (std::ostream &os, Ptr<const Object> object)
-{
- if (IsExamined (object))
- {
- return;
- }
- TypeId tid = object->GetInstanceTypeId ();
- m_currentPath.push_back ("$" + tid.GetName ());
- NS_LOG_DEBUG ("store " << tid.GetName ());
- for (uint32_t i = 0; i < tid.GetAttributeN (); ++i)
- {
- Ptr<const AttributeChecker> checker = tid.GetAttributeChecker (i);
- const PointerChecker *ptrChecker = dynamic_cast<const PointerChecker *> (PeekPointer (checker));
- if (ptrChecker != 0)
- {
- NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i));
- PointerValue ptr;
- object->GetAttribute (tid.GetAttributeName (i), ptr);
- Ptr<const Object> tmp = ptr.Get<Object> ();
- if (tmp != 0)
- {
- m_currentPath.push_back (tid.GetAttributeName (i));
- m_examined.push_back (object);
- Store (os, tmp);
- m_examined.pop_back ();
- m_currentPath.pop_back ();
- }
- continue;
- }
- // attempt to cast to an object vector.
- const ObjectVectorChecker *vectorChecker = dynamic_cast<const ObjectVectorChecker *> (PeekPointer (checker));
- if (vectorChecker != 0)
- {
- NS_LOG_DEBUG ("vector attribute " << tid.GetAttributeName (i));
- ObjectVectorValue vector;
- object->GetAttribute (tid.GetAttributeName (i), vector);
- for (uint32_t j = 0; j < vector.GetN (); ++j)
- {
- NS_LOG_DEBUG ("vector attribute item " << j);
- Ptr<const Object> tmp = vector.Get (j);
- std::ostringstream oss;
- oss << tid.GetAttributeName (i) << "/" << j;
- m_currentPath.push_back (oss.str ());
- m_examined.push_back (object);
- Store (os, tmp);
- m_examined.pop_back ();
- m_currentPath.pop_back ();
- }
- continue;
- }
- uint32_t flags = tid.GetAttributeFlags (i);
- Ptr<const AttributeAccessor> accessor = tid.GetAttributeAccessor (i);
- if ((flags & TypeId::ATTR_GET) && accessor->HasGetter () &&
- (flags & TypeId::ATTR_SET) && accessor->HasSetter ())
- {
- StringValue str;
- object->GetAttribute (tid.GetAttributeName (i), str);
- os << GetCurrentPath (tid.GetAttributeName (i)) << " " << str.Get () << std::endl;
- }
- else
- {
- NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (i));
- }
- }
- Object::AggregateIterator iter = object->GetAggregateIterator ();
- bool recursiveAggregate = false;
- while (iter.HasNext ())
- {
- Ptr<const Object> tmp = iter.Next ();
- if (IsExamined (tmp))
- {
- recursiveAggregate = true;
- }
- }
- if (!recursiveAggregate)
- {
- iter = object->GetAggregateIterator ();
- while (iter.HasNext ())
- {
- Ptr<const Object> tmp = iter.Next ();
- m_examined.push_back (object);
- Store (os, tmp);
- m_examined.pop_back ();
- }
- }
- m_currentPath.pop_back ();
-}
-
-
void
ConfigStore::Configure (void)
{
--- a/src/contrib/config-store.h Fri May 30 15:31:50 2008 -0400
+++ b/src/contrib/config-store.h Wed Jun 04 17:19:32 2008 -0400
@@ -2,14 +2,26 @@
#define CONFIG_STORE_H
#include "ns3/object-base.h"
-#include "ns3/object.h"
-#include <vector>
namespace ns3 {
/**
* \brief Store and load simulation attribute configuration
*
+ * While it is possible to generate a sample config file and lightly
+ * edit it to change a couple of values, there are cases where this
+ * process will not work because the same value on the same object
+ * can appear multiple times in the same automatically-generated
+ * configuration file under different configuration paths.
+ *
+ * As such, the best way to use this class is to use it to generate
+ * an initial configuration file, extract from that configuration
+ * file only the strictly necessary elements, and move these minimal
+ * elements to a new configuration file which can then safely
+ * be edited. Another option is to use the ns3::GtkConfigStore class
+ * which will allow you to edit the parameters and will generate
+ * configuration files where all the instances of the same parameter
+ * are changed.
*/
class ConfigStore : public ObjectBase
{
@@ -29,14 +41,9 @@
private:
void LoadFrom (std::string filename);
void StoreTo (std::string filename);
- void Store (std::ostream &os, Ptr<const Object> object);
- bool IsExamined (Ptr<const Object> object);
- std::string GetCurrentPath (std::string attr) const;
std::string m_loadFilename;
std::string m_storeFilename;
- std::vector<Ptr<const Object> > m_examined;
- std::vector<std::string> m_currentPath;
};
} // namespace ns3
--- a/src/contrib/delay-jitter-estimation.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/contrib/delay-jitter-estimation.cc Wed Jun 04 17:19:32 2008 -0400
@@ -2,61 +2,77 @@
#include "delay-jitter-estimation.h"
#include "ns3/tag.h"
#include "ns3/simulator.h"
+#include "ns3/string.h"
-namespace {
+namespace ns3 {
-class TimestampTag : public ns3::Tag
+class DelayJitterEstimationTimestampTag : public Tag
{
public:
- TimestampTag ();
- static uint32_t GetUid (void);
- void Print (std::ostream &os) const;
- void Serialize (ns3::Buffer::Iterator start) const;
- uint32_t Deserialize (ns3::Buffer::Iterator start);
- uint32_t GetSerializedSize (void) const;
+ DelayJitterEstimationTimestampTag ();
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
- ns3::Time GetTxTime (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
+
+ Time GetTxTime (void) const;
private:
uint64_t m_creationTime;
};
-TimestampTag::TimestampTag ()
- : m_creationTime (ns3::Simulator::Now ().GetTimeStep ())
+DelayJitterEstimationTimestampTag::DelayJitterEstimationTimestampTag ()
+ : m_creationTime (Simulator::Now ().GetTimeStep ())
{}
-uint32_t
-TimestampTag::GetUid (void)
+
+TypeId
+DelayJitterEstimationTimestampTag::GetTypeId (void)
{
- static uint32_t uid = ns3::Tag::AllocateUid<TimestampTag> ("mathieu.paper.TimestampTag");
- return uid;
+ static TypeId tid = TypeId ("anon::DelayJitterEstimationTimestampTag")
+ .SetParent<Tag> ()
+ .AddConstructor<DelayJitterEstimationTimestampTag> ()
+ .AddAttribute ("CreationTime",
+ "The time at which the timestamp was created",
+ StringValue ("0.0s"),
+ MakeTimeAccessor (&DelayJitterEstimationTimestampTag::GetTxTime),
+ MakeTimeChecker ())
+ ;
+ return tid;
}
-void
-TimestampTag::Print (std::ostream &os) const
+TypeId
+DelayJitterEstimationTimestampTag::GetInstanceTypeId (void) const
{
- os << ns3::TimeStep (m_creationTime);
+ return GetTypeId ();
+}
+
+uint32_t
+DelayJitterEstimationTimestampTag::GetSerializedSize (void) const
+{
+ return 8;
}
void
-TimestampTag::Serialize (ns3::Buffer::Iterator start) const
-{}
-uint32_t
-TimestampTag::Deserialize (ns3::Buffer::Iterator start)
+DelayJitterEstimationTimestampTag::Serialize (TagBuffer i) const
{
- return 0;
+ i.WriteU64 (m_creationTime);
}
-uint32_t
-TimestampTag::GetSerializedSize (void) const
+void
+DelayJitterEstimationTimestampTag::Deserialize (TagBuffer i)
{
- return 0;
+ m_creationTime = i.ReadU64 ();
}
-ns3::Time
-TimestampTag::GetTxTime (void) const
+void
+DelayJitterEstimationTimestampTag::Print (std::ostream &os) const
{
- return ns3::TimeStep (m_creationTime);
+ os << "CreationTime=" << m_creationTime;
}
-
+Time
+DelayJitterEstimationTimestampTag::GetTxTime (void) const
+{
+ return TimeStep (m_creationTime);
}
-namespace ns3 {
-
DelayJitterEstimation::DelayJitterEstimation ()
: m_previousRx (Simulator::Now ()),
m_previousRxTx (Simulator::Now ()),
@@ -66,15 +82,15 @@
void
DelayJitterEstimation::PrepareTx (Ptr<const Packet> packet)
{
- TimestampTag tag;
+ DelayJitterEstimationTimestampTag tag;
packet->AddTag (tag);
}
void
DelayJitterEstimation::RecordRx (Ptr<const Packet> packet)
{
- TimestampTag tag;
+ DelayJitterEstimationTimestampTag tag;
bool found;
- found = packet->PeekTag (tag);
+ found = packet->FindFirstMatchingTag (tag);
if (!found)
{
return;
--- a/src/contrib/delay-jitter-estimation.h Fri May 30 15:31:50 2008 -0400
+++ b/src/contrib/delay-jitter-estimation.h Wed Jun 04 17:19:32 2008 -0400
@@ -7,7 +7,7 @@
namespace ns3 {
/**
- * \brief quick and diry delay and jitter estimation
+ * \brief quick and dirty delay and jitter estimation
*
*/
class DelayJitterEstimation
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/gtk-config-store.cc Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,538 @@
+#include "gtk-config-store.h"
+#include "attribute-iterator.h"
+#include "ns3/config.h"
+#include "ns3/string.h"
+#include "ns3/pointer.h"
+#include "ns3/log.h"
+#include <gtk/gtk.h>
+#include <fstream>
+
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("GtkconfigStore");
+
+enum {
+ COL_NODE = 0,
+ COL_LAST
+};
+
+struct ModelNode
+{
+ enum {
+ // store object + attribute name
+ NODE_ATTRIBUTE,
+ // store object + attribute name
+ NODE_POINTER,
+ // store object + attribute name
+ NODE_VECTOR,
+ // store index + value (object)
+ NODE_VECTOR_ITEM,
+ // store object
+ NODE_OBJECT
+ } type;
+ std::string name;
+ Ptr<Object> object;
+ uint32_t index;
+};
+
+class ModelCreator : public AttributeIterator
+{
+public:
+ ModelCreator ();
+
+ void Build (GtkTreeStore *treestore);
+private:
+ virtual void DoVisitAttribute (Ptr<Object> object, std::string name);
+ virtual void DoStartVisitObject (Ptr<Object> object);
+ virtual void DoEndVisitObject (void);
+ virtual void DoStartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> value);
+ virtual void DoEndVisitPointerAttribute (void);
+ virtual void DoStartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector);
+ virtual void DoEndVisitArrayAttribute (void);
+ virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item);
+ virtual void DoEndVisitArrayItem (void);
+ void Add (ModelNode *node);
+ void Remove (void);
+
+ GtkTreeStore *m_treestore;
+ std::vector<GtkTreeIter *> m_iters;
+};
+
+ModelCreator::ModelCreator ()
+{}
+void
+ModelCreator::Build (GtkTreeStore *treestore)
+{
+ m_treestore = treestore;
+ m_iters.push_back (NULL);
+ Iterate ();
+ NS_ASSERT (m_iters.size () == 1);
+}
+
+
+void
+ModelCreator::Add (ModelNode *node)
+{
+ GtkTreeIter *parent = m_iters.back ();
+ GtkTreeIter *current = g_new (GtkTreeIter, 1);
+ gtk_tree_store_append (m_treestore, current, parent);
+ gtk_tree_store_set (m_treestore, current,
+ COL_NODE, node,
+ -1);
+ m_iters.push_back (current);
+}
+void
+ModelCreator::Remove (void)
+{
+ GtkTreeIter *iter = m_iters.back ();
+ g_free (iter);
+ m_iters.pop_back ();
+}
+
+void
+ModelCreator::DoVisitAttribute (Ptr<Object> object, std::string name)
+{
+ ModelNode *node = new ModelNode ();
+ node->type = ModelNode::NODE_ATTRIBUTE;
+ node->object = object;
+ node->name = name;
+ Add (node);
+ Remove ();
+}
+void
+ModelCreator::DoStartVisitObject (Ptr<Object> object)
+{
+ ModelNode *node = new ModelNode ();
+ node->type = ModelNode::NODE_OBJECT;
+ node->object = object;
+ Add (node);
+}
+void
+ModelCreator::DoEndVisitObject (void)
+{
+ Remove ();
+}
+void
+ModelCreator::DoStartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> value)
+{
+ ModelNode *node = new ModelNode ();
+ node->type = ModelNode::NODE_POINTER;
+ node->object = object;
+ node->name = name;
+ Add (node);
+}
+void
+ModelCreator::DoEndVisitPointerAttribute (void)
+{
+ Remove ();
+}
+void
+ModelCreator::DoStartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector)
+{
+ ModelNode *node = new ModelNode ();
+ node->type = ModelNode::NODE_VECTOR;
+ node->object = object;
+ node->name = name;
+ Add (node);
+}
+void
+ModelCreator::DoEndVisitArrayAttribute (void)
+{
+ Remove ();
+}
+void
+ModelCreator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item)
+{
+ GtkTreeIter *parent = m_iters.back ();
+ GtkTreeIter *current = g_new (GtkTreeIter, 1);
+ ModelNode *node = new ModelNode ();
+ node->type = ModelNode::NODE_VECTOR_ITEM;
+ node->object = item;
+ node->index = index;
+ gtk_tree_store_append (m_treestore, current, parent);
+ gtk_tree_store_set (m_treestore, current,
+ COL_NODE, node,
+ -1);
+ m_iters.push_back (current);
+}
+void
+ModelCreator::DoEndVisitArrayItem (void)
+{
+ GtkTreeIter *iter = m_iters.back ();
+ g_free (iter);
+ m_iters.pop_back ();
+}
+
+static void
+cell_data_function_col_1 (GtkTreeViewColumn *col,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ ModelNode *node;
+ gtk_tree_model_get (model, iter, COL_NODE, &node, -1);
+ if (node->type == ModelNode::NODE_ATTRIBUTE)
+ {
+ StringValue str;
+ node->object->GetAttribute (node->name, str);
+ g_object_set(renderer, "text", str.Get ().c_str (), NULL);
+ g_object_set(renderer, "editable", TRUE, NULL);
+ }
+ else
+ {
+ g_object_set(renderer, "text", "", NULL);
+ g_object_set(renderer, "editable", FALSE, NULL);
+ }
+}
+
+static void
+cell_data_function_col_0 (GtkTreeViewColumn *col,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ ModelNode *node;
+ gtk_tree_model_get (model, iter, COL_NODE, &node, -1);
+ g_object_set (renderer, "editable", FALSE, NULL);
+ switch (node->type) {
+ case ModelNode::NODE_OBJECT:
+ g_object_set(renderer, "text", node->object->GetInstanceTypeId ().GetName ().c_str (), NULL);
+ break;
+ case ModelNode::NODE_POINTER:
+ g_object_set(renderer, "text", node->name.c_str (), NULL);
+ break;
+ case ModelNode::NODE_VECTOR:
+ g_object_set(renderer, "text", node->name.c_str (), NULL);
+ break;
+ case ModelNode::NODE_VECTOR_ITEM: {
+ std::stringstream oss;
+ oss << node->index;
+ g_object_set(renderer, "text", oss.str ().c_str (), NULL);
+ } break;
+ case ModelNode::NODE_ATTRIBUTE:
+ g_object_set(renderer, "text", node->name.c_str (), NULL);
+ break;
+ }
+}
+
+
+static void
+cell_edited_callback (GtkCellRendererText *cell,
+ gchar *path_string,
+ gchar *new_text,
+ gpointer user_data)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (user_data);
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter_from_string (model, &iter, path_string);
+ ModelNode *node;
+ gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
+ NS_ASSERT (node->type == ModelNode::NODE_ATTRIBUTE);
+ node->object->SetAttribute (node->name, StringValue (new_text));
+}
+
+static int
+get_col_number_from_tree_view_column (GtkTreeViewColumn *col)
+{
+ GList *cols;
+ int num;
+ g_return_val_if_fail ( col != NULL, -1 );
+ g_return_val_if_fail ( col->tree_view != NULL, -1 );
+ cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
+ num = g_list_index(cols, (gpointer) col);
+ g_list_free(cols);
+ return num;
+}
+
+static gboolean
+cell_tooltip_callback (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_tip,
+ GtkTooltip *tooltip,
+ gpointer user_data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeViewColumn * column;
+ if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
+ &x, &y, keyboard_tip,
+ &model, NULL, &iter))
+ {
+ return FALSE;
+ }
+ if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+ x, y, NULL, &column, NULL, NULL))
+ {
+ return FALSE;
+ }
+ int col = get_col_number_from_tree_view_column (column);
+
+ ModelNode *node;
+ gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
+
+ switch (node->type) {
+ case ModelNode::NODE_OBJECT:
+ if (col == 0)
+ {
+ std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName ();
+ gtk_tooltip_set_text (tooltip, tip.c_str ());
+ return TRUE;
+ }
+ break;
+ case ModelNode::NODE_POINTER:
+ if (col == 0)
+ {
+ PointerValue ptr;
+ node->object->GetAttribute (node->name, ptr);
+ std::string tip = "This object is of type " + ptr.GetObject ()->GetInstanceTypeId ().GetName ();
+ gtk_tooltip_set_text (tooltip, tip.c_str ());
+ return TRUE;
+ }
+ break;
+ case ModelNode::NODE_VECTOR:
+ break;
+ case ModelNode::NODE_VECTOR_ITEM:
+ if (col == 0)
+ {
+ std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName ();
+ gtk_tooltip_set_text (tooltip, tip.c_str ());
+ return TRUE;
+ }
+ break;
+ case ModelNode::NODE_ATTRIBUTE: {
+ uint32_t attrIndex = 0;
+ TypeId tid;
+ for (tid = node->object->GetInstanceTypeId (); tid.HasParent (); tid = tid.GetParent ())
+ {
+ for (uint32_t i = 0; i < tid.GetAttributeN (); ++i)
+ {
+ if (tid.GetAttributeName (i) == node->name)
+ {
+ attrIndex = i;
+ goto out;
+ }
+ }
+ }
+ out:
+ if (col == 0)
+ {
+ std::string tip = tid.GetAttributeHelp (attrIndex);
+ gtk_tooltip_set_text (tooltip, tip.c_str ());
+ }
+ else
+ {
+ Ptr<const AttributeChecker> checker = tid.GetAttributeChecker (attrIndex);
+ std::string tip;
+ tip = "This attribute is of type " + checker->GetValueTypeName ();
+ if (checker->HasUnderlyingTypeInformation ())
+ {
+ tip += " " + checker->GetUnderlyingTypeInformation ();
+ }
+ gtk_tooltip_set_text (tooltip, tip.c_str ());
+ }
+ return TRUE;
+ } break;
+ }
+ return FALSE;
+}
+
+
+static GtkWidget *
+create_view (GtkTreeStore *model)
+{
+ GtkTreeViewColumn *col;
+ GtkCellRenderer *renderer;
+ GtkWidget *view;
+
+ view = gtk_tree_view_new();
+ g_object_set (view, "has-tooltip", TRUE, NULL);
+ g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback, NULL);
+
+ gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH);
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
+
+ col = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(col, "Object Attributes");
+ gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start(col, renderer, TRUE);
+ gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_0, NULL, NULL);
+ g_object_set(renderer, "editable", FALSE, NULL);
+
+ col = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(col, "Attribute Value");
+ gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+ renderer = gtk_cell_renderer_text_new();
+ g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, model);
+ gtk_tree_view_column_pack_start(col, renderer, TRUE);
+ gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_1, NULL, NULL);
+
+
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL (model));
+
+ g_object_unref(model); /* destroy model automatically with view */
+
+
+ return view;
+}
+
+static void
+save_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *parent_window = GTK_WIDGET (user_data);
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new ("Save File",
+ GTK_WINDOW (parent_window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "config.txt");
+
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+ {
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ std::ofstream os;
+ os.open (filename);
+ TextFileAttributeIterator file = TextFileAttributeIterator (os);
+ file.Save ();
+ os.close ();
+ g_free (filename);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+load_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *parent_window = GTK_WIDGET (user_data);
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new ("Open File",
+ GTK_WINDOW (parent_window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+ {
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ std::ifstream is;
+ is.open (filename, std::ios::in);
+ std::string path, value;
+ while (is.good())
+ {
+ is >> path >> value;
+ Config::Set (path, StringValue (value));
+ }
+ g_free (filename);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+exit_clicked_callback (GtkButton *button,
+ gpointer user_data)
+{
+ gtk_main_quit ();
+}
+
+static gboolean
+delete_event_callback (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ gtk_main_quit ();
+ return TRUE;
+}
+
+static gboolean
+clean_model_callback (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ ModelNode *node;
+ gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
+ COL_NODE, &node,
+ -1);
+ delete node;
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ COL_NODE, NULL,
+ -1);
+ return FALSE;
+}
+
+GtkConfigStore::GtkConfigStore ()
+{}
+
+void
+GtkConfigStore::Configure (void)
+{
+ GtkWidget *window;
+ GtkWidget *view;
+ GtkWidget *scroll;
+
+ gtk_init (0, 0);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "ns-3 Object attributes.");
+ gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
+
+ g_signal_connect (window, "delete_event", (GCallback)delete_event_callback, NULL);
+
+
+ GtkTreeStore *model = gtk_tree_store_new (COL_LAST, G_TYPE_POINTER);
+ ModelCreator creator;
+ creator.Build (model);
+
+ view = create_view (model);
+ scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (scroll), view);
+
+ GtkWidget *vbox = gtk_vbox_new (FALSE, 5);
+ gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
+ gtk_box_pack_end (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0);
+ GtkWidget *hbox = gtk_hbox_new (FALSE, 5);
+ gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ GtkWidget *save = gtk_button_new_with_label ("Save");
+ g_signal_connect (save, "clicked", (GCallback) save_clicked, window);
+ gtk_box_pack_end (GTK_BOX (hbox), save, FALSE, FALSE, 0);
+ GtkWidget *load = gtk_button_new_with_label ("Load");
+ g_signal_connect (load, "clicked", (GCallback) load_clicked, window);
+ gtk_box_pack_end (GTK_BOX (hbox), load, FALSE, FALSE, 0);
+ GtkWidget *exit = gtk_button_new_with_label ("Exit");
+ g_signal_connect (exit, "clicked", (GCallback) exit_clicked_callback, NULL);
+ gtk_box_pack_end (GTK_BOX (hbox), exit, FALSE, FALSE, 0);
+
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ gtk_tree_model_foreach (GTK_TREE_MODEL (model),
+ clean_model_callback,
+ NULL);
+
+ gtk_widget_destroy (window);
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/gtk-config-store.h Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,17 @@
+#ifndef GTK_CONFIG_STORE_H
+#define GTK_CONFIG_STORE_H
+
+namespace ns3 {
+
+class GtkConfigStore
+{
+public:
+ GtkConfigStore ();
+
+ void Configure (void);
+};
+
+
+} // namespace ns3
+
+#endif /* GTK_CONFIG_STORE_H */
--- a/src/contrib/wscript Fri May 30 15:31:50 2008 -0400
+++ b/src/contrib/wscript Wed Jun 04 17:19:32 2008 -0400
@@ -1,11 +1,20 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+def configure(conf):
+ check = conf.create_pkgconfig_configurator()
+ check.name = 'gtk+-2.0 >= 2.12'
+ check.uselib = 'GTK_CONFIG_STORE'
+ check.mandatory = False
+ conf.env['ENABLE_GTK_CONFIG_STORE'] = check.run()
+
+
def build(bld):
module = bld.create_ns3_module('contrib', ['simulator'])
module.source = [
'event-garbage-collector.cc',
'gnuplot.cc',
'delay-jitter-estimation.cc',
+ 'attribute-iterator.cc',
'config-store.cc',
]
@@ -17,3 +26,8 @@
'delay-jitter-estimation.h',
'config-store.h',
]
+
+ if bld.env()['ENABLE_GTK_CONFIG_STORE']:
+ headers.source.append ('gtk-config-store.h')
+ module.source.append ('gtk-config-store.cc')
+ module.uselib = 'GTK_CONFIG_STORE'
--- a/src/core/assert.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/assert.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,7 +28,12 @@
/**
* \ingroup core
+ * \defgroup debugging Debugging
+ */
+/**
+ * \ingroup debugging
* \defgroup assert Assert
+ *
* \brief assert functions and macros
*
* The assert macros are used to verify
--- a/src/core/attribute-accessor-helper.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/attribute-accessor-helper.h Wed Jun 04 17:19:32 2008 -0400
@@ -24,10 +24,16 @@
namespace ns3 {
+/**
+ * \ingroup AttributeHelper
+ */
template <typename V, typename T1>
Ptr<const AttributeAccessor>
MakeAccessorHelper (T1 a1);
+/**
+ * \ingroup AttributeHelper
+ */
template <typename V, typename T1, typename T2>
Ptr<const AttributeAccessor>
MakeAccessorHelper (T1 a1, T2 a2);
--- a/src/core/attribute-helper.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/attribute-helper.h Wed Jun 04 17:19:32 2008 -0400
@@ -83,8 +83,7 @@
*
* The simple macros are implemented in terms of the complex
* macros and should generally be prefered over the complex macros:
- * - \ref ATTRIBUTE_HELPER_HEADER_1,
- * - \ref ATTRIBUTE_HELPER_HEADER_2, and,
+ * - \ref ATTRIBUTE_HELPER_HEADER, and,
* - \ref ATTRIBUTE_HELPER_CPP,
*/
@@ -236,19 +235,10 @@
* \ingroup AttributeHelper
* \param type the name of the class
*
- * This macro should be invoked from a public section of the class
- * declaration.
- */
-#define ATTRIBUTE_HELPER_HEADER_1(type)
-
-/**
- * \ingroup AttributeHelper
- * \param type the name of the class
- *
* This macro should be invoked outside of the class
* declaration in its public header.
*/
-#define ATTRIBUTE_HELPER_HEADER_2(type) \
+#define ATTRIBUTE_HELPER_HEADER(type) \
ATTRIBUTE_VALUE_DEFINE (type); \
ATTRIBUTE_ACCESSOR_DEFINE (type); \
ATTRIBUTE_CHECKER_DEFINE (type);
--- a/src/core/attribute-list.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/core/attribute-list.cc Wed Jun 04 17:19:32 2008 -0400
@@ -212,7 +212,7 @@
std::string::size_type equal = str.find ("=", cur);
if (equal == std::string::npos)
{
- // XXX: invalid attribute.
+ NS_FATAL_ERROR ("Error while parsing serialized attribute: \"" << str << "\"");
break;
}
else
@@ -221,7 +221,7 @@
struct TypeId::AttributeInfo info;
if (!TypeId::LookupAttributeByFullName (name, &info))
{
- // XXX invalid name.
+ NS_FATAL_ERROR ("Error while parsing serialized attribute: name does not exist: \"" << name << "\"");
break;
}
else
@@ -242,7 +242,7 @@
bool ok = val->DeserializeFromString (value, info.checker);
if (!ok)
{
- // XXX invalid value
+ NS_FATAL_ERROR ("Error while parsing serialized attribute: value invalid: \"" << value << "\"");
break;
}
else
--- a/src/core/attribute-list.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/attribute-list.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,8 @@
namespace ns3 {
/**
+ * \ingroup attribute
+ *
* \brief a container of attributes to be used during object's construction
* and in ns3::Object::Set.
*
@@ -85,7 +87,6 @@
*/
static AttributeList *GetGlobal (void);
- // XXX: untested.
std::string SerializeToString (void) const;
bool DeserializeFromString (std::string value);
private:
--- a/src/core/attribute-test.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/core/attribute-test.cc Wed Jun 04 17:19:32 2008 -0400
@@ -53,7 +53,7 @@
{
return is;
}
-ATTRIBUTE_HELPER_HEADER_2 (ValueClassTest);
+ATTRIBUTE_HELPER_HEADER (ValueClassTest);
ATTRIBUTE_HELPER_CPP (ValueClassTest);
class AttributeTest : public Test
@@ -167,7 +167,7 @@
MakeTraceSourceAccessor (&AttributeObjectTest::m_cb))
.AddTraceSource ("ValueSource", "help text",
MakeTraceSourceAccessor (&AttributeObjectTest::m_valueSrc))
- .AddAttribute ("Pointer", "XXX",
+ .AddAttribute ("Pointer", "help text",
PointerValue (),
MakePointerAccessor (&AttributeObjectTest::m_ptr),
MakePointerChecker<Derived> ())
--- a/src/core/attribute.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/attribute.h Wed Jun 04 17:19:32 2008 -0400
@@ -33,6 +33,15 @@
class ObjectBase;
/**
+ *
+ * \ingroup core
+ * \defgroup attribute Attribute
+ */
+
+/**
+ *
+ * \ingroup attribute
+ *
* \brief Hold a value for an Attribute.
*
* Instances of this class should always be wrapped into an Attribute object.
@@ -78,6 +87,8 @@
/**
* \brief allow setting and getting the value of an attribute.
*
+ * \ingroup attribute
+ *
* The goal of this class is to hide from the user how an attribute
* is actually set or get to or from a class instance. Implementations
* of this base class are usually provided through the MakeAccessorHelper
@@ -124,6 +135,8 @@
/**
* \brief Represent the type of an attribute
*
+ * \ingroup attribute
+ *
* Each type of attribute has an associated unique AttributeChecker
* subclass. The type of the subclass can be safely used by users
* to infer the type of the associated attribute. i.e., we expect
@@ -131,7 +144,7 @@
* to detect the type of the associated attribute.
*
* Most subclasses of this base class are implemented by the
- * ATTRIBUTE_HELPER_* macros.
+ * \ref ATTRIBUTE_HELPER_HEADER and \ref ATTRIBUTE_HELPER_CPP macros.
*/
class AttributeChecker : public RefCountBase
{
@@ -180,6 +193,11 @@
};
+/**
+ * \brief A class for an empty attribute value
+ *
+ * \ingroup attribute
+ */
class EmptyAttributeValue : public AttributeValue
{
public:
--- a/src/core/boolean.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/boolean.h Wed Jun 04 17:19:32 2008 -0400
@@ -26,6 +26,8 @@
namespace ns3 {
/**
+ * \ingroup attribute
+ *
* \brief Hold a bool native type
*
* \anchor bool
--- a/src/core/command-line.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/command-line.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,7 @@
/**
* \brief parse command-line arguments
+ * \ingroup core
*
* Instances of this class can be used to parse command-line
* arguments: users can register new arguments with
--- a/src/core/config.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/core/config.cc Wed Jun 04 17:19:32 2008 -0400
@@ -765,7 +765,7 @@
// this should trigger a notification
d1->SetAttribute ("Source", IntegerValue (-3));
NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
- NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source")
+ NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source");
m_traceNotification = 0;
m_tracePath = "";
// this should trigger a notification
--- a/src/core/config.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/config.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,10 @@
class Object;
class CallbackBase;
+/**
+ * \brief Configuration of simulation parameters and tracing
+ * \ingroup core
+ */
namespace Config {
/**
--- a/src/core/double.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/double.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,8 @@
namespace ns3 {
/**
+ * \ingroup attribute
+ *
* \class ns3::DoubleValue
* \brief Hold an floating point type
*
--- a/src/core/empty.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/empty.h Wed Jun 04 17:19:32 2008 -0400
@@ -2,6 +2,9 @@
#define EMPTY_H
namespace ns3 {
+/**
+ * \brief make Callback use a separate empty type
+ */
class empty {};
}
--- a/src/core/enum.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/enum.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,8 @@
namespace ns3 {
/**
+ * \ingroup attribute
+ *
* \brief hold variables of type 'enum'
*
* This class can be used to hold variables of any kind
--- a/src/core/fatal-error.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/fatal-error.h Wed Jun 04 17:19:32 2008 -0400
@@ -24,8 +24,7 @@
#include <iostream>
/**
- * \ingroup core
- * \defgroup error Error
+ * \ingroup debugging
* \brief fatal error handling
*
* \param msg message to output when this macro is hit.
--- a/src/core/global-value.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/global-value.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,8 @@
namespace ns3 {
/**
+ * \ingroup Core
+ *
* \brief hold a so-called 'global value'.
*
* Instances of this class are expected to be allocated as static
--- a/src/core/integer.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/integer.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,7 @@
namespace ns3 {
/**
+ * \ingroup attribute
* \class ns3::IntegerValue
* \brief Hold a signed integer type
*
--- a/src/core/log.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/log.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,7 +28,7 @@
/**
- * \ingroup core
+ * \ingroup debugging
* \defgroup logging Logging
* \brief Logging functions and macros
*
@@ -69,7 +69,7 @@
#define NS_LOG_COMPONENT_DEFINE(name) \
static ns3::LogComponent g_log = ns3::LogComponent (name)
-#define APPEND_TIME_PREFIX \
+#define NS_LOG_APPEND_TIME_PREFIX \
if (g_log.IsEnabled (ns3::LOG_PREFIX_TIME)) \
{ \
LogTimePrinter printer = LogGetTimePrinter (); \
@@ -80,13 +80,17 @@
} \
}
-#define APPEND_FUNC_PREFIX \
+#define NS_LOG_APPEND_FUNC_PREFIX \
if (g_log.IsEnabled (ns3::LOG_PREFIX_FUNC)) \
{ \
std::clog << g_log.Name () << ":" << \
__FUNCTION__ << "(): "; \
} \
+#ifndef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT
+#endif /* NS_LOG_APPEND_CONTEXT */
+
/**
* \ingroup logging
@@ -107,8 +111,9 @@
{ \
if (g_log.IsEnabled (level)) \
{ \
- APPEND_TIME_PREFIX; \
- APPEND_FUNC_PREFIX; \
+ NS_LOG_APPEND_TIME_PREFIX; \
+ NS_LOG_APPEND_CONTEXT; \
+ NS_LOG_APPEND_FUNC_PREFIX; \
std::clog << msg << std::endl; \
} \
} \
@@ -160,7 +165,8 @@
{ \
if (g_log.IsEnabled (ns3::LOG_FUNCTION)) \
{ \
- APPEND_TIME_PREFIX; \
+ NS_LOG_APPEND_TIME_PREFIX; \
+ NS_LOG_APPEND_CONTEXT; \
std::clog << g_log.Name () << ":" \
<< __FUNCTION__ << "()" << std::endl; \
} \
@@ -189,7 +195,8 @@
{ \
if (g_log.IsEnabled (ns3::LOG_FUNCTION)) \
{ \
- APPEND_TIME_PREFIX; \
+ NS_LOG_APPEND_TIME_PREFIX; \
+ NS_LOG_APPEND_CONTEXT; \
std::clog << g_log.Name () << ":" \
<< __FUNCTION__ << "("; \
ParameterLogger (std::clog) << parameters; \
@@ -320,12 +327,10 @@
bool IsNoneEnabled (void) const;
void Enable (enum LogLevel level);
void Disable (enum LogLevel level);
- bool Decorate (void) const;
char const *Name (void) const;
private:
int32_t m_levels;
char const *m_name;
- bool m_decorate;
};
class ParameterLogger : public std::ostream
--- a/src/core/object-base.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/object-base.h Wed Jun 04 17:19:32 2008 -0400
@@ -42,6 +42,8 @@
class AttributeList;
/**
+ * \ingroup object
+ *
* \brief implement the ns-3 type and attribute system
*
* Every class which wants to integrate in the ns-3 type and attribute
--- a/src/core/object-factory.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/object-factory.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,8 @@
class AttributeValue;
/**
+ * \ingroup object
+ *
* \brief instantiate subclasses of ns3::Object.
*
* This class can also hold a set of attributes to set
@@ -77,7 +79,6 @@
template <typename T>
Ptr<T> Create (void) const;
- ATTRIBUTE_HELPER_HEADER_1 (ObjectFactory);
private:
friend std::ostream & operator << (std::ostream &os, const ObjectFactory &factory);
friend std::istream & operator >> (std::istream &is, ObjectFactory &factory);
@@ -94,7 +95,7 @@
* \brief hold objects of type ns3::ObjectFactory
*/
-ATTRIBUTE_HELPER_HEADER_2 (ObjectFactory);
+ATTRIBUTE_HELPER_HEADER (ObjectFactory);
} // namespace ns3
--- a/src/core/object-vector.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/core/object-vector.cc Wed Jun 04 17:19:32 2008 -0400
@@ -34,8 +34,16 @@
std::string
ObjectVectorValue::SerializeToString (Ptr<const AttributeChecker> checker) const
{
- // XXX
- return "";
+ std::ostringstream oss;
+ for (uint32_t i = 0; i < m_objects.size (); ++i)
+ {
+ oss << m_objects[i];
+ if (i != m_objects.size () - 1)
+ {
+ oss << " ";
+ }
+ }
+ return oss.str ();
}
bool
ObjectVectorValue::DeserializeFromString (std::string value, Ptr<const AttributeChecker> checker)
--- a/src/core/object-vector.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/object-vector.h Wed Jun 04 17:19:32 2008 -0400
@@ -9,6 +9,8 @@
namespace ns3 {
/**
+ * \ingroup object
+ *
* \brief contain a vector of ns3::Object pointers.
*
* This class it used to get attribute access to an array of
--- a/src/core/object.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/core/object.cc Wed Jun 04 17:19:32 2008 -0400
@@ -375,7 +375,7 @@
NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<DerivedA> (), 0);
NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<BaseA> (), 0);
NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<DerivedB> (), 0);
- NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0)
+ NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0);
baseA = CreateObject<BaseA> ();
baseB = CreateObject<BaseB> ();
--- a/src/core/object.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/object.h Wed Jun 04 17:19:32 2008 -0400
@@ -39,8 +39,21 @@
class TraceSourceAccessor;
/**
+ * \ingroup core
+ * \defgroup object Object
+ */
+/**
+ * \ingroup object
* \brief a base class which provides memory management and object aggregation
*
+ * The memory management scheme is based on reference-counting with dispose-like
+ * functionality to break the reference cycles. The reference count is increamented
+ * and decremented with the methods Object::Ref and Object::Unref. If a reference cycle is
+ * present, the user is responsible for breaking it by calling Object::Dispose in
+ * a single location. This will eventually trigger the invocation of Object::DoDispose
+ * on itself and all its aggregates. The Object::DoDispose method is always automatically
+ * invoked from the Object::Unref method before destroying the object, even if the user
+ * did not call Object::Dispose directly.
*/
class Object : public ObjectBase
{
--- a/src/core/pointer.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/pointer.h Wed Jun 04 17:19:32 2008 -0400
@@ -26,6 +26,8 @@
namespace ns3 {
/**
+ * \ingroup attribute
+ *
* \brief hold objects of type Ptr<T>
*/
class PointerValue : public AttributeValue
--- a/src/core/ptr.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/ptr.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,12 @@
namespace ns3 {
/**
+ * \ingroup core
+ * \defgroup ptr Smart Pointer
+ */
+/**
+ * \ingroup ptr
+ *
* \brief smart pointer class similar to boost::intrusive_ptr
*
* This smart-pointer class assumes that the underlying
--- a/src/core/singleton.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/singleton.h Wed Jun 04 17:19:32 2008 -0400
@@ -22,6 +22,17 @@
namespace ns3 {
+/**
+ * \brief a template singleton
+ *
+ * This template class can be used to implement the singleton pattern.
+ * The underlying object will be destroyed automatically when the process
+ * exits. Note that, if you call Singleton::Get again after the object has
+ * been destroyed, the object will be re-created which will result in a
+ * memory leak as reported by most memory leak checkers. It is up to the
+ * user to ensure that Singleton::Get is never called from a static variable
+ * finalizer.
+ */
template <typename T>
class Singleton
{
--- a/src/core/string.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/string.h Wed Jun 04 17:19:32 2008 -0400
@@ -7,6 +7,8 @@
namespace ns3 {
/**
+ * \ingroup attribute
+ *
* \class ns3::StringValue
* \brief hold variables of type string
*
--- a/src/core/test.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/test.h Wed Jun 04 17:19:32 2008 -0400
@@ -33,6 +33,12 @@
class TestManager;
/**
+ * \ingroup core
+ * \defgroup test Test
+ */
+/**
+ * \ingroup test
+ *
* \brief base class for new regressions tests
*
* To add a new regression test, you need to:
@@ -65,6 +71,8 @@
};
/**
+ * \ingroup test
+ *
* \brief gather and run all regression tests
*/
class TestManager {
@@ -100,6 +108,42 @@
};
}; // namespace ns3
+#define NS_TEST_ASSERT_EQUAL_FILELINE(got, expected, file, line) \
+ do { \
+ if ((got) != (expected)) \
+ { \
+ Failure () << file << ":" <<line \
+ << ": expected " << (expected) \
+ << ", got " << (got) << std::endl; \
+ result = false; \
+ } \
+ } while (false)
+
+#define NS_TEST_ASSERT_UNEQUAL_FILELINE(got, expected,file,line) \
+ do { \
+ if ((got) == (expected)) \
+ { \
+ Failure () << file << ":" <<line \
+ << ": did not want " << (expected) \
+ << ", got " << (got) << std::endl; \
+ result = false; \
+ } \
+ } while (false)
+
+
+#define NS_TEST_ASSERT_FILELINE(assertion, file, line) \
+ do { \
+ if (!(assertion)) \
+ { \
+ Failure () << file << ":" <<line \
+ << ": assertion `" << #assertion \
+ << "' failed." << std::endl; \
+ result = false; \
+ } \
+ } while (false)
+
+
+
/**
* Convenience macro to check that a value returned by a test is what
* is expected. Note: this macro assumes a 'bool result = true'
@@ -110,13 +154,8 @@
* \param expected value that the test is expected to return
*/
#define NS_TEST_ASSERT_EQUAL(got, expected) \
- if ((got) != (expected)) \
- { \
- Failure () << __FILE__ << ":" <<__LINE__ \
- << ": expected " << (expected) \
- << ", got " << (got) << std::endl; \
- result = false; \
- }
+ NS_TEST_ASSERT_EQUAL_FILELINE(got,expected,__FILE__,__LINE__)
+
/**
* Convenience macro to check that a value returned by a test is what
* is expected. Note: this macro assumes a 'bool result = true'
@@ -127,13 +166,8 @@
* \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; \
- }
+ NS_TEST_ASSERT_UNEQUAL_FILELINE(got,expected,__FILE__,__LINE__)
+
/**
* Convenience macro to check an assertion is held during an unit
* test. Note: this macro assumes a 'bool result = true' declaration
@@ -143,13 +177,7 @@
* \param assertion expression that must be true if the test did not fail
*/
#define NS_TEST_ASSERT(assertion) \
- if (!(assertion)) \
- { \
- Failure () << __FILE__ << ":" <<__LINE__ \
- << ": assertion `" << #assertion \
- << "' failed." << std::endl; \
- result = false; \
- }
+ NS_TEST_ASSERT_FILELINE (assertion, __FILE__,__LINE__)
#endif /* RUN_SELF_TESTS */
--- a/src/core/trace-source-accessor.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/trace-source-accessor.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,8 @@
class ObjectBase;
/**
+ * \ingroup tracing
+ *
* \brief control access to objects' trace sources
*
* This class abstracts the kind of trace source to which we want to connect
@@ -72,7 +74,10 @@
* \param a the trace source
*
* Create a TraceSourceAccessor which will control access to the underlying
- * trace source.
+ * trace source. This helper template method assumes that the underlying
+ * type implements a statically-polymorphic set of Connect and Disconnect
+ * methods and creates a dynamic-polymorphic class to wrap the underlying
+ * static-polymorphic class.
*/
template <typename T>
Ptr<const TraceSourceAccessor> MakeTraceSourceAccessor (T a);
--- a/src/core/traced-value.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/traced-value.h Wed Jun 04 17:19:32 2008 -0400
@@ -32,6 +32,13 @@
namespace ns3 {
/**
+ * \ingroup core
+ * \defgroup tracing Tracing
+ */
+
+/**
+ * \ingroup tracing
+ *
* \brief trace classes with value semantics
*
* If you want to trace the change of value of a class or
@@ -40,7 +47,7 @@
* this template: this instance will behave just like
* the original class (if it did not export any special method),
* and will define Connect/DisconnectWithoutContext methods to work
- * with an ns3::TraceSourceAccessor.
+ * with ns3::MakeTraceSourceAccessor.
*/
template <typename T>
class TracedValue
--- a/src/core/type-id.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/core/type-id.cc Wed Jun 04 17:19:32 2008 -0400
@@ -473,6 +473,12 @@
return TypeId (parent);
}
bool
+TypeId::HasParent (void) const
+{
+ uint16_t parent = Singleton<IidManager>::Get ()->GetParent (m_tid);
+ return parent != m_tid;
+}
+bool
TypeId::IsChildOf (TypeId other) const
{
TypeId tmp = *this;
--- a/src/core/type-id.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/type-id.h Wed Jun 04 17:19:32 2008 -0400
@@ -109,6 +109,8 @@
*/
TypeId GetParent (void) const;
+ bool HasParent (void) const;
+
/**
* \param other a parent TypeId
* \returns true if the input TypeId is really a parent
@@ -352,7 +354,6 @@
TypeId ();
~TypeId ();
- ATTRIBUTE_HELPER_HEADER_1 (TypeId);
private:
friend class AttributeList;
friend bool operator == (TypeId a, TypeId b);
@@ -386,7 +387,7 @@
*/
-ATTRIBUTE_HELPER_HEADER_2 (TypeId);
+ATTRIBUTE_HELPER_HEADER (TypeId);
} // namespace ns3
--- a/src/core/uinteger.h Fri May 30 15:31:50 2008 -0400
+++ b/src/core/uinteger.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,8 @@
namespace ns3 {
/**
+ * \ingroup attribute
+ *
* \class ns3::UintegerValue
* \brief Hold an unsigned integer type
*
--- a/src/devices/csma/csma-net-device.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/csma/csma-net-device.h Wed Jun 04 17:19:32 2008 -0400
@@ -420,7 +420,6 @@
* fire.
*
* @see class CallBackTraceSource
- * @see class TraceResolver
*/
TracedCallback<Ptr<const Packet> > m_rxTrace;
TracedCallback<Ptr<const Packet> > m_dropTrace;
--- a/src/devices/csma/csma.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/csma/csma.h Wed Jun 04 17:19:32 2008 -0400
@@ -1,9 +1,134 @@
/**
* \ingroup devices
- * \defgroup Csma Csma Models
+ * \defgroup CSMA CSMA Model
+ *
+ * \section CSMA Model
+ *
+ * The ns-3 CSMA device models a simple bus network in the spirit of Ethernet.
+ * Although it does not model any real physical network you could ever build
+ * or buy, it does provide some very useful functionality.
+ *
+ * Typically when one thinks of a bus network Ethernet or IEEE 802.3 comes to
+ * mind. Ethernet uses CSMA/CD (Carrier Sense Multiple Access with Collision
+ * Detection with exponentially increasing backoff to contend for the shared
+ * transmission medium. The ns-3 CSMA device models only a portion of this
+ * process, using the nature of the globally available channel to provide
+ * instantaneous (faster than light) carrier sense and priority-based
+ * collision "avoidance." Collisions in the sense of Ethernet never happen and
+ * so the ns-3 CSMA device does not model collision detection, nor will any
+ * transmission in progress be "jammed."
+ *
+ * \subsection CSMA Channel Model
+ *
+ * The class ns3::CsmaChannel models the actual transmission medium.
+ * There is no fixed limit for the number of devices connected to the channel.
+ * The ns3::CsmaChannel models a bitrate and a speed-of-light delay which can
+ * be accessed via the attributes "BitRate" and "Delay" respectively.
*
- * \section Csma Models
+ * The ns3::CsmaChannel has three states, IDLE, TRANSMITTING and PROPAGATING.
+ * These three states are "seen" instantaneously by all devices on the channel.
+ * By this we mean that if one device begins or ends a simulated transmission,
+ * all devices on the channel are immediately aware of the change in state.
+ * There is no time during which one device may see an IDLE channel while
+ * another device physically further away in the collision domain may have
+ * begun transmitting with the associated signals not propagated. Thus there
+ * is no need for collision detection in the ns3::CsmaChannel model and it is
+ * not implemented in any way.
+ *
+ * We do, as the name indicates, have a Carrier Sense aspect to the model.
+ * Since the simulator is single threaded, access to the common channel will
+ * be serialized by the simulator. This provides a deterministic mechanism
+ * for contending for the channel. The channel is allocated (transitioned from
+ * state IDLE to state TRANSMITTING) on a first-come first-served basis. The
+ * channel always goes through a three state process:
+ *
+ * IDLE -> TRANSMITTING -> PROPAGATING -> IDLE
+ *
+ * The TRANSMITTING state models the time during which the source net device
+ * is actually wiggling the signals on the wire. The PROPAGATING state models
+ * the time after the last bit was sent, when the signal is propagating down
+ * the wire to the "far end."
+ *
+ * The transition to the TRANSMITTING state is driven by a call to
+ * ns3::CsmaChannel::TransmitStart which is called by the net device that
+ * transmits the packet. It is the responsibility of that device to end the
+ * transmission with a call to ns3::CsmaChannel::TransmitEnd at the appropriate
+ * simulation time that reflects the time elapsed to put all of the packet bits
+ * on the wire. When TransmitEnd is called, the channel schedules an event
+ * corresponding to a single speed-of-light delay. This delay applies to all
+ * net devices on the channel identically. You can think of a symmetrical hub
+ * in which the packet bits propagate to a central location and then back out
+ * equal length cables to the other devices on the channel.
+ *
+ * The ns3::CsmaChannel models a broadcast medium so the packet is delivered
+ * to all of the devices on the channel (including the source) at the end of
+ * the propagation time.
+ *
+ * \subsection CSMA Net Device Model
*
- * The set of Csma models provides an abstrated shared media net device
- * and channel, similar to a switched ethernet.
+ * The CSMA network device appears somewhat like an Ethernet device. The
+ * ns3::CsmaNetDevice provides following Attributes:
+ *
+ * - Address: The ns3::Mac48Address of the device;
+ * - DataRate: The data rate of the device;
+ * - SendEnable: Enable packet transmission if true;
+ * - ReceiveEnable: Enable packet reception if true;
+ * - EncapsulationMode: Type of link layer encapsulation to use;
+ * - RxErrorModel: The receive error model;
+ * - TxQueue: The trasmit queue used by the device;
+ * - InterframeGap: The optional time to wait between "frames";
+ * - Rx: A trace source for received packets;
+ * - Drop: A trace source for dropped packets.
+ *
+ * The ns3::CsmaNetDevice supports the assignment of a "receive error model."
+ * This is an ns3::ErrorModel object that is used to simulate data corruption
+ * on the link.
+ *
+ * Packets sent over the ns3::CsmaNetDevice are always routed through the
+ * transmit queue to provide a trace hook for packets sent out over the
+ * network. This transmit queue can be set (via attribute) to model different
+ * queueing strategies.
+ *
+ * Also configurable by attribute is the encapsulation method used by the
+ * device. Every packet gets an ns3::EthernetHeader that includes the
+ * destination and source MAC addresses, and a length/type field. Every packet
+ * also gets an ns3::EthernetTrailer which includes the FCS. Data in the
+ * packet may be encapsulated in different ways. By default, or by setting
+ * the "EncapsulationMode" attribute to "Llc", the encapsulation is by
+ * LLC SNAP. In this case, a SNAP header is added that contains the EtherType
+ * (IP or ARP). The other implemented encapsulation modes are IP_ARP (set
+ * "EncapsulationMode" to "IpArp") in which the length type of the Ethernet
+ * header receives the protocol number of the packet; or ETHERNET_V1 (set
+ * "EncapsulationMode" to "EthernetV1") in which the length type of the
+ * Ethernet header receives the length of the packet. A "Raw" encapsulation
+ * mode is defined but not implemented -- use of the RAW mode results in an
+ * assert firing.
+ *
+ * The ns3::CsmaNetDevice implements a random exponential backoff algorithm
+ * that is executed if the channel is determined to be busy (TRANSMITTING or
+ * PROPAGATING) when the device wants to start propagating. This results in a
+ * random delay of up to pow (2, retries) - 1 microseconds before a retry is
+ * attempted. The default maximum number of retries is 1000.
+ *
+ * \subsection CSMA Model Summary
+ *
+ * The ns3 CSMA model is a simplistic model of an Ethernet-like network. It
+ * supports a Carrier-Sense function and allows for Multiple Access to a
+ * shared medium. It is not physical in the sense that the state of the
+ * medium is instantaneously shared among all devices. This means that there
+ * is no collision detection required in this model and none is implemented.
+ * There will never be a "jam" of a packet already on the medium. Access to
+ * the shared channel is on a first-come first-served basis as determined by
+ * the simulator scheduler. If the channel is determined to be busy by looking
+ * at the global state, a random exponential backoff is performed and a retry
+ * is attempted.
+ *
+ * Ns-3 Attributes provide a mechanism for setting various parameters in the
+ * device and channel such as addresses, encapsulation modes and error model
+ * selection. Trace hooks are provided in the usual manner.
+ *
+ * Although the ns-3 CsmaChannel and CsmaNetDevice does not model any kind of
+ * network you could build or buy, it does provide us with some useful
+ * functionality. You should, however, understand that it is explicitly not
+ * Ethernet or IEEE 802.3 but an interesting subset.
*/
--- a/src/devices/point-to-point/point-to-point-channel.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/point-to-point/point-to-point-channel.cc Wed Jun 04 17:19:32 2008 -0400
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2007 University of Washington
+ * Copyright (c) 2007, 2008 University of Washington
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,8 +14,6 @@
* You should have received a copy of the GNU General Public License
* 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"
@@ -36,10 +34,6 @@
static TypeId tid = TypeId ("ns3::PointToPointChannel")
.SetParent<Channel> ()
.AddConstructor<PointToPointChannel> ()
- .AddAttribute ("BitRate", "The maximum bitrate of the channel",
- DataRateValue (DataRate (0xffffffff)),
- MakeDataRateAccessor (&PointToPointChannel::m_bps),
- MakeDataRateChecker ())
.AddAttribute ("Delay", "Transmission delay through the channel",
TimeValue (Seconds (0)),
MakeTimeAccessor (&PointToPointChannel::m_delay),
@@ -54,7 +48,8 @@
PointToPointChannel::PointToPointChannel()
:
Channel ("PointToPoint Channel"),
- m_nDevices(0)
+ m_delay (Seconds (0.)),
+ m_nDevices (0)
{
NS_LOG_FUNCTION_NOARGS ();
}
@@ -81,9 +76,10 @@
}
bool
-PointToPointChannel::TransmitStart(Ptr<Packet> p,
- Ptr<PointToPointNetDevice> src,
- const Time& txTime)
+PointToPointChannel::TransmitStart(
+ Ptr<Packet> p,
+ Ptr<PointToPointNetDevice> src,
+ Time txTime)
{
NS_LOG_FUNCTION (this << p << src);
NS_LOG_LOGIC ("UID is " << p->GetUid () << ")");
@@ -93,12 +89,8 @@
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);
+ Simulator::Schedule (txTime + m_delay, &PointToPointNetDevice::Receive,
+ m_link[wire].m_dst, p);
return true;
}
@@ -117,20 +109,6 @@
return m_link[i].m_src;
}
-const DataRate&
-PointToPointChannel::GetDataRate (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_bps;
-}
-
-const Time&
-PointToPointChannel::GetDelay (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_delay;
-}
-
Ptr<NetDevice>
PointToPointChannel::GetDevice (uint32_t i) const
{
@@ -138,5 +116,4 @@
return GetPointToPointDevice (i);
}
-
} // namespace ns3
--- a/src/devices/point-to-point/point-to-point-channel.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/point-to-point/point-to-point-channel.h Wed Jun 04 17:19:32 2008 -0400
@@ -36,14 +36,7 @@
* 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.
+ * point-to-point net devices connected.
*
* 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
@@ -58,7 +51,7 @@
* \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.
+ * has zero transmission delay.
*/
PointToPointChannel ();
@@ -75,38 +68,32 @@
* \param txTime Transmit time to apply
*/
bool TransmitStart (Ptr<Packet> p, Ptr<PointToPointNetDevice> src,
- const Time& txTime);
+ Time txTime);
/**
* \brief Get number of devices on this channel
* \returns number of devices on this channel
*/
virtual uint32_t GetNDevices (void) const;
+
/*
* \brief Get PointToPointNetDevice corresponding to index i on this channel
* \param i Index number of the device requested
* \returns Ptr to PointToPointNetDevice requested
*/
Ptr<PointToPointNetDevice> GetPointToPointDevice (uint32_t i) const;
- virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
/*
- * \brief Get reference to DataRate for this channel
- * \returns const reference to underlying DataRate object
+ * \brief Get NetDevice corresponding to index i on this channel
+ * \param i Index number of the device requested
+ * \returns Ptr to NetDevice requested
*/
- const DataRate& GetDataRate (void);
- /*
- * \brief Get reference to Time object storing the delay on this channel
- * \returns const reference to underlying Time object
- */
- const Time& GetDelay (void);
+ virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
private:
-
// Each point to point link has exactly two net devices
static const int N_DEVICES = 2;
-
- DataRate m_bps;
Time m_delay;
int32_t m_nDevices;
@@ -122,7 +109,7 @@
{
public:
Link() : m_state (INITIALIZING), m_src (0), m_dst (0) {}
- WireState m_state;
+ WireState m_state;
Ptr<PointToPointNetDevice> m_src;
Ptr<PointToPointNetDevice> m_dst;
};
--- a/src/devices/point-to-point/point-to-point-net-device.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/point-to-point/point-to-point-net-device.cc Wed Jun 04 17:19:32 2008 -0400
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2005,2006 INRIA
+ * Copyright (c) 2007, 2008 University of Washington
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,9 +14,6 @@
* You should have received a copy of the GNU General Public License
* 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"
@@ -48,7 +45,7 @@
MakeMac48AddressAccessor (&PointToPointNetDevice::m_address),
MakeMac48AddressChecker ())
.AddAttribute ("DataRate", "The default data rate for point to point links",
- DataRateValue (DataRate ("10Mb/s")),
+ DataRateValue (DataRate ("32768b/s")),
MakeDataRateAccessor (&PointToPointNetDevice::m_bps),
MakeDataRateChecker ())
.AddAttribute ("ReceiveErrorModel", "XXX",
@@ -85,15 +82,10 @@
}
PointToPointNetDevice::~PointToPointNetDevice ()
-{}
-
-void
-PointToPointNetDevice::SetAddress (Mac48Address self)
{
- m_address = self;
}
-void
+ void
PointToPointNetDevice::AddHeader(Ptr<Packet> p, uint16_t protocolNumber)
{
NS_LOG_FUNCTION_NOARGS ();
@@ -103,7 +95,7 @@
p->AddHeader (ppp);
}
-bool
+ bool
PointToPointNetDevice::ProcessHeader(Ptr<Packet> p, uint16_t& param)
{
NS_LOG_FUNCTION_NOARGS ();
@@ -113,7 +105,8 @@
return true;
}
-void PointToPointNetDevice::DoDispose()
+ void
+PointToPointNetDevice::DoDispose()
{
NS_LOG_FUNCTION_NOARGS ();
m_node = 0;
@@ -122,22 +115,21 @@
NetDevice::DoDispose ();
}
-void PointToPointNetDevice::SetDataRate(const DataRate& bps)
+ void
+PointToPointNetDevice::SetDataRate(DataRate bps)
{
NS_LOG_FUNCTION_NOARGS ();
- if (!m_channel || bps <= m_channel->GetDataRate ())
- {
- m_bps = bps;
- }
+ m_bps = bps;
}
-void PointToPointNetDevice::SetInterframeGap(const Time& t)
+ void
+PointToPointNetDevice::SetInterframeGap(Time t)
{
NS_LOG_FUNCTION_NOARGS ();
m_tInterframeGap = t;
}
-bool
+ bool
PointToPointNetDevice::TransmitStart (Ptr<Packet> p)
{
NS_LOG_FUNCTION (this << p);
@@ -154,33 +146,40 @@
NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " <<
txCompleteTime.GetSeconds () << "sec");
- // Schedule the tx complete event
+
Simulator::Schedule (txCompleteTime,
- &PointToPointNetDevice::TransmitComplete,
- this);
+ &PointToPointNetDevice::TransmitComplete, this);
+
return m_channel->TransmitStart(p, this, txTime);
}
-void PointToPointNetDevice::TransmitComplete (void)
+ void
+PointToPointNetDevice::TransmitComplete (void)
{
NS_LOG_FUNCTION_NOARGS ();
//
-// This function is called to finish the process of transmitting a packet.
-// We need to tell the channel that we've stopped wiggling the wire and
-// get the next packet from the queue. If the queue is empty, we are
-// done, otherwise transmit the next packet.
+// This function is called to when we're all done transmitting a packet.
+// We try and pull another packet off of the transmit queue. If the queue
+// is empty, we are done, otherwise we need to start transmitting the
+// next packet.
//
NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
m_txMachineState = READY;
Ptr<Packet> p = m_queue->Dequeue ();
if (p == 0)
{
- return; // Nothing to do at this point
+//
+// No packet was on the queue, so we just exit.
+//
+ return;
}
+//
+// Got another packet off of the queue, so start the transmit process agin.
+//
TransmitStart(p);
}
-bool
+ bool
PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
{
NS_LOG_FUNCTION (this << &ch);
@@ -188,64 +187,64 @@
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.
- */
+//
+// This device is up whenever it is attached to a channel. A better plan
+// would be to have the link come up when both devices are attached, but this
+// is not done for now.
+//
NotifyLinkUp ();
return true;
}
-void PointToPointNetDevice::SetQueue (Ptr<Queue> q)
+ void
+PointToPointNetDevice::SetQueue (Ptr<Queue> q)
{
NS_LOG_FUNCTION (this << q);
-
m_queue = q;
}
-void PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
+ void
+PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
{
NS_LOG_FUNCTION ("(" << em << ")");
-
m_receiveErrorModel = em;
}
-void PointToPointNetDevice::Receive (Ptr<Packet> packet)
+ void
+PointToPointNetDevice::Receive (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
uint16_t protocol = 0;
if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) )
{
+//
+// If we have an error model and it indicates that it is time to lose a
+// corrupted packet, don't forward this packet up, let it go.
+//
m_dropTrace (packet);
- // Do not forward up; let this packet go
}
else
{
+//
+// Hit the receive trace hook, strip off the point-to-point protocol header
+// and forward this packet up the protocol stack.
+//
m_rxTrace (packet);
ProcessHeader(packet, protocol);
m_rxCallback (this, packet, protocol, GetBroadcast ());
}
}
-Ptr<Queue> PointToPointNetDevice::GetQueue(void) const
+ Ptr<Queue>
+PointToPointNetDevice::GetQueue(void) const
{
NS_LOG_FUNCTION_NOARGS ();
return m_queue;
}
-void
+ void
PointToPointNetDevice::NotifyLinkUp (void)
{
m_linkUp = true;
@@ -255,110 +254,167 @@
}
}
-void
+ void
PointToPointNetDevice::SetName(const std::string name)
{
m_name = name;
}
-std::string
+
+ std::string
PointToPointNetDevice::GetName(void) const
{
return m_name;
}
-void
+
+ void
PointToPointNetDevice::SetIfIndex(const uint32_t index)
{
m_ifIndex = index;
}
-uint32_t
+
+ uint32_t
PointToPointNetDevice::GetIfIndex(void) const
{
return m_ifIndex;
}
-Ptr<Channel>
+
+ Ptr<Channel>
PointToPointNetDevice::GetChannel (void) const
{
return m_channel;
}
-Address
+
+//
+// This is a point-to-point device, so we really don't need any kind of address
+// information. However, the base class NetDevice wants us to define the
+// methods to get and set the address. Rather than be rude and assert, we let
+// clients get and set the address, but simply ignore them.
+ void
+PointToPointNetDevice::SetAddress (Mac48Address addr)
+{
+ m_address = addr;
+}
+
+ Address
PointToPointNetDevice::GetAddress (void) const
{
return m_address;
}
-bool
+
+ bool
PointToPointNetDevice::SetMtu (const uint16_t mtu)
{
m_mtu = mtu;
return true;
}
-uint16_t
+
+ uint16_t
PointToPointNetDevice::GetMtu (void) const
{
return m_mtu;
}
-bool
+
+ bool
PointToPointNetDevice::IsLinkUp (void) const
{
return m_linkUp;
}
-void
+
+ void
PointToPointNetDevice::SetLinkChangeCallback (Callback<void> callback)
{
m_linkChangeCallback = callback;
}
-bool
+
+//
+// This is a point-to-point device, so every transmission is a broadcast to
+// all of the devices on the network.
+//
+ bool
PointToPointNetDevice::IsBroadcast (void) const
{
return true;
}
-Address
+
+//
+// We don't really need any addressing information since this is a
+// point-to-point device. The base class NetDevice wants us to return a
+// broadcast address, so we make up something reasonable.
+//
+ Address
PointToPointNetDevice::GetBroadcast (void) const
{
return Mac48Address ("ff:ff:ff:ff:ff:ff");
}
-bool
+
+//
+// We don't deal with multicast here. It doesn't make sense to include some
+// of the one destinations on the network but exclude some of the others.
+ bool
PointToPointNetDevice::IsMulticast (void) const
{
return false;
}
-Address
+
+//
+// Since we return false in the IsMulticast call, calls to other multicast
+// related methods returns are undefined according to the base class. So we
+// can freely make something up, which is the base of the MAC multicast
+// address space.
+//
+ Address
PointToPointNetDevice::GetMulticast (void) const
{
return Mac48Address ("01:00:5e:00:00:00");
}
-Address
+
+ Address
PointToPointNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const
{
return Mac48Address ("01:00:5e:00:00:00");
}
-bool
+
+ bool
PointToPointNetDevice::IsPointToPoint (void) const
{
return true;
}
-bool
-PointToPointNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
+
+ bool
+PointToPointNetDevice::Send(
+ Ptr<Packet> packet,
+ const Address &dest,
+ uint16_t protocolNumber)
{
NS_LOG_FUNCTION_NOARGS ();
NS_LOG_LOGIC ("p=" << packet << ", dest=" << &dest);
NS_LOG_LOGIC ("UID is " << packet->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 ());
+//
+// If IsLinkUp() is false it means there is no channel to send any packet
+// over so we just return an error.
+//
+ if (IsLinkUp () == false)
+ {
+ return false;
+ }
+
+//
+// Stick a point to point protocol header on the packet in preparation for
+// shoving it out the door.
+//
AddHeader(packet, 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
+//
+// Even if the transmitter is immediately available, we still enqueue and
+// dequeue the packet to hit the tracing hooks.
+//
m_queue->Enqueue (packet);
packet = m_queue->Dequeue ();
return TransmitStart (packet);
@@ -368,26 +424,29 @@
return m_queue->Enqueue(packet);
}
}
-Ptr<Node>
+
+ Ptr<Node>
PointToPointNetDevice::GetNode (void) const
{
return m_node;
}
-void
+
+ void
PointToPointNetDevice::SetNode (Ptr<Node> node)
{
m_node = node;
}
-bool
+
+ bool
PointToPointNetDevice::NeedsArp (void) const
{
return false;
}
-void
+
+ void
PointToPointNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
{
m_rxCallback = cb;
}
-
} // namespace ns3
--- a/src/devices/point-to-point/point-to-point-net-device.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/point-to-point/point-to-point-net-device.h Wed Jun 04 17:19:32 2008 -0400
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2007 University of Washington
+ * Copyright (c) 2007, 2008 University of Washington
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,8 +14,6 @@
* You should have received a copy of the GNU General Public License
* 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
@@ -62,16 +60,16 @@
* This is the constructor for the PointToPointNetDevice. It takes as a
* parameter a pointer to the Node to which this device is connected,
* as well as an optional DataRate object.
- *
- * @see PointToPointTopology::AddPointToPointLink ()
*/
PointToPointNetDevice ();
+
/**
* 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
@@ -80,48 +78,35 @@
* @see Attach ()
* @param bps the data rate at which this object operates
*/
- void SetDataRate (const DataRate& bps);
+ 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 (const Time& t);
+ 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.
+ * @param ch Ptr 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.
+ * The PointToPointNetDevice "owns" a queue that implements a queueing
+ * method such as DropTail or RED.
*
- * @see PointToPointTopology::AddPointToPointLink ()
* @see Queue
* @see DropTailQueue
- * @param queue a pointer to the queue for which object is assuming
- * ownership.
+ * @param queue Ptr to the new queue.
*/
void SetQueue (Ptr<Queue> queue);
+
/**
* Attach a receive ErrorModel to the PointToPointNetDevice.
*
@@ -129,9 +114,10 @@
* the packet receive chain.
*
* @see ErrorModel
- * @param em a pointer to the ErrorModel
+ * @param em Ptr to the ErrorModel.
*/
void SetReceiveErrorModel(Ptr<ErrorModel> em);
+
/**
* Receive a packet from a connected PointToPointChannel.
*
@@ -141,46 +127,67 @@
* arrived at the device.
*
* @see PointToPointChannel
- * @param p a reference to the received packet
+ * @param p Ptr to the received packet.
*/
void Receive (Ptr<Packet> p);
- void SetAddress (Mac48Address self);
+ /**
+ * Assign a MAC address to this device.
+ *
+ * @see Mac48Address
+ * @param addr The new address.
+ */
+ void SetAddress (Mac48Address addr);
- // inherited from NetDevice base class.
+//
+// Pure virtual methods inherited from NetDevice we must implement.
+//
virtual void SetName(const std::string name);
virtual std::string GetName(void) const;
+
virtual void SetIfIndex(const uint32_t index);
virtual uint32_t GetIfIndex(void) const;
+
virtual Ptr<Channel> GetChannel (void) const;
virtual Address GetAddress (void) const;
+
virtual bool SetMtu (const uint16_t mtu);
virtual uint16_t GetMtu (void) const;
+
virtual bool IsLinkUp (void) const;
+
virtual void SetLinkChangeCallback (Callback<void> callback);
+
virtual bool IsBroadcast (void) const;
virtual Address GetBroadcast (void) const;
+
virtual bool IsMulticast (void) const;
virtual Address GetMulticast (void) const;
virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
virtual bool IsPointToPoint (void) const;
- virtual bool Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
+
+ virtual bool Send(Ptr<Packet> packet, const Address &dest,
+ uint16_t protocolNumber);
+
virtual Ptr<Node> GetNode (void) const;
virtual void SetNode (Ptr<Node> node);
+
virtual bool NeedsArp (void) const;
+
virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
private:
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.
+ * @returns Ptr to the queue.
*/
Ptr<Queue> GetQueue(void) const;
@@ -190,6 +197,7 @@
* respect the protocol implemented by the agent.
*/
void AddHeader(Ptr<Packet> p, uint16_t protocolNumber);
+
/**
* Removes, from a packet of data, all headers and trailers that
* relate to the protocol implemented by the agent
@@ -197,6 +205,7 @@
* protocol stack.
*/
bool ProcessHeader(Ptr<Packet> p, uint16_t& param);
+
/**
* Start Sending a Packet Down the Wire.
*
@@ -213,14 +222,15 @@
* @returns true if success, false on failure
*/
bool TransmitStart (Ptr<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);
+
void NotifyLinkUp (void);
/**
@@ -236,24 +246,28 @@
* @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
@@ -262,20 +276,20 @@
* @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
*/
TracedCallback<Ptr<const Packet> > m_rxTrace;
+
/**
* The trace source for the packet drop events that the device can
* fire.
*
* @see class CallBackTraceSource
- * @see class TraceResolver
*/
TracedCallback<Ptr<const Packet> > m_dropTrace;
--- a/src/devices/point-to-point/point-to-point.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/point-to-point/point-to-point.h Wed Jun 04 17:19:32 2008 -0400
@@ -1,11 +1,45 @@
/**
* \ingroup devices
- * \defgroup PointToPoint Point-to-Point Models
+ * \defgroup PointToPoint Point-to-Point Model
+ *
+ * \section Point-to-Point Model
+ *
+ * The ns-3 point-to-point model is of a very simple point to point data link
+ * connecting exactly two ns3::PointToPointNetDevice devices over an
+ * ns3::PointToPointChannel. This can be viewed as equivalent to a full
+ * duplex RS-232 or RS-422 link with null modem and no handshaking.
*
- * \section Point-to-Point Models
+ * Data is encapsulated in the Point-to-Point Protocol (PPP -- RFC 1661),
+ * however the Link Control Protocol (LCP) and associated state machine is
+ * not implemented. The PPP link is assumed to be established and
+ * authenticated at all times.
+ *
+ * Data is not framed, therefore Address and Control fields will not be found.
+ * Since the data is not framed, there is no need to provide Flag Sequence and
+ * Control Escape octets, nor is a Frame Check Sequence appended. All that is
+ * required to implement non-framed PPP is to prepend the PPP protocol number
+ * for IP Version 4 which is the sixteen-bit number 0x21 (see
+ * http://www.iana.org/assignments/ppp-numbers).
*
- * The set of Point-to-Point models provides an abstrated point-to-point link
- * model, that simulates transmission delay (finite data rate) and
- * propagation delay, and can also optionally include an error model
- * (ns3::ErrorModel).
+ * The ns3::PointToPointNetDevice provides following Attributes:
+ *
+ * - Address: The ns3::Mac48Address of the device (if desired);
+ * - DataRate: The data rate of the device;
+ * - TxQueue: The trasmit queue used by the device;
+ * - InterframeGap: The optional time to wait between "frames";
+ * - Rx: A trace source for received packets;
+ * - Drop: A trace source for dropped packets.
+ *
+ * The ns3::PointToPointNetDevice supports the assignment of a "receive error
+ * model." This is an ns3::ErrorModel object that is used to simulate data
+ * corruption on the link.
+ *
+ * The point to point net devices are connected via an
+ * ns3::PointToPointChannel. This channel models two wires transmitting bits
+ * at the data rate specified by the source net device. There is no overhead
+ * beyond the eight bits per byte of the packet sent. That is, we do not
+ * model Flag Sequences, Frame Check Sequences nor do we "escape" any data.
+ *
+ * The ns3::PointToPointChannel does model a speed-of-light or transmission
+ * delay which can be set and get via the attribute "Delay."
*/
--- a/src/devices/point-to-point/ppp-header.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/point-to-point/ppp-header.cc Wed Jun 04 17:19:32 2008 -0400
@@ -55,7 +55,7 @@
void
PppHeader::Print (std::ostream &os) const
{
- os << "Point-to-Point Protocol: IP (0x0021)" << std::endl;
+ os << "Point-to-Point Protocol: IP (0x0021)";
}
uint32_t
--- a/src/devices/wifi/adhoc-wifi-mac.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/adhoc-wifi-mac.cc Wed Jun 04 17:19:32 2008 -0400
@@ -137,9 +137,7 @@
}
void
AdhocWifiMac::SetLinkDownCallback (Callback<void> linkDown)
-{
- //XXX
-}
+{}
Mac48Address
AdhocWifiMac::GetAddress (void) const
{
--- a/src/devices/wifi/constant-rate-wifi-manager.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/constant-rate-wifi-manager.cc Wed Jun 04 17:19:32 2008 -0400
@@ -77,11 +77,11 @@
static TypeId tid = TypeId ("ns3::ConstantRateWifiManager")
.SetParent<WifiRemoteStationManager> ()
.AddConstructor<ConstantRateWifiManager> ()
- .AddAttribute ("DataMode", "XXX",
+ .AddAttribute ("DataMode", "The transmission mode to use for every data packet transmission",
StringValue ("wifia-6mbs"),
MakeWifiModeAccessor (&ConstantRateWifiManager::m_dataMode),
MakeWifiModeChecker ())
- .AddAttribute ("ControlMode", "XXX",
+ .AddAttribute ("ControlMode", "The transmission mode to use for every control packet transmission.",
StringValue ("wifia-6mbs"),
MakeWifiModeAccessor (&ConstantRateWifiManager::m_ctlMode),
MakeWifiModeChecker ())
--- a/src/devices/wifi/dca-txop.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/dca-txop.cc Wed Jun 04 17:19:32 2008 -0400
@@ -99,17 +99,17 @@
static TypeId tid = TypeId ("DcaTxop")
.SetParent<Object> ()
.AddConstructor<DcaTxop> ()
- .AddAttribute ("MinCw", "XXX",
+ .AddAttribute ("MinCw", "The minimum value of the contention window.",
UintegerValue (15),
MakeUintegerAccessor (&DcaTxop::SetMinCw,
&DcaTxop::GetMinCw),
MakeUintegerChecker<uint32_t> ())
- .AddAttribute ("MaxCw", "XXX",
+ .AddAttribute ("MaxCw", "The maximum value of the contention window.",
UintegerValue (1023),
MakeUintegerAccessor (&DcaTxop::SetMaxCw,
&DcaTxop::GetMaxCw),
MakeUintegerChecker<uint32_t> ())
- .AddAttribute ("Aifsn", "XXX",
+ .AddAttribute ("Aifsn", "The AIFSN: the default value conforms to simple DCA.",
UintegerValue (2),
MakeUintegerAccessor (&DcaTxop::SetAifsn,
&DcaTxop::GetAifsn),
@@ -139,6 +139,9 @@
DcaTxop::DoDispose (void)
{
NS_LOG_FUNCTION (this);
+ m_queue = 0;
+ m_low = 0;
+ m_stationManager = 0;
delete m_transmissionListener;
delete m_dcf;
delete m_rng;
@@ -147,9 +150,6 @@
m_dcf = 0;
m_rng = 0;
m_txMiddle = 0;
- m_queue = 0;
- m_low = 0;
- m_stationManager = 0;
}
void
--- a/src/devices/wifi/mac-low.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/mac-low.cc Wed Jun 04 17:19:32 2008 -0400
@@ -40,14 +40,14 @@
class SnrTag : public Tag
{
public:
- SnrTag ();
- SnrTag (const SnrTag &o);
- ~SnrTag ();
- static uint32_t GetUid (void);
- void Print (std::ostream &os) const;
- uint32_t GetSerializedSize (void) const;
- void Serialize (Buffer::Iterator i) const;
- uint32_t Deserialize (Buffer::Iterator i);
+
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
void Set (double snr);
double Get (void) const;
@@ -55,40 +55,44 @@
double m_snr;
};
-SnrTag::SnrTag ()
- : m_snr (0.0)
-{}
-SnrTag::SnrTag (const SnrTag &o)
- : m_snr (o.m_snr)
-{}
-SnrTag::~SnrTag ()
-{}
+TypeId
+SnrTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::SnrTag")
+ .SetParent<Tag> ()
+ .AddConstructor<SnrTag> ()
+ .AddAttribute ("Snr", "The snr of the last packet received",
+ DoubleValue (0.0),
+ MakeDoubleAccessor (&SnrTag::Get),
+ MakeDoubleChecker<double> ())
+ ;
+ return tid;
+}
+TypeId
+SnrTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
uint32_t
-SnrTag::GetUid (void)
+SnrTag::GetSerializedSize (void) const
+{
+ return sizeof (double);
+}
+void
+SnrTag::Serialize (TagBuffer i) const
{
- static uint32_t uid = AllocateUid<SnrTag> ("SnrTag.ns3.inria.fr");
- return uid;
+ i.WriteDouble (m_snr);
+}
+void
+SnrTag::Deserialize (TagBuffer i)
+{
+ m_snr = i.ReadDouble ();
}
void
SnrTag::Print (std::ostream &os) const
{
- os << "snr="<<m_snr;
-}
-uint32_t
-SnrTag::GetSerializedSize (void) const
-{
- return 0;
-}
-void
-SnrTag::Serialize (Buffer::Iterator i) const
-{
- // would need to serialize double to platform-independent format.
-}
-uint32_t
-SnrTag::Deserialize (Buffer::Iterator i)
-{
- // would need to deserialize double from platform-independent format.
- return 0;
+ os << "Snr=" << m_snr;
}
void
SnrTag::Set (double snr)
@@ -472,7 +476,7 @@
{
MY_DEBUG ("receive cts from="<<m_currentHdr.GetAddr1 ());
SnrTag tag;
- packet->PeekTag (tag);
+ packet->FindFirstMatchingTag (tag);
WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ());
station->ReportRxOk (rxSnr, txMode);
station->ReportRtsOk (rxSnr, txMode, tag.Get ());
@@ -495,7 +499,7 @@
{
MY_DEBUG ("receive ack from="<<m_currentHdr.GetAddr1 ());
SnrTag tag;
- packet->PeekTag (tag);
+ packet->FindFirstMatchingTag (tag);
WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ());
station->ReportRxOk (rxSnr, txMode);
station->ReportDataOk (rxSnr, txMode, tag.Get ());
--- a/src/devices/wifi/nqap-wifi-mac.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/nqap-wifi-mac.cc Wed Jun 04 17:19:32 2008 -0400
@@ -44,7 +44,7 @@
.SetParent<WifiMac> ()
.AddConstructor<NqapWifiMac> ()
.AddAttribute ("BeaconInterval", "Delay between two beacons",
- TimeValue (Seconds (1.0)),
+ TimeValue (Seconds (0.1)),
MakeTimeAccessor (&NqapWifiMac::m_beaconInterval),
MakeTimeChecker ())
.AddAttribute ("BeaconGeneration", "Whether or not beacons are generated.",
--- a/src/devices/wifi/nqsta-wifi-mac.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/nqsta-wifi-mac.cc Wed Jun 04 17:19:32 2008 -0400
@@ -38,18 +38,18 @@
/*
* The state machine for this NQSTA is:
- -------------- -----------
+ -------------- -----------
| Associated | <-------------------- -------> | Refused |
- -------------- \ / -----------
- \ \ /
+ -------------- \ / -----------
+ \ \ /
\ ----------------- -----------------------------
\-> | Beacon Missed | --> | Wait Association Response |
- ----------------- -----------------------------
- \ ^
- \ |
- \ -----------------------
- \-> | Wait Probe Response |
- -----------------------
+ ----------------- -----------------------------
+ \ ^
+ \ |
+ \ -----------------------
+ \-> | Wait Probe Response |
+ -----------------------
*/
namespace ns3 {
@@ -62,11 +62,11 @@
static TypeId tid = TypeId ("ns3::NqstaWifiMac")
.SetParent<WifiMac> ()
.AddConstructor<NqstaWifiMac> ()
- .AddAttribute ("ProbeRequestTimeout", "XXX",
- TimeValue (Seconds (0.5)),
+ .AddAttribute ("ProbeRequestTimeout", "The interval between two consecutive probe request attempts.",
+ TimeValue (Seconds (0.05)),
MakeTimeAccessor (&NqstaWifiMac::m_probeRequestTimeout),
MakeTimeChecker ())
- .AddAttribute ("AssocRequestTimeout", "XXX",
+ .AddAttribute ("AssocRequestTimeout", "The interval between two consecutive assoc request attempts.",
TimeValue (Seconds (0.5)),
MakeTimeAccessor (&NqstaWifiMac::m_assocRequestTimeout),
MakeTimeChecker ())
@@ -76,7 +76,7 @@
UintegerValue (10),
MakeUintegerAccessor (&NqstaWifiMac::m_maxMissedBeacons),
MakeUintegerChecker<uint32_t> ())
- .AddAttribute ("ActiveProbing", "XXX",
+ .AddAttribute ("ActiveProbing", "If true, we send probe requests. If false, we don't.",
BooleanValue (false),
MakeBooleanAccessor (&NqstaWifiMac::SetActiveProbing),
MakeBooleanChecker ())
--- a/src/devices/wifi/onoe-wifi-manager.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/onoe-wifi-manager.cc Wed Jun 04 17:19:32 2008 -0400
@@ -40,7 +40,7 @@
TimeValue (Seconds (1.0)),
MakeTimeAccessor (&OnoeWifiManager::m_updatePeriod),
MakeTimeChecker ())
- .AddAttribute ("RaiseThreshold", "XXX",
+ .AddAttribute ("RaiseThreshold", "Attempt to raise the rate if we hit that threshold",
UintegerValue (10),
MakeUintegerAccessor (&OnoeWifiManager::m_raiseThreshold),
MakeUintegerChecker<uint32_t> ())
--- a/src/devices/wifi/propagation-loss-model.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/propagation-loss-model.cc Wed Jun 04 17:19:32 2008 -0400
@@ -55,7 +55,7 @@
static TypeId tid = TypeId ("ns3::RandomPropagationLossModel")
.SetParent<PropagationLossModel> ()
.AddConstructor<RandomPropagationLossModel> ()
- .AddAttribute ("Variable", "XXX",
+ .AddAttribute ("Variable", "The random variable used to pick a loss everytime GetLoss is invoked.",
RandomVariableValue (ConstantVariable (1.0)),
MakeRandomVariableAccessor (&RandomPropagationLossModel::m_variable),
MakeRandomVariableChecker ())
--- a/src/devices/wifi/ssid.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/ssid.h Wed Jun 04 17:19:32 2008 -0400
@@ -49,7 +49,6 @@
Buffer::Iterator Serialize (Buffer::Iterator i) const;
Buffer::Iterator Deserialize (Buffer::Iterator i);
- ATTRIBUTE_HELPER_HEADER_1 (Ssid);
private:
uint8_t m_ssid[33];
uint8_t m_length;
@@ -63,7 +62,7 @@
* \brief hold objects of type ns3::Ssid
*/
-ATTRIBUTE_HELPER_HEADER_2 (Ssid);
+ATTRIBUTE_HELPER_HEADER (Ssid);
} // namespace ns3
--- a/src/devices/wifi/wifi-channel.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-channel.cc Wed Jun 04 17:19:32 2008 -0400
@@ -38,11 +38,11 @@
static TypeId tid = TypeId ("ns3::WifiChannel")
.SetParent<Channel> ()
.AddConstructor<WifiChannel> ()
- .AddAttribute ("PropagationLossModel", "XXX",
+ .AddAttribute ("PropagationLossModel", "A pointer to the propagation loss model attached to this channel.",
PointerValue (),
MakePointerAccessor (&WifiChannel::m_loss),
MakePointerChecker<PropagationLossModel> ())
- .AddAttribute ("PropagationDelayModel", "XXX",
+ .AddAttribute ("PropagationDelayModel", "A pointer to the propagation delay model attached to this channel.",
PointerValue (),
MakePointerAccessor (&WifiChannel::m_delay),
MakePointerChecker<PropagationDelayModel> ())
--- a/src/devices/wifi/wifi-mac-header.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-mac-header.cc Wed Jun 04 17:19:32 2008 -0400
@@ -40,7 +40,9 @@
};
WifiMacHeader::WifiMacHeader ()
- : m_ctrlMoreData (0)
+ : m_ctrlMoreData (0),
+ m_ctrlWep (0),
+ m_ctrlOrder (1)
{}
WifiMacHeader::~WifiMacHeader ()
{}
--- a/src/devices/wifi/wifi-mac.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-mac.cc Wed Jun 04 17:19:32 2008 -0400
@@ -73,42 +73,43 @@
{
static TypeId tid = TypeId ("ns3::WifiMac")
.SetParent<Object> ()
- .AddAttribute ("CtsTimeout", "XXX",
+ .AddAttribute ("CtsTimeout", "When this timeout expires, the RTS/CTS handshake has failed.",
TimeValue (GetDefaultCtsAckTimeout ()),
MakeTimeAccessor (&WifiMac::m_ctsTimeout),
MakeTimeChecker ())
- .AddAttribute ("AckTimeout", "XXX",
+ .AddAttribute ("AckTimeout", "When this timeout expires, the DATA/ACK handshake has failed.",
TimeValue (GetDefaultCtsAckTimeout ()),
MakeTimeAccessor (&WifiMac::m_ackTimeout),
MakeTimeChecker ())
- .AddAttribute ("Sifs", "XXX",
+ .AddAttribute ("Sifs", "The value of the SIFS constant.",
TimeValue (GetDefaultSifs ()),
MakeTimeAccessor (&WifiMac::SetSifs,
&WifiMac::GetSifs),
MakeTimeChecker ())
- .AddAttribute ("EifsNoDifs", "XXX",
+ .AddAttribute ("EifsNoDifs", "The value of EIFS-DIFS",
TimeValue (GetDefaultEifsNoDifs ()),
MakeTimeAccessor (&WifiMac::SetEifsNoDifs,
&WifiMac::GetEifsNoDifs),
MakeTimeChecker ())
- .AddAttribute ("Slot", "XXX",
+ .AddAttribute ("Slot", "The duration of a Slot.",
TimeValue (GetDefaultSlot ()),
MakeTimeAccessor (&WifiMac::SetSlot,
&WifiMac::GetSlot),
MakeTimeChecker ())
- .AddAttribute ("Pifs", "XXX",
+ .AddAttribute ("Pifs", "The value of the PIFS constant.",
TimeValue (GetDefaultSifs () + GetDefaultSlot ()),
MakeTimeAccessor (&WifiMac::m_pifs),
MakeTimeChecker ())
- .AddAttribute ("MaxPropagationDelay", "XXX",
+ .AddAttribute ("MaxPropagationDelay", "The maximum propagation delay. Unused for now.",
TimeValue (GetDefaultMaxPropagationDelay ()),
MakeTimeAccessor (&WifiMac::m_maxPropagationDelay),
MakeTimeChecker ())
- .AddAttribute ("MaxMsduSize", "XXX",
+ .AddAttribute ("MaxMsduSize", "The maximum size of an MSDU accepted by the MAC layer."
+ "This value conforms to the specification.",
UintegerValue (2304),
MakeUintegerAccessor (&WifiMac::m_maxMsduSize),
MakeUintegerChecker<uint16_t> (1,2304))
- .AddAttribute ("Ssid", "XXX",
+ .AddAttribute ("Ssid", "The ssid we want to belong to.",
SsidValue (Ssid ("default")),
MakeSsidAccessor (&WifiMac::GetSsid,
&WifiMac::SetSsid),
--- a/src/devices/wifi/wifi-mac.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-mac.h Wed Jun 04 17:19:32 2008 -0400
@@ -70,13 +70,9 @@
*/
void SetAckTimeout (Time ackTimeout);
/**
- * \param msduLifetime
+ * \param delay the max propagation delay.
*
- * XXX: I cannot remmeber what this is used for.
- */
- void SetMsduLifetime (Time msduLifetime);
- /**
- * XXX: I cannot remember what this is used for.
+ * Unused for now.
*/
void SetMaxPropagationDelay (Time delay);
@@ -105,11 +101,11 @@
*/
Time GetAckTimeout (void) const;
/**
- * XXX: I cannot remember what this is used for.
+ * Unused for now.
*/
Time GetMsduLifetime (void) const;
/**
- * XXX: I cannot remember what this is used for.
+ * Unused for now.
*/
Time GetMaxPropagationDelay (void) const;
/**
--- a/src/devices/wifi/wifi-mode.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-mode.h Wed Jun 04 17:19:32 2008 -0400
@@ -107,7 +107,6 @@
*/
WifiMode ();
- ATTRIBUTE_HELPER_HEADER_1 (WifiMode);
private:
friend class WifiModeFactory;
WifiMode (uint32_t uid);
@@ -123,7 +122,7 @@
* \brief hold objects of type ns3::WifiMode
*/
-ATTRIBUTE_HELPER_HEADER_2 (WifiMode);
+ATTRIBUTE_HELPER_HEADER (WifiMode);
/**
* \brief create WifiMode class instances and keep track of them.
--- a/src/devices/wifi/wifi-phy.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-phy.cc Wed Jun 04 17:19:32 2008 -0400
@@ -227,7 +227,8 @@
MakeDoubleAccessor (&WifiPhy::SetRxNoise,
&WifiPhy::GetRxNoise),
MakeDoubleChecker<double> ())
- .AddAttribute ("Standard", "XXX",
+ .AddAttribute ("Standard", "The standard chosen configures a set of transmission modes"
+ " and some PHY-specific constants.",
EnumValue (WIFI_PHY_STANDARD_80211a),
MakeEnumAccessor (&WifiPhy::SetStandard),
MakeEnumChecker (WIFI_PHY_STANDARD_80211a, "802.11a",
@@ -712,7 +713,9 @@
return "SYNC";
break;
default:
- return "XXX";
+ NS_ASSERT (false);
+ // quiet compiler
+ return "INVALID";
break;
}
}
--- a/src/devices/wifi/wifi-remote-station-manager.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-remote-station-manager.cc Wed Jun 04 17:19:32 2008 -0400
@@ -126,23 +126,32 @@
{
static TypeId tid = TypeId ("ns3::WifiRemoteStationManager")
.SetParent<Object> ()
- .AddAttribute ("IsLowLatency", "XXX",
+ .AddAttribute ("IsLowLatency", "If true, we attempt to modelize a so-called low-latency device: a device"
+ " where decisions about tx parameters can be made on a per-packet basis and feedback about the"
+ " transmission of each packet is obtained before sending the next. Otherwise, we modelize a "
+ " high-latency device, that is a device where we cannot update our decision about tx parameters"
+ " after every packet transmission.",
BooleanValue (true),
MakeBooleanAccessor (&WifiRemoteStationManager::m_isLowLatency),
MakeBooleanChecker ())
- .AddAttribute ("MaxSsrc", "XXX",
+ .AddAttribute ("MaxSsrc", "The maximum number of retransmission attempts for an RTS. This value"
+ " will not have any effect on some rate control algorithms.",
UintegerValue (7),
MakeUintegerAccessor (&WifiRemoteStationManager::m_maxSsrc),
MakeUintegerChecker<uint32_t> ())
- .AddAttribute ("MaxSlrc", "XXX",
+ .AddAttribute ("MaxSlrc", "The maximum number of retransmission attempts for a DATA packet. This value"
+ " will not have any effect on some rate control algorithms.",
UintegerValue (7),
MakeUintegerAccessor (&WifiRemoteStationManager::m_maxSlrc),
MakeUintegerChecker<uint32_t> ())
- .AddAttribute ("RtsCtsThreshold", "XXX",
+ .AddAttribute ("RtsCtsThreshold", "If a data packet is bigger than this value, we use an RTS/CTS handshake"
+ " before sending the data. This value will not have any effect on some rate control algorithms.",
UintegerValue (1500),
MakeUintegerAccessor (&WifiRemoteStationManager::m_rtsCtsThreshold),
MakeUintegerChecker<uint32_t> ())
- .AddAttribute ("FragmentationThreshold", "XXX",
+ .AddAttribute ("FragmentationThreshold", "If a data packet is bigger than this value, we fragment it such that"
+ " the size of the fragments are equal or smaller than this value. This value will not have any effect"
+ " on some rate control algorithms.",
UintegerValue (1500),
MakeUintegerAccessor (&WifiRemoteStationManager::m_fragmentationThreshold),
MakeUintegerChecker<uint32_t> ())
@@ -314,11 +323,12 @@
WifiMode GetRtsMode (void) const;
WifiMode GetDataMode (void) const;
- static uint32_t GetUid (void);
- void Print (std::ostream &os) const;
- void Serialize (ns3::Buffer::Iterator start) const;
- uint32_t Deserialize (ns3::Buffer::Iterator start);
- uint32_t GetSerializedSize (void) const;
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
private:
WifiMode m_rtsMode;
WifiMode m_dataMode;
@@ -340,30 +350,51 @@
{
return m_dataMode;
}
-
+TypeId
+TxModeTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::TxModeTag")
+ .SetParent<Tag> ()
+ .AddConstructor<TxModeTag> ()
+ .AddAttribute ("RtsTxMode",
+ "Tx mode of rts to use later",
+ EmptyAttributeValue (),
+ MakeWifiModeAccessor (&TxModeTag::GetRtsMode),
+ MakeWifiModeChecker ())
+ .AddAttribute ("DataTxMode",
+ "Tx mode of data to use later",
+ EmptyAttributeValue (),
+ MakeWifiModeAccessor (&TxModeTag::GetDataMode),
+ MakeWifiModeChecker ())
+ ;
+ return tid;
+}
+TypeId
+TxModeTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
uint32_t
-TxModeTag::GetUid (void)
+TxModeTag::GetSerializedSize (void) const
+{
+ return sizeof (WifiMode) * 2;
+}
+void
+TxModeTag::Serialize (TagBuffer i) const
{
- static uint32_t uid = Tag::AllocateUid<TxModeTag> ("ns3.wifi.TxModeTag");
- return uid;
+ i.Write ((uint8_t *)&m_rtsMode, sizeof (WifiMode));
+ i.Write ((uint8_t *)&m_dataMode, sizeof (WifiMode));
+}
+void
+TxModeTag::Deserialize (TagBuffer i)
+{
+ i.Read ((uint8_t *)&m_rtsMode, sizeof (WifiMode));
+ i.Read ((uint8_t *)&m_dataMode, sizeof (WifiMode));
}
void
TxModeTag::Print (std::ostream &os) const
{
- os << "rts="<<m_rtsMode<<" data="<<m_dataMode;
-}
-void
-TxModeTag::Serialize (ns3::Buffer::Iterator start) const
-{}
-uint32_t
-TxModeTag::Deserialize (ns3::Buffer::Iterator start)
-{
- return 0;
-}
-uint32_t
-TxModeTag::GetSerializedSize (void) const
-{
- return 0;
+ os << "Rts=" << m_rtsMode << ", Data=" << m_dataMode;
}
} // namespace ns3
@@ -380,9 +411,9 @@
{
static TypeId tid = TypeId ("ns3::WifiRemoteStation")
.SetParent<Object> ()
- .AddTraceSource ("Ssrc", "XXX",
+ .AddTraceSource ("Ssrc", "The value of the ssrc counter: indicates the number of retransmissions of RTS.",
MakeTraceSourceAccessor (&WifiRemoteStation::m_ssrc))
- .AddTraceSource ("Slrc", "XXX",
+ .AddTraceSource ("Slrc", "The value of the slrc counter: indicates the number of retransmissions of DATA.",
MakeTraceSourceAccessor (&WifiRemoteStation::m_slrc))
;
return tid;
@@ -546,7 +577,7 @@
}
TxModeTag tag;
bool found;
- found = packet->PeekTag (tag);
+ found = packet->FindFirstMatchingTag (tag);
NS_ASSERT (found);
return tag.GetDataMode ();
}
@@ -559,7 +590,7 @@
}
TxModeTag tag;
bool found;
- found = packet->PeekTag (tag);
+ found = packet->FindFirstMatchingTag (tag);
NS_ASSERT (found);
return tag.GetRtsMode ();
}
--- a/src/devices/wifi/wifi-remote-station-manager.h Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-remote-station-manager.h Wed Jun 04 17:19:32 2008 -0400
@@ -35,12 +35,9 @@
class WifiPhy;
/**
- * \brief hold per-remote-station state.
+ * \brief hold a list of per-remote-station state.
*
- * The state in this class is used to keep track
- * of association status if we are in an infrastructure
- * network and to perform the selection of tx parameters
- * on a per-packet basis.
+ * \sa ns3::WifiRemoteStation.
*/
class WifiRemoteStationManager : public Object
{
@@ -106,6 +103,14 @@
namespace ns3 {
+/**
+ * \brief hold per-remote-station state.
+ *
+ * The state in this class is used to keep track
+ * of association status if we are in an infrastructure
+ * network and to perform the selection of tx parameters
+ * on a per-packet basis.
+ */
class WifiRemoteStation {
public:
@@ -114,14 +119,18 @@
WifiRemoteStation ();
virtual ~WifiRemoteStation ();
- // Invoked in an AP upon disassociation of a
- // specific STA.
+ /**
+ * Invoked in an AP upon disassociation of a
+ * specific STA.
+ */
void Reset (void);
- // Invoked in a STA or AP to store the set of
- // modes supported by a destination which is
- // also supported locally.
- // The set of supported modes includes
- // the BSSBasicRateSet.
+ /**
+ * Invoked in a STA or AP to store the set of
+ * modes supported by a destination which is
+ * also supported locally.
+ * The set of supported modes includes
+ * the BSSBasicRateSet.
+ */
void AddSupportedMode (WifiMode mode);
bool IsBrandNew (void) const;
@@ -132,30 +141,120 @@
void RecordGotAssocTxFailed (void);
void RecordDisassociated (void);
+ /**
+ * \param packet the packet to queue
+ * \param fullPacketSize the size of the packet after its 802.11 MAC header has been added.
+ *
+ * This method is typically invoked just before queuing a packet for transmission.
+ * It is a no-op unless the IsLowLatency attribute of the attached ns3::WifiRemoteStationManager
+ * is set to false, in which case, the tx parameters of the packet are calculated and stored in
+ * the packet as a tag. These tx parameters are later retrieved from GetDadaMode and GetRtsMode.
+ */
void PrepareForQueue (Ptr<const Packet> packet, uint32_t fullPacketSize);
+ /**
+ * \param packet the packet to send
+ * \param fullPacketSize the size of the packet after its 802.11 MAC header has been added.
+ * \returns the transmission mode to use to send this packet
+ */
WifiMode GetDataMode (Ptr<const Packet> packet, uint32_t fullPacketSize);
+ /**
+ * \param packet the packet to send
+ * \returns the transmission mode to use to send the RTS prior to the
+ * transmission of the data packet itself.
+ */
WifiMode GetRtsMode (Ptr<const Packet> packet);
- // transmission-related methods
+ /**
+ * Should be invoked whenever the RtsTimeout associated to a transmission
+ * attempt expires.
+ */
void ReportRtsFailed (void);
+ /**
+ * Should be invoked whenever the AckTimeout associated to a transmission
+ * attempt expires.
+ */
void ReportDataFailed (void);
+ /**
+ * Should be invoked whenever we receive the Cts associated to an RTS
+ * we just sent.
+ */
void ReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr);
+ /**
+ * Should be invoked whenever we receive the Ack associated to a data packet
+ * we just sent.
+ */
void ReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr);
+ /**
+ * Should be invoked after calling ReportRtsFailed if
+ * NeedRtsRetransmission returns false
+ */
void ReportFinalRtsFailed (void);
+ /**
+ * Should be invoked after calling ReportDataFailed if
+ * NeedDataRetransmission returns false
+ */
void ReportFinalDataFailed (void);
- // reception-related method
+ /**
+ * \param rxSnr the snr of the packet received
+ * \param txMode the transmission mode used for the packet received.
+ *
+ * Should be invoked whenever a packet is successfully received.
+ */
void ReportRxOk (double rxSnr, WifiMode txMode);
+ /**
+ * \param packet the packet to send
+ * \returns true if we want to use an RTS/CTS handshake for this
+ * packet before sending it, false otherwise.
+ */
virtual bool NeedRts (Ptr<const Packet> packet);
+ /**
+ * \param packet the packet to send
+ * \returns true if we want to restart a failed RTS/CTS
+ * handshake, false otherwise.
+ */
virtual bool NeedRtsRetransmission (Ptr<const Packet> packet);
+ /**
+ * \param packet the packet to send
+ * \returns true if we want to resend a packet
+ * after a failed transmission attempt, false otherwise.
+ */
virtual bool NeedDataRetransmission (Ptr<const Packet> packet);
+ /**
+ * \param packet the packet to send
+ * \returns true if this packet should be fragmented, false otherwise.
+ */
virtual bool NeedFragmentation (Ptr<const Packet> packet);
+ /**
+ * \param packet the packet to send
+ * \returns the number of fragments which should be used for this packet.
+ */
virtual uint32_t GetNFragments (Ptr<const Packet> packet);
+ /**
+ * \param packet the packet to send
+ * \param fragmentNumber the fragment index of the next fragment to send (starts at zero).
+ * \returns the size of the corresponding fragment.
+ */
virtual uint32_t GetFragmentSize (Ptr<const Packet> packet, uint32_t fragmentNumber);
+ /**
+ * \param packet the packet to send
+ * \param fragmentNumber the fragment index of the next fragment to send (starts at zero).
+ * \returns true if this is the last fragment, false otherwise.
+ */
virtual bool IsLastFragment (Ptr<const Packet> packet, uint32_t fragmentNumber);
+ /**
+ * \param rtsMode the transmission mode used to send an RTS we just received
+ * \returns the transmission mode to use for the CTS to complete the RTS/CTS
+ * handshake.
+ */
WifiMode GetCtsMode (WifiMode rtsMode);
+ /**
+ * \param dataMode the transmission mode used to send an ACK we just received
+ * \returns the transmission mode to use for the ACK to complete the data/ACK
+ * handshake.
+ */
WifiMode GetAckMode (WifiMode dataMode);
private:
--- a/src/devices/wifi/wifi-test.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/devices/wifi/wifi-test.cc Wed Jun 04 17:19:32 2008 -0400
@@ -81,7 +81,7 @@
Simulator::Run ();
Simulator::Destroy ();
- Simulator::StopAt (Seconds (10.0));
+ Simulator::Stop (Seconds (10.0));
}
bool
--- a/src/helper/ipv4-address-helper.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/helper/ipv4-address-helper.cc Wed Jun 04 17:19:32 2008 -0400
@@ -54,9 +54,9 @@
{
NS_LOG_FUNCTION_NOARGS ();
- m_network = network.GetHostOrder ();
- m_mask = mask.GetHostOrder ();
- m_base = m_address = address.GetHostOrder ();
+ m_network = network.Get ();
+ m_mask = mask.Get ();
+ m_base = m_address = address.Get ();
//
// Some quick reasonableness testing.
--- a/src/helper/mobility-helper.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/helper/mobility-helper.cc Wed Jun 04 17:19:32 2008 -0400
@@ -19,7 +19,6 @@
*/
#include "ns3/mobility-helper.h"
#include "ns3/mobility-model.h"
-#include "ns3/mobility-model-notifier.h"
#include "ns3/position-allocator.h"
#include "ns3/hierarchical-mobility-model.h"
#include "ns3/log.h"
@@ -30,7 +29,6 @@
NS_LOG_COMPONENT_DEFINE ("MobilityHelper");
MobilityHelper::MobilityHelper ()
- : m_notifierEnabled (false)
{
m_position = CreateObject<RandomRectanglePositionAllocator>
("X", RandomVariableValue (ConstantVariable (0.0)),
@@ -40,16 +38,6 @@
MobilityHelper::~MobilityHelper ()
{}
void
-MobilityHelper::EnableNotifier (void)
-{
- m_notifierEnabled = true;
-}
-void
-MobilityHelper::DisableNotifier (void)
-{
- m_notifierEnabled = false;
-}
-void
MobilityHelper::SetPositionAllocator (Ptr<PositionAllocator> allocator)
{
m_position = allocator;
@@ -156,15 +144,6 @@
}
Vector position = m_position->GetNext ();
model->SetPosition (position);
- if (m_notifierEnabled)
- {
- Ptr<MobilityModelNotifier> notifier =
- object->GetObject<MobilityModelNotifier> ();
- if (notifier == 0)
- {
- object->AggregateObject (CreateObject<MobilityModelNotifier> ());
- }
- }
}
}
--- a/src/helper/mobility-helper.h Fri May 30 15:31:50 2008 -0400
+++ b/src/helper/mobility-helper.h Wed Jun 04 17:19:32 2008 -0400
@@ -43,20 +43,6 @@
~MobilityHelper ();
/**
- * After this method is called, every call to MobilityHelper::Install
- * will also attach to the new ns3::MobilityModel an ns3::MobilityModelNotifier
- * which can be used to listen to CourseChange events.
- */
- void EnableNotifier (void);
- /**
- * After this method is called, no ns3::MobilityModelNotifier object will
- * be associated to any new ns3::MobilityModel created by MobilityHelper::Install.
- * This will make it impossible to listen to "CourseChange" events from these
- * new ns3::MobilityModel instances.
- */
- void DisableNotifier (void);
-
- /**
* \param allocator allocate initial node positions
*
* Set the position allocator which will be used to allocate
@@ -169,9 +155,6 @@
* subclass (the type of which was set with MobilityHelper::SetMobilityModel),
* aggregates it to the mode, and sets an initial position based on the current
* position allocator (set through MobilityHelper::SetPositionAllocator).
- * Optionally, this method will also create and aggregate a
- * ns3::MobilityModelNotifier to generate 'CourseChange' events based on the
- * boolean flag set by MobilityHelper::EnableNotifierAll and MobilityHelper::DisableNotifier.
*/
void Install (NodeContainer container);
@@ -183,7 +166,6 @@
private:
std::vector<Ptr<MobilityModel> > m_mobilityStack;
- bool m_notifierEnabled;
ObjectFactory m_mobility;
Ptr<PositionAllocator> m_position;
};
--- a/src/helper/ns2-mobility-helper.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/helper/ns2-mobility-helper.cc Wed Jun 04 17:19:32 2008 -0400
@@ -24,7 +24,6 @@
#include "ns3/node-list.h"
#include "ns3/node.h"
#include "ns3/static-speed-mobility-model.h"
-#include "ns3/mobility-model-notifier.h"
#include "ns2-mobility-helper.h"
NS_LOG_COMPONENT_DEFINE ("Ns2MobilityHelper");
@@ -36,17 +35,6 @@
: m_filename (filename)
{}
-void
-Ns2MobilityHelper::EnableNotifier (void)
-{
- m_notifierEnabled = true;
-}
-void
-Ns2MobilityHelper::DisableNotifier (void)
-{
- m_notifierEnabled = false;
-}
-
Ptr<StaticSpeedMobilityModel>
@@ -67,12 +55,6 @@
model = CreateObject<StaticSpeedMobilityModel> ();
object->AggregateObject (model);
}
- Ptr<MobilityModelNotifier> notifier = object->GetObject<MobilityModelNotifier> ();
- if (notifier == 0)
- {
- notifier = CreateObject<MobilityModelNotifier> ();
- object->AggregateObject (notifier);
- }
return model;
}
--- a/src/helper/ns2-mobility-helper.h Fri May 30 15:31:50 2008 -0400
+++ b/src/helper/ns2-mobility-helper.h Wed Jun 04 17:19:32 2008 -0400
@@ -42,9 +42,6 @@
*/
Ns2MobilityHelper (std::string filename);
- void EnableNotifier (void);
- void DisableNotifier (void);
-
/**
* Read the ns2 trace file and configure the movement
* patterns of all nodes contained in the global ns3::NodeList
@@ -77,7 +74,6 @@
Ptr<StaticSpeedMobilityModel> GetMobilityModel (std::string idString, const ObjectStore &store) const;
double ReadDouble (std::string valueString) const;
std::string m_filename;
- bool m_notifierEnabled;
};
} // namespace ns3
--- a/src/helper/wifi-helper.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/helper/wifi-helper.cc Wed Jun 04 17:19:32 2008 -0400
@@ -156,6 +156,7 @@
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/Tx";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapPhyTxEvent, pcap));
+ oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/RxOk";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapPhyRxEvent, pcap));
}
--- a/src/internet-node/arp-cache.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/arp-cache.cc Wed Jun 04 17:19:32 2008 -0400
@@ -20,24 +20,73 @@
#include "ns3/assert.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
+#include "ns3/uinteger.h"
+#include "ns3/log.h"
#include "arp-cache.h"
#include "arp-header.h"
#include "ipv4-interface.h"
+NS_LOG_COMPONENT_DEFINE ("ArpCache");
+
namespace ns3 {
-ArpCache::ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
- : m_device (device),
- m_interface (interface),
- m_aliveTimeout (Seconds (120)),
- m_deadTimeout (Seconds (100)),
- m_waitReplyTimeout (Seconds (1))
-{}
+TypeId
+ArpCache::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ArpCache")
+ .SetParent<Object> ()
+ .AddAttribute ("AliveTimeout",
+ "When this timeout expires, the matching cache entry needs refreshing",
+ TimeValue (Seconds (120)),
+ MakeTimeAccessor (&ArpCache::m_aliveTimeout),
+ MakeTimeChecker ())
+ .AddAttribute ("DeadTimeout",
+ "When this timeout expires, a new attempt to resolve the matching entry is made",
+ TimeValue (Seconds (100)),
+ MakeTimeAccessor (&ArpCache::m_deadTimeout),
+ MakeTimeChecker ())
+ .AddAttribute ("WaitReplyTimeout",
+ "When this timeout expires, the matching cache entry is marked dead",
+ TimeValue (Seconds (1)),
+ MakeTimeAccessor (&ArpCache::m_waitReplyTimeout),
+ MakeTimeChecker ())
+ .AddAttribute ("PendingQueueSize",
+ "The size of the queue for packets pending an arp reply.",
+ UintegerValue (3),
+ MakeUintegerAccessor (&ArpCache::m_pendingQueueSize),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+ArpCache::ArpCache ()
+ : m_device (0),
+ m_interface (0)
+{
+ NS_LOG_FUNCTION (this);
+}
ArpCache::~ArpCache ()
{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+ArpCache::DoDispose (void)
+{
+ NS_LOG_FUNCTION (this);
Flush ();
+ m_device = 0;
+ m_interface = 0;
+ Object::DoDispose ();
+}
+
+void
+ArpCache::SetDevice (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
+{
+ m_device = device;
+ m_interface = interface;
}
Ptr<NetDevice>
@@ -117,8 +166,7 @@
ArpCache::Entry::Entry (ArpCache *arp)
: m_arp (arp),
- m_state (ALIVE),
- m_waiting ()
+ m_state (ALIVE)
{}
@@ -143,23 +191,18 @@
ArpCache::Entry::MarkDead (void)
{
m_state = DEAD;
- //NS_ASSERT (m_waiting != 0);
UpdateSeen ();
}
-Ptr<Packet>
+void
ArpCache::Entry::MarkAlive (Address macAddress)
{
NS_ASSERT (m_state == WAIT_REPLY);
- //NS_ASSERT (m_waiting != 0);
m_macAddress = macAddress;
m_state = ALIVE;
UpdateSeen ();
- Ptr<Packet> waiting = m_waiting;
- //m_waiting = 0;
- return waiting;
}
-Ptr<Packet>
+bool
ArpCache::Entry::UpdateWaitReply (Ptr<Packet> waiting)
{
NS_ASSERT (m_state == WAIT_REPLY);
@@ -167,17 +210,20 @@
* we dump the previously waiting packet and
* replace it with this one.
*/
- Ptr<Packet> old = m_waiting;
- m_waiting = waiting;
- return old;
+ if (m_pending.size () >= m_arp->m_pendingQueueSize)
+ {
+ return false;
+ }
+ m_pending.push_back (waiting);
+ return true;
}
void
ArpCache::Entry::MarkWaitReply (Ptr<Packet> waiting)
{
NS_ASSERT (m_state == ALIVE || m_state == DEAD);
- //NS_ASSERT (m_waiting == 0);
+ NS_ASSERT (m_pending.empty ());
m_state = WAIT_REPLY;
- m_waiting = waiting;
+ m_pending.push_back (waiting);
UpdateSeen ();
}
@@ -217,6 +263,20 @@
return false;
}
}
+Ptr<Packet>
+ArpCache::Entry::DequeuePending (void)
+{
+ if (m_pending.empty ())
+ {
+ return 0;
+ }
+ else
+ {
+ Ptr<Packet> p = m_pending.front ();
+ m_pending.pop_front ();
+ return p;
+ }
+}
void
ArpCache::Entry::UpdateSeen (void)
{
--- a/src/internet-node/arp-cache.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/arp-cache.h Wed Jun 04 17:19:32 2008 -0400
@@ -21,12 +21,14 @@
#define ARP_CACHE_H
#include <stdint.h>
+#include <list>
#include "ns3/packet.h"
#include "ns3/nstime.h"
#include "ns3/net-device.h"
#include "ns3/ipv4-address.h"
#include "ns3/address.h"
#include "ns3/ptr.h"
+#include "ns3/object.h"
#include "sgi-hashmap.h"
namespace ns3 {
@@ -40,15 +42,19 @@
* A cached lookup table for translating layer 3 addresses to layer 2.
* This implementation does lookups from IPv4 to a MAC address
*/
-class ArpCache {
+class ArpCache : public Object
+{
public:
+ static TypeId GetTypeId (void);
class Entry;
+ ArpCache ();
+ ~ArpCache ();
+
/**
* \param device The hardware NetDevice associated with this ARP chache
* \param interface the Ipv4Interface associated with this ARP chache
*/
- ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface);
- ~ArpCache ();
+ void SetDevice (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface);
/**
* \return The NetDevice that this ARP cache is associated with
*/
@@ -98,9 +104,8 @@
void MarkDead (void);
/**
* \param macAddress
- * \return
*/
- Ptr<Packet> MarkAlive (Address macAddress);
+ void MarkAlive (Address macAddress);
/**
* \param waiting
*/
@@ -109,7 +114,7 @@
* \param waiting
* \return
*/
- Ptr<Packet> UpdateWaitReply (Ptr<Packet> waiting);
+ bool UpdateWaitReply (Ptr<Packet> waiting);
/**
* \return True if the state of this entry is dead; false otherwise.
*/
@@ -131,6 +136,12 @@
* \return True if this entry has timedout; false otherwise.
*/
bool IsExpired (void);
+
+ /**
+ * \returns 0 is no packet is pending, the next packet to send if
+ * packets are pending.
+ */
+ Ptr<Packet> DequeuePending (void);
private:
enum ArpCacheEntryState_e {
ALIVE,
@@ -143,18 +154,21 @@
ArpCacheEntryState_e m_state;
Time m_lastSeen;
Address m_macAddress;
- Ptr<Packet> m_waiting;
+ std::list<Ptr<Packet> > m_pending;
};
private:
typedef sgi::hash_map<Ipv4Address, ArpCache::Entry *, Ipv4AddressHash> Cache;
typedef sgi::hash_map<Ipv4Address, ArpCache::Entry *, Ipv4AddressHash>::iterator CacheI;
+ virtual void DoDispose (void);
+
Ptr<NetDevice> m_device;
Ptr<Ipv4Interface> m_interface;
Time m_aliveTimeout;
Time m_deadTimeout;
Time m_waitReplyTimeout;
+ uint32_t m_pendingQueueSize;
Cache m_arpCache;
};
--- a/src/internet-node/arp-ipv4-interface.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/arp-ipv4-interface.cc Wed Jun 04 17:19:32 2008 -0400
@@ -24,41 +24,64 @@
#include "ns3/node.h"
#include "ns3/net-device.h"
#include "ns3/address.h"
+#include "ns3/pointer.h"
#include "arp-ipv4-interface.h"
#include "ipv4-l3-protocol.h"
#include "arp-l3-protocol.h"
+#include "arp-cache.h"
NS_LOG_COMPONENT_DEFINE ("ArpIpv4Interface");
namespace ns3 {
-ArpIpv4Interface::ArpIpv4Interface ()
+TypeId
+ArpIpv4Interface::GetTypeId (void)
{
- NS_LOG_FUNCTION_NOARGS ();
+ static TypeId tid = TypeId ("ns3::ArpIpv4Interface")
+ .SetParent<Ipv4Interface> ()
+ .AddAttribute ("ArpCache",
+ "The arp cache for this ipv4 interface",
+ PointerValue (0),
+ MakePointerAccessor (&ArpIpv4Interface::m_cache),
+ MakePointerChecker<ArpIpv4Interface> ())
+ ;
+ return tid;
+}
+
+ArpIpv4Interface::ArpIpv4Interface ()
+ : m_node (0),
+ m_device (0)
+{
+ NS_LOG_FUNCTION (this);
}
ArpIpv4Interface::~ArpIpv4Interface ()
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (this);
}
void
ArpIpv4Interface::DoDispose (void)
{
+ NS_LOG_FUNCTION (this);
m_node = 0;
m_device = 0;
+ m_cache = 0;
+ Ipv4Interface::DoDispose ();
}
void
ArpIpv4Interface::SetNode (Ptr<Node> node)
{
m_node = node;
+ DoSetup ();
}
void
ArpIpv4Interface::SetDevice (Ptr<NetDevice> device)
{
m_device = device;
+ DoSetup ();
}
Ptr<NetDevice>
@@ -67,13 +90,24 @@
return m_device;
}
+void
+ArpIpv4Interface::DoSetup (void)
+{
+ if (m_node == 0 || m_device == 0)
+ {
+ return;
+ }
+ Ptr<ArpL3Protocol> arp = m_node->GetObject<ArpL3Protocol> ();
+ m_cache = arp->CreateCache (m_device, this);
+}
+
void
ArpIpv4Interface::SendTo (Ptr<Packet> p, Ipv4Address dest)
{
NS_LOG_FUNCTION (this << p << dest);
NS_ASSERT (GetDevice () != 0);
- if (GetDevice ()->NeedsArp ())
+ if (m_device->NeedsArp ())
{
NS_LOG_LOGIC ("Needs ARP");
Ptr<ArpL3Protocol> arp =
@@ -101,7 +135,7 @@
else
{
NS_LOG_LOGIC ("ARP Lookup");
- found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
+ found = arp->Lookup (p, dest, GetDevice (), m_cache, &hardwareDestination);
}
if (found)
--- a/src/internet-node/arp-ipv4-interface.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/arp-ipv4-interface.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,7 @@
namespace ns3 {
class Node;
+class ArpCache;
/**
* \brief an Ipv4 Interface which uses ARP
@@ -37,7 +38,9 @@
*/
class ArpIpv4Interface : public Ipv4Interface
{
- public:
+public:
+ static TypeId GetTypeId (void);
+
ArpIpv4Interface ();
virtual ~ArpIpv4Interface ();
@@ -49,8 +52,10 @@
private:
virtual void SendTo (Ptr<Packet> p, Ipv4Address dest);
virtual void DoDispose (void);
+ void DoSetup (void);
Ptr<Node> m_node;
Ptr<NetDevice> m_device;
+ Ptr<ArpCache> m_cache;
};
}//namespace ns3
--- a/src/internet-node/arp-l3-protocol.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/arp-l3-protocol.cc Wed Jun 04 17:19:32 2008 -0400
@@ -21,6 +21,8 @@
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/net-device.h"
+#include "ns3/object-vector.h"
+#include "ns3/trace-source-accessor.h"
#include "ipv4-l3-protocol.h"
#include "arp-l3-protocol.h"
@@ -41,18 +43,26 @@
{
static TypeId tid = TypeId ("ns3::ArpL3Protocol")
.SetParent<Object> ()
+ .AddAttribute ("CacheList",
+ "The list of ARP caches",
+ ObjectVectorValue (),
+ MakeObjectVectorAccessor (&ArpL3Protocol::m_cacheList),
+ MakeObjectVectorChecker<ArpCache> ())
+ .AddTraceSource ("Drop",
+ "Packet dropped because not enough room in pending queue for a specific cache entry.",
+ MakeTraceSourceAccessor (&ArpL3Protocol::m_dropTrace))
;
return tid;
}
ArpL3Protocol::ArpL3Protocol ()
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (this);
}
ArpL3Protocol::~ArpL3Protocol ()
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (this);
}
void
@@ -64,17 +74,30 @@
void
ArpL3Protocol::DoDispose (void)
{
- NS_LOG_FUNCTION_NOARGS ();
- for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
+ NS_LOG_FUNCTION (this);
+ for (CacheList::iterator i = m_cacheList.begin (); i != m_cacheList.end (); ++i)
{
- delete *i;
+ Ptr<ArpCache> cache = *i;
+ cache->Dispose ();
}
m_cacheList.clear ();
m_node = 0;
Object::DoDispose ();
}
-ArpCache *
+Ptr<ArpCache>
+ArpL3Protocol::CreateCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
+{
+ Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
+ Ptr<ArpCache> cache = CreateObject<ArpCache> ();
+ cache->SetDevice (device, interface);
+ NS_ASSERT (device->IsBroadcast ());
+ device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
+ m_cacheList.push_back (cache);
+ return cache;
+}
+
+Ptr<ArpCache>
ArpL3Protocol::FindCache (Ptr<NetDevice> device)
{
NS_LOG_FUNCTION_NOARGS ();
@@ -85,20 +108,16 @@
return *i;
}
}
- Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
- Ptr<Ipv4Interface> interface = ipv4->FindInterfaceForDevice (device);
- ArpCache * cache = new ArpCache (device, interface);
- NS_ASSERT (device->IsBroadcast ());
- device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
- m_cacheList.push_back (cache);
- return cache;
+ NS_ASSERT (false);
+ // quiet compiler
+ return 0;
}
void
ArpL3Protocol::Receive(Ptr<NetDevice> device, Ptr<Packet> packet, uint16_t protocol, const Address &from)
{
NS_LOG_FUNCTION_NOARGS ();
- ArpCache *cache = FindCache (device);
+ Ptr<ArpCache> cache = FindCache (device);
ArpHeader arp;
packet->RemoveHeader (arp);
@@ -135,8 +154,14 @@
arp.GetSourceIpv4Address ()
<< " for waiting entry -- flush");
Address from_mac = arp.GetSourceHardwareAddress ();
- Ptr<Packet> waiting = entry->MarkAlive (from_mac);
- cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ());
+ entry->MarkAlive (from_mac);
+ Ptr<Packet> pending = entry->DequeuePending();
+ while (pending != 0)
+ {
+ cache->GetInterface ()->Send (pending,
+ arp.GetSourceIpv4Address ());
+ pending = entry->DequeuePending();
+ }
}
else
{
@@ -145,13 +170,13 @@
NS_LOG_LOGIC("node="<<m_node->GetId ()<<", got reply from " <<
arp.GetSourceIpv4Address () <<
" for non-waiting entry -- drop");
- // XXX report packet as dropped.
+ m_dropTrace (packet);
}
}
else
{
NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
- // XXX report packet as dropped.
+ m_dropTrace (packet);
}
}
else
@@ -164,10 +189,10 @@
bool
ArpL3Protocol::Lookup (Ptr<Packet> packet, Ipv4Address destination,
Ptr<NetDevice> device,
+ Ptr<ArpCache> cache,
Address *hardwareDestination)
{
NS_LOG_FUNCTION_NOARGS ();
- ArpCache *cache = FindCache (device);
ArpCache::Entry *entry = cache->Lookup (destination);
if (entry != 0)
{
@@ -192,7 +217,13 @@
NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", wait reply for " << destination << " expired -- drop");
entry->MarkDead ();
- // XXX report packet as 'dropped'
+ Ptr<Packet> pending = entry->DequeuePending();
+ while (pending != 0)
+ {
+ m_dropTrace (pending);
+ pending = entry->DequeuePending();
+ }
+ m_dropTrace (packet);
}
}
else
@@ -200,25 +231,26 @@
if (entry->IsDead ())
{
NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
- ", dead entry for " << destination << " valid -- drop");
- // XXX report packet as 'dropped'
+ ", dead entry for " << destination << " valid -- drop");
+ m_dropTrace (packet);
}
else if (entry->IsAlive ())
{
NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
- ", alive entry for " << destination << " valid -- send");
+ ", alive entry for " << destination << " valid -- send");
*hardwareDestination = entry->GetMacAddress ();
return true;
}
else if (entry->IsWaitReply ())
{
NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
- ", wait reply for " << destination << " valid -- drop previous");
- Ptr<Packet> old = entry->UpdateWaitReply (packet);
- // XXX report 'old' packet as 'dropped'
+ ", wait reply for " << destination << " valid -- drop previous");
+ if (!entry->UpdateWaitReply (packet))
+ {
+ m_dropTrace (packet);
+ }
}
}
-
}
else
{
@@ -233,7 +265,7 @@
}
void
-ArpL3Protocol::SendArpRequest (ArpCache const *cache, Ipv4Address to)
+ArpL3Protocol::SendArpRequest (Ptr<const ArpCache> cache, Ipv4Address to)
{
NS_LOG_FUNCTION_NOARGS ();
ArpHeader arp;
@@ -252,7 +284,7 @@
}
void
-ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac)
+ArpL3Protocol::SendArpReply (Ptr<const ArpCache> cache, Ipv4Address toIp, Address toMac)
{
NS_LOG_FUNCTION_NOARGS ();
ArpHeader arp;
--- a/src/internet-node/arp-l3-protocol.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/arp-l3-protocol.h Wed Jun 04 17:19:32 2008 -0400
@@ -24,6 +24,9 @@
#include "ns3/ipv4-address.h"
#include "ns3/address.h"
#include "ns3/ptr.h"
+#include "ns3/traced-callback.h"
+
+#include "ipv4-interface.h"
namespace ns3 {
@@ -31,7 +34,7 @@
class NetDevice;
class Node;
class Packet;
-class TraceContext;
+
/**
* \brief An implementation of the ARP protocol
*/
@@ -46,6 +49,8 @@
void SetNode (Ptr<Node> node);
+ Ptr<ArpCache> CreateCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface);
+
/**
* \brief Recieve a packet
*/
@@ -55,21 +60,24 @@
* \param p
* \param destination
* \param device
+ * \param cache
* \param hardwareDestination
* \return
*/
bool Lookup (Ptr<Packet> p, Ipv4Address destination,
Ptr<NetDevice> device,
+ Ptr<ArpCache> cache,
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, Address toMac);
+ typedef std::list<Ptr<ArpCache> > CacheList;
+ Ptr<ArpCache> FindCache (Ptr<NetDevice> device);
+ void SendArpRequest (Ptr<const ArpCache>cache, Ipv4Address to);
+ void SendArpReply (Ptr<const ArpCache> cache, Ipv4Address toIp, Address toMac);
CacheList m_cacheList;
Ptr<Node> m_node;
+ TracedCallback<Ptr<const Packet> > m_dropTrace;
};
}//namespace ns3
--- a/src/internet-node/ascii-trace.cc Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 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 "ascii-trace.h"
-
-#include "ns3/config.h"
-#include "ns3/simulator.h"
-#include "ns3/node.h"
-#include "ns3/packet.h"
-#include "ns3/queue.h"
-
-namespace ns3 {
-
-AsciiTrace::AsciiTrace (std::string filename)
-{
- m_os.open (filename.c_str ());
-}
-AsciiTrace::~AsciiTrace ()
-{
- m_os.close ();
-}
-void
-AsciiTrace::TraceAllQueues (void)
-{
- Packet::EnableMetadata ();
- Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Enqueue",
- MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this));
- Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Dequeue",
- MakeCallback (&AsciiTrace::LogDevQueueDequeue, this));
- Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop",
- MakeCallback (&AsciiTrace::LogDevQueueDrop, this));
-}
-void
-AsciiTrace::TraceAllNetDeviceRx (void)
-{
- Packet::EnableMetadata ();
- Config::Connect ("/NodeList/*/DeviceList/*/Rx",
- MakeCallback (&AsciiTrace::LogDevRx, this));
-}
-
-void
-AsciiTrace::LogDevQueueEnqueue (std::string context,
- Ptr<const Packet> packet)
-{
- m_os << "+ ";
- m_os << Simulator::Now ().GetSeconds () << " ";
- m_os << context;
- m_os << " pkt-uid=" << packet->GetUid () << " ";
- packet->Print (m_os);
- m_os << std::endl;
-}
-
-void
-AsciiTrace::LogDevQueueDequeue (std::string context,
- Ptr<const Packet> packet)
-{
- m_os << "- ";
- m_os << Simulator::Now ().GetSeconds () << " ";
- m_os << context;
- m_os << " pkt-uid=" << packet->GetUid () << " ";
- packet->Print (m_os);
- m_os << std::endl;
-}
-
-void
-AsciiTrace::LogDevQueueDrop (std::string context,
- Ptr<const Packet> packet)
-{
- m_os << "d ";
- m_os << Simulator::Now ().GetSeconds () << " ";
- m_os << context;
- m_os << " pkt-uid=" << packet->GetUid () << " ";
- packet->Print (m_os);
- m_os << std::endl;
-}
-void
-AsciiTrace::LogDevRx (std::string context,
- Ptr<const Packet> p)
-{
- m_os << "r " << Simulator::Now ().GetSeconds () << " ";
- m_os << context;
- m_os << " pkt-uid=" << p->GetUid () << " ";
- p->Print (m_os);
- m_os << std::endl;
-}
-
-}//namespace ns3
--- a/src/internet-node/ascii-trace.h Fri May 30 15:31:50 2008 -0400
+++ /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) 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 ASCII_TRACE_H
-#define ASCII_TRACE_H
-
-#include <string>
-#include <fstream>
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class TraceContext;
-
-class AsciiTrace
-{
-public:
- AsciiTrace (std::string filename);
- ~AsciiTrace ();
- void TraceAllQueues (void);
- void TraceAllNetDeviceRx (void);
-private:
- void LogDevQueueEnqueue (std::string context, Ptr<const Packet> p);
- void LogDevQueueDequeue (std::string context, Ptr<const Packet> p);
- void LogDevQueueDrop (std::string context, Ptr<const Packet> p);
- void LogDevRx (std::string context, Ptr<const Packet> p);
- std::ofstream m_os;
-};
-
-}//namespace ns3
-
-#endif /* ASCII_TRACE_H */
--- a/src/internet-node/internet-stack.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/internet-stack.cc Wed Jun 04 17:19:32 2008 -0400
@@ -40,12 +40,6 @@
Ptr<ArpL3Protocol> arp = CreateObject<ArpL3Protocol> ();
ipv4->SetNode (node);
arp->SetNode (node);
- // XXX remove the PeekPointer below.
- node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, PeekPointer (ipv4)),
- Ipv4L3Protocol::PROT_NUMBER, 0);
- node->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (arp)),
- ArpL3Protocol::PROT_NUMBER, 0);
-
Ptr<Ipv4L4Demux> ipv4L4Demux = CreateObject<Ipv4L4Demux> ();
Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
--- a/src/internet-node/ipv4-header.cc Fri May 30 15:31:50 2008 -0400
+++ /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) 2005 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/assert.h"
-#include "ns3/log.h"
-#include "ns3/header.h"
-#include "ipv4-header.h"
-
-NS_LOG_COMPONENT_DEFINE ("Ipv4Header");
-
-namespace ns3 {
-
-NS_OBJECT_ENSURE_REGISTERED (Ipv4Header);
-
-bool Ipv4Header::m_calcChecksum = false;
-
-Ipv4Header::Ipv4Header ()
- : m_payloadSize (0),
- m_identification (0),
- m_tos (0),
- m_ttl (0),
- m_protocol (0),
- m_flags (0),
- m_fragmentOffset (0),
- m_goodChecksum (true)
-{}
-
-void
-Ipv4Header::EnableChecksums (void)
-{
- m_calcChecksum = true;
-}
-
-void
-Ipv4Header::SetPayloadSize (uint16_t size)
-{
- m_payloadSize = size;
-}
-uint16_t
-Ipv4Header::GetPayloadSize (void) const
-{
- return m_payloadSize;
-}
-
-uint16_t
-Ipv4Header::GetIdentification (void) const
-{
- return m_identification;
-}
-void
-Ipv4Header::SetIdentification (uint16_t identification)
-{
- m_identification = identification;
-}
-
-
-
-void
-Ipv4Header::SetTos (uint8_t tos)
-{
- m_tos = tos;
-}
-uint8_t
-Ipv4Header::GetTos (void) const
-{
- return m_tos;
-}
-void
-Ipv4Header::SetMoreFragments (void)
-{
- m_flags |= MORE_FRAGMENTS;
-}
-void
-Ipv4Header::SetLastFragment (void)
-{
- m_flags &= ~MORE_FRAGMENTS;
-}
-bool
-Ipv4Header::IsLastFragment (void) const
-{
- return !(m_flags & MORE_FRAGMENTS);
-}
-
-void
-Ipv4Header::SetDontFragment (void)
-{
- m_flags |= DONT_FRAGMENT;
-}
-void
-Ipv4Header::SetMayFragment (void)
-{
- m_flags &= ~DONT_FRAGMENT;
-}
-bool
-Ipv4Header::IsDontFragment (void) const
-{
- return (m_flags & DONT_FRAGMENT);
-}
-
-void
-Ipv4Header::SetFragmentOffset (uint16_t offset)
-{
- NS_ASSERT (!(offset & (~0x3fff)));
- m_fragmentOffset = offset;
-}
-uint16_t
-Ipv4Header::GetFragmentOffset (void) const
-{
- NS_ASSERT (!(m_fragmentOffset & (~0x3fff)));
- return m_fragmentOffset;
-}
-
-void
-Ipv4Header::SetTtl (uint8_t ttl)
-{
- m_ttl = ttl;
-}
-uint8_t
-Ipv4Header::GetTtl (void) const
-{
- return m_ttl;
-}
-
-uint8_t
-Ipv4Header::GetProtocol (void) const
-{
- return m_protocol;
-}
-void
-Ipv4Header::SetProtocol (uint8_t protocol)
-{
- m_protocol = protocol;
-}
-
-void
-Ipv4Header::SetSource (Ipv4Address source)
-{
- m_source = source;
-}
-Ipv4Address
-Ipv4Header::GetSource (void) const
-{
- return m_source;
-}
-
-void
-Ipv4Header::SetDestination (Ipv4Address dst)
-{
- m_destination = dst;
-}
-Ipv4Address
-Ipv4Header::GetDestination (void) const
-{
- return m_destination;
-}
-
-
-bool
-Ipv4Header::IsChecksumOk (void) const
-{
- return m_goodChecksum;
-}
-
-
-TypeId
-Ipv4Header::GetTypeId (void)
-{
- static TypeId tid = TypeId ("ns3::Ipv4Header")
- .SetParent<Header> ()
- .AddConstructor<Ipv4Header> ()
- ;
- return tid;
-}
-TypeId
-Ipv4Header::GetInstanceTypeId (void) const
-{
- return GetTypeId ();
-}
-void
-Ipv4Header::Print (std::ostream &os) const
-{
- // ipv4, right ?
- 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
-{
- return 5 * 4;
-}
-
-void
-Ipv4Header::Serialize (Buffer::Iterator start) const
-{
- Buffer::Iterator i = start;
-
- uint8_t verIhl = (4 << 4) | (5);
- i.WriteU8 (verIhl);
- i.WriteU8 (m_tos);
- i.WriteHtonU16 (m_payloadSize + 5*4);
- i.WriteHtonU16 (m_identification);
- uint32_t fragmentOffset = m_fragmentOffset / 8;
- uint8_t flagsFrag = (fragmentOffset >> 8) & 0x1f;
- if (m_flags & DONT_FRAGMENT)
- {
- flagsFrag |= (1<<6);
- }
- if (m_flags & MORE_FRAGMENTS)
- {
- flagsFrag |= (1<<5);
- }
- i.WriteU8 (flagsFrag);
- uint8_t frag = fragmentOffset & 0xff;
- i.WriteU8 (frag);
- i.WriteU8 (m_ttl);
- i.WriteU8 (m_protocol);
- i.WriteHtonU16 (0);
- i.WriteHtonU32 (m_source.GetHostOrder ());
- i.WriteHtonU32 (m_destination.GetHostOrder ());
-
- if (m_calcChecksum)
- {
-#if 0
- // XXX we need to add Buffer::Iterator::PeekData method
- uint8_t *data = start.PeekData ();
- uint16_t checksum = UtilsChecksumCalculate (0, data, GetSize ());
- checksum = UtilsChecksumComplete (checksum);
- NS_LOG_LOGIC ("checksum=" <<checksum);
- i = start;
- i.Next (10);
- i.WriteU16 (checksum);
-#endif
- }
-}
-uint32_t
-Ipv4Header::Deserialize (Buffer::Iterator start)
-{
- Buffer::Iterator i = start;
- uint8_t verIhl = i.ReadU8 ();
- uint8_t ihl = verIhl & 0x0f;
- uint16_t headerSize = ihl * 4;
- NS_ASSERT ((verIhl >> 4) == 4);
- m_tos = i.ReadU8 ();
- uint16_t size = i.ReadNtohU16 ();
- m_payloadSize = size - headerSize;
- m_identification = i.ReadNtohU16 ();
- uint8_t flags = i.ReadU8 ();
- m_flags = 0;
- if (flags & (1<<6))
- {
- m_flags |= DONT_FRAGMENT;
- }
- if (flags & (1<<5))
- {
- m_flags |= MORE_FRAGMENTS;
- }
- //XXXX I think we should clear some bits in fragmentOffset !
- i.Prev ();
- m_fragmentOffset = i.ReadNtohU16 ();
- m_fragmentOffset *= 8;
- m_ttl = i.ReadU8 ();
- m_protocol = i.ReadU8 ();
- i.Next (2); // checksum
- m_source.SetHostOrder (i.ReadNtohU32 ());
- m_destination.SetHostOrder (i.ReadNtohU32 ());
-
- if (m_calcChecksum)
- {
-#if 0
- uint8_t *data = start.PeekData ();
- uint16_t localChecksum = UtilsChecksumCalculate (0, data, headerSize);
- if (localChecksum == 0xffff)
- {
- m_goodChecksum = true;
- }
- else
- {
- m_goodChecksum = false;
- }
-#endif
- }
- return GetSerializedSize ();
-}
-
-}; // namespace ns3
--- a/src/internet-node/ipv4-header.h Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 IPV4_HEADER_H
-#define IPV4_HEADER_H
-
-#include "ns3/header.h"
-#include "ns3/ipv4-address.h"
-
-namespace ns3 {
-/**
- * \brief Packet header for IPv4
- */
-class Ipv4Header : public Header
-{
-public:
- /**
- * \brief Construct a null IPv4 header
- */
- Ipv4Header ();
- /**
- * \brief Enable checksum calculation for IP (XXX currently has no effect)
- */
- static void EnableChecksums (void);
- /**
- * \param size the size of the payload in bytes
- */
- void SetPayloadSize (uint16_t size);
- /**
- * \param identification the Identification field of IPv4 packets.
- *
- * By default, set to zero.
- */
- void SetIdentification (uint16_t identification);
- /**
- * \param tos the 8 bits of Ipv4 TOS.
- */
- void SetTos (uint8_t tos);
- /**
- * This packet is not the last packet of a fragmented ipv4 packet.
- */
- void SetMoreFragments (void);
- /**
- * This packet is the last packet of a fragmented ipv4 packet.
- */
- void SetLastFragment (void);
- /**
- * Don't fragment this packet: if you need to anyway, drop it.
- */
- void SetDontFragment (void);
- /**
- * If you need to fragment this packet, you can do it.
- */
- void SetMayFragment (void);
- /**
- * \param offset the ipv4 fragment offset
- */
- void SetFragmentOffset (uint16_t offset);
- /**
- * \param ttl the ipv4 TTL
- */
- void SetTtl (uint8_t ttl);
- /**
- * \param num the ipv4 protocol field
- */
- void SetProtocol (uint8_t num);
- /**
- * \param source the source of this packet
- */
- void SetSource (Ipv4Address source);
- /**
- * \param destination the destination of this packet.
- */
- void SetDestination (Ipv4Address destination);
- /**
- * \returns the size of the payload in bytes
- */
- uint16_t GetPayloadSize (void) const;
- /**
- * \returns the identification field of this packet.
- */
- uint16_t GetIdentification (void) const;
- /**
- * \returns the TOS field of this packet.
- */
- uint8_t GetTos (void) const;
- /**
- * \returns true if this is the last fragment of a packet, false otherwise.
- */
- bool IsLastFragment (void) const;
- /**
- * \returns true if this is this packet can be fragmented.
- */
- bool IsDontFragment (void) const;
- /**
- * \returns the offset of this fragment.
- */
- uint16_t GetFragmentOffset (void) const;
- /**
- * \returns the TTL field of this packet
- */
- uint8_t GetTtl (void) const;
- /**
- * \returns the protocol field of this packet
- */
- uint8_t GetProtocol (void) const;
- /**
- * \returns the source address of this packet
- */
- Ipv4Address GetSource (void) const;
- /**
- * \returns the destination address of this packet
- */
- Ipv4Address GetDestination (void) const;
-
- /**
- * \returns true if the upv4 checksum is correct, false otherwise.
- *
- * If Ipv4Header::EnableChecksums has not been called prior to
- * creating this packet, this method will always return true.
- */
- bool IsChecksumOk (void) const;
-
- static TypeId GetTypeId (void);
- virtual TypeId GetInstanceTypeId (void) const;
- virtual void Print (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void Serialize (Buffer::Iterator start) const;
- virtual uint32_t Deserialize (Buffer::Iterator start);
-private:
-
- enum FlagsE {
- DONT_FRAGMENT = (1<<0),
- MORE_FRAGMENTS = (1<<1)
- };
-
- static bool m_calcChecksum;
-
- uint16_t m_payloadSize;
- uint16_t m_identification;
- uint32_t m_tos : 8;
- uint32_t m_ttl : 8;
- uint32_t m_protocol : 8;
- uint32_t m_flags : 3;
- uint16_t m_fragmentOffset : 13;
- Ipv4Address m_source;
- Ipv4Address m_destination;
- bool m_goodChecksum;
-};
-
-} // namespace ns3
-
-
-#endif /* IPV4_HEADER_H */
--- a/src/internet-node/ipv4-interface.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-interface.cc Wed Jun 04 17:19:32 2008 -0400
@@ -80,8 +80,8 @@
Ipv4Interface::GetBroadcast (void) const
{
NS_LOG_FUNCTION_NOARGS ();
- uint32_t mask = m_netmask.GetHostOrder ();
- uint32_t address = m_address.GetHostOrder ();
+ uint32_t mask = m_netmask.Get ();
+ uint32_t address = m_address.Get ();
Ipv4Address broadcast = Ipv4Address (address | (~mask));
return broadcast;
}
--- a/src/internet-node/ipv4-interface.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-interface.h Wed Jun 04 17:19:32 2008 -0400
@@ -31,7 +31,6 @@
class NetDevice;
class Packet;
-class TraceContext;
/**
* \brief The IPv4 representation of a network interface
--- a/src/internet-node/ipv4-l3-protocol.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-l3-protocol.cc Wed Jun 04 17:19:32 2008 -0400
@@ -29,10 +29,11 @@
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/object-vector.h"
+#include "ns3/ipv4-header.h"
+#include "arp-l3-protocol.h"
#include "ipv4-l3-protocol.h"
#include "ipv4-l4-protocol.h"
-#include "ipv4-header.h"
#include "ipv4-interface.h"
#include "ipv4-loopback-interface.h"
#include "arp-ipv4-interface.h"
@@ -81,7 +82,7 @@
Ipv4L3Protocol::~Ipv4L3Protocol ()
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (this);
}
void
@@ -94,7 +95,12 @@
void
Ipv4L3Protocol::DoDispose (void)
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (this);
+ for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); ++i)
+ {
+ Ptr<Ipv4Interface> interface = *i;
+ interface->Dispose ();
+ }
m_interfaces.clear ();
m_node = 0;
m_staticRouting->Dispose ();
@@ -315,6 +321,13 @@
Ipv4L3Protocol::AddInterface (Ptr<NetDevice> device)
{
NS_LOG_FUNCTION (this << &device);
+
+ Ptr<Node> node = GetObject<Node> ();
+ node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
+ Ipv4L3Protocol::PROT_NUMBER, device);
+ node->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject<ArpL3Protocol> ())),
+ ArpL3Protocol::PROT_NUMBER, device);
+
Ptr<ArpIpv4Interface> interface = CreateObject<ArpIpv4Interface> ();
interface->SetNode (m_node);
interface->SetDevice (device);
@@ -490,9 +503,7 @@
// Set TTL to 1 if it is a broadcast packet of any type. Otherwise,
// possibly override the default TTL if the packet is tagged
SocketIpTtlTag tag;
- bool found = packet->PeekTag (tag);
- uint8_t socketTtl = tag.GetTtl ();
- packet->RemoveTag (tag);
+ bool found = packet->FindFirstMatchingTag (tag);
if (destination.IsBroadcast ())
{
@@ -500,7 +511,8 @@
}
else if (found)
{
- ipHeader.SetTtl (socketTtl);
+ ipHeader.SetTtl (tag.GetTtl ());
+ // XXX remove tag here?
}
else
{
--- a/src/internet-node/ipv4-l3-protocol.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-l3-protocol.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,7 +27,7 @@
#include "ns3/ptr.h"
#include "ns3/ipv4.h"
#include "ns3/traced-callback.h"
-#include "ipv4-header.h"
+#include "ns3/ipv4-header.h"
#include "ipv4-static-routing.h"
namespace ns3 {
--- a/src/internet-node/ipv4-l4-demux.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-l4-demux.h Wed Jun 04 17:19:32 2008 -0400
@@ -32,7 +32,6 @@
class Ipv4L4Protocol;
class Node;
-class TraceContext;
/**
* \brief L4 Ipv4 Demux
--- a/src/internet-node/ipv4-l4-protocol.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-l4-protocol.h Wed Jun 04 17:19:32 2008 -0400
@@ -31,8 +31,6 @@
class Packet;
class Ipv4Address;
-class TraceResolver;
-class TraceContext;
/**
* \brief L4 Protocol base class
--- a/src/internet-node/ipv4-loopback-interface.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-loopback-interface.cc Wed Jun 04 17:19:32 2008 -0400
@@ -31,15 +31,24 @@
namespace ns3 {
+TypeId
+Ipv4LoopbackInterface::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::Ipv4LoopbackInterface")
+ .SetParent<Ipv4Interface> ()
+ ;
+ return tid;
+}
+
Ipv4LoopbackInterface::Ipv4LoopbackInterface ()
: m_node (0)
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (this);
}
Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (this);
NS_ASSERT (m_node != 0);
}
--- a/src/internet-node/ipv4-loopback-interface.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-loopback-interface.h Wed Jun 04 17:19:32 2008 -0400
@@ -32,7 +32,8 @@
*/
class Ipv4LoopbackInterface : public Ipv4Interface
{
- public:
+public:
+ static TypeId GetTypeId (void);
Ipv4LoopbackInterface ();
virtual ~Ipv4LoopbackInterface ();
--- a/src/internet-node/ipv4-static-routing.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/ipv4-static-routing.h Wed Jun 04 17:19:32 2008 -0400
@@ -25,7 +25,7 @@
#include <list>
#include <stdint.h>
#include "ns3/ipv4-address.h"
-#include "ipv4-header.h"
+#include "ns3/ipv4-header.h"
#include "ns3/ptr.h"
#include "ns3/ipv4.h"
--- a/src/internet-node/pcap-trace.cc Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "pcap-trace.h"
-
-#include <sstream>
-
-#include "ns3/config.h"
-#include "ns3/callback.h"
-#include "ns3/pcap-writer.h"
-#include "ns3/node-list.h"
-#include "ns3/node.h"
-#include "ns3/packet.h"
-#include "ns3/log.h"
-
-#include "ipv4-l3-protocol.h"
-
-NS_LOG_COMPONENT_DEFINE ("PcapTrace");
-
-namespace ns3 {
-
-
-PcapTrace::PcapTrace (std::string filename)
- : m_filename (filename)
-{}
-PcapTrace::~PcapTrace ()
-{
- for (std::vector<Trace>::iterator i = m_traces.begin ();
- i != m_traces.end (); i++)
- {
- delete i->writer;
- }
-}
-
-void
-PcapTrace::TraceAllIp (void)
-{
- Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
- MakeCallback (&PcapTrace::LogTxIp, this));
- Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Rx",
- MakeCallback (&PcapTrace::LogRxIp, this));
-}
-
-PcapWriter *
-PcapTrace::GetStream (uint32_t nodeId, uint32_t interfaceId)
-{
- for (std::vector<Trace>::iterator i = m_traces.begin ();
- i != m_traces.end (); i++)
- {
- if (i->nodeId == nodeId &&
- i->interfaceId == interfaceId)
- {
- return i->writer;
- }
- }
- PcapTrace::Trace trace;
- trace.nodeId = nodeId;
- trace.interfaceId = interfaceId;
- trace.writer = new PcapWriter ();
- std::ostringstream oss;
- oss << m_filename << "-" << nodeId << "-" << interfaceId;
- std::string filename = oss.str ();
- trace.writer->Open (filename);
- trace.writer->WriteIpHeader ();
- m_traces.push_back (trace);
- return trace.writer;
-}
-
-uint32_t
-PcapTrace::GetNodeIndex (std::string context) const
-{
- std::string::size_type pos;
- pos = context.find ("/NodeList/");
- NS_ASSERT (pos == 0);
- std::string::size_type afterNodeIndex = context.find ("/", 11);
- NS_ASSERT (afterNodeIndex != std::string::npos);
- std::string index = context.substr (10, afterNodeIndex - 10);
- NS_LOG_DEBUG ("index="<<index);
- std::istringstream iss;
- iss.str (index);
- uint32_t nodeIndex;
- iss >> nodeIndex;
- return nodeIndex;
-}
-
-void
-PcapTrace::LogTxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex)
-{
- PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex);
- writer->WritePacket (p);
-}
-
-void
-PcapTrace::LogRxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex)
-{
- PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex);
- writer->WritePacket (p);
-}
-
-
-}//namespace ns3
--- a/src/internet-node/pcap-trace.h Fri May 30 15:31:50 2008 -0400
+++ /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
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * 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 PCAP_TRACE_H
-#define PCAP_TRACE_H
-
-#include <string>
-#include <vector>
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class TraceContext;
-class PcapWriter;
-
-class PcapTrace
-{
-public:
- PcapTrace (std::string filename);
- ~PcapTrace ();
-
- void TraceAllIp (void);
-private:
- PcapWriter *GetStream (uint32_t nodeId, uint32_t interfaceId);
- void LogRxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex);
- void LogTxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex);
- uint32_t GetNodeIndex (std::string context) const;
- std::string m_filename;
- struct Trace {
- uint32_t nodeId;
- uint32_t interfaceId;
- PcapWriter *writer;
- };
- std::vector<Trace> m_traces;
-};
-
-}//namespace ns3
-
-#endif /* PCAP_TRACE_H */
--- a/src/internet-node/tcp-l4-protocol.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/tcp-l4-protocol.h Wed Jun 04 17:19:32 2008 -0400
@@ -37,7 +37,6 @@
namespace ns3 {
class Node;
-class TraceContext;
class Socket;
class TcpHeader;
/**
--- a/src/internet-node/tcp-socket-factory-impl.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/tcp-socket-factory-impl.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,7 +30,9 @@
/**
* \ingroup internetNode
* \defgroup Tcp Tcp
- *
+ */
+/**
+ * \ingroup Tcp
* \section Tcp Overview
*
* The TCP code in ns3::InternetNode is ported from the
--- a/src/internet-node/tcp-socket-impl.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/tcp-socket-impl.cc Wed Jun 04 17:19:32 2008 -0400
@@ -125,7 +125,9 @@
m_lastMeasuredRtt (Seconds(0.0)),
m_cnTimeout (sock.m_cnTimeout),
m_cnCount (sock.m_cnCount),
- m_rxAvailable (0)
+ m_rxAvailable (0),
+ m_wouldBlock (false),
+ m_sndBufSize (sock.m_sndBufSize)
{
NS_LOG_FUNCTION_NOARGS ();
NS_LOG_LOGIC("Invoked the copy constructor");
@@ -500,14 +502,11 @@
return 0;
}
Ptr<Packet> outPacket = Create<Packet>();
- SocketRxAddressTag tag; //Packet AddAt* APIs don't preserve tags
- out.begin()->second->PeekTag (tag); //XXX so manually copy the address tag
- outPacket->AddTag (tag);
for(i = out.begin(); i!=out.end(); ++i)
{
if (outPacket->GetSize() + i->second->GetSize() <= maxSize )
{
- outPacket->AddAtEnd(i->second); //XXX this doesn't copy the tags
+ outPacket->AddAtEnd(i->second);
}
else
{
--- a/src/internet-node/udp-l4-protocol.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/udp-l4-protocol.h Wed Jun 04 17:19:32 2008 -0400
@@ -32,7 +32,6 @@
namespace ns3 {
class Node;
-class TraceContext;
class Socket;
/**
* \brief Implementation of the UDP protocol
--- a/src/internet-node/udp-socket-impl.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/udp-socket-impl.cc Wed Jun 04 17:19:32 2008 -0400
@@ -133,8 +133,8 @@
{
return -1;
}
- m_endPoint->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp, this));
- m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, this));
+ m_endPoint->SetRxCallback (MakeCallback (&UdpSocketImpl::ForwardUp, Ptr<UdpSocketImpl> (this)));
+ m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, Ptr<UdpSocketImpl> (this)));
return 0;
}
@@ -217,6 +217,13 @@
}
int
+UdpSocketImpl::Listen (uint32_t queueLimit)
+{
+ m_errno = Socket::ERROR_OPNOTSUPP;
+ return -1;
+}
+
+int
UdpSocketImpl::Send (Ptr<Packet> p)
{
NS_LOG_FUNCTION (this << p);
@@ -530,14 +537,16 @@
void UdpSocketImplTest::ReceivePkt (Ptr<Socket> socket)
{
- uint32_t availableData = socket->GetRxAvailable ();
+ uint32_t availableData;
+ availableData = socket->GetRxAvailable ();
m_receivedPacket = socket->Recv (std::numeric_limits<uint32_t>::max(), 0);
NS_ASSERT (availableData == m_receivedPacket->GetSize ());
}
void UdpSocketImplTest::ReceivePkt2 (Ptr<Socket> socket)
{
- uint32_t availableData = socket->GetRxAvailable ();
+ uint32_t availableData;
+ availableData = socket->GetRxAvailable ();
m_receivedPacket2 = socket->Recv (std::numeric_limits<uint32_t>::max(), 0);
NS_ASSERT (availableData == m_receivedPacket2->GetSize ());
}
--- a/src/internet-node/udp-socket-impl.h Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/udp-socket-impl.h Wed Jun 04 17:19:32 2008 -0400
@@ -57,6 +57,7 @@
virtual int ShutdownSend (void);
virtual int ShutdownRecv (void);
virtual int Connect(const Address &address);
+ virtual int Listen (uint32_t queueLimit);
virtual int Send (Ptr<Packet> p);
virtual int SendTo (Ptr<Packet> p, const Address &address);
virtual uint32_t GetTxAvailable (void) const;
--- a/src/internet-node/wscript Fri May 30 15:31:50 2008 -0400
+++ b/src/internet-node/wscript Wed Jun 04 17:19:32 2008 -0400
@@ -7,7 +7,6 @@
'internet-stack.cc',
'ipv4-l4-demux.cc',
'ipv4-l4-protocol.cc',
- 'ipv4-header.cc',
'udp-header.cc',
'tcp-header.cc',
'ipv4-checksum.cc',
@@ -26,8 +25,6 @@
'tcp-socket-impl.cc',
'ipv4-end-point-demux.cc',
'ipv4-impl.cc',
- 'ascii-trace.cc',
- 'pcap-trace.cc',
'udp-socket-factory-impl.cc',
'tcp-socket-factory-impl.cc',
'pending-data.cc',
@@ -39,9 +36,6 @@
headers.module = 'internet-node'
headers.source = [
'internet-stack.h',
- 'ascii-trace.h',
- 'pcap-trace.h',
- 'ipv4-header.h',
'udp-header.h',
'tcp-header.h',
'sequence-number.h',
--- a/src/mobility/hierarchical-mobility-model.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/hierarchical-mobility-model.cc Wed Jun 04 17:19:32 2008 -0400
@@ -18,7 +18,6 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "hierarchical-mobility-model.h"
-#include "mobility-model-notifier.h"
#include "ns3/pointer.h"
namespace ns3 {
@@ -33,11 +32,13 @@
.AddConstructor<HierarchicalMobilityModel> ()
.AddAttribute ("Child", "The child mobility model.",
PointerValue (),
- MakePointerAccessor (&HierarchicalMobilityModel::SetChild),
+ MakePointerAccessor (&HierarchicalMobilityModel::SetChild,
+ &HierarchicalMobilityModel::GetChild),
MakePointerChecker<MobilityModel> ())
.AddAttribute ("Parent", "The parent mobility model.",
PointerValue (),
- MakePointerAccessor (&HierarchicalMobilityModel::SetParent),
+ MakePointerAccessor (&HierarchicalMobilityModel::SetParent,
+ &HierarchicalMobilityModel::GetParent),
MakePointerChecker<MobilityModel> ())
;
return tid;
@@ -52,28 +53,14 @@
HierarchicalMobilityModel::SetChild (Ptr<MobilityModel> model)
{
m_child = model;
- Ptr<MobilityModelNotifier> notifier =
- m_child->GetObject<MobilityModelNotifier> ();
- if (notifier == 0)
- {
- notifier = CreateObject<MobilityModelNotifier> ();
- m_child->AggregateObject (notifier);
- }
- notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
+ m_child->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
}
void
HierarchicalMobilityModel::SetParent (Ptr<MobilityModel> model)
{
m_parent = model;
- Ptr<MobilityModelNotifier> notifier =
- m_parent->GetObject<MobilityModelNotifier> ();
- if (notifier == 0)
- {
- notifier = CreateObject<MobilityModelNotifier> ();
- m_parent->AggregateObject (notifier);
- }
- notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
+ m_parent->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
}
--- a/src/mobility/mobility-model-notifier.cc Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "mobility-model-notifier.h"
-#include "ns3/trace-source-accessor.h"
-
-namespace ns3 {
-
-TypeId
-MobilityModelNotifier::GetTypeId (void)
-{
- static TypeId tid = TypeId ("MobilityModelNotifier")
- .SetParent<Object> ()
- .AddConstructor<MobilityModelNotifier> ()
- .AddTraceSource ("CourseChange",
- "The value of the position and/or velocity vector changed",
- MakeTraceSourceAccessor (&MobilityModelNotifier::m_trace))
- ;
- return tid;
-}
-
-MobilityModelNotifier::MobilityModelNotifier ()
-{}
-
-void
-MobilityModelNotifier::Notify (Ptr<const MobilityModel> position) const
-{
- m_trace (position);
-}
-
-} // namespace ns3
--- a/src/mobility/mobility-model-notifier.h Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 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 MOBILITY_MODEL_NOTIFIER_H
-#define MOBILITY_MODEL_NOTIFIER_H
-
-#include "ns3/object.h"
-#include "ns3/callback.h"
-#include "ns3/traced-callback.h"
-#include "mobility-model.h"
-
-namespace ns3 {
-
-/**
- * \brief notify listeners of position changes.
- */
-class MobilityModelNotifier : public Object
-{
-public:
- static TypeId GetTypeId (void);
-
- /**
- * Create a new position notifier
- */
- MobilityModelNotifier ();
-
- /**
- * \param position the position which just changed.
- */
- void Notify (Ptr<const MobilityModel> position) const;
-private:
- TracedCallback<Ptr<const MobilityModel> > m_trace;
-};
-
-} // namespace ns3
-
-#endif /* MOBILITY_MODEL_NOTIFIER_H */
--- a/src/mobility/mobility-model.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/mobility-model.cc Wed Jun 04 17:19:32 2008 -0400
@@ -17,9 +17,11 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+
+#include <math.h>
+
#include "mobility-model.h"
-#include "mobility-model-notifier.h"
-#include <math.h>
+#include "ns3/trace-source-accessor.h"
namespace ns3 {
@@ -39,6 +41,9 @@
VectorValue (Vector (0.0, 0.0, 0.0)), // ignored initial value.
MakeVectorAccessor (&MobilityModel::GetVelocity),
MakeVectorChecker ())
+ .AddTraceSource ("CourseChange",
+ "The value of the position and/or velocity vector changed",
+ MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace))
;
return tid;
}
@@ -77,11 +82,7 @@
void
MobilityModel::NotifyCourseChange (void) const
{
- Ptr<MobilityModelNotifier> notifier = GetObject<MobilityModelNotifier> ();
- if (notifier != 0)
- {
- notifier->Notify (this);
- }
+ m_courseChangeTrace(this);
}
} // namespace ns3
--- a/src/mobility/mobility-model.h Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/mobility-model.h Wed Jun 04 17:19:32 2008 -0400
@@ -20,8 +20,10 @@
#ifndef MOBILITY_MODEL_H
#define MOBILITY_MODEL_H
+#include "vector.h"
+
#include "ns3/object.h"
-#include "vector.h"
+#include "ns3/traced-callback.h"
namespace ns3 {
@@ -84,6 +86,13 @@
* implement this method.
*/
virtual Vector DoGetVelocity (void) const = 0;
+
+ /**
+ * Used to alert subscribers that a change in direction, velocity,
+ * or position has occurred.
+ */
+ TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
+
};
}; // namespace ns3
--- a/src/mobility/mobility.h Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/mobility.h Wed Jun 04 17:19:32 2008 -0400
@@ -5,8 +5,8 @@
* - a set of mobility models which are used to track and maintain
* the "current" cartesian position and speed of an object.
*
- * - a "course change notifier" which can be used to register listeners
- * to the course changes of a mobility model: ns3::MobilityModelNotifier.
+ * - a "course change notifier" trace which can be used to register
+ * listeners to the course changes of a mobility model
*
* The mobility models themselves are:
* - ns3::StaticMobilityModel: a model which maintains a constant position
--- a/src/mobility/random-walk-2d-mobility-model.h Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/random-walk-2d-mobility-model.h Wed Jun 04 17:19:32 2008 -0400
@@ -37,8 +37,10 @@
* Each instance moves with a speed and direction choosen at random
* with the user-provided random variables until
* either a fixed distance has been walked or until a fixed amount
- * of time.
- *
+ * of time. If we hit one of the boundaries (specified by a rectangle),
+ * of the model, we rebound on the boundary with a reflexive angle
+ * and speed. This model is often identified as a brownian motion
+ * model.
*/
class RandomWalk2dMobilityModel : public MobilityModel
{
--- a/src/mobility/random-waypoint-mobility-model.h Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/random-waypoint-mobility-model.h Wed Jun 04 17:19:32 2008 -0400
@@ -38,7 +38,8 @@
*
* The implementation of this model is not 2d-specific. i.e. if you provide
* a 3d random waypoint position model to this mobility model, the model
- * will still work.
+ * will still work. There is no 3d position allocator for now but it should
+ * be trivial to add one.
*/
class RandomWaypointMobilityModel : public MobilityModel
{
--- a/src/mobility/rectangle.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/rectangle.cc Wed Jun 04 17:19:32 2008 -0400
@@ -86,6 +86,7 @@
Vector
Rectangle::CalculateIntersection (const Vector ¤t, const Vector &speed) const
{
+ NS_ASSERT (IsInside (current));
double xMaxY = current.y + (this->xMax - current.x) / speed.x * speed.y;
double xMinY = current.y + (this->xMin - current.x) / speed.x * speed.y;
double yMaxX = current.x + (this->yMax - current.y) / speed.y * speed.x;
--- a/src/mobility/rectangle.h Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/rectangle.h Wed Jun 04 17:19:32 2008 -0400
@@ -53,16 +53,43 @@
* Create a zero-sized rectangle located at coordinates (0.0,0.0)
*/
Rectangle ();
+ /**
+ * \param position the position to test.
+ * \returns true if the input position is located within the rectangle,
+ * false otherwise.
+ *
+ * This method compares only the x and y coordinates of the input position.
+ * It ignores the z coordinate.
+ */
bool IsInside (const Vector &position) const;
+ /**
+ * \param position the position to test.
+ * \returns the side of the rectangle the input position is closest to.
+ *
+ * This method compares only the x and y coordinates of the input position.
+ * It ignores the z coordinate.
+ */
Side GetClosestSide (const Vector &position) const;
+ /**
+ * \param current the current position
+ * \param speed the current speed
+ * \returns the intersection point between the rectangle and the current+speed vector.
+ *
+ * This method assumes that the current position is located _inside_
+ * the rectangle and checks for this with an assert.
+ * This method compares only the x and y coordinates of the input position
+ * and speed. It ignores the z coordinate.
+ */
Vector CalculateIntersection (const Vector ¤t, const Vector &speed) const;
+ /* The x coordinate of the left bound of the rectangle */
double xMin;
+ /* The x coordinate of the right bound of the rectangle */
double xMax;
+ /* The y coordinate of the bottom bound of the rectangle */
double yMin;
+ /* The y coordinate of the top bound of the rectangle */
double yMax;
-
- ATTRIBUTE_HELPER_HEADER_1 (Rectangle);
};
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
@@ -73,7 +100,7 @@
* \brief hold objects of type ns3::Rectangle
*/
-ATTRIBUTE_HELPER_HEADER_2 (Rectangle);
+ATTRIBUTE_HELPER_HEADER (Rectangle);
} // namespace ns3
--- a/src/mobility/vector.h Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/vector.h Wed Jun 04 17:19:32 2008 -0400
@@ -57,10 +57,13 @@
* z coordinate of vector vector
*/
double z;
-
- ATTRIBUTE_HELPER_HEADER_1 (Vector);
};
+/**
+ * \param a one point
+ * \param b another point
+ * \returns the cartesian distance between a and b.
+ */
double CalculateDistance (const Vector &a, const Vector &b);
/**
@@ -68,7 +71,7 @@
* \brief hold objects of type ns3::Vector
*/
-ATTRIBUTE_HELPER_HEADER_2 (Vector);
+ATTRIBUTE_HELPER_HEADER (Vector);
std::ostream &operator << (std::ostream &os, const Vector &vector);
std::istream &operator >> (std::istream &is, Vector &vector);
--- a/src/mobility/wscript Fri May 30 15:31:50 2008 -0400
+++ b/src/mobility/wscript Wed Jun 04 17:19:32 2008 -0400
@@ -6,7 +6,6 @@
'vector.cc',
'hierarchical-mobility-model.cc',
'mobility-model.cc',
- 'mobility-model-notifier.cc',
'position-allocator.cc',
'rectangle.cc',
'static-mobility-model.cc',
@@ -23,7 +22,6 @@
'vector.h',
'hierarchical-mobility-model.h',
'mobility-model.h',
- 'mobility-model-notifier.h',
'position-allocator.h',
'rectangle.h',
'static-mobility-model.h',
--- a/src/node/address-utils.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/address-utils.cc Wed Jun 04 17:19:32 2008 -0400
@@ -23,7 +23,7 @@
void WriteTo (Buffer::Iterator &i, Ipv4Address ad)
{
- i.WriteHtonU32 (ad.GetHostOrder ());
+ i.WriteHtonU32 (ad.Get ());
}
void WriteTo (Buffer::Iterator &i, const Address &ad)
{
@@ -40,7 +40,7 @@
void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad)
{
- ad.SetHostOrder (i.ReadNtohU32 ());
+ ad.Set (i.ReadNtohU32 ());
}
void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len)
{
--- a/src/node/address.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/address.cc Wed Jun 04 17:19:32 2008 -0400
@@ -107,6 +107,29 @@
return type;
}
+uint32_t
+Address::GetSerializedSize (void) const
+{
+ return 1 + 1 + m_len;
+}
+
+void
+Address::Serialize (TagBuffer buffer) const
+{
+ buffer.WriteU8 (m_type);
+ buffer.WriteU8 (m_len);
+ buffer.Write (m_data, m_len);
+}
+
+void
+Address::Deserialize (TagBuffer buffer)
+{
+ m_type = buffer.ReadU8 ();
+ m_len = buffer.ReadU8 ();
+ NS_ASSERT (m_len <= MAX_SIZE);
+ buffer.Read (m_data, m_len);
+}
+
ATTRIBUTE_HELPER_CPP (Address);
@@ -139,8 +162,14 @@
}
bool operator < (const Address &a, const Address &b)
{
- // XXX: it is not clear to me how to order based on type.
- // so, we do not compare the types here but we should.
+ if (a.m_type < b.m_type)
+ {
+ return true;
+ }
+ else if (a.m_type > b.m_type)
+ {
+ return false;
+ }
if (a.m_len < b.m_len)
{
return true;
--- a/src/node/address.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/address.h Wed Jun 04 17:19:32 2008 -0400
@@ -5,10 +5,16 @@
#include <ostream>
#include "ns3/attribute.h"
#include "ns3/attribute-helper.h"
+#include "ns3/tag-buffer.h"
namespace ns3 {
/**
+ * \ingroup node
+ * \defgroup address Address
+ */
+/**
+ * \ingroup address
* \brief a polymophic address class
*
* This class is very similar in design and spirit to the BSD sockaddr
@@ -153,8 +159,26 @@
* \returns a new type id.
*/
static uint8_t Register (void);
+ /**
+ * Get the number of bytes needed to serialize the underlying Address
+ * Typically, this is GetLength () + 2
+ *
+ * \returns the number of bytes required for an Address in serialized form
+ */
+ uint32_t GetSerializedSize (void) const;
+ /**
+ * Serialize this address in host byte order to a byte buffer
+ *
+ * \param buffer output buffer that gets written with this Address
+ */
+ void Serialize (TagBuffer buffer) const;
+ /**
+ * \param buffer buffer to read address from
+ *
+ * The input address buffer is expected to be in host byte order format.
+ */
+ void Deserialize (TagBuffer buffer);
- ATTRIBUTE_HELPER_HEADER_1 (Address);
private:
friend bool operator == (const Address &a, const Address &b);
friend bool operator < (const Address &a, const Address &b);
@@ -171,7 +195,7 @@
* \brief hold objects of type ns3::Address
*/
-ATTRIBUTE_HELPER_HEADER_2 (Address);
+ATTRIBUTE_HELPER_HEADER (Address);
bool operator == (const Address &a, const Address &b);
bool operator != (const Address &a, const Address &b);
--- a/src/node/application.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/application.cc Wed Jun 04 17:19:32 2008 -0400
@@ -108,15 +108,13 @@
// Private helpers
void Application::ScheduleStart (const Time &startTime)
{
- m_startEvent = Simulator::Schedule(startTime -
- Simulator::Now(),
- &Application::StartApplication, this);
+ m_startEvent = Simulator::Schedule (startTime,
+ &Application::StartApplication, this);
}
void Application::ScheduleStop (const Time &stopTime)
{
- m_stopEvent = Simulator::Schedule(stopTime -
- Simulator::Now(),
+ m_stopEvent = Simulator::Schedule (stopTime,
&Application::StopApplication, this);
}
--- a/src/node/application.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/application.h Wed Jun 04 17:19:32 2008 -0400
@@ -33,7 +33,12 @@
class RandomVariable;
/**
- * \brief The base class for all ns3 applicationes
+ * \ingroup node
+ * \defgroup application Application
+ */
+/**
+ * \ingroup application
+ * \brief The base class for all ns3 applications
*
* Class Application is the base class for all ns3 applications.
* Applications are associated with individual nodes.
@@ -53,13 +58,13 @@
{
public:
static TypeId GetTypeId (void);
- Application();
- virtual ~Application();
+ Application ();
+ virtual ~Application ();
/**
* \brief Specify application start time
- * \param startTime Start time for this application, absolute time,
- * relative to the start of the simulation.
+ * \param startTime Start time for this application,
+ * relative to the current simulation time.
*
* Applications start at various times in the simulation scenario.
* The Start method specifies when the application should be
@@ -67,20 +72,20 @@
* private "StartApplication" method defined below, which is called at the
* time specified, to cause the application to begin.
*/
- void Start(const Time& startTime);
+ void Start (const Time& startTime);
/**
* \brief Specify application start time.
* \param startVariable the random variable to use to pick
- * the real start time as an absolute time, in units of
- * seconds, relative to the start of the simulation.
+ * the real start time as a relative time, in units of
+ * seconds, relative to the current simulation time.
*/
- void Start(const RandomVariable& startVariable);
+ void Start (const RandomVariable& startVariable);
/**
* \brief Specify application stop time
* \param stopTime Stop time for this application, relative to the
- * start of the simulation.
+ * current simulation time.
*
* Once an application has started, it is sometimes useful
* to stop the application. The Stop method specifies when an
@@ -88,20 +93,20 @@
* the private StopApplication method, to be notified when that
* time has come.
*/
- void Stop(const Time& stopTime);
+ void Stop (const Time& stopTime);
/**
* \brief Specify application stop time
* \param stopVariable the random variable to use to pick
* the real stop time, in units of seconds,
- * relative to the start of the simulation.
+ * relative to the current simulation time.
*/
- void Stop(const RandomVariable& stopVariable);
+ void Stop (const RandomVariable& stopVariable);
/**
* \returns the Node to which this Application object is attached.
*/
- Ptr<Node> GetNode() const;
+ Ptr<Node> GetNode () const;
/**
* \param node the node to which this Application object is attached.
--- a/src/node/channel.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/channel.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,11 @@
class NetDevice;
/**
+ * \ingroup node
+ * \defgroup channel Channel
+ */
+/**
+ * \ingroup channel
* \brief Abstract Channel Base Class.
*
* A channel is a logical path over which information flows. The path can
--- a/src/node/drop-tail-queue.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/drop-tail-queue.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,8 @@
class TraceContainer;
/**
+ * \ingroup queue
+ *
* \brief A FIFO packet queue that drops tail-end packets on overflow
*/
class DropTailQueue : public Queue {
--- a/src/node/ethernet-header.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ethernet-header.h Wed Jun 04 17:19:32 2008 -0400
@@ -38,6 +38,8 @@
QINQ /**< Double tagged packet. Header includes two VLAN tags */
};
/**
+ * \ingroup node
+ *
* \brief Packet header for Ethernet
*
* This class can be used to add a header to an ethernet packet that
--- a/src/node/ethernet-trailer.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ethernet-trailer.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,8 @@
class Packet;
/**
+ * \ingroup node
+ *
* \brief Packet trailer for Ethernet
*
* This class can be used to add and verify the FCS at the end of an
--- a/src/node/inet-socket-address.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/inet-socket-address.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,8 @@
/**
+ * \ingroup address
+ *
* \brief an Inet address class
*
* This class is similar to inet_sockaddr in the BSD socket
--- a/src/node/ipv4-address-generator.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ipv4-address-generator.cc Wed Jun 04 17:19:32 2008 -0400
@@ -137,9 +137,9 @@
// We're going to be playing with the actual bits in the network and mask so
// pull them out into ints.
//
- uint32_t maskBits __attribute__((unused)) = mask.GetHostOrder ();
- uint32_t netBits = net.GetHostOrder ();
- uint32_t addrBits = addr.GetHostOrder ();
+ uint32_t maskBits __attribute__((unused)) = mask.Get ();
+ uint32_t netBits = net.Get ();
+ uint32_t addrBits = addr.Get ();
//
// Some quick reasonableness testing.
//
@@ -203,7 +203,7 @@
NS_LOG_FUNCTION_NOARGS ();
uint32_t index = MaskToIndex (mask);
- uint32_t addrBits = addr.GetHostOrder ();
+ uint32_t addrBits = addr.Get ();
NS_ASSERT_MSG (addrBits <= m_netTable[index].addrMax,
"Ipv4AddressGeneratorImpl::InitAddress(): Address overflow");
@@ -258,7 +258,7 @@
{
NS_LOG_FUNCTION_NOARGS ();
- uint32_t addr = address.GetHostOrder ();
+ uint32_t addr = address.Get ();
NS_ASSERT_MSG (addr, "Ipv4AddressGeneratorImpl::Add(): "
"Allocating the broadcast address is not a good idea");
@@ -367,7 +367,7 @@
// We use the number of bits in the mask as the number of bits in the network
// number and as the index into the network number state table.
//
- uint32_t maskBits = mask.GetHostOrder ();
+ uint32_t maskBits = mask.Get ();
for (uint32_t i = 0; i < N_BITS; ++i)
{
--- a/src/node/ipv4-address-generator.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ipv4-address-generator.h Wed Jun 04 17:19:32 2008 -0400
@@ -23,6 +23,12 @@
namespace ns3 {
+/**
+ * \ingroup address
+ *
+ * \brief This generator assigns addresses sequentially from a provided
+ * network address; used in topology code.
+ */
class Ipv4AddressGenerator {
public:
static void Init (const Ipv4Address net, const Ipv4Mask mask,
--- a/src/node/ipv4-address.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ipv4-address.cc Wed Jun 04 17:19:32 2008 -0400
@@ -81,7 +81,7 @@
bool
Ipv4Mask::IsMatch (Ipv4Address a, Ipv4Address b) const
{
- if ((a.GetHostOrder () & m_mask) == (b.GetHostOrder () & m_mask)) {
+ if ((a.Get () & m_mask) == (b.Get () & m_mask)) {
return true;
} else {
return false;
@@ -89,14 +89,14 @@
}
uint32_t
-Ipv4Mask::GetHostOrder (void) const
+Ipv4Mask::Get (void) const
{
return m_mask;
}
void
-Ipv4Mask::SetHostOrder (uint32_t value)
+Ipv4Mask::Set (uint32_t mask)
{
- m_mask = value;
+ m_mask = mask;
}
uint32_t
Ipv4Mask::GetInverse (void) const
@@ -139,6 +139,11 @@
m_address = AsciiToIpv4Host (address);
}
+uint32_t
+Ipv4Address::Get (void) const
+{
+ return m_address;
+}
void
Ipv4Address::Set (uint32_t address)
{
@@ -153,19 +158,19 @@
Ipv4Address
Ipv4Address::CombineMask (Ipv4Mask const &mask) const
{
- return Ipv4Address (GetHostOrder () & mask.GetHostOrder ());
+ return Ipv4Address (Get () & mask.Get ());
}
Ipv4Address
Ipv4Address::GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const
{
- return Ipv4Address (GetHostOrder () | mask.GetInverse ());
+ return Ipv4Address (Get () | mask.GetInverse ());
}
bool
Ipv4Address::IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const
{
- return ( (GetHostOrder () | mask.GetInverse ()) == GetHostOrder () );
+ return ( (Get () | mask.GetInverse ()) == Get () );
}
bool
@@ -184,16 +189,6 @@
return (m_address >= 0xe0000000 && m_address <= 0xefffffff);
}
-uint32_t
-Ipv4Address::GetHostOrder (void) const
-{
- return m_address;
-}
-void
-Ipv4Address::SetHostOrder (uint32_t ip)
-{
- m_address = ip;
-}
void
Ipv4Address::Serialize (uint8_t buf[4]) const
{
@@ -287,7 +282,7 @@
size_t Ipv4AddressHash::operator()(Ipv4Address const &x) const
{
- return x.GetHostOrder ();
+ return x.Get ();
}
std::ostream& operator<< (std::ostream& os, Ipv4Address const& address)
--- a/src/node/ipv4-address.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ipv4-address.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,9 +30,11 @@
class Ipv4Mask;
-/** Ipv4 addresses are stored in host order in
- * this class.
- */
+/**
+ * \ingroup address
+ *
+ * \brief Ipv4 addresses are stored in host order in this class.
+ */
class Ipv4Address {
public:
Ipv4Address ();
@@ -51,7 +53,11 @@
* \param address C-string containing the address as described above
*/
Ipv4Address (char const *address);
-
+ /**
+ * Get the host-order 32-bit IP address
+ * \return the host-order 32-bit IP address
+ */
+ uint32_t Get (void) const;
/**
* input address is in host order.
* \param address The host order 32-bit address
@@ -67,7 +73,6 @@
* \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
@@ -77,17 +82,6 @@
{
return m_address == other.m_address;
}
-
- /**
- * \brief Get the host-order 32-bit IP address
- *
- * Using this method is frowned upon.
- * Please, do _not_ use this method.
- * It is there only for chunk-ipv4.
- * \return the host-order 32-bit IP address
- */
- uint32_t GetHostOrder (void) const;
- void SetHostOrder (uint32_t ip);
/**
* Serialize this address to a 4-byte buffer
*
@@ -142,7 +136,6 @@
static Ipv4Address GetBroadcast (void);
static Ipv4Address GetLoopback (void);
- ATTRIBUTE_HELPER_HEADER_1 (Ipv4Address);
private:
Address ConvertTo (void) const;
static uint8_t GetType (void);
@@ -153,7 +146,11 @@
friend bool operator < (Ipv4Address const &addrA, Ipv4Address const &addrB);
};
-
+/**
+ * \ingroup address
+ *
+ * \brief a class to represent an Ipv4 address mask
+ */
class Ipv4Mask {
public:
Ipv4Mask ();
@@ -163,13 +160,16 @@
bool IsMatch (Ipv4Address a, Ipv4Address b) const;
bool IsEqual (Ipv4Mask other) const;
-
-
- /* Using this method is frowned upon.
- * Please, do _not_ use this method.
+ /**
+ * Get the host-order 32-bit IP mask
+ * \return the host-order 32-bit IP mask
*/
- uint32_t GetHostOrder (void) const;
- void SetHostOrder (uint32_t value);
+ uint32_t Get (void) const;
+ /**
+ * input mask is in host order.
+ * \param mask The host order 32-bit mask
+ */
+ void Set (uint32_t mask);
/**
* \brief Return the inverse mask in host order.
*/
@@ -180,7 +180,6 @@
static Ipv4Mask GetLoopback (void);
static Ipv4Mask GetZero (void);
- ATTRIBUTE_HELPER_HEADER_1 (Ipv4Mask);
private:
uint32_t m_mask;
};
@@ -194,8 +193,8 @@
* \brief hold objects of type ns3::Ipv4Mask
*/
-ATTRIBUTE_HELPER_HEADER_2 (Ipv4Address);
-ATTRIBUTE_HELPER_HEADER_2 (Ipv4Mask);
+ATTRIBUTE_HELPER_HEADER (Ipv4Address);
+ATTRIBUTE_HELPER_HEADER (Ipv4Mask);
std::ostream& operator<< (std::ostream& os, Ipv4Address const& address);
std::ostream& operator<< (std::ostream& os, Ipv4Mask const& mask);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ipv4-header.cc Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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/assert.h"
+#include "ns3/log.h"
+#include "ns3/header.h"
+#include "ipv4-header.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4Header");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (Ipv4Header);
+
+bool Ipv4Header::m_calcChecksum = false;
+
+Ipv4Header::Ipv4Header ()
+ : m_payloadSize (0),
+ m_identification (0),
+ m_tos (0),
+ m_ttl (0),
+ m_protocol (0),
+ m_flags (0),
+ m_fragmentOffset (0),
+ m_goodChecksum (true)
+{}
+
+void
+Ipv4Header::EnableChecksums (void)
+{
+ m_calcChecksum = true;
+}
+
+void
+Ipv4Header::SetPayloadSize (uint16_t size)
+{
+ m_payloadSize = size;
+}
+uint16_t
+Ipv4Header::GetPayloadSize (void) const
+{
+ return m_payloadSize;
+}
+
+uint16_t
+Ipv4Header::GetIdentification (void) const
+{
+ return m_identification;
+}
+void
+Ipv4Header::SetIdentification (uint16_t identification)
+{
+ m_identification = identification;
+}
+
+
+
+void
+Ipv4Header::SetTos (uint8_t tos)
+{
+ m_tos = tos;
+}
+uint8_t
+Ipv4Header::GetTos (void) const
+{
+ return m_tos;
+}
+void
+Ipv4Header::SetMoreFragments (void)
+{
+ m_flags |= MORE_FRAGMENTS;
+}
+void
+Ipv4Header::SetLastFragment (void)
+{
+ m_flags &= ~MORE_FRAGMENTS;
+}
+bool
+Ipv4Header::IsLastFragment (void) const
+{
+ return !(m_flags & MORE_FRAGMENTS);
+}
+
+void
+Ipv4Header::SetDontFragment (void)
+{
+ m_flags |= DONT_FRAGMENT;
+}
+void
+Ipv4Header::SetMayFragment (void)
+{
+ m_flags &= ~DONT_FRAGMENT;
+}
+bool
+Ipv4Header::IsDontFragment (void) const
+{
+ return (m_flags & DONT_FRAGMENT);
+}
+
+void
+Ipv4Header::SetFragmentOffset (uint16_t offset)
+{
+ NS_ASSERT (!(offset & (~0x3fff)));
+ m_fragmentOffset = offset;
+}
+uint16_t
+Ipv4Header::GetFragmentOffset (void) const
+{
+ NS_ASSERT (!(m_fragmentOffset & (~0x3fff)));
+ return m_fragmentOffset;
+}
+
+void
+Ipv4Header::SetTtl (uint8_t ttl)
+{
+ m_ttl = ttl;
+}
+uint8_t
+Ipv4Header::GetTtl (void) const
+{
+ return m_ttl;
+}
+
+uint8_t
+Ipv4Header::GetProtocol (void) const
+{
+ return m_protocol;
+}
+void
+Ipv4Header::SetProtocol (uint8_t protocol)
+{
+ m_protocol = protocol;
+}
+
+void
+Ipv4Header::SetSource (Ipv4Address source)
+{
+ m_source = source;
+}
+Ipv4Address
+Ipv4Header::GetSource (void) const
+{
+ return m_source;
+}
+
+void
+Ipv4Header::SetDestination (Ipv4Address dst)
+{
+ m_destination = dst;
+}
+Ipv4Address
+Ipv4Header::GetDestination (void) const
+{
+ return m_destination;
+}
+
+
+bool
+Ipv4Header::IsChecksumOk (void) const
+{
+ return m_goodChecksum;
+}
+
+
+TypeId
+Ipv4Header::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::Ipv4Header")
+ .SetParent<Header> ()
+ .AddConstructor<Ipv4Header> ()
+ ;
+ return tid;
+}
+TypeId
+Ipv4Header::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+void
+Ipv4Header::Print (std::ostream &os) const
+{
+ // ipv4, right ?
+ 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
+{
+ return 5 * 4;
+}
+
+void
+Ipv4Header::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ uint8_t verIhl = (4 << 4) | (5);
+ i.WriteU8 (verIhl);
+ i.WriteU8 (m_tos);
+ i.WriteHtonU16 (m_payloadSize + 5*4);
+ i.WriteHtonU16 (m_identification);
+ uint32_t fragmentOffset = m_fragmentOffset / 8;
+ uint8_t flagsFrag = (fragmentOffset >> 8) & 0x1f;
+ if (m_flags & DONT_FRAGMENT)
+ {
+ flagsFrag |= (1<<6);
+ }
+ if (m_flags & MORE_FRAGMENTS)
+ {
+ flagsFrag |= (1<<5);
+ }
+ i.WriteU8 (flagsFrag);
+ uint8_t frag = fragmentOffset & 0xff;
+ i.WriteU8 (frag);
+ i.WriteU8 (m_ttl);
+ i.WriteU8 (m_protocol);
+ i.WriteHtonU16 (0);
+ i.WriteHtonU32 (m_source.Get ());
+ i.WriteHtonU32 (m_destination.Get ());
+
+ if (m_calcChecksum)
+ {
+#if 0
+ // XXX we need to add Buffer::Iterator::PeekData method
+ uint8_t *data = start.PeekData ();
+ uint16_t checksum = UtilsChecksumCalculate (0, data, GetSize ());
+ checksum = UtilsChecksumComplete (checksum);
+ NS_LOG_LOGIC ("checksum=" <<checksum);
+ i = start;
+ i.Next (10);
+ i.WriteU16 (checksum);
+#endif
+ }
+}
+uint32_t
+Ipv4Header::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ uint8_t verIhl = i.ReadU8 ();
+ uint8_t ihl = verIhl & 0x0f;
+ uint16_t headerSize = ihl * 4;
+ NS_ASSERT ((verIhl >> 4) == 4);
+ m_tos = i.ReadU8 ();
+ uint16_t size = i.ReadNtohU16 ();
+ m_payloadSize = size - headerSize;
+ m_identification = i.ReadNtohU16 ();
+ uint8_t flags = i.ReadU8 ();
+ m_flags = 0;
+ if (flags & (1<<6))
+ {
+ m_flags |= DONT_FRAGMENT;
+ }
+ if (flags & (1<<5))
+ {
+ m_flags |= MORE_FRAGMENTS;
+ }
+ i.Prev ();
+ m_fragmentOffset = i.ReadU8 () & 0x1f;
+ m_fragmentOffset <<= 8;
+ m_fragmentOffset |= i.ReadU8 ();
+ m_fragmentOffset <<= 3;
+ m_ttl = i.ReadU8 ();
+ m_protocol = i.ReadU8 ();
+ i.Next (2); // checksum
+ m_source.Set (i.ReadNtohU32 ());
+ m_destination.Set (i.ReadNtohU32 ());
+
+ if (m_calcChecksum)
+ {
+#if 0
+ uint8_t *data = start.PeekData ();
+ uint16_t localChecksum = UtilsChecksumCalculate (0, data, headerSize);
+ if (localChecksum == 0xffff)
+ {
+ m_goodChecksum = true;
+ }
+ else
+ {
+ m_goodChecksum = false;
+ }
+#endif
+ }
+ return GetSerializedSize ();
+}
+
+}; // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ipv4-header.h Wed Jun 04 17:19:32 2008 -0400
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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 IPV4_HEADER_H
+#define IPV4_HEADER_H
+
+#include "ns3/header.h"
+#include "ns3/ipv4-address.h"
+
+namespace ns3 {
+/**
+ * \brief Packet header for IPv4
+ */
+class Ipv4Header : public Header
+{
+public:
+ /**
+ * \brief Construct a null IPv4 header
+ */
+ Ipv4Header ();
+ /**
+ * \brief Enable checksum calculation for IP (XXX currently has no effect)
+ */
+ static void EnableChecksums (void);
+ /**
+ * \param size the size of the payload in bytes
+ */
+ void SetPayloadSize (uint16_t size);
+ /**
+ * \param identification the Identification field of IPv4 packets.
+ *
+ * By default, set to zero.
+ */
+ void SetIdentification (uint16_t identification);
+ /**
+ * \param tos the 8 bits of Ipv4 TOS.
+ */
+ void SetTos (uint8_t tos);
+ /**
+ * This packet is not the last packet of a fragmented ipv4 packet.
+ */
+ void SetMoreFragments (void);
+ /**
+ * This packet is the last packet of a fragmented ipv4 packet.
+ */
+ void SetLastFragment (void);
+ /**
+ * Don't fragment this packet: if you need to anyway, drop it.
+ */
+ void SetDontFragment (void);
+ /**
+ * If you need to fragment this packet, you can do it.
+ */
+ void SetMayFragment (void);
+ /**
+ * \param offset the ipv4 fragment offset
+ */
+ void SetFragmentOffset (uint16_t offset);
+ /**
+ * \param ttl the ipv4 TTL
+ */
+ void SetTtl (uint8_t ttl);
+ /**
+ * \param num the ipv4 protocol field
+ */
+ void SetProtocol (uint8_t num);
+ /**
+ * \param source the source of this packet
+ */
+ void SetSource (Ipv4Address source);
+ /**
+ * \param destination the destination of this packet.
+ */
+ void SetDestination (Ipv4Address destination);
+ /**
+ * \returns the size of the payload in bytes
+ */
+ uint16_t GetPayloadSize (void) const;
+ /**
+ * \returns the identification field of this packet.
+ */
+ uint16_t GetIdentification (void) const;
+ /**
+ * \returns the TOS field of this packet.
+ */
+ uint8_t GetTos (void) const;
+ /**
+ * \returns true if this is the last fragment of a packet, false otherwise.
+ */
+ bool IsLastFragment (void) const;
+ /**
+ * \returns true if this is this packet can be fragmented.
+ */
+ bool IsDontFragment (void) const;
+ /**
+ * \returns the offset of this fragment.
+ */
+ uint16_t GetFragmentOffset (void) const;
+ /**
+ * \returns the TTL field of this packet
+ */
+ uint8_t GetTtl (void) const;
+ /**
+ * \returns the protocol field of this packet
+ */
+ uint8_t GetProtocol (void) const;
+ /**
+ * \returns the source address of this packet
+ */
+ Ipv4Address GetSource (void) const;
+ /**
+ * \returns the destination address of this packet
+ */
+ Ipv4Address GetDestination (void) const;
+
+ /**
+ * \returns true if the upv4 checksum is correct, false otherwise.
+ *
+ * If Ipv4Header::EnableChecksums has not been called prior to
+ * creating this packet, this method will always return true.
+ */
+ bool IsChecksumOk (void) const;
+
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual void Print (std::ostream &os) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (Buffer::Iterator start) const;
+ virtual uint32_t Deserialize (Buffer::Iterator start);
+private:
+
+ enum FlagsE {
+ DONT_FRAGMENT = (1<<0),
+ MORE_FRAGMENTS = (1<<1)
+ };
+
+ static bool m_calcChecksum;
+
+ uint16_t m_payloadSize;
+ uint16_t m_identification;
+ uint32_t m_tos : 8;
+ uint32_t m_ttl : 8;
+ uint32_t m_protocol : 8;
+ uint32_t m_flags : 3;
+ uint16_t m_fragmentOffset : 13;
+ Ipv4Address m_source;
+ Ipv4Address m_destination;
+ bool m_goodChecksum;
+};
+
+} // namespace ns3
+
+
+#endif /* IPV4_HEADER_H */
--- a/src/node/ipv4-route.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ipv4-route.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,7 @@
namespace ns3 {
/**
+ * \ingroup ipv4
* \brief A record of an IPv4 route
*/
class Ipv4Route {
@@ -106,6 +107,7 @@
std::ostream& operator<< (std::ostream& os, Ipv4Route const& route);
/**
+ * \ingroup ipv4
* \brief A record of an IPv4 multicast route
*/
class Ipv4MulticastRoute {
--- a/src/node/ipv4.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/ipv4.h Wed Jun 04 17:19:32 2008 -0400
@@ -32,10 +32,16 @@
class NetDevice;
class Packet;
class Ipv4Route;
-class Ipv4Header; // FIXME: ipv4-header.h needs to move from module
- // "internet-node" to module "node"
+class Ipv4Header;
/**
+ * \ingroup node
+ * \defgroup ipv4 Ipv4
+ */
+
+/**
+ * \ingroup ipv4
+ *
* \brief Base class for IPv4 routing protocols.
*
* This class represents the interface between the IPv4 routing core
--- a/src/node/llc-snap-header.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/llc-snap-header.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,11 @@
namespace ns3 {
+/**
+ * \ingroup node
+ *
+ * \brief Header for the LLC/SNAP encapsulation
+ */
class LlcSnapHeader : public Header
{
public:
--- a/src/node/mac48-address.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/mac48-address.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,6 +30,8 @@
class Address;
/**
+ * \ingroup address
+ *
* \brief an EUI-48 address
*
* This class can contain 48 bit IEEE addresses.
@@ -96,7 +98,6 @@
*/
static Mac48Address GetBroadcast (void);
- ATTRIBUTE_HELPER_HEADER_1 (Mac48Address);
private:
/**
* \returns a new Address instance
@@ -117,7 +118,7 @@
* \brief hold objects of type ns3::Mac48Address
*/
-ATTRIBUTE_HELPER_HEADER_2 (Mac48Address);
+ATTRIBUTE_HELPER_HEADER (Mac48Address);
bool operator == (const Mac48Address &a, const Mac48Address &b);
bool operator != (const Mac48Address &a, const Mac48Address &b);
--- a/src/node/mac64-address.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/mac64-address.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,8 @@
class Address;
/**
+ * \ingroup address
+ *
* \brief an EUI-64 address
*
* This class can contain 64 bit IEEE addresses.
--- a/src/node/net-device.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/net-device.h Wed Jun 04 17:19:32 2008 -0400
@@ -32,11 +32,16 @@
namespace ns3 {
class Node;
-class TraceContext;
class Channel;
class Packet;
/**
+ * \ingroup node
+ * \defgroup netdevice NetDevice
+ */
+/**
+ * \ingroup netdevice
+ *
* \brief Network layer to device interface
*
* This interface defines the API which the IP and ARP
--- a/src/node/node-list.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/node-list.h Wed Jun 04 17:19:32 2008 -0400
@@ -31,6 +31,8 @@
/**
+ * \ingroup node
+ *
* \brief the list of simulation nodes.
*
* Every Node created is automatically added to this list.
--- a/src/node/node.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/node.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,7 +29,6 @@
namespace ns3 {
-class TraceContext;
class NetDevice;
class Application;
class Packet;
@@ -37,6 +36,8 @@
/**
+ * \ingroup node
+ *
* \brief A network Node.
*
* This class holds together:
@@ -169,9 +170,6 @@
* \param device the device added to this Node.
*
* This method is invoked whenever a user calls Node::AddDevice.
- * Subclasses are expected to call NetDevice::SetReceiveCallback
- * at this point to setup the node's receive function for
- * the NetDevice packets.
*/
virtual void NotifyDeviceAdded (Ptr<NetDevice> device);
--- a/src/node/packet-socket-address.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/packet-socket-address.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,6 +30,11 @@
class NetDevice;
+/**
+ * \ingroup address
+ *
+ * \brief an address for a packet socket
+ */
class PacketSocketAddress
{
public:
--- a/src/node/packet-socket-factory.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/packet-socket-factory.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,8 @@
class Socket;
/**
+ * \ingroup 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.
*/
--- a/src/node/packet-socket.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/packet-socket.cc Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,8 @@
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
+#include <algorithm>
+
NS_LOG_COMPONENT_DEFINE ("PacketSocket");
namespace ns3 {
@@ -220,6 +222,12 @@
NotifyConnectionFailed ();
return -1;
}
+int
+PacketSocket::Listen(uint32_t queueLimit)
+{
+ m_errno = Socket::ERROR_OPNOTSUPP;
+ return -1;
+}
int
PacketSocket::Send (Ptr<Packet> p)
@@ -234,11 +242,35 @@
return SendTo (p, m_destAddr);
}
-// XXX must limit it to interface MTU
+uint32_t
+PacketSocket::GetMinMtu (PacketSocketAddress ad) const
+{
+ if (ad.IsSingleDevice ())
+ {
+ Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
+ return device->GetMtu ();
+ }
+ else
+ {
+ uint32_t minMtu = 0xffff;
+ for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
+ {
+ Ptr<NetDevice> device = m_node->GetDevice (i);
+ minMtu = std::min (minMtu, (uint32_t)device->GetMtu ());
+ }
+ return minMtu;
+ }
+}
+
uint32_t
PacketSocket::GetTxAvailable (void) const
{
- // Use 65536 for now
+ if (m_state == STATE_CONNECTED)
+ {
+ PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (m_destAddr);
+ return GetMinMtu (ad);
+ }
+ // If we are not connected, we return a 'safe' value by default.
return 0xffff;
}
@@ -253,13 +285,6 @@
m_errno = ERROR_BADF;
return -1;
}
- if (m_state == STATE_OPEN)
- {
- // XXX should return another error here.
- NS_LOG_LOGIC ("ERROR_INVAL");
- m_errno = ERROR_INVAL;
- return -1;
- }
if (m_shutdownSend)
{
NS_LOG_LOGIC ("ERROR_SHUTDOWN");
@@ -272,12 +297,12 @@
m_errno = ERROR_AFNOSUPPORT;
return -1;
}
- if (p->GetSize () > GetTxAvailable ())
+ ad = PacketSocketAddress::ConvertFrom (address);
+ if (p->GetSize () > GetMinMtu (ad))
{
m_errno = ERROR_MSGSIZE;
return -1;
}
- ad = PacketSocketAddress::ConvertFrom (address);
bool error = false;
Address dest = ad.GetPhysicalAddress ();
--- a/src/node/packet-socket.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/packet-socket.h Wed Jun 04 17:19:32 2008 -0400
@@ -36,6 +36,8 @@
class PacketSocketAddress;
/**
+ * \ingroup socket
+ *
* \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
@@ -69,6 +71,8 @@
* The fields "physical address", device, and protocol are filled.
*
* - Accept: not allowed
+ *
+ * - Listen: returns -1 (OPNOTSUPP)
*/
class PacketSocket : public Socket
{
@@ -88,6 +92,7 @@
virtual int ShutdownSend (void);
virtual int ShutdownRecv (void);
virtual int Connect(const Address &address);
+ virtual int Listen(uint32_t queueLimit);
virtual int Send (Ptr<Packet> p);
virtual uint32_t GetTxAvailable (void) const;
@@ -100,6 +105,7 @@
void ForwardUp (Ptr<NetDevice> device, Ptr<Packet> packet,
uint16_t protocol, const Address &from);
int DoBind (const PacketSocketAddress &address);
+ uint32_t GetMinMtu (PacketSocketAddress ad) const;
virtual void DoDispose (void);
enum State {
--- a/src/node/queue.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/queue.cc Wed Jun 04 17:19:32 2008 -0400
@@ -100,8 +100,11 @@
void
Queue::DequeueAll (void)
{
- NS_LOG_FUNCTION_NOARGS ();
- NS_ASSERT_MSG (0, "Don't know what to do with dequeued packets!");
+ NS_LOG_FUNCTION (this);
+ while (!IsEmpty ())
+ {
+ Dequeue ();
+ }
}
Ptr<Packet>
--- a/src/node/queue.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/queue.h Wed Jun 04 17:19:32 2008 -0400
@@ -33,6 +33,11 @@
namespace ns3 {
/**
+ * \ingroup node
+ * \defgroup queue Queue
+ */
+/**
+ * \ingroup queue
* \brief Abstract base class for packet Queues
*
* This class defines the base APIs for packet queues in the ns-3 system
@@ -66,7 +71,7 @@
Ptr<Packet> Peek (void) const;
/**
- * XXX Doesn't do anything right now, think its supposed to flush the queue
+ * Flush the queue.
*/
void DequeueAll (void);
/**
--- a/src/node/simple-channel.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/simple-channel.h Wed Jun 04 17:19:32 2008 -0400
@@ -10,6 +10,10 @@
class SimpleNetDevice;
class Packet;
+/**
+ * \ingroup channel
+ * \brief A simple channel, for simple things and testing
+ */
class SimpleChannel : public Channel
{
public:
--- a/src/node/simple-net-device.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/simple-net-device.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,6 +30,11 @@
class SimpleChannel;
class Node;
+/**
+ * \ingroup netdevice
+ *
+ * \brief simple net device for simple things and testing
+ */
class SimpleNetDevice : public NetDevice
{
public:
--- a/src/node/socket-defaults.cc Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#include "socket-defaults.h"
-#include "ns3/uinteger.h"
-
-namespace ns3 {
-
-NS_OBJECT_ENSURE_REGISTERED (SocketDefaults);
-
-TypeId SocketDefaults::GetTypeId (void)
-{
- static TypeId tid = TypeId ("ns3::SocketDefaults")
- .SetParent<Object> ()
- .AddAttribute ("DefaultSndBufLimit",
- "Default maximum receive buffer size (bytes)",
- UintegerValue (0xffffffffl),
- MakeUintegerAccessor (&SocketDefaults::m_defaultSndBufLimit),
- MakeUintegerChecker<uint32_t> ())
- .AddAttribute ("DefaultRcvBufLimit",
- "Default maximum receive buffer size (bytes)",
- UintegerValue (0xffffffffl),
- MakeUintegerAccessor (&SocketDefaults::m_defaultRcvBufLimit),
- MakeUintegerChecker<uint32_t> ())
- ;
- return tid;
-}
-
-} // namespace ns3
--- a/src/node/socket-defaults.h Fri May 30 15:31:50 2008 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +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
- */
-#ifndef SOCKET_DEFAULTS_H
-#define SOCKET_DEFAULTS_H
-
-#include "ns3/object.h"
-
-namespace ns3 {
-
-/**
- * \brief Object to hold socket option defaults
- *
- * This class can be aggregated to a Node and can be used to store
- * socket defaults for a Node.
- *
- */
-class SocketDefaults : public Object
-{
-public:
- static TypeId GetTypeId (void);
-
-private:
- uint32_t m_defaultSndBufLimit;
- uint32_t m_defaultRcvBufLimit;
-};
-
-} // namespace ns3
-
-#endif /* SOCKET_DEFAULTS_H */
--- a/src/node/socket-factory.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/socket-factory.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,8 @@
class Socket;
/**
+ * \ingroup socket
+ *
* \brief Object to create transport layer instances that provide a
* socket API to applications.
*
--- a/src/node/socket.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/node/socket.cc Wed Jun 04 17:19:32 2008 -0400
@@ -30,19 +30,6 @@
namespace ns3 {
-#if 0
-TypeId
-Socket::GetTypeId (void)
-{
- static TypeId tid = TypeId ("ns3::Socket")
- .SetParent<Object> ()
- .AddConstructor<Socket> ()
- ;
- return tid;
-}
-
-#endif
-
Socket::Socket (void)
{
NS_LOG_FUNCTION_NOARGS ();
@@ -123,11 +110,6 @@
m_receivedData = receivedData;
}
-int Socket::Listen (uint32_t queueLimit)
-{
- return 0; //XXX the base class version does nothing
-}
-
void
Socket::NotifyCloseUnblocks (void)
{
@@ -138,6 +120,11 @@
}
}
+int Socket::Listen (uint32_t queueLimit)
+{
+ return 0; //XXX the base class version does nothing
+}
+
int Socket::Send (const uint8_t* buf, uint32_t size)
{
NS_LOG_FUNCTION_NOARGS ();
@@ -159,6 +146,14 @@
return Recv (std::numeric_limits<uint32_t>::max(), 0);
}
+int
+Socket::Recv (uint8_t* buf, uint32_t size, uint32_t flags)
+{
+ Ptr<Packet> p = Recv (size, flags); // read up to "size" bytes
+ memcpy (buf, p->PeekData (), p->GetSize());
+ return p->GetSize ();
+}
+
int Socket::SendTo (const uint8_t* buf, uint32_t size, const Address &address)
{
NS_LOG_FUNCTION_NOARGS ();
@@ -282,42 +277,14 @@
}
}
+/***************************************************************
+ * Socket Tags
+ ***************************************************************/
+
SocketRxAddressTag::SocketRxAddressTag ()
{
}
-uint32_t
-SocketRxAddressTag::GetUid (void)
-{
- static uint32_t uid = ns3::Tag::AllocateUid<SocketRxAddressTag> ("SocketRxAddressTag.ns3");
- return uid;
-}
-
-void
-SocketRxAddressTag::Print (std::ostream &os) const
-{
- os << "address="<< m_address;
-}
-
-uint32_t
-SocketRxAddressTag::GetSerializedSize (void) const
-{
- return 0;
-}
-
-void
-SocketRxAddressTag::Serialize (Buffer::Iterator i) const
-{
- // for local use in stack only
-}
-
-uint32_t
-SocketRxAddressTag::Deserialize (Buffer::Iterator i)
-{
- // for local use in stack only
- return 0;
-}
-
void
SocketRxAddressTag::SetAddress (Address addr)
{
@@ -330,40 +297,44 @@
return m_address;
}
-SocketIpTtlTag::SocketIpTtlTag ()
+
+TypeId
+SocketRxAddressTag::GetTypeId (void)
{
+ static TypeId tid = TypeId ("ns3::SocketRxAddressTag")
+ .SetParent<Tag> ()
+ .AddConstructor<SocketRxAddressTag> ()
+ ;
+ return tid;
}
-
-uint32_t
-SocketIpTtlTag::GetUid (void)
+TypeId
+SocketRxAddressTag::GetInstanceTypeId (void) const
{
- static uint32_t uid = ns3::Tag::AllocateUid<SocketIpTtlTag> ("SocketIpTtlTag.ns3");
- return uid;
+ return GetTypeId ();
+}
+uint32_t
+SocketRxAddressTag::GetSerializedSize (void) const
+{
+ return m_address.GetSerializedSize ();
}
-
+void
+SocketRxAddressTag::Serialize (TagBuffer i) const
+{
+ m_address.Serialize (i);
+}
void
-SocketIpTtlTag::Print (std::ostream &os) const
+SocketRxAddressTag::Deserialize (TagBuffer i)
{
- os << "ttl="<< m_ttl;
+ m_address.Deserialize (i);
+}
+void
+SocketRxAddressTag::Print (std::ostream &os) const
+{
+ os << "address=" << m_address;
}
-uint32_t
-SocketIpTtlTag::GetSerializedSize (void) const
-{
- return 0;
-}
-
-void
-SocketIpTtlTag::Serialize (Buffer::Iterator i) const
+SocketIpTtlTag::SocketIpTtlTag ()
{
- // for local use in stack only
-}
-
-uint32_t
-SocketIpTtlTag::Deserialize (Buffer::Iterator i)
-{
- // for local use in stack only
- return 0;
}
void
@@ -378,4 +349,41 @@
return m_ttl;
}
+
+TypeId
+SocketIpTtlTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::SocketIpTtlTag")
+ .SetParent<Tag> ()
+ .AddConstructor<SocketIpTtlTag> ()
+ ;
+ return tid;
+}
+TypeId
+SocketIpTtlTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+SocketIpTtlTag::GetSerializedSize (void) const
+{
+ return 1;
+}
+void
+SocketIpTtlTag::Serialize (TagBuffer i) const
+{
+ i.WriteU8 (m_ttl);
+}
+void
+SocketIpTtlTag::Deserialize (TagBuffer i)
+{
+ m_ttl = i.ReadU8 ();
+}
+void
+SocketIpTtlTag::Print (std::ostream &os) const
+{
+ os << "Ttl=" << (uint32_t) m_ttl;
+}
+
}//namespace ns3
--- a/src/node/socket.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/socket.h Wed Jun 04 17:19:32 2008 -0400
@@ -37,19 +37,32 @@
class Packet;
/**
- * \brief Define a Socket API based on the BSD Socket API.
+ * \ingroup node
+ * \defgroup socket Socket
+ */
+
+/**
+ * \brief A low-level Socket API based loosely on the BSD Socket API.
+ * \ingroup socket
*
- * In contrast to the original BSD socket API, this API is asynchronous:
- * it does not contain blocking calls. It also uses class ns3::Packet
- * as a fancy byte buffer, allowing data to be passed across the API
- * using an ns3::Packet instead of a raw data pointer. Other than that,
- * it tries to stick to the BSD API to make it easier for those who know
- * the BSD API to use this API.
+ * A few things to keep in mind about this type of socket:
+ * - it uses ns-3 API constructs such as class ns3::Address instead of
+ * C-style structs
+ * - in contrast to the original BSD socket API, this API is asynchronous:
+ * it does not contain blocking calls. Sending and receiving operations
+ * must make use of the callbacks provided.
+ * - It also uses class ns3::Packet as a fancy byte buffer, allowing
+ * data to be passed across the API using an ns-3 Packet instead of
+ * a raw data pointer.
+ * - Not all of the full POSIX sockets API is supported
+ *
+ * Other than that, it tries to stick to the BSD API to make it
+ * easier for those who know the BSD API to use this API.
+ * More details are provided in the ns-3 tutorial.
*/
class Socket : public Object
{
public:
-// static TypeId GetTypeId (void);
Socket (void);
virtual ~Socket (void);
@@ -224,9 +237,9 @@
/**
* \brief Listen for incoming connections.
* \param queueLimit maximum number of incoming request to queue
- * \returns XXX an error code
+ * \returns 0 on success, -1 on error (in which case errno is set).
*/
- virtual int Listen (uint32_t queueLimit);
+ virtual int Listen (uint32_t queueLimit) = 0;
/**
* \brief Send data (or dummy data) to the remote host
@@ -331,6 +344,19 @@
*/
Ptr<Packet> Recv (void);
/**
+ * \brief Recv data (or dummy data) from the remote host
+ * \param buf A pointer to a raw byte buffer to write the data to.
+ * If the underlying packet was carring null (fake) data, this buffer
+ * will be zeroed up to the length specified by the return value.
+ * \param size Number of bytes (at most) to copy to buf
+ * \param flags any flags to pass to the socket
+ * \returns number of bytes copied into buf
+ *
+ * This is provided so as to have an API which is closer in appearance
+ * to that of real network or BSD sockets.
+ */
+ int Recv (uint8_t* buf, uint32_t size, uint32_t flags);
+ /**
* Return number of bytes which can be returned from one or
* multiple calls to Recv.
* Must be possible to call this method from the Recv callback.
@@ -372,14 +398,16 @@
{
public:
SocketRxAddressTag ();
- static uint32_t GetUid (void);
- void Print (std::ostream &os) const;
- uint32_t GetSerializedSize (void) const;
- void Serialize (Buffer::Iterator i) const;
- uint32_t Deserialize (Buffer::Iterator i);
-
void SetAddress (Address addr);
Address GetAddress (void) const;
+
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
+
private:
Address m_address;
};
@@ -392,14 +420,16 @@
{
public:
SocketIpTtlTag ();
- static uint32_t GetUid (void);
- void Print (std::ostream &os) const;
- uint32_t GetSerializedSize (void) const;
- void Serialize (Buffer::Iterator i) const;
- uint32_t Deserialize (Buffer::Iterator i);
-
void SetTtl (uint8_t ttl);
uint8_t GetTtl (void) const;
+
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer i) const;
+ virtual void Deserialize (TagBuffer i);
+ virtual void Print (std::ostream &os) const;
+
private:
uint8_t m_ttl;
};
--- a/src/node/tcp-socket-factory.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/tcp-socket-factory.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,8 @@
class Socket;
/**
+ * \ingroup socket
+ *
* \brief API to create TCP socket instances
*
* This abstract class defines the API for TCP sockets.
--- a/src/node/tcp-socket.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/tcp-socket.h Wed Jun 04 17:19:32 2008 -0400
@@ -36,6 +36,8 @@
class Packet;
/**
+ * \ingroup socket
+ *
* \brief (abstract) base class of all TcpSockets
*
* This class exists solely for hosting TcpSocket attributes that can
--- a/src/node/udp-socket-factory.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/udp-socket-factory.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,6 +27,8 @@
class Socket;
/**
+ * \ingroup socket
+ *
* \brief API to create UDP socket instances
*
* This abstract class defines the API for UDP socket factory.
--- a/src/node/udp-socket.h Fri May 30 15:31:50 2008 -0400
+++ b/src/node/udp-socket.h Wed Jun 04 17:19:32 2008 -0400
@@ -35,6 +35,8 @@
class Packet;
/**
+ * \ingroup socket
+ *
* \brief (abstract) base class of all UdpSockets
*
* This class exists solely for hosting UdpSocket attributes that can
--- a/src/node/wscript Fri May 30 15:31:50 2008 -0400
+++ b/src/node/wscript Wed Jun 04 17:19:32 2008 -0400
@@ -11,6 +11,7 @@
'node.cc',
'ipv4-address.cc',
'ipv4-address-generator.cc',
+ 'ipv4-header.cc',
'net-device.cc',
'address-utils.cc',
'llc-snap-header.cc',
@@ -46,6 +47,7 @@
'node.h',
'ipv4-address.h',
'ipv4-address-generator.h',
+ 'ipv4-header.h',
'net-device.h',
'address-utils.h',
'ipv4-route.h',
--- a/src/routing/global-routing/global-route-manager-impl.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/routing/global-routing/global-route-manager-impl.cc Wed Jun 04 17:19:32 2008 -0400
@@ -1275,7 +1275,7 @@
// 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)
+ for (uint32_t j = 0; j < nLinkRecords; ++j)
{
//
// We are only concerned about point-to-point links
--- a/src/routing/global-routing/global-router-interface.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/routing/global-routing/global-router-interface.cc Wed Jun 04 17:19:32 2008 -0400
@@ -584,7 +584,7 @@
plr->SetLinkId (addrLocal.CombineMask(maskLocal));
// Link Data is network mask; convert to Ipv4Address
Ipv4Address maskLocalAddr;
- maskLocalAddr.Set(maskLocal.GetHostOrder ());
+ maskLocalAddr.Set(maskLocal.Get ());
plr->SetLinkData (maskLocalAddr);
plr->SetMetric (metricLocal);
pLSA->AddLinkRecord(plr);
@@ -689,7 +689,7 @@
plr = new GlobalRoutingLinkRecord;
plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
plr->SetLinkId (addrRemote);
- plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown
+ plr->SetLinkData (Ipv4Address(maskRemote.Get())); // Frown
plr->SetMetric (metricLocal);
pLSA->AddLinkRecord (plr);
plr = 0;
--- a/src/routing/olsr/olsr-agent-impl.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/routing/olsr/olsr-agent-impl.cc Wed Jun 04 17:19:32 2008 -0400
@@ -312,7 +312,8 @@
receivedPacket = socket->Recv ();
SocketRxAddressTag tag;
- bool found = receivedPacket->PeekTag (tag);
+ bool found;
+ found = receivedPacket->FindFirstMatchingTag (tag);
NS_ASSERT (found);
Address sourceAddress = tag.GetAddress ();
--- a/src/routing/olsr/olsr-header.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/routing/olsr/olsr-header.cc Wed Jun 04 17:19:32 2008 -0400
@@ -211,7 +211,7 @@
i.WriteU8 (m_messageType);
i.WriteU8 (m_vTime);
i.WriteHtonU16 (GetSerializedSize ());
- i.WriteHtonU32 (m_originatorAddress.GetHostOrder ());
+ i.WriteHtonU32 (m_originatorAddress.Get ());
i.WriteU8 (m_timeToLive);
i.WriteU8 (m_hopCount);
i.WriteHtonU16 (m_messageSequenceNumber);
@@ -293,7 +293,7 @@
for (std::vector<Ipv4Address>::const_iterator iter = this->interfaceAddresses.begin ();
iter != this->interfaceAddresses.end (); iter++)
{
- i.WriteHtonU32 (iter->GetHostOrder ());
+ i.WriteHtonU32 (iter->Get ());
}
}
@@ -364,7 +364,7 @@
for (std::vector<Ipv4Address>::const_iterator neigh_iter = lm.neighborInterfaceAddresses.begin ();
neigh_iter != lm.neighborInterfaceAddresses.end (); neigh_iter++)
{
- i.WriteHtonU32 (neigh_iter->GetHostOrder ());
+ i.WriteHtonU32 (neigh_iter->Get ());
}
}
}
@@ -432,7 +432,7 @@
for (std::vector<Ipv4Address>::const_iterator iter = this->neighborAddresses.begin ();
iter != this->neighborAddresses.end (); iter++)
{
- i.WriteHtonU32 (iter->GetHostOrder ());
+ i.WriteHtonU32 (iter->Get ());
}
}
@@ -478,8 +478,8 @@
for (size_t n = 0; n < this->associations.size (); ++n)
{
- i.WriteHtonU32 (this->associations[n].address.GetHostOrder ());
- i.WriteHtonU32 (this->associations[n].mask.GetHostOrder ());
+ i.WriteHtonU32 (this->associations[n].address.Get ());
+ i.WriteHtonU32 (this->associations[n].mask.Get ());
}
}
--- a/src/simulator/event-id.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/event-id.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,11 +29,24 @@
class EventImpl;
/**
+ * \ingroup simulator
* \brief an identifier for simulation events.
+ *
+ * Each EventId identifies a unique event scheduled with one
+ * of the many Simulator::Schedule methods. This EventId can
+ * be used to Cancel or Remove events after they are scheduled
+ * with Simulator::Cancel or Simulator::Remove.
+ *
+ * The important thing to remember about this class is that
+ * every variable of this type is _always_ in a valid state,
+ * even when it has not been assigned an EventId coming from a Schedule
+ * method: calling Cancel, IsRunning, IsExpired or passing around
+ * instances of this object will not result in crashes or memory leaks.
*/
class EventId {
public:
EventId ();
+ // internal.
EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid);
/**
* This method is syntactic sugar for the ns3::Simulator::cancel
@@ -46,6 +59,11 @@
* \returns true if the event has expired, false otherwise.
*/
bool IsExpired (void) const;
+ /**
+ * This method is syntactic sugar for the ns3::Simulator::isExpired
+ * method.
+ * \returns true if the event has not expired, false otherwise.
+ */
bool IsRunning (void) const;
public:
/* The following methods are semi-private
--- a/src/simulator/event-impl.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/event-impl.h Wed Jun 04 17:19:32 2008 -0400
@@ -24,6 +24,17 @@
namespace ns3 {
+/**
+ * \ingroup simulator
+ * \brief a simulation event
+ *
+ * Each subclass of this base class represents a simulation event. The
+ * EventImpl::Invoke method will be invoked by the simulation engine
+ * when the time associated to this event expires. This class is
+ * obviously (there are Ref and Unref methods) reference-counted and
+ * most subclasses are usually created by one of the many Simulator::Schedule
+ * methods.
+ */
class EventImpl
{
public:
@@ -31,8 +42,21 @@
inline void Ref (void) const;
inline void Unref (void) const;
virtual ~EventImpl () = 0;
+ /**
+ * Called by the simulation engine to notify the event that it has expired.
+ */
void Invoke (void);
+ /**
+ * Marks the event as 'canceled'. The event will not be removed from
+ * the event list but the simulation engine will check its canceled status
+ * before calling Invoke.
+ */
void Cancel (void);
+ /**
+ * \returns true if the event has been canceled.
+ *
+ * Invoked by the simulation engine before calling Invoke.
+ */
bool IsCancelled (void);
protected:
virtual void Notify (void) = 0;
--- a/src/simulator/heap-scheduler.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/heap-scheduler.cc Wed Jun 04 17:19:32 2008 -0400
@@ -18,17 +18,6 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*
- * This code started as a c++ translation of a java-based code written in 2005
- * to implement a heap sort. Which explains the "Copyright Mathieu Lacage" at the
- * top of this file.
- *
- * What is smart about this code ?
- * - it does not use the index 0 in the array to avoid having to convert
- * C-style array indexes (which start at zero) and heap-style indexes
- * (which start at 1). This is why _all_ indexes start at 1, and that
- * the index of the root is 1.
- * - It uses a slightly non-standard while loop for top-down heapify
- * to move one if statement out of the loop.
*/
#include "heap-scheduler.h"
--- a/src/simulator/heap-scheduler.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/heap-scheduler.h Wed Jun 04 17:19:32 2008 -0400
@@ -29,6 +29,23 @@
class EventHolder;
+/**
+ * \ingroup scheduler
+ * \brief a binary heap event scheduler
+ *
+ * This code started as a c++ translation of a java-based code written in 2005
+ * to implement a heap sort. So, this binary heap is really a pretty
+ * straightforward implementation of the classic data structure. Not much to say
+ * about it.
+ *
+ * What is smart about this code ?
+ * - it does not use the index 0 in the array to avoid having to convert
+ * C-style array indexes (which start at zero) and heap-style indexes
+ * (which start at 1). This is why _all_ indexes start at 1, and that
+ * the index of the root is 1.
+ * - It uses a slightly non-standard while loop for top-down heapify
+ * to move one if statement out of the loop.
+ */
class HeapScheduler : public Scheduler {
public:
HeapScheduler ();
--- a/src/simulator/list-scheduler.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/list-scheduler.h Wed Jun 04 17:19:32 2008 -0400
@@ -31,6 +31,13 @@
class EventImpl;
+/**
+ * \ingroup scheduler
+ * \brief a std::list event scheduler
+ *
+ * This class implements the an event scheduler using an std::list
+ * data structure, that is, a double linked-list.
+ */
class ListScheduler : public Scheduler {
public:
ListScheduler ();
--- a/src/simulator/map-scheduler.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/map-scheduler.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,6 +30,13 @@
class EventImpl;
+/**
+ * \ingroup scheduler
+ * \brief a std::map event scheduler
+ *
+ * This class implements the an event scheduler using an std::map
+ * data structure.
+ */
class MapScheduler : public Scheduler {
public:
MapScheduler ();
--- a/src/simulator/nstime.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/nstime.h Wed Jun 04 17:19:32 2008 -0400
@@ -60,6 +60,11 @@
/**
+ * \ingroup simulator
+ * \defgroup time Time
+ */
+/**
+ * \ingroup time
* \brief keep track of time unit.
*
* This template class is used to keep track of the value
--- a/src/simulator/scheduler.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/scheduler.h Wed Jun 04 17:19:32 2008 -0400
@@ -28,6 +28,11 @@
namespace ns3 {
/**
+ * \ingroup simulator
+ * \defgroup scheduler Scheduler
+ */
+/**
+ * \ingroup scheduler
* \brief Maintain the event list
*
* This base class specifies the interface used to maintain the
@@ -40,13 +45,6 @@
* - 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
- * a subclass of the ns3::SchedulerFactory base class and
- * feed it to ns3::Simulator::setExternal.
- * The simplest example of a scheduler is the linked-list
- * scheduler included in ns3: see the files
- * src/simulator/scheduler-list.h and src/simulator/scheduler-list.cc
*/
class Scheduler : public Object
{
--- a/src/simulator/simulator.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/simulator.cc Wed Jun 04 17:19:32 2008 -0400
@@ -68,7 +68,7 @@
bool IsFinished (void) const;
Time Next (void) const;
void Stop (void);
- void StopAt (Time const &time);
+ void Stop (Time const &time);
EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
EventId ScheduleNow (const Ptr<EventImpl> &event);
EventId ScheduleDestroy (const Ptr<EventImpl> &event);
@@ -115,8 +115,8 @@
.AddAttribute ("Scheduler",
"The Scheduler used to handle all simulation events.",
PointerValue (),
- // XXX: allow getting the scheduler too.
- MakePointerAccessor (&SimulatorPrivate::SetScheduler),
+ MakePointerAccessor (&SimulatorPrivate::SetScheduler,
+ &SimulatorPrivate::GetScheduler),
MakePointerChecker<Scheduler> ())
;
return tid;
@@ -249,10 +249,11 @@
m_stop = true;
}
void
-SimulatorPrivate::StopAt (Time const &at)
+SimulatorPrivate::Stop (Time const &time)
{
- NS_ASSERT (at.IsPositive ());
- m_stopAt = at.GetTimeStep ();
+ NS_ASSERT (time.IsPositive ());
+ Time absolute = Simulator::Now () + time;
+ m_stopAt = absolute.GetTimeStep ();
}
EventId
SimulatorPrivate::Schedule (Time const &time, const Ptr<EventImpl> &event)
@@ -485,9 +486,9 @@
GetPriv ()->Stop ();
}
void
-Simulator::StopAt (Time const &at)
+Simulator::Stop (Time const &time)
{
- GetPriv ()->StopAt (at);
+ GetPriv ()->Stop (time);
}
Time
Simulator::Now (void)
@@ -1125,7 +1126,7 @@
Simulator::Destroy ();
Simulator::Schedule (Seconds (10.0), &SimulatorTests::baz1, this, 0);
- Simulator::StopAt (Seconds (1.0));
+ Simulator::Stop (Seconds (1.0));
Simulator::Run ();
Simulator::Destroy ();
--- a/src/simulator/simulator.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/simulator.h Wed Jun 04 17:19:32 2008 -0400
@@ -35,6 +35,8 @@
class SchedulerFactory;
/**
+ * \ingroup simulator
+ *
* \brief Control the scheduling of simulation events.
*
* The internal simulation clock is maintained
@@ -59,7 +61,11 @@
*/
static void EnableParallelSimulation (void);
/**
- * XXX
+ * \param scheduler a new event scheduler
+ *
+ * The event scheduler can be set at any time: the events scheduled
+ * in the previous scheduler will be transfered to the new scheduler
+ * before we start to use it.
*/
static void SetScheduler (Ptr<Scheduler> scheduler);
@@ -126,12 +132,13 @@
*/
static void Stop (void);
/**
- * Force the Simulator::run method to return to the caller
- * when the expiration time of the next event to be processed
- * is greater than or equal to the stop time.
- * @param time the stop time.
+ * Force the Simulator::run method to return to the caller when the
+ * expiration time of the next event to be processed is greater than
+ * or equal to the stop time. The stop time is relative to the
+ * current simulation time.
+ * @param time the stop time, relative to the current time.
*/
- static void StopAt (Time const &time);
+ static void Stop (Time const &time);
/**
* Schedule an event to expire when the time "now + time"
--- a/src/simulator/time.cc Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/time.cc Wed Jun 04 17:19:32 2008 -0400
@@ -271,7 +271,6 @@
else
{
is.setstate (std::ios_base::failbit);
- // XXX: problem ?
}
return is;
}
--- a/src/simulator/timer.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/timer.h Wed Jun 04 17:19:32 2008 -0400
@@ -30,6 +30,8 @@
class TimerImpl;
/**
+ * \ingroup simulator
+ *
* \brief a simple Timer class
*
* A timer is used to hold together a delay, a function to invoke
--- a/src/simulator/watchdog.h Fri May 30 15:31:50 2008 -0400
+++ b/src/simulator/watchdog.h Wed Jun 04 17:19:32 2008 -0400
@@ -27,12 +27,26 @@
class TimerImpl;
+/**
+ * \ingroup simulator
+ * \brief a very simple watchdog
+ *
+ * If you don't ping the watchdog sufficiently often, it triggers its
+ * listening function.
+ */
class Watchdog
{
public:
Watchdog ();
~Watchdog ();
+ /**
+ * \param delay the watchdog delay
+ *
+ * After a call to this method, the watchdog will not be triggered
+ * until the delay specified has been expired. This operation is
+ * sometimes named "re-arming" a watchdog in some operating systems.
+ */
void Ping (Time delay);
/**
--- a/src/wscript Fri May 30 15:31:50 2008 -0400
+++ b/src/wscript Wed Jun 04 17:19:32 2008 -0400
@@ -47,6 +47,7 @@
def configure(conf):
conf.sub_config('core')
conf.sub_config('simulator')
+ conf.sub_config('contrib')
blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant()))
conf.env['NS3_MODULE_PATH'] = [blddir]
--- a/utils/bench-packets.cc Fri May 30 15:31:50 2008 -0400
+++ b/utils/bench-packets.cc Wed Jun 04 17:19:32 2008 -0400
@@ -22,6 +22,7 @@
#include "ns3/packet-metadata.h"
#include <iostream>
#include <sstream>
+#include <string>
using namespace ns3;
@@ -39,6 +40,7 @@
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
private:
+ static std::string GetTypeName (void);
bool m_ok;
};
@@ -55,12 +57,19 @@
}
template <int N>
+std::string
+BenchHeader<N>::GetTypeName (void)
+{
+ std::ostringstream oss;
+ oss << "ns3::BenchHeader<" << N << ">";
+ return oss.str ();
+}
+
+template <int N>
TypeId
BenchHeader<N>::GetTypeId (void)
{
- std::ostringstream oss;
- oss << "ns3::BenchHeader<"<<N<<">";
- static TypeId tid = TypeId (oss.str ().c_str ())
+ static TypeId tid = TypeId (GetTypeName ().c_str ())
.SetParent<Header> ()
;
return tid;
@@ -105,10 +114,75 @@
return N;
}
+template <int N>
+class BenchTag : public Tag
+{
+public:
+ static std::string GetName (void) {
+ std::ostringstream oss;
+ oss << "anon::BenchTag<" << N << ">";
+ return oss.str ();
+ }
+ static TypeId GetTypeId (void) {
+ static TypeId tid = TypeId (GetName ().c_str ())
+ .SetParent<Tag> ()
+ .AddConstructor<BenchTag > ()
+ .HideFromDocumentation ()
+ ;
+ return tid;
+ }
+ virtual TypeId GetInstanceTypeId (void) const {
+ return GetTypeId ();
+ }
+ virtual uint32_t GetSerializedSize (void) const {
+ return N;
+ }
+ virtual void Serialize (TagBuffer buf) const {
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ buf.WriteU8 (N);
+ }
+ }
+ virtual void Deserialize (TagBuffer buf) {
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ buf.ReadU8 ();
+ }
+ }
+ virtual void Print (std::ostream &os) const {
+ os << "N=" << N;
+ }
+ BenchTag ()
+ : Tag () {}
+};
static void
-benchPtrA (uint32_t n)
+benchD (uint32_t n)
+{
+ BenchHeader<25> ipv4;
+ BenchHeader<8> udp;
+ BenchTag<16> tag1;
+ BenchTag<17> tag2;
+
+ for (uint32_t i = 0; i < n; i++) {
+ Ptr<Packet> p = Create<Packet> (2000);
+ p->AddTag (tag1);
+ p->AddHeader (udp);
+ p->FindFirstMatchingTag (tag1);
+ p->AddTag (tag2);
+ p->AddHeader (ipv4);
+ Ptr<Packet> o = p->Copy ();
+ o->RemoveHeader (ipv4);
+ p->FindFirstMatchingTag (tag2);
+ o->RemoveHeader (udp);
+ }
+}
+
+
+
+static void
+benchA (uint32_t n)
{
BenchHeader<25> ipv4;
BenchHeader<8> udp;
@@ -124,7 +198,7 @@
}
static void
-benchPtrB (uint32_t n)
+benchB (uint32_t n)
{
BenchHeader<25> ipv4;
BenchHeader<8> udp;
@@ -137,7 +211,7 @@
}
static void
-ptrC2 (Ptr<Packet> p)
+C2 (Ptr<Packet> p)
{
BenchHeader<8> udp;
@@ -145,15 +219,15 @@
}
static void
-ptrC1 (Ptr<Packet> p)
+C1 (Ptr<Packet> p)
{
BenchHeader<25> ipv4;
p->RemoveHeader (ipv4);
- ptrC2 (p);
+ C2 (p);
}
static void
-benchPtrC (uint32_t n)
+benchC (uint32_t n)
{
BenchHeader<25> ipv4;
BenchHeader<8> udp;
@@ -162,28 +236,10 @@
Ptr<Packet> p = Create<Packet> (2000);
p->AddHeader (udp);
p->AddHeader (ipv4);
- ptrC1 (p);
+ C1 (p);
}
}
-#if 0
-static void
-benchPrint (uint32_t n)
-{
- PacketPrinter printer;
- BenchHeader<25> ipv4;
- BenchHeader<8> udp;
- Ptr<Packet> p = Create<Packet> (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)
@@ -218,15 +274,17 @@
}
std::cout << "Running bench-packets with n=" << n << std::endl;
- Packet::EnableMetadata ();
- runBench (&benchPtrA, n, "a");
- runBench (&benchPtrB, n, "b");
- runBench (&benchPtrC, n, "c");
+ runBench (&benchA, n, "a");
+ runBench (&benchB, n, "b");
+ runBench (&benchC, n, "c");
+ runBench (&benchD, n, "d");
- //runBench (&benchPrint, n, "print");
- runBench (&benchPtrA, n, "meta-a");
- runBench (&benchPtrB, n, "meta-b");
- runBench (&benchPtrC, n, "meta-c");
+ Packet::EnableMetadata ();
+ runBench (&benchA, n, "meta-a");
+ runBench (&benchB, n, "meta-b");
+ runBench (&benchC, n, "meta-c");
+ runBench (&benchD, n, "meta-d");
+
return 0;
--- a/wscript Fri May 30 15:31:50 2008 -0400
+++ b/wscript Wed Jun 04 17:19:32 2008 -0400
@@ -217,6 +217,9 @@
conf.env['NS3_ENABLED_MODULES'] = ['ns3-'+mod for mod in
Params.g_options.enable_modules.split(',')]
+ ## we cannot run regression tests without diff
+ conf.find_program('diff', var='DIFF')
+
def create_ns3_program(bld, name, dependencies=('simulator',)):
program = bld.create_obj('cpp', 'program')
@@ -326,11 +329,14 @@
#ut.want_to_see_test_error = True
#ut.run()
#ut.print_results()
+ env = Params.g_build.env_of_name('default')
if Params.g_commands['check']:
_run_waf_check()
if Params.g_options.regression or Params.g_options.regression_generate:
+ if not env['DIFF']:
+ Params.fatal("Cannot run regression tests: the 'diff' program is not installed.")
_dir = os.getcwd()
os.chdir("regression")
try:
@@ -657,6 +663,8 @@
class Regression(object):
def __init__(self, testdir):
self.testdir = testdir
+ env = Params.g_build.env_of_name('default')
+ self.diff = env['DIFF']
def run_test(self, verbose, generate, refDirName, testName):
refTestDirName = os.path.join(refDirName, (testName + ".ref"))
@@ -692,7 +700,7 @@
if verbose:
#diffCmd = "diff traces " + refTestDirName + " | head"
- diffCmd = subprocess.Popen(["diff", "traces", refTestDirName],
+ diffCmd = subprocess.Popen([self.diff, "traces", refTestDirName],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
headCmd = subprocess.Popen("head", stdin=diffCmd.stdout)
rc2 = headCmd.wait()
@@ -700,7 +708,7 @@
rc1 = diffCmd.wait()
rc = rc1 or rc2
else:
- diffCmd = "diff traces " + refTestDirName + \
+ diffCmd = self.diff +" traces " + refTestDirName + \
" > /dev/null 2>&1"
rc = os.system(diffCmd)
if rc:
@@ -710,7 +718,7 @@
print "Traces in directory: traces"
print "Rerun regression test as: " + \
"\"./waf --regression --regression-tests=test-" + testName + "\""
- print "Then do \"diff -u regression/traces regression/" + refTestDirName + \
+ print "Then do \"diff -u regression/" + refTestDirName + " regression/traces" \
"\" for details"
print "----------"
return rc