# HG changeset patch # User Raj Bhattacharjea # Date 1212614372 14400 # Node ID 39f736210ab2b4faf4bf8321a3854b8d0134d464 # Parent 05e66ff64e105dfe56b7e627f2e37b4e809eda26# Parent ec45f705b9ca71c89b2b7d9da775a3883886c564 Merge with ns-3-dev diff -r 05e66ff64e10 -r 39f736210ab2 .hgtags --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 RELEASE_NOTES --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 VERSION --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 doc/modules --- 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 + */ diff -r 05e66ff64e10 -r 39f736210ab2 doc/release_steps.txt --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/Makefile --- 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/ diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/dumbbell.png Binary file doc/tutorial/dumbbell.png has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/README --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/buffer.dia --- /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 @@ + + + + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Count# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Size# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Initial Start# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Dirty Start# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Unused Area# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Dirty Size# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Dirty Area# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Virtual Zero Area# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Unused Area# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Zero Area Size# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Used start# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Used Size# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Data# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Zero Area Size# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Used start# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Used Size# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Used# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Used# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Virtual Zero Area# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Buffer# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #BufferData# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Buffer# + + + + + + + + + + + + + + + + + + + + + + + + diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/dumbbell.dia Binary file doc/tutorial/figures/dumbbell.dia has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/oneobj.png Binary file doc/tutorial/figures/oneobj.png has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/packet.obj --- /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'],[ +]). diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/pp.dia Binary file doc/tutorial/figures/pp.dia has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/sockets-overview.dia Binary file doc/tutorial/figures/sockets-overview.dia has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/star.dia Binary file doc/tutorial/figures/star.dia has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/figures/threeobj.png Binary file doc/tutorial/figures/threeobj.png has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/oneobj.png Binary file doc/tutorial/oneobj.png has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/other.texi --- 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. diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/packets.texi --- /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 + 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 + 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 + 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 + +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 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. + diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/pp.png Binary file doc/tutorial/pp.png has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/sockets.texi --- /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 CreateSocket (Ptr 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 n0; + // Do some stuff to build up the Node's internet stack + Ptr 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 p) = 0; + int Send (const uint8_t* buf, uint32_t size); + + Ptr 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 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 (size);} instead of @code{Create (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." + diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/star.png Binary file doc/tutorial/star.png has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/threeobj.png Binary file doc/tutorial/threeobj.png has changed diff -r 05e66ff64e10 -r 39f736210ab2 doc/tutorial/tutorial.texi --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 examples/csma-packet-socket.cc --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 examples/mixed-global-routing.cc --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 examples/mixed-wireless.cc --- 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 positionAlloc = CreateObject (); - 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 (); } diff -r 05e66ff64e10 -r 39f736210ab2 examples/simple-alternate-routing.cc --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 examples/simple-error-model.cc --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 examples/simple-global-routing.cc --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 examples/simple-point-to-point-olsr.cc --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 examples/tcp-large-transfer.cc --- 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 (); } diff -r 05e66ff64e10 -r 39f736210ab2 examples/wifi-adhoc.cc --- 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 Experiment::SetupPacketReceive (Ptr node) { - TypeId tid = TypeId::LookupByName ("ns3::PacketSocket"); + TypeId tid = TypeId::LookupByName ("ns3::PacketSocketFactory"); Ptr 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))); diff -r 05e66ff64e10 -r 39f736210ab2 examples/wifi-ap.cc --- 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)); diff -r 05e66ff64e10 -r 39f736210ab2 samples/main-packet-tag.cc --- 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 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 () + .AddConstructor () + .AddAttribute ("SimpleValue", + "A simple value", + EmptyAttributeValue (), + MakeUintegerAccessor (&MyTag::GetSimpleValue), + MakeUintegerChecker ()) + ; + 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.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 p = Create (); + Ptr p = Create (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 ()); diff -r 05e66ff64e10 -r 39f736210ab2 samples/main-random-topology.cc --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 samples/main-random-walk.cc --- 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 mobility) +CourseChange (std::string foo, Ptr 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/applications/packet-sink/packet-sink.cc --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 src/applications/udp-echo/udp-echo-client.cc --- 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 > ()); } @@ -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); diff -r 05e66ff64e10 -r 39f736210ab2 src/applications/udp-echo/udp-echo-server.cc --- 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 > ()); } @@ -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); diff -r 05e66ff64e10 -r 39f736210ab2 src/common/buffer.cc --- 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/common/buffer.h --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/common/chunk.h --- 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/common/data-rate.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/data-writer.cc --- 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 - */ -#include "data-writer.h" - -#include -#include -#include -#include -#include -#include "ns3/assert.h" -#include -#include - -#define noTRACE_DATA_WRITER 1 - -#ifdef TRACE_DATA_WRITER -#include -# 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/data-writer.h --- 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 - */ - -#ifndef DATA_WRITER_H -#define DATA_WRITER_H - -#include - -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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/common/error-model.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. diff -r 05e66ff64e10 -r 39f736210ab2 src/common/header.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/packet-metadata-test.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
() + ; + return tid; +} + +HistoryHeaderBase::HistoryHeaderBase () + : m_ok (true) +{} + +bool +HistoryHeaderBase::IsOk (void) const +{ + return m_ok; +} +void +HistoryHeaderBase::ReportError (void) +{ + m_ok = false; +} + template -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 HistoryHeader::HistoryHeader () - : m_ok (false) + : HistoryHeaderBase () {} template -bool -HistoryHeader::IsOk (void) const -{ - return m_ok; -} - -template TypeId HistoryHeader::GetTypeId (void) { std::ostringstream oss; oss << "ns3::HistoryHeader<"<"; static TypeId tid = TypeId (oss.str ().c_str ()) - .SetParent
() + .SetParent () + .AddConstructor > () ; return tid; } @@ -98,19 +128,53 @@ uint32_t HistoryHeader::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 () + ; + return tid; +} +HistoryTrailerBase::HistoryTrailerBase () + : m_ok (true) +{} +bool +HistoryTrailerBase::IsOk (void) const +{ + return m_ok; +} +void +HistoryTrailerBase::ReportError (void) +{ + m_ok = false; +} + + template -class HistoryTrailer : public Trailer +class HistoryTrailer : public HistoryTrailerBase { public: HistoryTrailer (); @@ -128,24 +192,17 @@ template HistoryTrailer::HistoryTrailer () - : m_ok (false) {} template -bool -HistoryTrailer::IsOk (void) const -{ - return m_ok; -} - -template TypeId HistoryTrailer::GetTypeId (void) { std::ostringstream oss; oss << "ns3::HistoryTrailer<"<"; static TypeId tid = TypeId (oss.str ().c_str ()) - .SetParent () + .SetParent () + .AddConstructor > () ; return tid; } @@ -179,18 +236,21 @@ uint32_t HistoryTrailer::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 constructor = item.tid.GetConstructor (); + HistoryHeaderBase *header = dynamic_cast (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 constructor = item.tid.GetConstructor (); + HistoryTrailerBase *trailer = dynamic_cast (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 (16383); p = Create (16384); - return ok; + + // bug 179. + p = Create (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 (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 (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 (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 (200); + ADD_HEADER (p, 24); + p1 = p->CreateFragment(0, 100); + p2 = p->CreateFragment(100, 100); + p1->AddAtEnd (p2); + + return result; } static PacketMetadataTest g_packetHistoryTest; diff -r 05e66ff64e10 -r 39f736210ab2 src/common/packet-metadata.cc --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/common/packet-metadata.h --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 src/common/packet.cc --- 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::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 (new Packet (buffer, m_tags, metadata), false); + return Ptr (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 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 constructor = item.GetTypeId ().GetConstructor (); + if (constructor.IsNull ()) + { + if (i.HasNext ()) + { + os << " "; + } + continue; + } + Tag *tag = dynamic_cast (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 (&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 +#include + +using namespace ns3; + +namespace { + +class ATestTagBase : public Tag +{ +public: + ATestTagBase () : m_error (false) {} + bool m_error; +}; + +template +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 () + .AddConstructor > () + .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 +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
() + .AddConstructor > () + .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 p, const char *file, int line, uint32_t n, ...); }; PacketTest::PacketTest () : Test ("Packet") {} +bool +PacketTest::DoCheck (Ptr p, const char *file, int line, uint32_t n, ...) +{ + bool result = true; + std::vector 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 (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 pkt1 = Create (reinterpret_cast ("hello"), 5); Ptr pkt2 = Create (reinterpret_cast (" 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(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 p = Create (1000); + + p->AddTag (ATestTag<1> ()); + CHECK (p, 1, E (1, 0, 1000)); + Ptr 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 frag0 = p->CreateFragment (0, 10); + Ptr frag1 = p->CreateFragment (10, 90); + Ptr 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 (1000); + frag0->AddHeader (ATestHeader<10> ()); + frag0 = 0; + + p = Create (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 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/packet.h --- 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 - 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 - 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 - 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 -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 -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 -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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/common/pcap-writer.cc --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/pcap-writer.h --- 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); /** diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag-buffer.cc --- /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 + */ +#include "tag-buffer.h" +#include "ns3/assert.h" +#include + +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 + diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag-buffer.h --- /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 + */ +#ifndef TAG_BUFFER_H +#define TAG_BUFFER_H + +#include + +#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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag-list.cc --- /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 + */ +#include "tag-list.h" +#include + +#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 +{ +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 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag-list.h --- /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 + */ +#ifndef TAG_LIST_H +#define TAG_LIST_H + +#include +#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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag-registry.cc --- 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 - */ -#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 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag-registry.h --- 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 - */ -#ifndef TAG_REGISTRY_H -#define TAG_REGISTRY_H - -#include -#include -#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 - 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 TagInfoVector; - - template - static void DoDestruct (uint8_t *data); - template - static void DoPrint (uint8_t *data, std::ostream &os); - template - static uint32_t DoGetSerializedSize (uint8_t *data); - template - static void DoSerialize (uint8_t *data, Buffer::Iterator start); - template - static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start); - - static TagInfoVector *GetInfo (void); -}; - -} // namespace ns3 - -namespace ns3 { - -template -void -TagRegistry::DoDestruct (uint8_t *data) -{ - T *tag = reinterpret_cast (data); - tag->~T (); -} -template -void -TagRegistry::DoPrint (uint8_t *data, std::ostream &os) -{ - T *tag = reinterpret_cast (data); - tag->Print (os); -} -template -uint32_t -TagRegistry::DoGetSerializedSize (uint8_t *data) -{ - T *tag = reinterpret_cast (data); - return tag->GetSerializedSize (); -} -template -void -TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start) -{ - T *tag = reinterpret_cast (data); - tag->Serialize (start); -} -template -uint32_t -TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start) -{ - T *tag = reinterpret_cast (data); - return tag->Deserialize (start); -} - -template -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; - info.print = &TagRegistry::DoPrint; - info.getSerializedSize = &TagRegistry::DoGetSerializedSize; - info.serialize = &TagRegistry::DoSerialize; - info.deserialize = &TagRegistry::DoDeserialize; - vec->push_back (info); - uint32_t uid = vec->size (); - return uid; -} - -} // namespace ns3 - -#endif /* TAG_REGISTRY_H */ diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag.cc --- /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 + */ +#include "tag.h" + +namespace ns3 { + +TypeId +Tag::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Tag") + .SetParent () + ; + return tid; +} + + +} // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tag.h --- 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 -#include - -/** - * \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 - 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 -uint32_t -Tag::AllocateUid (std::string name) -{ - return TagRegistry::Register (name); -} - -} // namespace ns3 - #endif /* TAG_H */ diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tags.cc --- 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 - */ -#include "tags.h" -#include -#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 -#include - -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.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.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.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.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.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.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 */ - diff -r 05e66ff64e10 -r 39f736210ab2 src/common/tags.h --- 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 - */ -#ifndef TAGS_H -#define TAGS_H - -#include -#include -#include -#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 - void Add (T const&tag) const; - - template - bool Remove (T &tag); - - template - 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 - -namespace ns3 { - -template -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 (this)->m_next = newStart; -} - -template -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 -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 (&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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/common/trailer.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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/common/wscript --- 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', ] diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/attribute-iterator.cc --- /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 + + +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 = Config::GetRootNamespaceObject (i); + StartVisitObject (object); + DoIterate (object); + EndVisitObject (); + } + NS_ASSERT (m_currentPath.empty ()); + NS_ASSERT (m_examined.empty ()); +} + +bool +AttributeIterator::IsExamined (Ptr 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) +{} +void +AttributeIterator::DoEndVisitObject (void) +{} +void +AttributeIterator::DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr item) +{} +void +AttributeIterator::DoEndVisitPointerAttribute (void) +{} +void +AttributeIterator::DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector) +{} +void +AttributeIterator::DoEndVisitArrayAttribute (void) +{} +void +AttributeIterator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item) +{} +void +AttributeIterator::DoEndVisitArrayItem (void) +{} + +void +AttributeIterator::VisitAttribute (Ptr object, std::string name) +{ + m_currentPath.push_back (name); + DoVisitAttribute (object, name); + m_currentPath.pop_back (); +} + +void +AttributeIterator::StartVisitObject (Ptr object) +{ + m_currentPath.push_back ("$" + object->GetInstanceTypeId ().GetName ()); + DoStartVisitObject (object); +} +void +AttributeIterator::EndVisitObject (void) +{ + m_currentPath.pop_back (); + DoEndVisitObject (); +} +void +AttributeIterator::StartVisitPointerAttribute (Ptr object, std::string name, Ptr 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, 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 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) +{ + 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 checker = tid.GetAttributeChecker (i); + const PointerChecker *ptrChecker = dynamic_cast (PeekPointer (checker)); + if (ptrChecker != 0) + { + NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i)); + PointerValue ptr; + object->GetAttribute (tid.GetAttributeName (i), ptr); + Ptr tmp = ptr.Get (); + 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 (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 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 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 tmp = iter.Next (); + if (IsExamined (tmp)) + { + recursiveAggregate = true; + } + } + if (!recursiveAggregate) + { + iter = object->GetAggregateIterator (); + while (iter.HasNext ()) + { + Ptr tmp = const_cast (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, std::string name) +{ + StringValue str; + object->GetAttribute (name, str); + m_os << GetCurrentPath () << " " << str.Get () << std::endl; +} + +void +TextFileAttributeIterator::Save (void) +{ + Iterate (); +} + + + +} // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/attribute-iterator.h --- /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 + +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, std::string name) = 0; + virtual void DoStartVisitObject (Ptr object); + virtual void DoEndVisitObject (void); + virtual void DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value); + virtual void DoEndVisitPointerAttribute (void); + virtual void DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); + virtual void DoEndVisitArrayAttribute (void); + virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item); + virtual void DoEndVisitArrayItem (void); + + void DoIterate (Ptr object); + bool IsExamined (Ptr object); + std::string GetCurrentPath (std::string attr) const; + + void VisitAttribute (Ptr object, std::string name); + void StartVisitObject (Ptr object); + void EndVisitObject (void); + void StartVisitPointerAttribute (Ptr object, std::string name, Ptr value); + void EndVisitPointerAttribute (void); + void StartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); + void EndVisitArrayAttribute (void); + void StartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item); + void EndVisitArrayItem (void); + + + std::vector > m_examined; + std::vector m_currentPath; +}; + +class TextFileAttributeIterator : public AttributeIterator +{ +public: + TextFileAttributeIterator (std::ostream &os); + void Save (void); +private: + virtual void DoVisitAttribute (Ptr object, std::string name); + std::ostream &m_os; +}; + + +} // namespace ns3 + +#endif /* ATTRIBUTE_ITERATOR_H */ diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/config-store.cc --- 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 #include #include @@ -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 = 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 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 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 checker = tid.GetAttributeChecker (i); - const PointerChecker *ptrChecker = dynamic_cast (PeekPointer (checker)); - if (ptrChecker != 0) - { - NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i)); - PointerValue ptr; - object->GetAttribute (tid.GetAttributeName (i), ptr); - Ptr tmp = ptr.Get (); - 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 (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 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 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 tmp = iter.Next (); - if (IsExamined (tmp)) - { - recursiveAggregate = true; - } - } - if (!recursiveAggregate) - { - iter = object->GetAggregateIterator (); - while (iter.HasNext ()) - { - Ptr tmp = iter.Next (); - m_examined.push_back (object); - Store (os, tmp); - m_examined.pop_back (); - } - } - m_currentPath.pop_back (); -} - - void ConfigStore::Configure (void) { diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/config-store.h --- 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 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 object); - bool IsExamined (Ptr object); - std::string GetCurrentPath (std::string attr) const; std::string m_loadFilename; std::string m_storeFilename; - std::vector > m_examined; - std::vector m_currentPath; }; } // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/delay-jitter-estimation.cc --- 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 ("mathieu.paper.TimestampTag"); - return uid; + static TypeId tid = TypeId ("anon::DelayJitterEstimationTimestampTag") + .SetParent () + .AddConstructor () + .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 packet) { - TimestampTag tag; + DelayJitterEstimationTimestampTag tag; packet->AddTag (tag); } void DelayJitterEstimation::RecordRx (Ptr packet) { - TimestampTag tag; + DelayJitterEstimationTimestampTag tag; bool found; - found = packet->PeekTag (tag); + found = packet->FindFirstMatchingTag (tag); if (!found) { return; diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/delay-jitter-estimation.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/gtk-config-store.cc --- /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 +#include + + +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; + uint32_t index; +}; + +class ModelCreator : public AttributeIterator +{ +public: + ModelCreator (); + + void Build (GtkTreeStore *treestore); +private: + virtual void DoVisitAttribute (Ptr object, std::string name); + virtual void DoStartVisitObject (Ptr object); + virtual void DoEndVisitObject (void); + virtual void DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value); + virtual void DoEndVisitPointerAttribute (void); + virtual void DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); + virtual void DoEndVisitArrayAttribute (void); + virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item); + virtual void DoEndVisitArrayItem (void); + void Add (ModelNode *node); + void Remove (void); + + GtkTreeStore *m_treestore; + std::vector 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, 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) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_OBJECT; + node->object = object; + Add (node); +} +void +ModelCreator::DoEndVisitObject (void) +{ + Remove (); +} +void +ModelCreator::DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr 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, 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 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 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/gtk-config-store.h --- /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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/contrib/wscript --- 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' diff -r 05e66ff64e10 -r 39f736210ab2 src/core/assert.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/attribute-accessor-helper.h --- 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 Ptr MakeAccessorHelper (T1 a1); +/** + * \ingroup AttributeHelper + */ template Ptr MakeAccessorHelper (T1 a1, T2 a2); diff -r 05e66ff64e10 -r 39f736210ab2 src/core/attribute-helper.h --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 src/core/attribute-list.cc --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/attribute-list.h --- 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/core/attribute-test.cc --- 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 ()) diff -r 05e66ff64e10 -r 39f736210ab2 src/core/attribute.h --- 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/core/boolean.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/command-line.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/config.cc --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/config.h --- 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 { /** diff -r 05e66ff64e10 -r 39f736210ab2 src/core/double.h --- 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 * diff -r 05e66ff64e10 -r 39f736210ab2 src/core/empty.h --- 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 {}; } diff -r 05e66ff64e10 -r 39f736210ab2 src/core/enum.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/fatal-error.h --- 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 /** - * \ingroup core - * \defgroup error Error + * \ingroup debugging * \brief fatal error handling * * \param msg message to output when this macro is hit. diff -r 05e66ff64e10 -r 39f736210ab2 src/core/global-value.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/integer.h --- 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 * diff -r 05e66ff64e10 -r 39f736210ab2 src/core/log.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/object-base.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/object-factory.h --- 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 Ptr 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/object-vector.cc --- 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 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 checker) diff -r 05e66ff64e10 -r 39f736210ab2 src/core/object-vector.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/object.cc --- 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 (), 0); NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); - NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0) + NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); baseA = CreateObject (); baseB = CreateObject (); diff -r 05e66ff64e10 -r 39f736210ab2 src/core/object.h --- 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/core/pointer.h --- 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 */ class PointerValue : public AttributeValue diff -r 05e66ff64e10 -r 39f736210ab2 src/core/ptr.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/singleton.h --- 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 class Singleton { diff -r 05e66ff64e10 -r 39f736210ab2 src/core/string.h --- 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 * diff -r 05e66ff64e10 -r 39f736210ab2 src/core/test.h --- 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 << ":" < Ptr MakeTraceSourceAccessor (T a); diff -r 05e66ff64e10 -r 39f736210ab2 src/core/traced-value.h --- 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 class TracedValue diff -r 05e66ff64e10 -r 39f736210ab2 src/core/type-id.cc --- 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::Get ()->GetParent (m_tid); + return parent != m_tid; +} +bool TypeId::IsChildOf (TypeId other) const { TypeId tmp = *this; diff -r 05e66ff64e10 -r 39f736210ab2 src/core/type-id.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/core/uinteger.h --- 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 * diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/csma/csma-net-device.h --- 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 > m_rxTrace; TracedCallback > m_dropTrace; diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/csma/csma.h --- 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. */ diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/point-to-point/point-to-point-channel.cc --- 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 */ #include "point-to-point-channel.h" @@ -36,10 +34,6 @@ static TypeId tid = TypeId ("ns3::PointToPointChannel") .SetParent () .AddConstructor () - .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 p, - Ptr src, - const Time& txTime) +PointToPointChannel::TransmitStart( + Ptr p, + Ptr 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 PointToPointChannel::GetDevice (uint32_t i) const { @@ -138,5 +116,4 @@ return GetPointToPointDevice (i); } - } // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/point-to-point/point-to-point-channel.h --- 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 p, Ptr 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 GetPointToPointDevice (uint32_t i) const; - virtual Ptr 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 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 m_src; Ptr m_dst; }; diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/point-to-point/point-to-point-net-device.cc --- 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 - * Revised: George Riley */ #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 p, uint16_t protocolNumber) { NS_LOG_FUNCTION_NOARGS (); @@ -103,7 +95,7 @@ p->AddHeader (ppp); } -bool + bool PointToPointNetDevice::ProcessHeader(Ptr 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 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 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 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 q) + void +PointToPointNetDevice::SetQueue (Ptr q) { NS_LOG_FUNCTION (this << q); - m_queue = q; } -void PointToPointNetDevice::SetReceiveErrorModel (Ptr em) + void +PointToPointNetDevice::SetReceiveErrorModel (Ptr em) { NS_LOG_FUNCTION ("(" << em << ")"); - m_receiveErrorModel = em; } -void PointToPointNetDevice::Receive (Ptr packet) + void +PointToPointNetDevice::Receive (Ptr 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 PointToPointNetDevice::GetQueue(void) const + Ptr +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 + + Ptr 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 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, const Address& dest, uint16_t protocolNumber) + + bool +PointToPointNetDevice::Send( + Ptr 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 + + Ptr PointToPointNetDevice::GetNode (void) const { return m_node; } -void + + void PointToPointNetDevice::SetNode (Ptr node) { m_node = node; } -bool + + bool PointToPointNetDevice::NeedsArp (void) const { return false; } -void + + void PointToPointNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) { m_rxCallback = cb; } - } // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/point-to-point/point-to-point-net-device.h --- 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 */ #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 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); + /** * 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 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 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 GetChannel (void) const; virtual Address GetAddress (void) const; + virtual bool SetMtu (const uint16_t mtu); virtual uint16_t GetMtu (void) const; + virtual bool IsLinkUp (void) const; + virtual void SetLinkChangeCallback (Callback callback); + virtual bool IsBroadcast (void) const; virtual Address GetBroadcast (void) const; + virtual bool IsMulticast (void) const; virtual Address GetMulticast (void) const; virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const; + virtual bool IsPointToPoint (void) const; - virtual bool Send(Ptr packet, const Address& dest, uint16_t protocolNumber); + + virtual bool Send(Ptr packet, const Address &dest, + uint16_t protocolNumber); + virtual Ptr GetNode (void) const; virtual void SetNode (Ptr node); + virtual bool NeedsArp (void) const; + virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); 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 GetQueue(void) const; @@ -190,6 +197,7 @@ * respect the protocol implemented by the agent. */ void AddHeader(Ptr 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 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 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 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 m_queue; + /** * The trace source for the packet reception events that the device can * fire. * * @see class CallBackTraceSource - * @see class TraceResolver */ TracedCallback > m_rxTrace; + /** * The trace source for the packet drop events that the device can * fire. * * @see class CallBackTraceSource - * @see class TraceResolver */ TracedCallback > m_dropTrace; diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/point-to-point/point-to-point.h --- 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." */ diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/point-to-point/ppp-header.cc --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/adhoc-wifi-mac.cc --- 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 linkDown) -{ - //XXX -} +{} Mac48Address AdhocWifiMac::GetAddress (void) const { diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/constant-rate-wifi-manager.cc --- 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 () .AddConstructor () - .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 ()) diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/dca-txop.cc --- 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 () .AddConstructor () - .AddAttribute ("MinCw", "XXX", + .AddAttribute ("MinCw", "The minimum value of the contention window.", UintegerValue (15), MakeUintegerAccessor (&DcaTxop::SetMinCw, &DcaTxop::GetMinCw), MakeUintegerChecker ()) - .AddAttribute ("MaxCw", "XXX", + .AddAttribute ("MaxCw", "The maximum value of the contention window.", UintegerValue (1023), MakeUintegerAccessor (&DcaTxop::SetMaxCw, &DcaTxop::GetMaxCw), MakeUintegerChecker ()) - .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 diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/mac-low.cc --- 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 () + .AddConstructor () + .AddAttribute ("Snr", "The snr of the last packet received", + DoubleValue (0.0), + MakeDoubleAccessor (&SnrTag::Get), + MakeDoubleChecker ()) + ; + 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.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="< | 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 () .AddConstructor () - .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 ()) - .AddAttribute ("ActiveProbing", "XXX", + .AddAttribute ("ActiveProbing", "If true, we send probe requests. If false, we don't.", BooleanValue (false), MakeBooleanAccessor (&NqstaWifiMac::SetActiveProbing), MakeBooleanChecker ()) diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/onoe-wifi-manager.cc --- 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 ()) diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/propagation-loss-model.cc --- 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 () .AddConstructor () - .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 ()) diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/ssid.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-channel.cc --- 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 () .AddConstructor () - .AddAttribute ("PropagationLossModel", "XXX", + .AddAttribute ("PropagationLossModel", "A pointer to the propagation loss model attached to this channel.", PointerValue (), MakePointerAccessor (&WifiChannel::m_loss), MakePointerChecker ()) - .AddAttribute ("PropagationDelayModel", "XXX", + .AddAttribute ("PropagationDelayModel", "A pointer to the propagation delay model attached to this channel.", PointerValue (), MakePointerAccessor (&WifiChannel::m_delay), MakePointerChecker ()) diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-mac-header.cc --- 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 () {} diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-mac.cc --- 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 () - .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 (1,2304)) - .AddAttribute ("Ssid", "XXX", + .AddAttribute ("Ssid", "The ssid we want to belong to.", SsidValue (Ssid ("default")), MakeSsidAccessor (&WifiMac::GetSsid, &WifiMac::SetSsid), diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-mac.h --- 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; /** diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-mode.h --- 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. diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-phy.cc --- 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 ()) - .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; } } diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-remote-station-manager.cc --- 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 () - .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 ()) - .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 ()) - .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 ()) - .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 ()) @@ -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 () + .AddConstructor () + .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 ("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="< () - .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 (); } diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-remote-station-manager.h --- 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 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 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 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 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 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 packet); + /** + * \param packet the packet to send + * \returns true if this packet should be fragmented, false otherwise. + */ virtual bool NeedFragmentation (Ptr packet); + /** + * \param packet the packet to send + * \returns the number of fragments which should be used for this packet. + */ virtual uint32_t GetNFragments (Ptr packet); + /** + * \param packet the packet to send + * \param fragmentNumber the fragment index of the next fragment to send (starts at zero). + * \returns the size of the corresponding fragment. + */ virtual uint32_t GetFragmentSize (Ptr packet, uint32_t fragmentNumber); + /** + * \param packet the packet to send + * \param fragmentNumber the fragment index of the next fragment to send (starts at zero). + * \returns true if this is the last fragment, false otherwise. + */ virtual bool IsLastFragment (Ptr 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/devices/wifi/wifi-test.cc --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/helper/ipv4-address-helper.cc --- 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. diff -r 05e66ff64e10 -r 39f736210ab2 src/helper/mobility-helper.cc --- 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 ("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 allocator) { m_position = allocator; @@ -156,15 +144,6 @@ } Vector position = m_position->GetNext (); model->SetPosition (position); - if (m_notifierEnabled) - { - Ptr notifier = - object->GetObject (); - if (notifier == 0) - { - object->AggregateObject (CreateObject ()); - } - } } } diff -r 05e66ff64e10 -r 39f736210ab2 src/helper/mobility-helper.h --- 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 > m_mobilityStack; - bool m_notifierEnabled; ObjectFactory m_mobility; Ptr m_position; }; diff -r 05e66ff64e10 -r 39f736210ab2 src/helper/ns2-mobility-helper.cc --- 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 @@ -67,12 +55,6 @@ model = CreateObject (); object->AggregateObject (model); } - Ptr notifier = object->GetObject (); - if (notifier == 0) - { - notifier = CreateObject (); - object->AggregateObject (notifier); - } return model; } diff -r 05e66ff64e10 -r 39f736210ab2 src/helper/ns2-mobility-helper.h --- 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 GetMobilityModel (std::string idString, const ObjectStore &store) const; double ReadDouble (std::string valueString) const; std::string m_filename; - bool m_notifierEnabled; }; } // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/helper/wifi-helper.cc --- 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)); } diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/arp-cache.cc --- 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 device, Ptr 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 () + .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 ()) + ; + 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 device, Ptr interface) +{ + m_device = device; + m_interface = interface; } Ptr @@ -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 +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 waiting = m_waiting; - //m_waiting = 0; - return waiting; } -Ptr +bool ArpCache::Entry::UpdateWaitReply (Ptr waiting) { NS_ASSERT (m_state == WAIT_REPLY); @@ -167,17 +210,20 @@ * we dump the previously waiting packet and * replace it with this one. */ - Ptr 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 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 +ArpCache::Entry::DequeuePending (void) +{ + if (m_pending.empty ()) + { + return 0; + } + else + { + Ptr p = m_pending.front (); + m_pending.pop_front (); + return p; + } +} void ArpCache::Entry::UpdateSeen (void) { diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/arp-cache.h --- 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 +#include #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 device, Ptr interface); - ~ArpCache (); + void SetDevice (Ptr device, Ptr interface); /** * \return The NetDevice that this ARP cache is associated with */ @@ -98,9 +104,8 @@ void MarkDead (void); /** * \param macAddress - * \return */ - Ptr MarkAlive (Address macAddress); + void MarkAlive (Address macAddress); /** * \param waiting */ @@ -109,7 +114,7 @@ * \param waiting * \return */ - Ptr UpdateWaitReply (Ptr waiting); + bool UpdateWaitReply (Ptr 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 DequeuePending (void); private: enum ArpCacheEntryState_e { ALIVE, @@ -143,18 +154,21 @@ ArpCacheEntryState_e m_state; Time m_lastSeen; Address m_macAddress; - Ptr m_waiting; + std::list > m_pending; }; private: typedef sgi::hash_map Cache; typedef sgi::hash_map::iterator CacheI; + virtual void DoDispose (void); + Ptr m_device; Ptr m_interface; Time m_aliveTimeout; Time m_deadTimeout; Time m_waitReplyTimeout; + uint32_t m_pendingQueueSize; Cache m_arpCache; }; diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/arp-ipv4-interface.cc --- 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 () + .AddAttribute ("ArpCache", + "The arp cache for this ipv4 interface", + PointerValue (0), + MakePointerAccessor (&ArpIpv4Interface::m_cache), + MakePointerChecker ()) + ; + 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) { m_node = node; + DoSetup (); } void ArpIpv4Interface::SetDevice (Ptr device) { m_device = device; + DoSetup (); } Ptr @@ -67,13 +90,24 @@ return m_device; } +void +ArpIpv4Interface::DoSetup (void) +{ + if (m_node == 0 || m_device == 0) + { + return; + } + Ptr arp = m_node->GetObject (); + m_cache = arp->CreateCache (m_device, this); +} + void ArpIpv4Interface::SendTo (Ptr 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 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) diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/arp-ipv4-interface.h --- 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 p, Ipv4Address dest); virtual void DoDispose (void); + void DoSetup (void); Ptr m_node; Ptr m_device; + Ptr m_cache; }; }//namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/arp-l3-protocol.cc --- 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 () + .AddAttribute ("CacheList", + "The list of ARP caches", + ObjectVectorValue (), + MakeObjectVectorAccessor (&ArpL3Protocol::m_cacheList), + MakeObjectVectorChecker ()) + .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 cache = *i; + cache->Dispose (); } m_cacheList.clear (); m_node = 0; Object::DoDispose (); } -ArpCache * +Ptr +ArpL3Protocol::CreateCache (Ptr device, Ptr interface) +{ + Ptr ipv4 = m_node->GetObject (); + Ptr cache = CreateObject (); + cache->SetDevice (device, interface); + NS_ASSERT (device->IsBroadcast ()); + device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache)); + m_cacheList.push_back (cache); + return cache; +} + +Ptr ArpL3Protocol::FindCache (Ptr device) { NS_LOG_FUNCTION_NOARGS (); @@ -85,20 +108,16 @@ return *i; } } - Ptr ipv4 = m_node->GetObject (); - Ptr 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 device, Ptr packet, uint16_t protocol, const Address &from) { NS_LOG_FUNCTION_NOARGS (); - ArpCache *cache = FindCache (device); + Ptr cache = FindCache (device); ArpHeader arp; packet->RemoveHeader (arp); @@ -135,8 +154,14 @@ arp.GetSourceIpv4Address () << " for waiting entry -- flush"); Address from_mac = arp.GetSourceHardwareAddress (); - Ptr waiting = entry->MarkAlive (from_mac); - cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ()); + entry->MarkAlive (from_mac); + Ptr pending = entry->DequeuePending(); + while (pending != 0) + { + cache->GetInterface ()->Send (pending, + arp.GetSourceIpv4Address ()); + pending = entry->DequeuePending(); + } } else { @@ -145,13 +170,13 @@ NS_LOG_LOGIC("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="<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, Ipv4Address destination, Ptr device, + Ptr 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="<GetId ()<< ", wait reply for " << destination << " expired -- drop"); entry->MarkDead (); - // XXX report packet as 'dropped' + Ptr 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="<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="<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="<GetId ()<< - ", wait reply for " << destination << " valid -- drop previous"); - Ptr 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 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 cache, Ipv4Address toIp, Address toMac) { NS_LOG_FUNCTION_NOARGS (); ArpHeader arp; diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/arp-l3-protocol.h --- 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); + Ptr CreateCache (Ptr device, Ptr interface); + /** * \brief Recieve a packet */ @@ -55,21 +60,24 @@ * \param p * \param destination * \param device + * \param cache * \param hardwareDestination * \return */ bool Lookup (Ptr p, Ipv4Address destination, Ptr device, + Ptr cache, Address *hardwareDestination); protected: virtual void DoDispose (void); private: - typedef std::list CacheList; - ArpCache *FindCache (Ptr device); - void SendArpRequest (ArpCache const *cache, Ipv4Address to); - void SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac); + typedef std::list > CacheList; + Ptr FindCache (Ptr device); + void SendArpRequest (Ptrcache, Ipv4Address to); + void SendArpReply (Ptr cache, Ipv4Address toIp, Address toMac); CacheList m_cacheList; Ptr m_node; + TracedCallback > m_dropTrace; }; }//namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ascii-trace.cc --- 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 - */ -#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 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 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 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 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ascii-trace.h --- 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 - */ -#ifndef ASCII_TRACE_H -#define ASCII_TRACE_H - -#include -#include -#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 p); - void LogDevQueueDequeue (std::string context, Ptr p); - void LogDevQueueDrop (std::string context, Ptr p); - void LogDevRx (std::string context, Ptr p); - std::ofstream m_os; -}; - -}//namespace ns3 - -#endif /* ASCII_TRACE_H */ diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/internet-stack.cc --- 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 arp = CreateObject (); 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 = CreateObject (); Ptr udp = CreateObject (); diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-header.cc --- 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 - */ - -#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
() - .AddConstructor () - ; - 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=" <> 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-header.h --- 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 - */ - -#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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-interface.cc --- 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; } diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-interface.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-l3-protocol.cc --- 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 interface = *i; + interface->Dispose (); + } m_interfaces.clear (); m_node = 0; m_staticRouting->Dispose (); @@ -315,6 +321,13 @@ Ipv4L3Protocol::AddInterface (Ptr device) { NS_LOG_FUNCTION (this << &device); + + Ptr node = GetObject (); + node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this), + Ipv4L3Protocol::PROT_NUMBER, device); + node->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject ())), + ArpL3Protocol::PROT_NUMBER, device); + Ptr interface = CreateObject (); 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-l3-protocol.h --- 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-l4-demux.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-l4-protocol.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-loopback-interface.cc --- 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 () + ; + 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); } diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-loopback-interface.h --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/ipv4-static-routing.h --- 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 #include #include "ns3/ipv4-address.h" -#include "ipv4-header.h" +#include "ns3/ipv4-header.h" #include "ns3/ptr.h" #include "ns3/ipv4.h" diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/pcap-trace.cc --- 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 - */ -#include "pcap-trace.h" - -#include - -#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::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::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="<> nodeIndex; - return nodeIndex; -} - -void -PcapTrace::LogTxIp (std::string context, Ptr p, uint32_t interfaceIndex) -{ - PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex); - writer->WritePacket (p); -} - -void -PcapTrace::LogRxIp (std::string context, Ptr p, uint32_t interfaceIndex) -{ - PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex); - writer->WritePacket (p); -} - - -}//namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/pcap-trace.h --- 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 - */ -#ifndef PCAP_TRACE_H -#define PCAP_TRACE_H - -#include -#include -#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 p, uint32_t interfaceIndex); - void LogTxIp (std::string context, Ptr 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 m_traces; -}; - -}//namespace ns3 - -#endif /* PCAP_TRACE_H */ diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/tcp-l4-protocol.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; /** diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/tcp-socket-factory-impl.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/tcp-socket-impl.cc --- 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 outPacket = Create(); - 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/udp-l4-protocol.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/udp-socket-impl.cc --- 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 (this))); + m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocketImpl::Destroy, Ptr (this))); return 0; } @@ -217,6 +217,13 @@ } int +UdpSocketImpl::Listen (uint32_t queueLimit) +{ + m_errno = Socket::ERROR_OPNOTSUPP; + return -1; +} + +int UdpSocketImpl::Send (Ptr p) { NS_LOG_FUNCTION (this << p); @@ -530,14 +537,16 @@ void UdpSocketImplTest::ReceivePkt (Ptr socket) { - uint32_t availableData = socket->GetRxAvailable (); + uint32_t availableData; + availableData = socket->GetRxAvailable (); m_receivedPacket = socket->Recv (std::numeric_limits::max(), 0); NS_ASSERT (availableData == m_receivedPacket->GetSize ()); } void UdpSocketImplTest::ReceivePkt2 (Ptr socket) { - uint32_t availableData = socket->GetRxAvailable (); + uint32_t availableData; + availableData = socket->GetRxAvailable (); m_receivedPacket2 = socket->Recv (std::numeric_limits::max(), 0); NS_ASSERT (availableData == m_receivedPacket2->GetSize ()); } diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/udp-socket-impl.h --- 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 p); virtual int SendTo (Ptr p, const Address &address); virtual uint32_t GetTxAvailable (void) const; diff -r 05e66ff64e10 -r 39f736210ab2 src/internet-node/wscript --- 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', diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/hierarchical-mobility-model.cc --- 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 */ #include "hierarchical-mobility-model.h" -#include "mobility-model-notifier.h" #include "ns3/pointer.h" namespace ns3 { @@ -33,11 +32,13 @@ .AddConstructor () .AddAttribute ("Child", "The child mobility model.", PointerValue (), - MakePointerAccessor (&HierarchicalMobilityModel::SetChild), + MakePointerAccessor (&HierarchicalMobilityModel::SetChild, + &HierarchicalMobilityModel::GetChild), MakePointerChecker ()) .AddAttribute ("Parent", "The parent mobility model.", PointerValue (), - MakePointerAccessor (&HierarchicalMobilityModel::SetParent), + MakePointerAccessor (&HierarchicalMobilityModel::SetParent, + &HierarchicalMobilityModel::GetParent), MakePointerChecker ()) ; return tid; @@ -52,28 +53,14 @@ HierarchicalMobilityModel::SetChild (Ptr model) { m_child = model; - Ptr notifier = - m_child->GetObject (); - if (notifier == 0) - { - notifier = CreateObject (); - m_child->AggregateObject (notifier); - } - notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this)); + m_child->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this)); } void HierarchicalMobilityModel::SetParent (Ptr model) { m_parent = model; - Ptr notifier = - m_parent->GetObject (); - if (notifier == 0) - { - notifier = CreateObject (); - m_parent->AggregateObject (notifier); - } - notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this)); + m_parent->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this)); } diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/mobility-model-notifier.cc --- 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 - */ -#include "mobility-model-notifier.h" -#include "ns3/trace-source-accessor.h" - -namespace ns3 { - -TypeId -MobilityModelNotifier::GetTypeId (void) -{ - static TypeId tid = TypeId ("MobilityModelNotifier") - .SetParent () - .AddConstructor () - .AddTraceSource ("CourseChange", - "The value of the position and/or velocity vector changed", - MakeTraceSourceAccessor (&MobilityModelNotifier::m_trace)) - ; - return tid; -} - -MobilityModelNotifier::MobilityModelNotifier () -{} - -void -MobilityModelNotifier::Notify (Ptr position) const -{ - m_trace (position); -} - -} // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/mobility-model-notifier.h --- 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 - */ -#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 position) const; -private: - TracedCallback > m_trace; -}; - -} // namespace ns3 - -#endif /* MOBILITY_MODEL_NOTIFIER_H */ diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/mobility-model.cc --- 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 */ + +#include + #include "mobility-model.h" -#include "mobility-model-notifier.h" -#include +#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 notifier = GetObject (); - if (notifier != 0) - { - notifier->Notify (this); - } + m_courseChangeTrace(this); } } // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/mobility-model.h --- 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 > m_courseChangeTrace; + }; }; // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/mobility.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/random-walk-2d-mobility-model.h --- 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/random-waypoint-mobility-model.h --- 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/rectangle.cc --- 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; diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/rectangle.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/vector.h --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 src/mobility/wscript --- 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', diff -r 05e66ff64e10 -r 39f736210ab2 src/node/address-utils.cc --- 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) { diff -r 05e66ff64e10 -r 39f736210ab2 src/node/address.cc --- 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; diff -r 05e66ff64e10 -r 39f736210ab2 src/node/address.h --- 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 #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); diff -r 05e66ff64e10 -r 39f736210ab2 src/node/application.cc --- 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); } diff -r 05e66ff64e10 -r 39f736210ab2 src/node/application.h --- 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 GetNode() const; + Ptr GetNode () const; /** * \param node the node to which this Application object is attached. diff -r 05e66ff64e10 -r 39f736210ab2 src/node/channel.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/drop-tail-queue.h --- 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ethernet-header.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ethernet-trailer.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/inet-socket-address.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4-address-generator.cc --- 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) { diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4-address-generator.h --- 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, diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4-address.cc --- 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) diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4-address.h --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4-header.cc --- /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 + */ + +#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
() + .AddConstructor () + ; + 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=" <> 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4-header.h --- /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 + */ + +#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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4-route.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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/node/ipv4.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/llc-snap-header.h --- 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/node/mac48-address.h --- 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); diff -r 05e66ff64e10 -r 39f736210ab2 src/node/mac64-address.h --- 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. diff -r 05e66ff64e10 -r 39f736210ab2 src/node/net-device.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/node-list.h --- 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. diff -r 05e66ff64e10 -r 39f736210ab2 src/node/node.h --- 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 device); diff -r 05e66ff64e10 -r 39f736210ab2 src/node/packet-socket-address.h --- 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/node/packet-socket-factory.h --- 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. */ diff -r 05e66ff64e10 -r 39f736210ab2 src/node/packet-socket.cc --- 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 + 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 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 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 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/node/packet-socket.h --- 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 p); virtual uint32_t GetTxAvailable (void) const; @@ -100,6 +105,7 @@ void ForwardUp (Ptr device, Ptr packet, uint16_t protocol, const Address &from); int DoBind (const PacketSocketAddress &address); + uint32_t GetMinMtu (PacketSocketAddress ad) const; virtual void DoDispose (void); enum State { diff -r 05e66ff64e10 -r 39f736210ab2 src/node/queue.cc --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/queue.h --- 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 Peek (void) const; /** - * XXX Doesn't do anything right now, think its supposed to flush the queue + * Flush the queue. */ void DequeueAll (void); /** diff -r 05e66ff64e10 -r 39f736210ab2 src/node/simple-channel.h --- 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/node/simple-net-device.h --- 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: diff -r 05e66ff64e10 -r 39f736210ab2 src/node/socket-defaults.cc --- 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 () - .AddAttribute ("DefaultSndBufLimit", - "Default maximum receive buffer size (bytes)", - UintegerValue (0xffffffffl), - MakeUintegerAccessor (&SocketDefaults::m_defaultSndBufLimit), - MakeUintegerChecker ()) - .AddAttribute ("DefaultRcvBufLimit", - "Default maximum receive buffer size (bytes)", - UintegerValue (0xffffffffl), - MakeUintegerAccessor (&SocketDefaults::m_defaultRcvBufLimit), - MakeUintegerChecker ()) - ; - return tid; -} - -} // namespace ns3 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/socket-defaults.h --- 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 */ diff -r 05e66ff64e10 -r 39f736210ab2 src/node/socket-factory.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. * diff -r 05e66ff64e10 -r 39f736210ab2 src/node/socket.cc --- 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 () - .AddConstructor () - ; - 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::max(), 0); } +int +Socket::Recv (uint8_t* buf, uint32_t size, uint32_t flags) +{ + Ptr p = Recv (size, flags); // read up to "size" bytes + memcpy (buf, p->PeekData (), p->GetSize()); + return p->GetSize (); +} + int Socket::SendTo (const uint8_t* buf, uint32_t size, const Address &address) { 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.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 () + .AddConstructor () + ; + return tid; } - -uint32_t -SocketIpTtlTag::GetUid (void) +TypeId +SocketRxAddressTag::GetInstanceTypeId (void) const { - static uint32_t uid = ns3::Tag::AllocateUid ("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 () + .AddConstructor () + ; + 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/socket.h --- 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 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; }; diff -r 05e66ff64e10 -r 39f736210ab2 src/node/tcp-socket-factory.h --- 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. diff -r 05e66ff64e10 -r 39f736210ab2 src/node/tcp-socket.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/udp-socket-factory.h --- 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. diff -r 05e66ff64e10 -r 39f736210ab2 src/node/udp-socket.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/node/wscript --- 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', diff -r 05e66ff64e10 -r 39f736210ab2 src/routing/global-routing/global-route-manager-impl.cc --- 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 . // - 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/routing/global-routing/global-router-interface.cc --- 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; diff -r 05e66ff64e10 -r 39f736210ab2 src/routing/olsr/olsr-agent-impl.cc --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/routing/olsr/olsr-header.cc --- 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::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::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::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 ()); } } diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/event-id.h --- 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 &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 diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/event-impl.h --- 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; diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/heap-scheduler.cc --- 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 * - * 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" diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/list-scheduler.h --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/map-scheduler.h --- 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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/nstime.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/scheduler.h --- 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 { diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/simulator.cc --- 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 &event); EventId ScheduleNow (const Ptr &event); EventId ScheduleDestroy (const Ptr &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 ()) ; 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 &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 (); diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/simulator.h --- 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); @@ -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" diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/time.cc --- 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; } diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/timer.h --- 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 diff -r 05e66ff64e10 -r 39f736210ab2 src/simulator/watchdog.h --- 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); /** diff -r 05e66ff64e10 -r 39f736210ab2 src/wscript --- 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] diff -r 05e66ff64e10 -r 39f736210ab2 utils/bench-packets.cc --- 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 #include +#include 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 +std::string +BenchHeader::GetTypeName (void) +{ + std::ostringstream oss; + oss << "ns3::BenchHeader<" << N << ">"; + return oss.str (); +} + +template TypeId BenchHeader::GetTypeId (void) { - std::ostringstream oss; - oss << "ns3::BenchHeader<"<"; - static TypeId tid = TypeId (oss.str ().c_str ()) + static TypeId tid = TypeId (GetTypeName ().c_str ()) .SetParent
() ; return tid; @@ -105,10 +114,75 @@ return N; } +template +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 () + .AddConstructor () + .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 p = Create (2000); + p->AddTag (tag1); + p->AddHeader (udp); + p->FindFirstMatchingTag (tag1); + p->AddTag (tag2); + p->AddHeader (ipv4); + Ptr 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 p) +C2 (Ptr p) { BenchHeader<8> udp; @@ -145,15 +219,15 @@ } static void -ptrC1 (Ptr p) +C1 (Ptr 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 p = Create (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 p = Create (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; diff -r 05e66ff64e10 -r 39f736210ab2 wscript --- 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