Compare commits
491 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e70c7ac38 | |||
| bf0d4e7154 | |||
| e8fc6ec946 | |||
| be2b52ac8f | |||
| 7bb06e0661 | |||
| b56cad3cbc | |||
| 5bec43f720 | |||
| ee5f2a5475 | |||
| 2806d0edbe | |||
| 85cbeccd3e | |||
| 147510bb00 | |||
| cdc9002e41 | |||
| f8ae534480 | |||
| c6f3793178 | |||
| 96451fdb37 | |||
| feb47b3bb1 | |||
| 4f02439cb1 | |||
| a14e1de6cc | |||
| a30e3a7e94 | |||
| 450f9db5c6 | |||
| eca7dc5b27 | |||
| b4c23f8ebf | |||
| dd8985b92d | |||
| 9fcd20505c | |||
| a142d30a9d | |||
| c3658bd810 | |||
| 6e7d9062cb | |||
| a6438d91b4 | |||
| d2d16360c1 | |||
| 3b277785c0 | |||
| c3719a2eca | |||
| 3b58cf8c0e | |||
| b390f1ef73 | |||
| 02fd903228 | |||
| 52ca0dd3f6 | |||
| 6a874b283c | |||
| fd238f3e40 | |||
| 438036550f | |||
| a0e14bd523 | |||
| c8a76b7dd5 | |||
| c86c3ce16d | |||
| dd48772c9e | |||
| 53833582b7 | |||
| f262b76a41 | |||
| 441e17174d | |||
| defd58bc77 | |||
| 38f2897c29 | |||
| d9d019c5d4 | |||
| f23152d7a7 | |||
| d625837eb9 | |||
| cecd35e20b | |||
| 5ade799440 | |||
| 2786b195ee | |||
| 5f5518e05b | |||
| bd33305e5b | |||
| aa8bd8a8ba | |||
| 84cdad7f7d | |||
| 3c38ca5a1b | |||
| ffaf3e7d91 | |||
| a81a6fc0ec | |||
| 6c3559792c | |||
| 6292ead1f7 | |||
| 9a15ceadf6 | |||
| f61e9a9941 | |||
| 21a113f38f | |||
| 4f3bd6f9dd | |||
| d2c80f4d1a | |||
| 2949d86908 | |||
| 0fcbdbf0fe | |||
| 1dc22a9e8f | |||
| 5c769d2d24 | |||
| a2e63b7f0b | |||
| 44c33f1618 | |||
| 4730d7087f | |||
| 3b31a0234e | |||
| cac5b2ca97 | |||
| 3b08f13bf3 | |||
| e51bb180d4 | |||
| 4e97b6b47c | |||
| ed6ee71ded | |||
| 6c69295696 | |||
| fb72939392 | |||
| b61692f121 | |||
| 9ff2549315 | |||
| 3a4eb97315 | |||
| 4f58be6548 | |||
| 33bd62d32f | |||
| c547c88e89 | |||
| 2a4dcce444 | |||
| b41d008223 | |||
| a144ad9a1e | |||
| 93be0562cc | |||
| 64bb988613 | |||
| 3fcff1b1b3 | |||
| 6150ba4860 | |||
| 676307027c | |||
| 976f16c4d9 | |||
| b88e90fec3 | |||
| 2103459845 | |||
| 348eb1e187 | |||
| 1fb6ad5488 | |||
| 328aa2cc45 | |||
| 2deb2ea0f0 | |||
| bc1ab2d79b | |||
| f3e77eea3d | |||
| 6b0e717a19 | |||
| 906a9748b5 | |||
| 414c33ffc9 | |||
| 77f8c5cbf2 | |||
| 3f5d7030cb | |||
| c53c3afd46 | |||
| 33fd7f0c67 | |||
| 853f0a13e9 | |||
| 9569ad645b | |||
| 3a98117aa5 | |||
| 42092bc91e | |||
| 2d6f46dfa8 | |||
| f1f400bcee | |||
| a6e289c8ef | |||
| a83ec513a1 | |||
| f043a8789c | |||
| 30bbef4b14 | |||
| 26fb62c748 | |||
| 77c0e85775 | |||
| ac45276835 | |||
| cfa242a6a5 | |||
| 26599981a0 | |||
| 8fe2191d04 | |||
| 35b4c6c6b8 | |||
| e42ccef4a7 | |||
| 8449139061 | |||
| 16e7e60cab | |||
| c53988d01e | |||
| 1fea8b38fc | |||
| 7d6cd9ae7c | |||
| bd70c33606 | |||
| f2a0ca2b0e | |||
| 282543b759 | |||
| 15748575d8 | |||
| cc9655af45 | |||
| 465bf1c10a | |||
| eb1200a2cd | |||
| c1a71e53f9 | |||
| f5fe661c13 | |||
| f42e5c4814 | |||
| 135a4ab58c | |||
| b192207132 | |||
| 3464e84e90 | |||
| a0ee98cb4b | |||
| 01d7a64670 | |||
| cbafcb5aa6 | |||
| b604bf2d7a | |||
| 05efca8430 | |||
| 007f125e46 | |||
| 83dd618e5b | |||
| ffc992893f | |||
| b04e3d6cd6 | |||
| 5e19f9707b | |||
| 457d07a50f | |||
| 3262a4e103 | |||
| df27c80c72 | |||
| bc54e34375 | |||
| 49deb08b81 | |||
| b8fbe8341f | |||
| 07e46fb8aa | |||
| 0ee86b72fb | |||
| b54c43b966 | |||
| 1b82e5cba7 | |||
| 8a825ee775 | |||
| c91b667c13 | |||
| 32611749b2 | |||
| dd9e29c425 | |||
| 8debe6ef1d | |||
| bab56b0d88 | |||
| 0b43b4fdc2 | |||
| 210fb3539c | |||
| 026f3f2aef | |||
| 9b5d0a50f7 | |||
| d3df13225d | |||
| fb2ebab793 | |||
| 2f71efe6a7 | |||
| 7813d6fdd7 | |||
| 8ce92e1bc2 | |||
| 9316a5c23f | |||
| 64684b6b71 | |||
| f133bfaf9f | |||
| 3f174e0bd0 | |||
| 39a0e3b29c | |||
| ac8e86643e | |||
| 6a51ea96c0 | |||
| 94e2d9059a | |||
| 85c67ca048 | |||
| 99a5a8370f | |||
| 284ebcc23f | |||
| c156f29c86 | |||
| e075fcd4f3 | |||
| 49a8c459a8 | |||
| 1e45a4c9f5 | |||
| dd825831c7 | |||
| 1b17161758 | |||
| 908971e48b | |||
| ca76e83370 | |||
| 4774f44062 | |||
| f198acda79 | |||
| 86a564094c | |||
| f2c5dd8d71 | |||
| ed8ef96a61 | |||
| 87a1ae56d7 | |||
| 63331e705a | |||
| 6f447c2b6a | |||
| f415e99a36 | |||
| b699ad9ae1 | |||
| 632a762654 | |||
| a4a3bc72fc | |||
| b809739d8c | |||
| 7ad2a4c3f2 | |||
| 4c4332c88b | |||
| 6c0ef59a30 | |||
| 83714d4d03 | |||
| 7498ef647c | |||
| 321dfcf741 | |||
| bdc6fcf5dd | |||
| 50cd61e7c3 | |||
| 125796fec7 | |||
| d1d0e1c732 | |||
| 820fd1c13a | |||
| 577373aed9 | |||
| f992fe0b8d | |||
| ac99f9e46c | |||
| 225df7593f | |||
| 5ecad32251 | |||
| cfd44fc50c | |||
| 20f47863bf | |||
| c6cfbd4e8c | |||
| 8422056873 | |||
| 80ba651375 | |||
| 18e5bf9c07 | |||
| 0394180213 | |||
| b52be989ed | |||
| b15597dbe7 | |||
| 6aa4ae880a | |||
| 01d2d77a76 | |||
| 640a49e1ce | |||
| c8cf6df4cd | |||
| 7f0a1a1caf | |||
| d9942c0c32 | |||
| 391adea516 | |||
| aad088e588 | |||
| ed31e39491 | |||
| 34345b47d0 | |||
| 873a2c8dda | |||
| 838bef63b3 | |||
| 6d97118181 | |||
| 008e02b03c | |||
| 21baa41ccf | |||
| d20ccf186e | |||
| 3128aadfe0 | |||
| 03da97b0b8 | |||
| 2d39b3c2d0 | |||
| dada8dc1db | |||
| 5b47785ae4 | |||
| c18e92df67 | |||
| 8828ac5d30 | |||
| 83d717bcae | |||
| 21f9524b3e | |||
| c7078a3e10 | |||
| 1bbd9675b6 | |||
| 87db306da0 | |||
| c41da878f9 | |||
| 0a17e5ab7f | |||
| 2f356fd916 | |||
| 1bf52bda9e | |||
| 89117a326c | |||
| 51bc877b4e | |||
| f5772f0423 | |||
| 95596a53b0 | |||
| bb9c35ffea | |||
| 9e215a3493 | |||
| 3321873fc6 | |||
| fc57cac746 | |||
| dbdd00fef8 | |||
| 0986cb46d9 | |||
| e55384067b | |||
| 1a8421bbfe | |||
| ecc4bab8f2 | |||
| b5a64f2fae | |||
| 7e11cfb891 | |||
| cdcfbd8ab2 | |||
| 9964005525 | |||
| 3dd8898aaf | |||
| d3acfdfa07 | |||
| cb0eeaeb32 | |||
| b114ba4ec6 | |||
| 688683fdaf | |||
| f0740d8235 | |||
| bf33ac89eb | |||
| d030b978ab | |||
| 1acb811437 | |||
| 1bf7be4d2a | |||
| 44096d2f95 | |||
| 136cb036b4 | |||
| a1bfcd1216 | |||
| 277173ae0f | |||
| 28e6e63c5d | |||
| a49623136a | |||
| 9041f3ed1f | |||
| 745412ffb8 | |||
| 680c125dde | |||
| d072cdd527 | |||
| 570126f8ff | |||
| 5de828fa15 | |||
| 32f3411eca | |||
| 7509e66617 | |||
| 92d65a529f | |||
| 51590ad30f | |||
| ecd20983e8 | |||
| 7dca6e0b04 | |||
| 60b6fb3d39 | |||
| 9d1a3eff16 | |||
| d58602289d | |||
| 8845f347d3 | |||
| d6611f02ba | |||
| 3ed9dc6a94 | |||
| dbfc58c5ed | |||
| aedad2ccb0 | |||
| 1aa79965c7 | |||
| 4bef99703a | |||
| 1afa21922f | |||
| ca7f175fb7 | |||
| 81f5e4c039 | |||
| cb1b1daacd | |||
| 6862cc0ce9 | |||
| 6ff8bda568 | |||
| 8e78937160 | |||
| d7bfb88be9 | |||
| 46654ba28a | |||
| 34889dfb6a | |||
| e2a3b89175 | |||
| 6a51a05171 | |||
| 09bfa883ac | |||
| 6f0268171d | |||
| 4e5203a3dd | |||
| 58363c9dab | |||
| 0e7024488d | |||
| 6310a6040b | |||
| ec31e714d6 | |||
| a80d3bcf38 | |||
| ad9b41e45e | |||
| 9d643387fb | |||
| c570beefbd | |||
| 6f97972582 | |||
| 736368f441 | |||
| 7aede726ca | |||
| 228150cd72 | |||
| 9f4f9e7b2f | |||
| 629de5c931 | |||
| 30af256bb6 | |||
| 7340c86c61 | |||
| 0c5de08870 | |||
| 36a6d0c93c | |||
| 2d66b73e34 | |||
| 18517c1fe5 | |||
| 69dfc4fe32 | |||
| d7fe272673 | |||
| 40add040f9 | |||
| 766d7138ac | |||
| dc3fb38cbb | |||
| eb1e734628 | |||
| ba95d49a67 | |||
| a90aee32a0 | |||
| 8a9502ce01 | |||
| 8d46c4debc | |||
| fe2ab99c52 | |||
| a5467f201c | |||
| 976c3bbe98 | |||
| 551de62f42 | |||
| 434226dd01 | |||
| e770997d09 | |||
| 52d42bca30 | |||
| 3b5eba1c85 | |||
| 76af0aa6ed | |||
| 4a6e000a07 | |||
| cf2fbcb6e3 | |||
| 11c2f8c991 | |||
| 0d3182c278 | |||
| 1d2a21fa1f | |||
| c6763e76ee | |||
| 818c1ea9e9 | |||
| 0b4d0fcf67 | |||
| 384c4b998e | |||
| 449bd78db7 | |||
| 5d2227d3a6 | |||
| 0058449576 | |||
| 2059a57d96 | |||
| 8bb9ab629f | |||
| 73c536fa04 | |||
| 2d07bbdf2c | |||
| 83e7cf54f4 | |||
| 54725d30b1 | |||
| e688cc520b | |||
| ec5e79f86b | |||
| 87d56eb866 | |||
| 2922488eb9 | |||
| b8230bf5e6 | |||
| e66a3625b4 | |||
| 0c760dc107 | |||
| ad7ea01ee8 | |||
| 1026821e33 | |||
| 0296999ec8 | |||
| b2a44942a8 | |||
| 268e4d5ec9 | |||
| 4f562dbbfb | |||
| e9127c0427 | |||
| b2545f4d89 | |||
| 9c922e0c73 | |||
| d6721ea8ef | |||
| c8503d149e | |||
| d7f63afae7 | |||
| f79ee4b582 | |||
| 03fd848f18 | |||
| 258a44de1a | |||
| 20a04408a6 | |||
| 662356311a | |||
| 806cba6352 | |||
| fc0089c0f4 | |||
| 2c9b70a674 | |||
| 0bb0cb7b93 | |||
| 0e9a8e6c3d | |||
| c7d39c7975 | |||
| 382c3d1787 | |||
| 2ac8e7e496 | |||
| 230645ffa5 | |||
| 3861eada88 | |||
| a1691fda9b | |||
| ec7d64d30d | |||
| 8cda08d41c | |||
| 05fe040f88 | |||
| 756cc86a23 | |||
| 9e470dffc3 | |||
| 6e2080f092 | |||
| 24a0b73ce3 | |||
| 473c0eecb1 | |||
| dec333d063 | |||
| 61d85c75d3 | |||
| 8dab22328c | |||
| ac0991a7cc | |||
| bc276b2bc1 | |||
| 1e6415ce45 | |||
| e4f6408939 | |||
| 497bb74d5a | |||
| dee939e78c | |||
| bb9a9fb06d | |||
| 1a0edab86e | |||
| 673ac3faa9 | |||
| 3833b9b585 | |||
| 6ba9224f32 | |||
| d138a49895 | |||
| 0e434f0212 | |||
| f807067337 | |||
| 5e5800363e | |||
| d643cf8c1d | |||
| 0873562023 | |||
| ca890b509a | |||
| 59fc14c57c | |||
| 728d858f15 | |||
| 2029981f00 | |||
| 17a02b8fbb | |||
| 75a174bc7b | |||
| 086e01fcb8 | |||
| a219428887 | |||
| ca86b0acf9 | |||
| f20df8a492 | |||
| d742b306d7 | |||
| 119c647097 | |||
| 64c6fa6525 | |||
| 5a7965468d | |||
| 855ccbf300 | |||
| 9e055bd52f | |||
| d4a36c2e0f | |||
| 1d0c9511a5 | |||
| cd73b37673 | |||
| caf0a2c143 | |||
| 06cb649b55 | |||
| 3745686f38 | |||
| 327e60b275 | |||
| 2450bac944 | |||
| 46fe0fbc29 | |||
| 4bf8491d01 | |||
| a62ac4df3a | |||
| 9a7206b971 | |||
| e23f26a8f3 |
@@ -8,4 +8,4 @@
|
||||
^doc/latex
|
||||
^\.lock-wscript
|
||||
^\.waf
|
||||
^doc/trace-source-list\.h$
|
||||
^doc/introspected-doxygen\.h$
|
||||
|
||||
@@ -7,3 +7,6 @@
|
||||
267e2ebc28e4e4ae2f579e1cfc29902acade0c34 buffer-working-before-breaking
|
||||
606df29888e7573b825fc891a002f0757166b616 release ns-3.0.6
|
||||
36472385a1cc7c44d34fb7a5951b930010f4e8d2 release ns-3.0.7
|
||||
560a5091e0e6ded47d269e2f2dee780f13950a63 release ns-3.0.8
|
||||
4db981a0d9eb135e3e1c07765cff8d66f7a55cca release ns-3.0.9
|
||||
b5bf2588cde2f1273b1095cc5c83a0c272e55370 release ns-3.0.10
|
||||
|
||||
@@ -2,6 +2,7 @@ Raj Bhattarcharjea (raj.b@gatech.edu)
|
||||
Gustavo Carneiro (gjc@inescporto.pt, gjcarneiro@gmail.com)
|
||||
Craig Dowell (craigdo@ee.washington.edu)
|
||||
Tom Henderson (tomhend@u.washington.edu)
|
||||
Joe Kopena (tjkopena@cs.drexel.edu)
|
||||
Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
|
||||
Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
|
||||
George F. Riley (riley@ece.gatech.edu)
|
||||
|
||||
@@ -3,6 +3,36 @@
|
||||
|
||||
This file contains ns-3 release notes (most recent releases first).
|
||||
|
||||
Release 3.0.11 (2008/02/15)
|
||||
========================
|
||||
- Initial port of GTNetS TCP implementation (initial version
|
||||
that does not support multitasking or delayed acknowledgments yet,
|
||||
but supports a reliable stream service)
|
||||
- Changes to the ns-3 object model to create a TypeId-based
|
||||
metadata system
|
||||
- lots of bug fixes throughout the system
|
||||
- tutorial updates
|
||||
|
||||
Release 3.0.10 (2008/01/15)
|
||||
========================
|
||||
- Add tutorial document content;
|
||||
- Valgrind option for "waf" tool;
|
||||
- Doxygen organization changes.
|
||||
|
||||
Release 3.0.9 (2007/12/15)
|
||||
========================
|
||||
- A 802.11 model ported from Yans. This model supports:
|
||||
* a rather extensive PHY model
|
||||
* log-distance and friis propagation model
|
||||
* a simple set of rate control algorithms (ARF, Ideal,
|
||||
AARF, constant-rate)
|
||||
* adhoc and infrastructure mode (beacon+assoc)
|
||||
- Use smart pointer for Packet in the APIs
|
||||
- A new contrib directory with helper classes:
|
||||
EventGarbageCollector, Gnuplot
|
||||
- Tracing support for Applications
|
||||
- many bugs fixed
|
||||
|
||||
Release 3.0.8 (2007/11/15)
|
||||
========================
|
||||
- A simple error model
|
||||
|
||||
+7
-5
@@ -185,7 +185,7 @@ TAB_SIZE = 4
|
||||
# will result in a user-defined paragraph with heading "Side Effects:".
|
||||
# You can put \n's in the value part of an alias to insert newlines.
|
||||
|
||||
ALIASES =
|
||||
ALIASES = valueref{1}="\ref DefaultValue\1 \"\1\""
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
|
||||
# sources only. Doxygen will then generate output that is more tailored for C.
|
||||
@@ -493,10 +493,12 @@ WARN_LOGFILE =
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = src \
|
||||
doc/main.txt \
|
||||
doc/trace-source-list.h \
|
||||
doc/tracing.h
|
||||
INPUT = doc/modules \
|
||||
doc/main.h \
|
||||
doc/introspected-doxygen.h \
|
||||
doc/tracing.h \
|
||||
doc/howtos/ \
|
||||
src
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files that
|
||||
# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*!
|
||||
\page callbacks Using ns-3 callbacks
|
||||
\anchor howtos-callbacks
|
||||
|
||||
\section null_callbacks Null Callbacks
|
||||
|
||||
<b>Question:</b> The API I am using calls for using a callback (in the
|
||||
function signature), but I do not
|
||||
want to provide one. Is there a way to provide a null callback?
|
||||
|
||||
<b>Answer:</b> Use the ns3::MakeNullCallback construct:
|
||||
\code
|
||||
template<typename R>
|
||||
Callback< R, T1, T2, T3, T4, T5, T6 > ns3::MakeNullCallback (void)
|
||||
\endcode
|
||||
|
||||
Example usage: The ns3::Socket class uses callbacks to indicate completion
|
||||
of events such as a successful TCP connect(). These callbacks are set
|
||||
in the following function:
|
||||
\code
|
||||
void Socket::SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
|
||||
Callback<void, Ptr<Socket> > connectionFailed,
|
||||
Callback<void, Ptr<Socket> > halfClose);
|
||||
|
||||
\endcode
|
||||
But suppose you do not care about registering a callback for the
|
||||
halfClose event (but you want to register one for the
|
||||
connectionSucceeded and connectionFailed cases). In that case, you
|
||||
can pass a null callback as the third argument. You just need to
|
||||
pass a callback with the matching signature, as follows:
|
||||
\code
|
||||
localSocket->SetConnectCallback (
|
||||
MakeCallback (&ConnectionSucceededCallback),
|
||||
MakeCallback (&ConnectionFailedCallback),
|
||||
MakeNullCallback<void, Ptr<Socket> > () );
|
||||
\endcode
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,17 @@
|
||||
/*!
|
||||
\page howtos ns-3 HOWTOs
|
||||
\anchor howtos-anchor
|
||||
|
||||
This is an organized set of frequently asked questions (FAQ) and HOWTOs
|
||||
for ns-3. This complements the following wiki pages:
|
||||
|
||||
- <a href="http://www.nsnam.org/wiki/index.php/User_FAQ">User FAQ</a>
|
||||
- <a href="http://www.nsnam.org/wiki/index.php/Developer_FAQ">Developer FAQ</a>
|
||||
|
||||
Please consider contributing tips to either the wiki (yourself) or
|
||||
by submitting a patch to this maintained documentation.
|
||||
|
||||
- \subpage callbacks
|
||||
|
||||
*/
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* \mainpage ns-3 Documentation
|
||||
*
|
||||
* \section intro-sec Introduction
|
||||
* <a href="http://www.nsnam.org/">ns-3</a> documentation is maintained using
|
||||
* <a href="http://www.doxygen.org">Doxygen</a>.
|
||||
* Doxygen is typically used for
|
||||
* API documentation, and organizes such documentation across different
|
||||
* modules. This project uses Doxygen both for building the manual around
|
||||
* the API documentation, and a separate GNU texinfo document is used for
|
||||
* the manual.
|
||||
*
|
||||
* The ns-3 project documentation is organized as follows:
|
||||
* - <b><a href="modules.html">modules</a></b>: The "Modules" tab (above)
|
||||
* organizes all of the public API and supporting manual text
|
||||
* along the source code directory structure. This forms the
|
||||
* "ns-3 manual", and it is available in HTML and PDF forms.
|
||||
* - \ref howtos-anchor "HOWTOs": A set of HOWTOs and FAQs is
|
||||
* maintained on another Doxygen "Related Page"
|
||||
* - <a href="http://www.nsnam.org/docs/tutorial/tutorial.html">tutorial</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
|
||||
* - The <b><a href="http://www.nsnam.org/wiki/index.php/Main_Page">ns-3 wiki</a></b>
|
||||
* contains additional user-contributed material. Some wiki-contributed
|
||||
* material may migrate to and overlap with the Doxygen information.
|
||||
*
|
||||
* \section install-sec Building the Documentation
|
||||
*
|
||||
* ns-3 requires Doxygen version 1.5.4 or greater to fully build all items,
|
||||
* although earlier versions of Doxygen will mostly work.
|
||||
*
|
||||
* Type "./waf check" followed by "./waf --doxygen" to build the documentation.
|
||||
* There is a program that runs during "./waf check" that builds pieces of
|
||||
* the documentation through introspection. The doc/ directory contains
|
||||
* configuration for Doxygen (doxygen.conf and main.txt). The Doxygen
|
||||
* build process puts html files into the doc/html/ directory, and latex
|
||||
* filex into the doc/latex/ directory.
|
||||
*
|
||||
* \section module-sec Module overview
|
||||
*
|
||||
* The ns-3 library is split across multiple modules:
|
||||
* - core: located in src/core and contains a number of facilities which
|
||||
* do not depend on any other module. Some of these facilities are
|
||||
* OS-dependent.
|
||||
* - simulator: located in src/simulator and contains event scheduling
|
||||
* facilities.
|
||||
* - common: located in src/common and contains facilities specific
|
||||
* to network simulations but shared by pretty much every model
|
||||
* of a network component.
|
||||
* - node: located in src/node. Defines the abstract interfaces which
|
||||
* must be implemented by every node and more specifically, by ipv4 nodes.
|
||||
* - devices: located in src/devices. Contains a set of MAC-level models
|
||||
*
|
||||
* More detail can be found in the <b><a href="modules.html">Modules</a></b>
|
||||
* tab.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* \namespace ns3
|
||||
* \brief Every class exported by the ns3 library is enclosed in the
|
||||
* ns3 namespace.
|
||||
*/
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* \mainpage An Introduction to ns-3
|
||||
*
|
||||
* The ns-3 library is split across multiple modules:
|
||||
* - core: located in src/core and contains a number of facilities which
|
||||
* do not depend on any other module. Some of these facilities are
|
||||
* OS-dependent.
|
||||
* - simulator: located in src/simulator and contains event scheduling
|
||||
* facilities.
|
||||
* - common: located in src/common and contains facilities specific
|
||||
* to network simulations but shared by pretty much every model
|
||||
* of a network component.
|
||||
* - node: located in src/node. Defines the abstract interfaces which
|
||||
* must be implemented by every node and more specifically, by ipv4 nodes.
|
||||
* - devices: located in src/devices. Contains a set of MAC-level models
|
||||
*
|
||||
* The "core" module contains:
|
||||
* - 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
|
||||
* - \ref randomvariable
|
||||
* - \ref config
|
||||
* - a base class for objects which need to support reference counting
|
||||
* and QueryInterface: ns3::Object and ns3::InterfaceId
|
||||
* - a set of low-level trace facilities integrated in the ns3::Object system: \ref tracing
|
||||
* - a ns3::ComponentManager which can be used to manage the creation
|
||||
* of any object which derives from ns3::Object through an ns3::ClassId
|
||||
* - a smart-pointer class ns3::Ptr designed to work together with ns3::Object
|
||||
*
|
||||
* The "simulator" module contains:
|
||||
* - a time management class to hold a time and convert between various time units: ns3::Time
|
||||
* - a scheduler base class used to implement new simulation event schedulers:
|
||||
* ns3::Scheduler and ns3::SchedulerFactory
|
||||
* - a simulator class used to create, schedule and cancel events: ns3::Simulator
|
||||
*
|
||||
* The "core" module contains:
|
||||
* - a packet class to create and manipulate simulation packets: ns3::Packet, ns3::Header,
|
||||
* and ns3::Trailer. This packet class also supports per-packet ns3::Tag which are
|
||||
* globs of data which can be attached to any packet.
|
||||
*
|
||||
* The "node" module contains:
|
||||
* - a ns3::Node base class which should be subclassed by any new type of
|
||||
* network Node.
|
||||
* - models which abstract the MAC-layer from the IP layer protocols:
|
||||
* ns3::NetDevice and ns3::Channel.
|
||||
* - models which abstract the application-layer API: ns3::Application,
|
||||
* ns3::Socket, ns3::SocketFactory, and, ns3::Udp
|
||||
*
|
||||
* The "internet-node" module contains a set of classes which implement the
|
||||
* APIs defined in the "node" module:
|
||||
* - an Ipv4/Udp stack with socket support
|
||||
* - an ARP module
|
||||
* - an InternetNode class which is a Node subclass.
|
||||
*
|
||||
* The "devices" module contains:
|
||||
* - a PointToPoint MAC device: ns3::PointToPointNetDevice, ns3::PointToPointChannel,
|
||||
* and ns3::PointToPointTopology.
|
||||
*/
|
||||
/**
|
||||
* \namespace ns3
|
||||
* \brief Every class exported by the ns3 library is enclosed in the
|
||||
* ns3 namespace.
|
||||
*/
|
||||
/**
|
||||
* \defgroup constants Constants
|
||||
* \brief Constants you can change
|
||||
*/
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @anchor modules_anchor
|
||||
*
|
||||
* @defgroup simulator Simulator
|
||||
* The "simulator" module contains:
|
||||
* - a time management class to hold a time and convert between various time units: ns3::Time
|
||||
* - a scheduler base class used to implement new simulation event schedulers:
|
||||
* ns3::Scheduler and ns3::SchedulerFactory
|
||||
* - a simulator class used to create, schedule and cancel events: ns3::Simulator
|
||||
*
|
||||
* @defgroup core Core
|
||||
* \brief The "core" module contains:
|
||||
* - 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
|
||||
* - \ref randomvariable
|
||||
* - \ref config
|
||||
* - a base class for objects which need to support reference counting
|
||||
* and QueryInterface: ns3::Object and ns3::InterfaceId
|
||||
* - a set of low-level trace facilities integrated in the ns3::Object system: \ref tracing
|
||||
* - a ns3::ComponentManager which can be used to manage the creation
|
||||
* of any object which derives from ns3::Object through an ns3::ClassId
|
||||
* - a smart-pointer class ns3::Ptr designed to work together with ns3::Object
|
||||
*
|
||||
* @defgroup common Common
|
||||
* The "core" module contains:
|
||||
* - a packet class to create and manipulate simulation packets:
|
||||
* ns3::Packet, ns3::Header, and ns3::Trailer. This packet class
|
||||
* also supports per-packet ns3::Tag which are globs of data
|
||||
* which can be attached to any packet.
|
||||
*
|
||||
* @defgroup node Node
|
||||
* The "node" module contains:
|
||||
* - a ns3::Node base class which should be subclassed by any new type of
|
||||
* network Node.
|
||||
* - models which abstract the MAC-layer from the IP layer protocols:
|
||||
* ns3::NetDevice and ns3::Channel.
|
||||
* - models which abstract the application-layer API: ns3::Application,
|
||||
* ns3::Socket, ns3::SocketFactory, and, ns3::Udp
|
||||
*
|
||||
*
|
||||
* @defgroup devices Devices
|
||||
* The "devices" module contains:
|
||||
* - a PointToPoint MAC device: ns3::PointToPointNetDevice, ns3::PointToPointChannel,
|
||||
* and ns3::PointToPointTopology.
|
||||
*
|
||||
* @defgroup internetNode InternetNode
|
||||
*
|
||||
* The "internet-node" module contains a set of classes which implement the
|
||||
* APIs defined in the "node" module:
|
||||
* - an Ipv4/Udp stack with socket support
|
||||
* - an ARP module
|
||||
* - an InternetNode class which is a Node subclass.
|
||||
*
|
||||
* @defgroup applications Applications
|
||||
*
|
||||
* @defgroup mobility Mobility
|
||||
*
|
||||
* @defgroup routing Routing
|
||||
*
|
||||
* @defgroup constants Constants
|
||||
* @brief Constants you can change
|
||||
*
|
||||
* @defgroup contrib Contrib
|
||||
*/
|
||||
|
||||
+13
-12
@@ -7,28 +7,29 @@ Steps in doing an ns-3 release
|
||||
- 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
|
||||
2. make a new "architecture.pdf" document and place it in the doc/ directory
|
||||
of the ns-3-dev working directory
|
||||
3. ./waf configure; ./waf dist
|
||||
2. ./waf configure; ./waf dist
|
||||
- this will create a ns-3.0.x.tar.bz2 tarball
|
||||
4. test tarball on release platforms (waf check and maybe some other scripts)
|
||||
5. once you are happy with the tarball, tag ns-3-dev with "release ns-3.0.X"
|
||||
3. test tarball on release platforms (waf check and maybe some other scripts)
|
||||
4. once you are happy with the tarball, tag ns-3-dev with "release ns-3.0.X"
|
||||
- hg tag "release ns-3.0.x"
|
||||
- hg push
|
||||
6. clone the tagged ns-3-dev and place it on the repository
|
||||
5. clone the tagged ns-3-dev and place it on the repository
|
||||
- ssh code.nsnam.org; sudo; su code;
|
||||
- cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x
|
||||
- cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately
|
||||
7. upload "ns-3.0.x.tar.bz2" to the /var/www/html/releases/ directory on
|
||||
- cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately:
|
||||
"description = ns-3.0.x release
|
||||
name = ns-3.0.x"
|
||||
6. upload "ns-3.0.x.tar.bz2" to the /var/www/html/releases/ directory on
|
||||
the www.nsnam.org server
|
||||
8. update web page
|
||||
- give it 600 permissions, and user/group = apache
|
||||
8. update web pages on www.nsnam.org (source is in the www/ module)
|
||||
- add link to news.html
|
||||
- update getting_started.html
|
||||
- update documents.html
|
||||
- update roadmap on wiki
|
||||
- build and update Doxygen directory on the server
|
||||
-- ssh www.nsnam.org; sudo tcsh; su nsnam;
|
||||
-- ~/bin/update-doxygen-release
|
||||
- update and upload software architecture document (PDF, HTML)
|
||||
-- note: HTML image generation is not currently automatic
|
||||
-- edit ~/bin/update-doxygen-release file and change RELEASE variable
|
||||
to the right version number
|
||||
-- run ~/bin/update-doxygen-release
|
||||
9. announce to ns-developers, with summary of release notes
|
||||
|
||||
+38
-36
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup TraceSourceList List of trace sources
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup tracing Tracing
|
||||
*
|
||||
* The flexibility of the ns-3 tracing system comes at the cost of quite
|
||||
@@ -55,7 +57,7 @@
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void DoSomething (Packet packet)
|
||||
* void DoSomething (Ptr<Packet> packet)
|
||||
* {
|
||||
* // report this event on packet
|
||||
* m_doSomething (packet);
|
||||
@@ -63,7 +65,7 @@
|
||||
* }
|
||||
* private:
|
||||
* // report every "something" function call.
|
||||
* CallbackTraceSource<Packet> m_doSomething;
|
||||
* CallbackTraceSource<Ptr<Packet> > m_doSomething;
|
||||
* };
|
||||
* \endcode
|
||||
* Every type of trace source derives from the ns3::TraceSource base class.
|
||||
@@ -86,10 +88,10 @@
|
||||
* std::cout << "cwnd=" << newValue << std::endl;
|
||||
* }
|
||||
* void
|
||||
* DoSomethingTraceSink (const TraceContext &context, Packet packet)
|
||||
* DoSomethingTraceSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // for example, print the arguments
|
||||
* std::cout << "packet " << packet << std::endl;
|
||||
* // for example, print the packet
|
||||
* std::cout << "packet " << packet->Print () << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
* Each of these sink function takes, as a first argument, a reference to a
|
||||
@@ -121,19 +123,19 @@
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void DoSomething (Packet packet)
|
||||
* void DoSomething (Ptr<Packet> packet)
|
||||
* {
|
||||
* // report this event on packet
|
||||
* m_doSomething (packet);
|
||||
* // do something
|
||||
* }
|
||||
* CallbackTraceSource<Packet> *PeekSomethingTraceSource (void) const
|
||||
* CallbackTraceSource<Ptr<Packet>> *PeekSomethingTraceSource (void) const
|
||||
* {
|
||||
* return &m_doSomething
|
||||
* }
|
||||
* private:
|
||||
* // report every "something" function call.
|
||||
* CallbackTraceSource<Packet> m_doSomething;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_doSomething;
|
||||
* };
|
||||
* \endcode
|
||||
* If your users hold a pointer to an instance of MyModel, and if they want to connect
|
||||
@@ -142,12 +144,12 @@
|
||||
* sink with the MakeCallback function.
|
||||
* \code
|
||||
* void
|
||||
* MySomethingSink (const TraceContext &context, Packet packet)
|
||||
* MySomethingSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // do whatever you want.
|
||||
* }
|
||||
* MyModel *model = ...;
|
||||
* CallbackTraceSource<Packet> *source = model->PeekSomethingTraceSource ();
|
||||
* CallbackTraceSource<Ptr<Packet>> *source = model->PeekSomethingTraceSource ();
|
||||
* source->AddCallback (MakeCallback (&MySomethingSink));
|
||||
* \endcode
|
||||
*
|
||||
@@ -170,13 +172,13 @@
|
||||
* located in some nodes of the system, we could write the following:
|
||||
* \code
|
||||
* void
|
||||
* DoSomethingTraceSink (const TraceContext &context, Packet packet)
|
||||
* DoSomethingTraceSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // for example, print the arguments
|
||||
* std::cout << "packet: " << packet << std::endl;
|
||||
* // for example, print the packet
|
||||
* std::cout << "packet: " << packet->Print () << std::endl;
|
||||
* }
|
||||
* // connect the above sink to a matching trace source
|
||||
* NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback &DoSomethingTraceSink);
|
||||
* NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback (&DoSomethingTraceSink));
|
||||
* \endcode
|
||||
*
|
||||
* The connection path string "/nodes/* /devices/* /rx" matches the "rx" trace source
|
||||
@@ -203,10 +205,10 @@
|
||||
* the TraceContext object:
|
||||
* \code
|
||||
* void
|
||||
* DoSomethingTraceSink (const TraceContext &context, Packet packet)
|
||||
* DoSomethingTraceSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // for example, print the arguments
|
||||
* std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
|
||||
* // for example, print the packet
|
||||
* std::cout << "context=\"" << context << "\" packet: " << packet->Print () << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
* The above code is going to generate output which looks like the following:
|
||||
@@ -223,7 +225,7 @@
|
||||
* in the \ref TraceSourceList. For example, we could write the following to
|
||||
* generate adhoc trace output:
|
||||
* \code
|
||||
* void DeviceRxSink (const TraceContext &context, const Packet &packet)
|
||||
* void DeviceRxSink (const TraceContext &context, Ptr<const Packet> packet)
|
||||
* {
|
||||
* NodeListIndex nodeIndex;
|
||||
* NodeNetDeviceIndex deviceIndex;
|
||||
@@ -231,7 +233,7 @@
|
||||
* context.GetElement (deviceIndex);
|
||||
* std::cout << "node-index=" << nodeIndex.Get ();
|
||||
* std::cout << ", device-index=" << deviceIndex.Get ();
|
||||
* std::cout << ", packet: " << packet;
|
||||
* std::cout << ", packet: " << packet->Print ();
|
||||
* std::cout << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
@@ -247,7 +249,7 @@
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void DoSomething (Packet packet)
|
||||
* void DoSomething (Ptr<Packet> packet)
|
||||
* {
|
||||
* // report this event on packet with value
|
||||
* m_doSomething (packet);
|
||||
@@ -255,7 +257,7 @@
|
||||
* }
|
||||
* private:
|
||||
* // report every "something" function call.
|
||||
* CallbackTraceSource<Packet> m_doSomething;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_doSomething;
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
@@ -279,7 +281,7 @@
|
||||
* virtual Ptr<TraceResolver> GetTraceResolver (void) const;
|
||||
* private:
|
||||
* // the new trace source to export.
|
||||
* CallbackTraceSource<Packet> m_rxSource;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_rxSource;
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
@@ -362,15 +364,15 @@
|
||||
* class MyModel
|
||||
* {
|
||||
* private:
|
||||
* CallbackTraceSource<Packet> m_rxSource;
|
||||
* CallbackTraceSource<Packet> m_txSource;
|
||||
* CallbackTraceSource<Packet> m_dropSource;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_rxSource;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_txSource;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_dropSource;
|
||||
* };
|
||||
* \endcode
|
||||
* When a single sink is connected to all 3 sources here, one might want
|
||||
* to write code like the following:
|
||||
* \code
|
||||
* void DeviceRxSink (const TraceContext &context, const Packet &packet)
|
||||
* void DeviceRxSink (const TraceContext &context, Ptr<const Packet> &packet)
|
||||
* {
|
||||
* switch (type) {
|
||||
* case RX:
|
||||
@@ -407,23 +409,23 @@
|
||||
* };
|
||||
* private:
|
||||
* // generate events
|
||||
* void NotifyRxPacket (Packet p) {
|
||||
* void NotifyRxPacket (Ptr<Packet> p) {
|
||||
* m_rxSource (p, MyModel::RX);
|
||||
* }
|
||||
* void NotifyTxPacket (Packet p) {
|
||||
* void NotifyTxPacket (Ptr<Packet> p) {
|
||||
* m_rxSource (p, MyModel::TX);
|
||||
* }
|
||||
* void NotifyDropPacket (Packet p) {
|
||||
* void NotifyDropPacket (Ptr<Packet> p) {
|
||||
* m_rxSource (p, MyModel::DROP);
|
||||
* }
|
||||
* CallbackTraceSource<Packet,enum TraceType> m_rxSource;
|
||||
* CallbackTraceSource<Packet,enum TraceType> m_txSource;
|
||||
* CallbackTraceSource<Packet,enum TraceType> m_dropSource;
|
||||
* CallbackTraceSource<Ptr<Packet>,enum TraceType> m_rxSource;
|
||||
* CallbackTraceSource<Ptr<Packet>,enum TraceType> m_txSource;
|
||||
* CallbackTraceSource<Ptr<Packet>,enum TraceType> m_dropSource;
|
||||
* };
|
||||
* \endcode
|
||||
* These 3 new sources can be connected easily to a new trace sink:
|
||||
* \code
|
||||
* void ASimpleTraceSink (const TraceContext &context, const Packet &packet, enum MyModel::TraceType type)
|
||||
* void ASimpleTraceSink (const TraceContext &context, Ptr<const Packet> packet, enum MyModel::TraceType type)
|
||||
* {
|
||||
* // here, read the "type" argument
|
||||
* }
|
||||
@@ -447,7 +449,7 @@
|
||||
* define a new MyModelTraceType class which contains the type of trace, your users can
|
||||
* then write trace sink code which looks like this:
|
||||
* \code
|
||||
* void AFancyTraceSink (const TraceContext &context, const Packet &packet)
|
||||
* void AFancyTraceSink (const TraceContext &context, Ptr<const Packet> packet)
|
||||
* {
|
||||
* MyModelTraceType type;
|
||||
* if (context.GetElement (type))
|
||||
@@ -471,9 +473,9 @@
|
||||
* Of course, since the type of trace is stored in the TraceContext, your users can
|
||||
* also take the shortcut which uses the printing functionality of the TraceContext:
|
||||
* \code
|
||||
* void ALessFancyTraceSink (const TraceContext &context, const Packet &packet)
|
||||
* void ALessFancyTraceSink (const TraceContext &context, Ptr<const Packet> packet)
|
||||
* {
|
||||
* std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
|
||||
* std::cout << "context=\"" << context << "\" packet: " << packet->Print () << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
* which will generate something like the following when the trace source comes
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
@node ns-3 Callbacks
|
||||
@chapter ns-3 Callbacks
|
||||
|
||||
Some new users to @command{ns-3} are unfamiliar with an extensively used
|
||||
programming idiom used throughout the code: the ``ns-3 callback''. This
|
||||
chapter provides some motivation on the callback, guidance on how to use
|
||||
it, and details on its implementation.
|
||||
|
||||
@menu
|
||||
* Motivation::
|
||||
* Using the Callback API::
|
||||
* Callback locations in ns-3::
|
||||
* Implementation details::
|
||||
@end menu
|
||||
|
||||
@node Motivation
|
||||
@section Motivation
|
||||
|
||||
Consider that you have two simulation models A and B, and you wish
|
||||
to have them pass information between them during the simulation. One
|
||||
way that you can do that is that you can make A and B each explicitly
|
||||
knowledgable about the other, so that they can invoke methods on each
|
||||
other.
|
||||
|
||||
@verbatim
|
||||
class A {
|
||||
public:
|
||||
void ReceiveInput ( // parameters );
|
||||
...
|
||||
}
|
||||
|
||||
(in another source file:)
|
||||
|
||||
class B {
|
||||
public:
|
||||
void ReceiveInput ( // parameters);
|
||||
void DoSomething (void);
|
||||
...
|
||||
|
||||
private:
|
||||
A* a_instance; // pointer to an A
|
||||
}
|
||||
|
||||
void
|
||||
B::DoSomething()
|
||||
{
|
||||
// Tell a_instance that something happened
|
||||
a_instance->ReceiveInput ( // parameters);
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This certainly works, but it has the drawback that it introduces a
|
||||
dependency on A and B to know about the other at compile time (this
|
||||
makes it harder to have independent compilation units in the simulator)
|
||||
and is not generalized; if in a later usage scenario, B needs to talk
|
||||
to a completely different C object, the source code for B needs to be
|
||||
changed to add a ``c_instance'' and so forth. It is easy to see that
|
||||
this is a brute force mechanism of communication that can lead to
|
||||
programming cruft in the models.
|
||||
|
||||
This is not to say that objects should not know about one another
|
||||
if there is a hard dependency between them, but that often the model
|
||||
can be made more flexible if its interactions are less constrained at
|
||||
compile time.
|
||||
|
||||
This is not an abstract problem for network simulation research,
|
||||
but rather it has been a source of problems in previous simulators,
|
||||
when researchers want to extend or modify the system to do different
|
||||
things (as they are apt to do in research). Consider, for example,
|
||||
a user who wants to add an IPsec security protocol sublayer
|
||||
between TCP and IP:
|
||||
@verbatim
|
||||
------------ -----------
|
||||
| TCP | | TCP |
|
||||
------------ -----------
|
||||
| becomes -> |
|
||||
----------- -----------
|
||||
| IP | | IPsec |
|
||||
----------- -----------
|
||||
|
|
||||
-----------
|
||||
| IP |
|
||||
-----------
|
||||
@end verbatim
|
||||
If the simulator has
|
||||
made assumptions, and hard coded into the code, that IP always talks
|
||||
to a transport protocol above, the user may be forced to hack the
|
||||
system to get the desired interconnections.
|
||||
|
||||
An alternative that provides this flexibility is to use a level of
|
||||
indirection that is commonly known in programming as a callback.
|
||||
A callback function is not invoked explicitly by the caller but is
|
||||
rather delegated to another function that receives the callback
|
||||
function's address and can call it.
|
||||
|
||||
You may be familiar with function pointers in C or C++; these can
|
||||
be used to implement callbacks. For more information on introductory
|
||||
callbacks, an online reference is:
|
||||
@uref{http://www.inquiry.com/techtips/cpp_pro/10min/10min0300.asp,,Declaring Function Pointers and Implementing Callbacks} and
|
||||
@uref{http://en.wikipedia.org/wiki/Callback_(computer_science),,Callback (computer science)-- Wikipedia}.
|
||||
|
||||
The callback API in @command{ns-3} is designed to minimize the overall
|
||||
coupling between various pieces of of the simulator
|
||||
by making each module depend on the callback API
|
||||
itself rather than depend on other modules. It acts as a sort of
|
||||
third-party to which work is delegated and which forwards this
|
||||
work to the proper target module. This callback API, being based
|
||||
on C++ templates,
|
||||
is type-safe; that is, it performs static type checks to enforce
|
||||
proper signature compatibility between callers and callees. It
|
||||
is therefore more type-safe to use than traditional function
|
||||
pointers, but the syntax may look imposing at first. This section
|
||||
is designed to walk you through the callback system so that you
|
||||
can be comfortable using it in @command{ns-3}.
|
||||
|
||||
@node Using the Callback API
|
||||
@section Using the Callback API
|
||||
|
||||
The Callback API is fairly minimal, providing only two services:
|
||||
@itemize @bullet
|
||||
@item callback type declaration: a way to declare a type of callback
|
||||
with a given signature, and,
|
||||
@item callback instantiation: a way to instantiate a
|
||||
template-generated forwarding callback which can forward any calls
|
||||
to another C++ class member method or C++ function.
|
||||
@end itemize
|
||||
|
||||
This is best observed via walking through an example, based on
|
||||
@code{samples/main-callback.cc}.
|
||||
|
||||
@node Using the Callback API with static functions
|
||||
@subsection Using the Callback API with static functions
|
||||
|
||||
Consider a function:
|
||||
@verbatim
|
||||
static double
|
||||
CbOne (double a, double b)
|
||||
{
|
||||
std::cout << "invoke cbOne a=" << a << ", b=" << b << std::endl;
|
||||
return a;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Consider also the following main program snippett:
|
||||
@verbatim
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// return type: double
|
||||
// first arg type: double
|
||||
// second arg type: double
|
||||
Callback<double, double, double> one;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This class template Callback implements what is known as the Functor
|
||||
Design Pattern. It is used to declare the type of a callback. It contains
|
||||
one mandatory argument (the return type of the function to be assigned
|
||||
to this callback) and up to five optional arguments, which each specify
|
||||
the type of the arguments (if your function has more than five arguments,
|
||||
then this can be handled by extending the callback implementation).
|
||||
|
||||
So in the above, we have a declared a callback named "one" that will
|
||||
eventually hold a function pointer. The function that it will hold
|
||||
must return double and must support two double arguments. If one
|
||||
tries to pass a function whose signature does not match the declared
|
||||
callback, the compilation will fail.
|
||||
|
||||
Now, we need to tie together this callback instance and the actual
|
||||
target function (CbOne). Notice above that CbOne has the same function
|
||||
signature types as the callback-- this is important. We can
|
||||
pass in any such properly-typed function to this callback. Let's
|
||||
look at this more closely:
|
||||
@verbatim
|
||||
static double CbOne (double a, double b) {}
|
||||
^ ^ ^
|
||||
| ---| ------|
|
||||
| | |
|
||||
Callback<double, double, double> one;
|
||||
@end verbatim
|
||||
You can only bind a function to a callback if they have the matching
|
||||
signature. The first template argument is the return type, and the
|
||||
additional template arguments are the types of the arguments of
|
||||
the function signature.
|
||||
|
||||
Now, let's bind our callback "one" to the function that matches its
|
||||
signature:
|
||||
@verbatim
|
||||
// build callback instance which points to cbOne function
|
||||
one = MakeCallback (&CbOne);
|
||||
@end verbatim
|
||||
|
||||
Then, later in the program, if the callback is to be used, it can be
|
||||
used as follows:
|
||||
@verbatim
|
||||
// this is not a null callback
|
||||
NS_ASSERT (!one.IsNull ());
|
||||
// invoke cbOne function through callback instance
|
||||
double retOne;
|
||||
retOne = one (10.0, 20.0);
|
||||
@end verbatim
|
||||
|
||||
The check @code{IsNull()} ensures that the callback is not null; that there
|
||||
is a function to call behind this callback. Then, @code{one()} returns the
|
||||
same result as if @code{CbOne()} had been called directly.
|
||||
|
||||
|
||||
@node Using the Callback API with member functions
|
||||
@subsection Using the Callback API with member functions
|
||||
|
||||
Generally, you will not be calling static functions but instead
|
||||
public member functions of an object. In this case, an extra
|
||||
argument is needed to the MakeCallback function, to tell the system
|
||||
on which object the function should be invoked. Consider this example,
|
||||
also from main-callback.cc:
|
||||
|
||||
@verbatim
|
||||
class MyCb {
|
||||
public:
|
||||
int CbTwo (double a) {
|
||||
std::cout << "invoke cbTwo a=" << a << std::endl;
|
||||
return -5;
|
||||
}
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
// return type: int
|
||||
// first arg type: double
|
||||
Callback<int, double> two;
|
||||
MyCb cb;
|
||||
// build callback instance which points to MyCb::cbTwo
|
||||
two = MakeCallback (&MyCb::CbTwo, &cb);
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Here, we pass a (raw) pointer to the @code{MakeCallback<>} function,
|
||||
that says, when @code{two ()} is invoked, to call the @code{CbTwo} function
|
||||
on the object pointed to by @code{&cb}.
|
||||
|
||||
A variation of this is used when objects are referred to by ns-3 smart
|
||||
pointers. The MakeCallback API takes a raw pointer, so we need to
|
||||
call @code{PeekPointer ()} to obtain this raw pointer. So the example
|
||||
above would look like:
|
||||
|
||||
@verbatim
|
||||
class MyCb : public Object {
|
||||
public:
|
||||
int CbTwo (double a) {
|
||||
std::cout << "invoke cbTwo a=" << a << std::endl;
|
||||
return -5;
|
||||
}
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
// return type: int
|
||||
// first arg type: double
|
||||
Callback<int, double> two;
|
||||
Ptr<MyCb> cb = CreateObject<MyCb> ();
|
||||
// build callback instance which points to MyCb::cbTwo
|
||||
two = MakeCallback (&MyCb::CbTwo, PeekPointer (cb));
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@node Building Null Callbacks
|
||||
@subsection Building Null Callbacks
|
||||
|
||||
It is possible for callbacks to be null; hence it may be wise to
|
||||
check before using them. There is a special construct for a null
|
||||
callback, which is preferable to simply passing "0" as an argument;
|
||||
it is the @code{MakeNullCallback<>} construct:
|
||||
@verbatim
|
||||
two = MakeNullCallback<int, double> ();
|
||||
// invoking a null callback is just like
|
||||
// invoking a null function pointer:
|
||||
// it will crash at runtime.
|
||||
//int retTwoNull = two (20.0);
|
||||
NS_ASSERT (two.IsNull ());
|
||||
@end verbatim
|
||||
|
||||
@node Callback locations in ns-3
|
||||
@section Callback locations in @command{ns-3}
|
||||
|
||||
Where are callbacks frequently used in @command{ns-3}? Here are some of the
|
||||
more visible ones to typical users:
|
||||
|
||||
@subsection Socket API
|
||||
@subsection Layer-2/Layer-3 API
|
||||
@subsection Tracing subsystem
|
||||
@subsection Routing
|
||||
Route Reply
|
||||
|
||||
@node Implementation details
|
||||
@section Implementation details
|
||||
|
||||
This section is advanced explanation for C++ experts interested in
|
||||
the implementation, and may be skipped by most users.
|
||||
|
||||
This code was originally written based on the techniques described
|
||||
@uref{http://www.codeproject.com/cpp/TTLFunction.asp,,here}.
|
||||
It was subsequently rewritten to follow the architecture
|
||||
outlined in
|
||||
@uref{http://www.amazon.com/Modern-C\%2B\%2B-Design-Programming-Patterns/dp/0201704315/ref=pd_bbs_sr_1/102-0157303-1900156?ie=UTF8\&s=books\&qid=1187982662\&sr=1-1,,Modern C++ Design: Generic Programming and Design Patterns Applied-- Alexandrescu}, chapter 5, "Generalized Functors".
|
||||
|
||||
This code uses:
|
||||
@itemize @bullet
|
||||
@item default template parameters to saves users from having to
|
||||
specify empty parameters when the number of parameters
|
||||
is smaller than the maximum supported number
|
||||
@item the pimpl idiom: the Callback class is passed around by
|
||||
value and delegates the crux of the work to its pimpl pointer.
|
||||
@item two pimpl implementations which derive from CallbackImpl
|
||||
FunctorCallbackImpl can be used with any functor-type
|
||||
while MemPtrCallbackImpl can be used with pointers to
|
||||
member functions.
|
||||
@item a reference list implementation to implement the Callback's
|
||||
value semantics.
|
||||
@end itemize
|
||||
|
||||
This code most notably departs from the Alexandrescu
|
||||
implementation in that it does not use type lists to specify
|
||||
and pass around the types of the callback arguments.
|
||||
Of course, it also does not use copy-destruction semantics
|
||||
and relies on a reference list rather than autoPtr to hold
|
||||
the pointer.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,468 @@
|
||||
|
||||
@c ========================================================================
|
||||
@c Simulation Output
|
||||
@c ========================================================================
|
||||
|
||||
@node Simulation Output
|
||||
@chapter Simulation Output
|
||||
|
||||
At this point, you should be able to execute any of the built-in
|
||||
programs distributed with @command{ns-3}. Next, we will look at
|
||||
how to generate and tailor the simulation output, before turning
|
||||
to how to modify simulation scripts to do different things.
|
||||
|
||||
@node Tracing Basics
|
||||
@section Tracing Basics
|
||||
|
||||
The whole point of simulation is to generate output for further
|
||||
study, and the @command{ns-3} tracing system is a primary
|
||||
mechanism for this.
|
||||
Since @command{ns-3} is a C++ program, standard facilities for
|
||||
generating output from C++ programs apply:
|
||||
|
||||
@verbatim
|
||||
#include <iostream>
|
||||
...
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
std::cout << "The value of x is " << x << std::endl;
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The goal of the @command{ns-3} tracing system is to
|
||||
provide a structured way to configure the simulator to output results
|
||||
in standard or modifiable formats.
|
||||
@itemize @bullet
|
||||
@item For basic tasks, the tracing system should allow the user to
|
||||
generate standard tracing for popular tracing sources, and to customize
|
||||
which objects generate the tracing.
|
||||
@item Intermediate users will be able to extend the tracing system to
|
||||
modify the output format generated, or to insert new tracing sources,
|
||||
without modifying the core of the simulator.
|
||||
@item Advanced users can modify the simulator core to add new
|
||||
tracing sources and sinks.
|
||||
@end itemize
|
||||
|
||||
The @command{ns-3} tracing system is fundamentally built on the
|
||||
concept of separating tracing sources from sinks.
|
||||
@enumerate
|
||||
@item Trace sources (e.g., provide access to every packet received)
|
||||
@item Trace sinks (e.g., print out the packet)
|
||||
@item A mechanism to tie together sources and sinks
|
||||
@end enumerate
|
||||
The rationale for this division is to allow users to attach new
|
||||
types of sinks to existing tracing sources, without requiring
|
||||
users to edit and recompile the core of the simulator.
|
||||
Thus, in the example above, a user could write a new tracing sink
|
||||
and attach it to an existing tracing source. What remains to
|
||||
be defined is a way for users to find these hooks (tracing sources)
|
||||
and attach sinks to them. A new tracing namespace is defined for
|
||||
this purpose.
|
||||
|
||||
We will first walk through how some pre-defined sources and sinks
|
||||
are provided and may be customized with little user effort. We
|
||||
return later in this chapter to advanced tracing configuration including
|
||||
extending the tracing namespace and creating new tracing sources.
|
||||
|
||||
@subsection ASCII tracing
|
||||
@cindex ASCII
|
||||
For Internet nodes, the ASCII trace wrapper is a wrapper around
|
||||
the @command{ns-3} low-level
|
||||
tracing system that lets you get access to underlying trace events easily.
|
||||
The output of a trace of a simulation run is an ASCII file --- thus the name.
|
||||
In the spririt of keeping things simple, you won't be able to control or
|
||||
configure the output at this stage.
|
||||
|
||||
For those familiar with @command{ns-2} output, this type of trace is
|
||||
analogous to the @command{out.tr} generated by many scripts.
|
||||
|
||||
@cindex tracing packets
|
||||
Let's just jump right in. As usual, we need to include the definitions
|
||||
related to using ASCII tracing (don't edit any files quite yet):
|
||||
|
||||
@verbatim
|
||||
#include "ns3/ascii-trace.h"
|
||||
@end verbatim
|
||||
|
||||
We then need to add the code to the script to actually enable the ASCII tracing
|
||||
code. The following code must be inserted before the call to
|
||||
@code{Simulator::Run ();}:
|
||||
|
||||
@verbatim
|
||||
AsciiTrace asciitrace ("tutorial.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
@end verbatim
|
||||
|
||||
The first line declares an object of type @code{AsciiTrace} named
|
||||
@code{asciitrace} and passes a string parameter to its constructor. This
|
||||
parameter is a file name to which all of the trace information will be written.
|
||||
The second line, @code{asciitrace.TraceAllQueues ();} asks the trace object to
|
||||
arrange that all queue operations (enqueue, dequeue, drop) on the queues
|
||||
in all of the nodes of the system be traced. On the receive side,
|
||||
@code{asciitrace.TraceAlllNetDeviceRx ()} traces packets received by
|
||||
a NetDevice. For those familiar with @command{ns-2}, these are equivalent
|
||||
to the popular trace points that log "+", "-", "d", and "r" events.
|
||||
|
||||
Try running the following program from the command line:
|
||||
@verbatim
|
||||
./waf --run tutorial-csma-echo-ascii-trace
|
||||
@end verbatim
|
||||
|
||||
@cindex tutorial.tr
|
||||
Just as you have seen previously, you will see some messages from @emph{Waf}
|
||||
and then the ``Compilation finished successfully'' message. The
|
||||
next message, @code{UDP Echo Simulation} is from the running program. When
|
||||
it ran, the program will have created a file named @code{tutorial.tr}.
|
||||
Because of the way that Waf works, the file is not created in the local
|
||||
directory, it is created at the top-level directory of the repository. So,
|
||||
change into the top level directory and take a look at the file
|
||||
@code{tutorial.tr} in your favorite editor.
|
||||
|
||||
@subsubsection Parsing Ascii Traces
|
||||
@cindex parsing ascii traces
|
||||
|
||||
This section parses in detail the structure of the ascii tracing
|
||||
output. If you find this output format self explanatory (it
|
||||
resembles tcpdump output), you may skip to the next
|
||||
section on pcap tracing.
|
||||
|
||||
@cindex trace event
|
||||
There's a lot of information there in a pretty dense form, but the first thing
|
||||
to notice is that there are a number of distinct lines in this file. It may
|
||||
be difficult to see this clearly unless you widen your windows considerably.
|
||||
Each line in the file corresponds to a @emph{trace event}. A trace event
|
||||
happens whenever specific conditions happen in the simulation. In this case
|
||||
we are tracing events on the @emph{device queue} present in every net device
|
||||
on every node in the simulation. The device queue is a queue through which
|
||||
every packet destined for a channel must pass --- it is the device
|
||||
@emph{transmit} queue. Note that each line in the trace file begins with a
|
||||
lone character (has a space after it). This character will have the following
|
||||
meaning:
|
||||
|
||||
@cindex enqueue
|
||||
@cindex dequeue
|
||||
@cindex drop
|
||||
@itemize @bullet
|
||||
@item @code{+}: An enqueue operation occurred on the device queue;
|
||||
@item @code{-}: A dequeue operation occurred on the device queue;
|
||||
@item @code{d}: A packet was dropped, typically because the queue was full.
|
||||
@end itemize
|
||||
|
||||
Let's take a more detailed view of the first line. I'll break it down into
|
||||
sections (indented for clarity) with a two digit reference number on the
|
||||
left side:
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=9
|
||||
06 ETHERNET
|
||||
07 length/type=0x806,
|
||||
08 source=08:00:2e:00:00:00,
|
||||
09 destination=ff:ff:ff:ff:ff:ff
|
||||
10 ARP(request
|
||||
11 source mac: 08:00:2e:00:00:00
|
||||
12 source ipv4: 10.1.1.1
|
||||
13 dest ipv4: 10.1.1.2)
|
||||
14 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex trace event
|
||||
@cindex simulation time
|
||||
The first line of this expanded trace event (reference number 00) is the
|
||||
queue operation. We have a @code{+} character, so this corresponds to an
|
||||
@emph{enqueue} operation. The second line (reference 01) is the simulation
|
||||
time expressed in seconds. You may recall that we asked the
|
||||
@code{UdpEchoClient} to start sending packets at two seconds. Here we see
|
||||
confirmation that this is, indeed, happening.
|
||||
|
||||
@cindex node number
|
||||
@cindex net device number
|
||||
@cindex smart pointer
|
||||
The next lines of the example listing (references 02 and 03) tell us that
|
||||
this trace event originated in a given node and net device. Each time a node
|
||||
is created it is given an identifying number that monotonically increases from
|
||||
zero. Therefore, @code{nodeid=0} means that the node in which the given trace
|
||||
event originated is the first node we created. In the case of our script,
|
||||
this first node is is the node pointed to by the smart pointer @code{n0}. Not
|
||||
too surpsisingly, this is also the node to which we attached the
|
||||
@code{UdpEchoClient}. The device number is local to each node, and so the
|
||||
device given by @code{device=0} is the first net device that we added to the
|
||||
node in question. In our simulation, this corresponds to the
|
||||
@code{CsmaNetDevice} we added to node zero (@code{n0}).
|
||||
|
||||
@cindex uid
|
||||
@cindex unique ID
|
||||
@cindex packet
|
||||
The next line (reference 04) is a more readable form of the operation code
|
||||
seen in the first line --- i.e., the character @code{+} means
|
||||
@code{queue-enqueue}. Reference number 05 indicates that the @emph{unique id}
|
||||
of the packet being enqueued is @code{9}. The fact that the first packet we
|
||||
see has a unique ID of 9 should indicates to you that other things have
|
||||
happened in the protocol stack before we got to this point. This will become
|
||||
clear momentarily.
|
||||
|
||||
@cindex Ethernet
|
||||
@cindex MAC address
|
||||
Reference items 06 and 14 indicate that this is an Ethernet packet with
|
||||
a zero (not computed) checksum (note the indentation to make parsing this
|
||||
trace event a little easier). Reference 08 and 09 are the source and
|
||||
destination addresses of this packet. The packet is from the MAC address we
|
||||
assigned to the node zero net device in the script, and is destined for the
|
||||
broadcast address --- this is a broadcast packet.
|
||||
|
||||
@cindex Address Resolution Protocol
|
||||
@cindex ARP
|
||||
@cindex ARP|request
|
||||
Reference items 10 through 13 make clear what is happening. This is an ARP
|
||||
(Address Resolution Protocol) request for the MAC address of the node on
|
||||
which the @code{UdpEchoServer} resides. The protocol stack can't send a UDP
|
||||
packet to be echoed until it knows (resolves) the MAC address; and this trace
|
||||
event corresponds to an ARP request being queued for transmission to the local
|
||||
network. The next line in the trace file (partially expanded),
|
||||
|
||||
@verbatim
|
||||
00 -
|
||||
01 2
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-dequeue
|
||||
05 pkt-uid=9
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
shows the (same) ARP request packet being dequeued from the device queue by
|
||||
the net device and (implicitly) being sent down the channel to the broadcast
|
||||
MAC address. We are not tracing net device reception events so we don't
|
||||
actually see all of the net devices receiving the broadcast packet. We do,
|
||||
however see the following in the third line of the trace file:
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2.00207
|
||||
02 nodeid=1
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=10
|
||||
06 ETHERNET
|
||||
07 length/type=0x806,
|
||||
08 source=08:00:2e:00:00:01,
|
||||
09 destination=08:00:2e:00:00:00,
|
||||
10 ARP(reply
|
||||
11 source mac: 08:00:2e:00:00:01
|
||||
12 source ipv4: 10.1.1.2
|
||||
13 dest mac: 08:00:2e:00:00:00
|
||||
14 dest ipv4: 10.1.1.1)
|
||||
15 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex simulation time
|
||||
@cindex ARP|response
|
||||
Notice that this is a queue-enqueue operation (references 00 and 04) happening
|
||||
on node one (reference 02) at simulation time 2.00207 seconds (reference 01).
|
||||
Looking at the packet payload (references 10-14) we see that this is an ARP
|
||||
reply to the request sent by node one. Note that the simulation time
|
||||
(reference 01) is now 2.00207 seconds. This is direct result of the data rate
|
||||
(5 mb/s) and latency (2 ms) parameters that we passed to the
|
||||
@code{CsmaChannel} when we created it. Clearly the ARP request packet was
|
||||
sent over the channel and received approximately 2 ms later by node one. A
|
||||
corresponding ARP response packet was created and enqueued on node one's net
|
||||
device. It is this enqueue trace event that has being logged.
|
||||
|
||||
@cindex queue
|
||||
@cindex queue|transmit
|
||||
@cindex echo
|
||||
Given the current state of affairs, the next thing you may expect to see is
|
||||
this ARP request being received by node zero, but remember we are only looking
|
||||
at trace events on the device @emph{transmit} queue. The reception of the ARP
|
||||
response by node zero will not directly trigger any trace event in this case,
|
||||
but it will enable the protocol stack to continue what it was originally doing
|
||||
(trying to send an echo packet). Thus, the next line we see in the trace file
|
||||
(@code{tutorial.tr}) is the first UDP echo packet being sent to the net device.
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2.00415
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=7
|
||||
06 ETHERNET
|
||||
07 length/type=0x800,
|
||||
08 source=08:00:2e:00:00:00,
|
||||
09 destination=08:00:2e:00:00:01
|
||||
10 IPV4(
|
||||
11 tos 0x0
|
||||
12 ttl 64
|
||||
13 id 0
|
||||
14 offset 0
|
||||
15 flags [none]
|
||||
16 length: 1052) 10.1.1.1 > 10.1.1.2
|
||||
17 UDP(length: 1032)
|
||||
18 49153 > 7
|
||||
19 DATA (length 1024)
|
||||
20 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex simulation time
|
||||
@cindex echo
|
||||
@cindex ARP
|
||||
@cindex ARP|request
|
||||
@cindex ARP|response
|
||||
@cindex IP
|
||||
@cindex Ipv4
|
||||
I won't go into too much detail about this packet, but I will point out a
|
||||
few key items in the trace. First, the packet was enqueued at simulation time
|
||||
of 2.00415 seconds. This time reflects the fact that the echo client
|
||||
application started at 2. seconds and there were two ARP packets transmitted
|
||||
across the network (two milliseconds + data transmission time each way). The
|
||||
packet unique identifier (reference 05) is 7. Notice that this is a lower
|
||||
number than the ARP request packet, which had a unique ID of 9. This tells
|
||||
us that the UDP packet was actually created before the ARP request packet ---
|
||||
which makes perfect sense since it was the attempt to send packet 7 that
|
||||
triggered sending the ARP request packet 9. Note that this an Ethernet
|
||||
packet (reference 06) like all other packets in this simulation, however this
|
||||
particular packet carries an IPV4 payload and therefore has an IP version 4
|
||||
header (indicated by references 10-16). This Ipv4 in turn contains a UDP
|
||||
header (references 17, 18) and finally 1024 bytes of data (reference 20).
|
||||
Clearly, this is the UDP echo packet emitted by the
|
||||
@code{UdpEchoClient Application}.
|
||||
|
||||
The next trace event is an ARP request from node one. We can infer that node
|
||||
one has received the UDP echo packet and the @code{UdpEchoServer Application}
|
||||
on that node has turned the packet around. Just as node zero needed to ARP
|
||||
for the MAC address of node one, now node one must ARP for the MAC address of
|
||||
node zero. We see the ARP request enqueued on the transmit queue of node one;
|
||||
then we see the ARP request dequeued from the tranmit queue of node one (and
|
||||
implicitly transmitted to node zero). Then we see an ARP response enqueued
|
||||
on the transmit queue of node zero; and finally the ARP response dequeued (and
|
||||
implicitly transmitted back to node one).
|
||||
|
||||
This exchange is summarized in the following trace event excerpts,
|
||||
|
||||
@verbatim
|
||||
+ 2.00786 nodeid=1 ... ARP(request ...
|
||||
- 2.00786 nodeid=1 ... ARP(request ...
|
||||
+ 2.00994 nodeid=0 ... ARP(reply ...
|
||||
- 2.00994 nodeid=0 ... ARP(reply ...
|
||||
@end verbatim
|
||||
|
||||
The final two trace events in the @code{tutorial.tr} file correspond to the
|
||||
echoed packet being enqueued for transmission on the net device for node one,
|
||||
and that packet being dequeued (and implicitly transmitted back to node zero).
|
||||
|
||||
@cindex AsciiTrace!TraceAllNetDeviceRx
|
||||
@cindex ARP!request
|
||||
If you look at the trace file (@code{tutorial.tr}) you will also see some
|
||||
entries with an @code{r} event, indicating a
|
||||
@emph{receive} trace event. Recall that the first packet sent on the network
|
||||
was a broadcast ARP request. We should then see all four nodes receive a
|
||||
copy of this request. This is the case, as the first four receive trace
|
||||
events are,
|
||||
|
||||
@verbatim
|
||||
r 2.00207 nodeid=0 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=1 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=2 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=3 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
@end verbatim
|
||||
|
||||
@cindex unique ID
|
||||
You can see that a copy of the broadcast packet with unique ID 9 was received
|
||||
by the net devices on nodes 0, 1, 2 and 3. We leave it up to you to parse the
|
||||
rest of the trace file and understand the remaining reception events.
|
||||
|
||||
@subsection PCAP Trace Wrapper
|
||||
@cindex pcap
|
||||
@cindex Wireshark
|
||||
The @command{ns-3} @emph{pcap trace wrapper} is used to create trace files in
|
||||
@code{.pcap} format. The acronym pcap (usually written in lower case) stands
|
||||
for @emph{p}acket @emph{cap}ture, and is actually an API that includes the
|
||||
definition of a @code{.pcap} file format. The most popular program that can
|
||||
read and display this format is Wireshark (formerly called Ethereal).
|
||||
However, there are many traffic trace analyzers that use this packet
|
||||
format, including X, Y, and Z. We encourage users to exploit the
|
||||
many tools available for analyzing pcap traces; below, we show how
|
||||
tcpdump and Wireshark can be used..
|
||||
|
||||
@cindex tutorial-csma-echo-ascii-trace.cc
|
||||
@cindex tutorial-csma-echo-pcap-trace.cc
|
||||
The code used to enable pcap tracing is similar to that for ASCII tracing.
|
||||
We have provided another file, @code{tutorial-csma-echo-pcap-trace.cc} that
|
||||
uses the pcap trace wrapper. We have added the code to include the pcap
|
||||
trace wrapper defintions:
|
||||
|
||||
@verbatim
|
||||
#include "ns3/pcap-trace.h"
|
||||
@end verbatim
|
||||
|
||||
And then added the following code below the AsciiTrace methods:
|
||||
|
||||
@cindex PcapTrace
|
||||
@cindex PcapTrace!TraceAllIp
|
||||
@verbatim
|
||||
PcapTrace pcaptrace ("tutorial.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
@end verbatim
|
||||
|
||||
The first line of the code immediately above declares an object of type
|
||||
@code{PcapTrace} named @code{pcaptrace} and passes a string parameter to its
|
||||
constructor. This object is used to hide the details of the actual tracing
|
||||
subsystem. The parameter is a base file name from which the actual trace file
|
||||
names will be built. The second line of code tells the @code{PcamTrace}
|
||||
object to trace all IP activity in all of the nodes present in the simulation.
|
||||
|
||||
@cindex interface index
|
||||
Trace files are not created until trace activity is detected. Each file name
|
||||
is composed of the base file name, followed by a @code{'-'}, a node id followed
|
||||
by a @code{'-}', and an IP interface index. You will soon see a file named
|
||||
@code{tutorial.pcap-0-1}, for example. This will be the trace file generated
|
||||
as events are detected on node zero, interface index one. N.B. Interface
|
||||
indices are different that net device indices --- interface index zero
|
||||
corresponds to the loopback interface and interface index one corresponds to
|
||||
the first net device you added to a node.
|
||||
|
||||
You may run the new program just like all of the others so far:
|
||||
|
||||
@cindex Waf
|
||||
@verbatim
|
||||
./waf --run tutorial-csma-echo-pcap-trace
|
||||
@end verbatim
|
||||
|
||||
If you look at the top level directory of your distribution, you should now
|
||||
see three log files: @code{tutorial.tr} is the ASCII trace file we have
|
||||
previously examined. @code{tutorial.pcap-0-1} and @code{tutorial.pcap-1-1}
|
||||
are the new pcap files we just generated. There will not be files
|
||||
corresponding to nodes two and three since we have not sent any IP packets to
|
||||
those nodes.
|
||||
|
||||
@subsubsection Reading output with tcpdump
|
||||
@cindex tcpdump
|
||||
|
||||
@subsubsection Reading output with Wireshark
|
||||
@cindex Wireshark
|
||||
If you are unfamilar with Wireshark, there is a web site available from which
|
||||
you can download programs and documentation: @uref{http://www.wireshark.org/}.
|
||||
|
||||
If you have Wireshark available, you can open each of the trace files and
|
||||
display the contents as if you had captured the packets using a
|
||||
@emph{packet sniffer}. Note that only IP packets are traced using this
|
||||
wrapper, so you will not see the ARP exchanges that were logged when using
|
||||
the ASCII trace wrapper. You are encouraged to take a look at the contents
|
||||
of these pcap files using your favorite pcap software (or Wireshark).
|
||||
|
||||
@node Logging
|
||||
@section Logging
|
||||
|
||||
@node Statistics
|
||||
@section Statistics
|
||||
|
||||
@node Advanced Tracing
|
||||
@section Advanced Tracing
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,373 @@
|
||||
@node ns-3 routing overview
|
||||
@chapter ns-3 routing overview
|
||||
|
||||
This chapter describes the overall design of routing in the
|
||||
@code{src/internet-node}
|
||||
module, and some details about the routing approachs currently
|
||||
implemented.
|
||||
|
||||
@node Routing-Overview
|
||||
@section Overview
|
||||
|
||||
We intend to support traditional routing approaches and protocols,
|
||||
ports of open source routing implementations, and facilitate research
|
||||
into unorthodox routing techniques.
|
||||
For simulations that are not primarily focused on routing and that
|
||||
simply want correct routing tables to occur somehow, we have an
|
||||
global centralized routing capability. A singleton object
|
||||
(GlobalRouteManager) be instantiated, builds a network map, and
|
||||
populates a forwarding table on each node at time t=0 in the
|
||||
simulation. Simulation script writers can use the same node
|
||||
API to manually enter routes as well.
|
||||
|
||||
@node Support for multiple routing protocols
|
||||
@section Support for multiple routing protocols
|
||||
|
||||
Typically, multiple routing protocols are supported in user space and
|
||||
coordinate to write a single forwarding table in the kernel. Presently
|
||||
in @command{ns-3}, the implementation instead allows for multiple routing
|
||||
protocols to build/keep their own routing state, and the IPv4 implementation
|
||||
will query each one of these routing protocols (in some order determined
|
||||
by the simulation author) until a route is found.
|
||||
|
||||
We chose this approach because it may better
|
||||
faciliate the integration of disparate routing approaches that may
|
||||
be difficult to coordinate the writing to a single table, approaches
|
||||
where more information than destination IP address (e.g., source
|
||||
routing) is used to determine the next hop, and on-demand
|
||||
routing approaches where packets must be cached.
|
||||
|
||||
There are presently two routing protocols defined:
|
||||
@itemize @bullet
|
||||
@item class Ipv4StaticRouting (covering both unicast and multicast)
|
||||
@item Optimized Link State Routing (a MANET protocol defined in
|
||||
@uref{http://www.ietf.org/rfc/rfc3626.txt,,RFC 3626})
|
||||
@end itemize
|
||||
but first we describe how multiple routing protocols are supported.
|
||||
|
||||
@subsection class Ipv4RoutingProtocol
|
||||
|
||||
@code{class Ipv4RoutingProtocol} derives from ns-3 Object which means
|
||||
that it supports interface aggregation and reference counting. Routing
|
||||
protocols should inherit from this class, defined in src/node/ipv4.cc.
|
||||
|
||||
The main function that must be supported by these protocols is called
|
||||
@code{RequestRoute}.
|
||||
@verbatim
|
||||
* This method is called whenever a node's IPv4 forwarding engine
|
||||
* needs to lookup a route for a given packet and IP header.
|
||||
*
|
||||
* The routing protocol implementation may determine immediately it
|
||||
* should not be handling this particular the route request. For
|
||||
* instance, a routing protocol may decline to search for routes for
|
||||
* certain classes of addresses, like link-local. In this case,
|
||||
* RequestRoute() should return false and the routeReply callback
|
||||
* must not be invoked.
|
||||
*
|
||||
* If the routing protocol implementations assumes it can provide
|
||||
* the requested route, then it should return true, and the
|
||||
* routeReply callback must be invoked, either immediately before
|
||||
* returning true (synchronously), or in the future (asynchronous).
|
||||
* The routing protocol may use any information available in the IP
|
||||
* header and packet as routing key, although most routing protocols
|
||||
* use only the destination address (as given by
|
||||
* ipHeader.GetDestination ()). The routing protocol is also
|
||||
* allowed to add a new header to the packet, which will appear
|
||||
* immediately after the IP header, although most routing do not
|
||||
* insert any extra header.
|
||||
*/
|
||||
virtual bool RequestRoute (uint32_t ifIndex,
|
||||
const Ipv4Header &ipHeader,
|
||||
Ptr<Packet> packet,
|
||||
RouteReplyCallback routeReply) = 0;
|
||||
@end verbatim
|
||||
|
||||
This class also provides a typedef (used above) for a special Callback
|
||||
that will pass to the callback function the Ipv4Route that is found (see the
|
||||
Doxygen documentation):
|
||||
@verbatim
|
||||
typedef Callback<void, bool, const Ipv4Route&, Ptr<Packet>, const Ipv4Header&> RouteReplyCallback;
|
||||
@end verbatim
|
||||
|
||||
@subsection Ipv4::AddRoutingProtocol
|
||||
|
||||
Class Ipv4 provides a pure virtual function declaration for the
|
||||
method that allows one to add a routing protocol:
|
||||
@verbatim
|
||||
void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
|
||||
int16_t priority);
|
||||
@end verbatim
|
||||
This method is implemented by class Ipv4L3Protocol in the internet-node
|
||||
module.
|
||||
|
||||
The priority variable above governs the priority in which the routing
|
||||
protocols are inserted. Notice that it is a signed int.
|
||||
When the class Ipv4L3Protocol is instantiated, a single routing
|
||||
protocol (Ipv4StaticRouting, introduced below) is added at priority
|
||||
zero. Internally, a list of Ipv4RoutingProtocols is stored, and
|
||||
and the routing protocols are each consulted in decreasing order
|
||||
of priority to see whether a match is found. Therefore, if you
|
||||
want your Ipv4RoutingProtocol to have priority lower than the static
|
||||
routing, insert it with priority less than 0; e.g.:
|
||||
@verbatim
|
||||
m_ipv4->AddRoutingProtocol (m_routingTable, -10);
|
||||
@end verbatim
|
||||
|
||||
@subsection Ipv4L3Protocol::Lookup
|
||||
|
||||
The main function for obtaining a route is shown below:
|
||||
@verbatim
|
||||
Ipv4L3Protocol::Lookup (
|
||||
uint32_t ifIndex,
|
||||
Ipv4Header const &ipHeader,
|
||||
Ptr<Packet> packet,
|
||||
Ipv4RoutingProtocol::RouteReplyCallback routeReply)
|
||||
@end verbatim
|
||||
|
||||
This function will search the list of routing protocols, in priority order,
|
||||
until a route is found. It will then invoke the RouteReplyCallback
|
||||
and no further routing protocols will be searched. If the caller does
|
||||
not want to constrain the possible interface, it can be wildcarded
|
||||
as such:
|
||||
@verbatim
|
||||
Lookup (Ipv4RoutingProtocol::IF_INDEX_ANY, ipHeader, packet, routeReply);
|
||||
@end verbatim
|
||||
|
||||
@node Roadmap and Future work
|
||||
@section Roadmap and Future work
|
||||
|
||||
Some goals for future support are:
|
||||
|
||||
Users should be able to trace (either debug print, or redirect to a trace
|
||||
file) the routing table in a format such as used in an
|
||||
Unix implementation:
|
||||
@verbatim
|
||||
# netstat -nr (or # route -n)
|
||||
Kernel IP routing table
|
||||
Destination Gateway Genmask Flags MSS Window irtt Iface
|
||||
127.0.0.1 * 255.255.255.255 UH 0 0 0 lo
|
||||
172.16.1.0 * 255.255.255.0 U 0 0 0 eth0
|
||||
172.16.2.0 172.16.1.1 255.255.255.0 UG 0 0 0 eth0
|
||||
|
||||
# ip route show
|
||||
192.168.99.0/24 dev eth0 scope link
|
||||
127.0.0.0/8 dev lo scope link
|
||||
default via 192.168.99.254 dev eth0
|
||||
@end verbatim
|
||||
|
||||
Global computation of multicast routing should be implemented as well.
|
||||
This would ignore group membership and ensure that a copy of every
|
||||
sourced multicast datagram would be delivered to each node.
|
||||
This might be implemented as an RPF mechanism that functioned on-demand
|
||||
by querying the forwarding table,
|
||||
and perhaps optimized by a small multicast forwarding cache. It is
|
||||
a bit trickier to implement over wireless links where the input
|
||||
interface is the same as the output interface; other aspects of the
|
||||
packet must be considered and the forwarding logic slightly changed
|
||||
to allow for forwarding out the same interface.
|
||||
|
||||
In the future, work on bringing XORP or quagga routing to ns, but it will
|
||||
take several months to port and enable.
|
||||
|
||||
There are presently no roadmap plans for IPv6.
|
||||
|
||||
@node Static routing
|
||||
@section Static routing
|
||||
|
||||
The internet-node module provides one routing protocol (Ipv4StaticRouting)
|
||||
by default. This routing protocol allows one to add unicast or multicast
|
||||
static routes to a node.
|
||||
|
||||
@node Unicast routing
|
||||
@section Unicast routing
|
||||
|
||||
The unicast static routing API may be accessed via the functions
|
||||
@verbatim
|
||||
void Ipv4::AddHostRouteTo ()
|
||||
void Ipv4::AddNetworkRouteTo ()
|
||||
void Ipv4::SetDefaultRoute ()
|
||||
uint32_t Ipv4::GetNRoutes ()
|
||||
Ipv4Route Ipv4::GetRoute ()
|
||||
@end verbatim
|
||||
|
||||
@uref{http://www.nsnam.org/doxygen/index.html,,Doxygen} documentation
|
||||
provides full documentation of these methods. These methods are forwarding
|
||||
functions to the actual implementation in Ipv4StaticRouting, when using
|
||||
the internet-node module.
|
||||
|
||||
@node Multicast routing
|
||||
@section Multicast routing
|
||||
|
||||
The following function is used to add a static multicast route
|
||||
to a node:
|
||||
@verbatim
|
||||
void
|
||||
Ipv4StaticRouting::AddMulticastRoute (Ipv4Address origin,
|
||||
Ipv4Address group,
|
||||
uint32_t inputInterface,
|
||||
std::vector<uint32_t> outputInterfaces);
|
||||
@end verbatim
|
||||
|
||||
A multicast route must specify an origin IP address, a multicast group and
|
||||
an input network interface index as conditions and provide a vector of
|
||||
output network interface indices over which packets matching the conditions
|
||||
are sent.
|
||||
|
||||
Typically there are two main types of multicast routes: routes of the
|
||||
first kind are used during forwarding. All of the conditions must be
|
||||
exlicitly provided. The second kind of routes are used to get packets off
|
||||
of a local node. The difference is in the input interface. Routes for
|
||||
forwarding will always have an explicit input interface specified. Routes
|
||||
off of a node will always set the input interface to a wildcard specified
|
||||
by the index Ipv4RoutingProtocol::IF\_INDEX\_ANY.
|
||||
|
||||
For routes off of a local node wildcards may be used in the origin and
|
||||
multicast group addresses. The wildcard used for Ipv4Adresses is that
|
||||
address returned by Ipv4Address::GetAny () -- typically "0.0.0.0". Usage
|
||||
of a wildcard allows one to specify default behavior to varying degrees.
|
||||
|
||||
For example, making the origin address a wildcard, but leaving the
|
||||
multicast group specific allows one (in the case of a node with multiple
|
||||
interfaces) to create different routes using different output interfaces
|
||||
for each multicast group.
|
||||
|
||||
If the origin and multicast addresses are made wildcards, you have created
|
||||
essentially a default multicast address that can forward to multiple
|
||||
interfaces. Compare this to the actual default multicast address that is
|
||||
limited to specifying a single output interface for compatibility with
|
||||
existing functionality in other systems.
|
||||
|
||||
Another command sets the default multicast route:
|
||||
@verbatim
|
||||
void
|
||||
Ipv4StaticRouting::SetDefaultMulticastRoute (uint32_t outputInterface);
|
||||
@end verbatim
|
||||
|
||||
This is the multicast equivalent of the unicast version SetDefaultRoute.
|
||||
We tell the routing system what to do in the case where a specific route
|
||||
to a destination multicast group is not found. The system forwards
|
||||
packets out the specified interface in the hope that "something out there"
|
||||
knows better how to route the packet. This method is only used in
|
||||
initially sending packets off of a host. The default multicast route is
|
||||
not consulted during forwarding -- exact routes must be specified using
|
||||
AddMulticastRoute for that case.
|
||||
|
||||
Since we're basically sending packets to some entity we think may know
|
||||
better what to do, we don't pay attention to "subtleties" like origin
|
||||
address, nor do we worry about forwarding out multiple interfaces. If the
|
||||
default multicast route is set, it is returned as the selected route from
|
||||
LookupStatic irrespective of origin or multicast group if another specific
|
||||
route is not found.
|
||||
|
||||
Finally, a number of additional functions are provided to fetch and
|
||||
remove multicast routes:
|
||||
@verbatim
|
||||
uint32_t GetNMulticastRoutes (void) const;
|
||||
|
||||
Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
|
||||
|
||||
Ipv4MulticastRoute *GetDefaultMulticastRoute (void) const;
|
||||
|
||||
bool RemoveMulticastRoute (Ipv4Address origin,
|
||||
Ipv4Address group,
|
||||
uint32_t inputInterface);
|
||||
|
||||
void RemoveMulticastRoute (uint32_t index);
|
||||
@end verbatim
|
||||
|
||||
@node Global centralized routing
|
||||
@section Global centralized routing
|
||||
|
||||
Presently, global centralized IPv4 @emph{unicast} routing over both
|
||||
point-to-point and shared (CSMA) links is supported.
|
||||
The global centralized routing will be modified in the future to
|
||||
reduce computations once profiling finds the performance bottlenecks.
|
||||
|
||||
@node Global Unicast Routing API
|
||||
@section Global Unicast Routing API
|
||||
|
||||
The public API is very minimal. User scripts include the following:
|
||||
@verbatim
|
||||
#include "ns3/global-route-manager.h"
|
||||
@end verbatim
|
||||
|
||||
After IP addresses are configured, the following function call will
|
||||
cause all of the nodes that have an Ipv4 interface to receive
|
||||
forwarding tables entered automatically by the GlobalRouteManager:
|
||||
@verbatim
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
@end verbatim
|
||||
|
||||
@emph{Note:} A reminder that the wifi NetDevice is not yet supported
|
||||
(only CSMA and PointToPoint).
|
||||
|
||||
@node Global Routing Implementation
|
||||
@section Global Routing Implementation
|
||||
|
||||
A singleton object (GlobalRouteManager) is responsible for populating
|
||||
the static routes on each node, using the public Ipv4 API of that node.
|
||||
It queries each node in the topology for a "globalRouter" interface.
|
||||
If found, it uses the API of that interface to obtain a "link state
|
||||
advertisement (LSA)" for the router. Link State Advertisements
|
||||
are used in OSPF routing, and we follow their formatting.
|
||||
|
||||
The GlobalRouteManager populates a link state database with LSAs
|
||||
gathered from the entire topology. Then, for each router in the topology,
|
||||
the GlobalRouteManager executes the OSPF shortest path first (SPF)
|
||||
computation on the database, and populates the routing tables on each
|
||||
node.
|
||||
|
||||
The quagga (http://www.quagga.net) OSPF implementation was used as the
|
||||
basis for the routing computation logic.
|
||||
One benefit of following an existing OSPF SPF implementation is that
|
||||
OSPF already has defined link state advertisements for all common
|
||||
types of network links:
|
||||
@itemize @bullet
|
||||
@item point-to-point (serial links)
|
||||
@item point-to-multipoint (Frame Relay, ad hoc wireless)
|
||||
@item non-broadcast multiple access (ATM)
|
||||
@item broadcast (Ethernet)
|
||||
@end itemize
|
||||
Therefore, we think that enabling these other link types will be more
|
||||
straightforward now that the underlying OSPF SPF framework is in place.
|
||||
|
||||
Presently, we can handle IPv4 point-to-point, numbered links, as well
|
||||
as shared broadcast (CSMA) links, and we do not do equal-cost multipath.
|
||||
|
||||
The GlobalRouteManager first walks the list of nodes and aggregates
|
||||
a GlobalRouter interface to each one as follows:
|
||||
@verbatim
|
||||
typedef std::vector < Ptr<Node> >::iterator Iterator;
|
||||
for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
|
||||
{
|
||||
Ptr<Node> node = *i;
|
||||
Ptr<GlobalRouter> globalRouter = CreateObject<GlobalRouter> (node);
|
||||
node->AggregateObject (globalRouter);
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This interface is later queried and used to generate a Link State
|
||||
Advertisement for each router, and this link state database is
|
||||
fed into the OSPF shortest path computation logic. The Ipv4 API
|
||||
is finally used to populate the routes themselves.
|
||||
|
||||
@node Optimized Link State Routing (OLSR)
|
||||
@section Optimized Link State Routing (OLSR)
|
||||
|
||||
This is the first dynamic routing protocol for @command{ns-3}. The implementation
|
||||
is found in the src/routing/olsr directory, and an example script is in
|
||||
examples/simple-point-to-point-olsr.cc.
|
||||
|
||||
The following commands will enable OLSR in a simulation.
|
||||
|
||||
@verbatim
|
||||
olsr::EnableAllNodes (); // Start OLSR on all nodes
|
||||
olsr::EnableNodes(InputIterator begin, InputIterator end); // Start on
|
||||
// a list of nodes
|
||||
olsr::EnableNode (Ptr<Node> node); // Start OLSR on "node" only
|
||||
@end verbatim
|
||||
|
||||
Once instantiated, the agent can be started with the Start() command,
|
||||
and the OLSR "main interface" can be set with the SetMainInterface()
|
||||
command. A number of protocol constants are defined in olsr-agent-impl.cc.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,82 @@
|
||||
@node Troubleshooting
|
||||
@chapter Troubleshooting
|
||||
|
||||
This chapter posts some information about possibly common errors in building
|
||||
or running ns-3 programs.
|
||||
|
||||
Please note that the wiki (@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting}) may have contributed items.
|
||||
|
||||
@node Build errors
|
||||
@section Build errors
|
||||
|
||||
@node Run-time errors
|
||||
@section Run-time errors
|
||||
|
||||
Sometimes, errors can occur with a program after a successful build. These
|
||||
are run-time errors, and can commonly occur when memory is corrupted or
|
||||
pointer values are unexpectedly null.
|
||||
|
||||
Here is an example of what might occur:
|
||||
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
Command ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] exited with code -11
|
||||
@end verbatim
|
||||
|
||||
The error message says that the program terminated unsuccessfully, but it is
|
||||
not clear from this information what might be wrong. To examine more
|
||||
closely, try running it under the @uref{http://sources.redhat.com/gdb/,,gdb debugger}:
|
||||
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="gdb %s"
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
GNU gdb Red Hat Linux (6.3.0.0-1.134.fc5rh)
|
||||
Copyright 2004 Free Software Foundation, Inc.
|
||||
GDB is free software, covered by the GNU General Public License, and you are
|
||||
welcome to change it and/or distribute copies of it under certain conditions.
|
||||
Type "show copying" to see the conditions.
|
||||
There is absolutely no warranty for GDB. Type "show warranty" for details.
|
||||
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
|
||||
|
||||
(gdb) run
|
||||
Starting program: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point
|
||||
Reading symbols from shared object read from target memory...done.
|
||||
Loaded system supplied DSO at 0xf5c000
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0x0804aa12 in main (argc=1, argv=0xbfdfefa4)
|
||||
at ../examples/tcp-point-to-point.cc:136
|
||||
136 Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
(gdb) p localSocket
|
||||
$1 = {m_ptr = 0x3c5d65}
|
||||
(gdb) p socketFactory
|
||||
$2 = {m_ptr = 0x0}
|
||||
(gdb) quit
|
||||
The program is running. Exit anyway? (y or n) y
|
||||
@end verbatim
|
||||
|
||||
Note first the way the program was invoked-- pass the command to run as
|
||||
an argument to the command template "gdb %s".
|
||||
|
||||
This tells us that there was an attempt to dereference a null pointer
|
||||
socketFactory.
|
||||
|
||||
Let's look around line 136 of tcp-point-to-point, as gdb suggests:
|
||||
@verbatim
|
||||
Ptr<SocketFactory> socketFactory = n2->GetObject<SocketFactory> (Tcp::iid);
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
@end verbatim
|
||||
|
||||
The culprit here is that the return value of GetObject is not being
|
||||
checked and may be null.
|
||||
|
||||
Sometimes you may need to use the @uref{http://valgrind.org,,valgrind memory
|
||||
checker} for more subtle errors. Again, you invoke the use of valgrind
|
||||
similarly:
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="valgrind %s"
|
||||
@end verbatim
|
||||
@@ -0,0 +1,111 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename ns-3.info
|
||||
@settitle ns-3 tutorial
|
||||
@c @setchapternewpage odd
|
||||
@c %**end of header
|
||||
|
||||
@ifinfo
|
||||
Primary documentation for the @command{ns-3} project is available in
|
||||
three forms:
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator
|
||||
@item Tutorial (this document)
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
|
||||
@end itemize
|
||||
|
||||
This document is written in GNU Texinfo and is to be maintained in
|
||||
revision control on the @command{ns-3} code server. Both PDF and HTML versions
|
||||
should be available on the server. Changes to
|
||||
the document should be discussed on the ns-developers@@isi.edu mailing list.
|
||||
@end ifinfo
|
||||
|
||||
@copying
|
||||
|
||||
This is an @command{ns-3} tutorial.
|
||||
Primary documentation for the @command{ns-3} project is available in
|
||||
three forms:
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator
|
||||
@item Tutorial (this document)
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
|
||||
@end itemize
|
||||
|
||||
This document is written in GNU Texinfo and is to be maintained in
|
||||
revision control on the @command{ns-3} code server. Both PDF and HTML
|
||||
versions should be available on the server. Changes to
|
||||
the document should be discussed on the ns-developers@@isi.edu mailing list.
|
||||
|
||||
This software is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This software is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see @uref{http://www.gnu.org/licenses/}.
|
||||
@end copying
|
||||
|
||||
@titlepage
|
||||
@title ns-3 Tutorial
|
||||
@author ns-3 project
|
||||
@author feedback: ns-developers@@isi.edu
|
||||
@today{}
|
||||
|
||||
@c @page
|
||||
@vskip 0pt plus 1filll
|
||||
@insertcopying
|
||||
@end titlepage
|
||||
|
||||
@c So the toc is printed at the start.
|
||||
@anchor{Full Table of Contents}
|
||||
@contents
|
||||
|
||||
@ifnottex
|
||||
@node Top, Overview, Full Table of Contents
|
||||
@top ns-3 Tutorial (html version)
|
||||
|
||||
For a pdf version of this tutorial,
|
||||
see @uref{http://www.nsnam.org/docs/tutorial.pdf}.
|
||||
|
||||
@insertcopying
|
||||
@end ifnottex
|
||||
|
||||
@menu
|
||||
* Tutorial Goals::
|
||||
Part 1: Getting Started with ns-3
|
||||
* Overview::
|
||||
* Browsing::
|
||||
* Resources::
|
||||
* Downloading and Compiling::
|
||||
* Some-Prerequisites::
|
||||
* A-First-ns-3-Script::
|
||||
Part 2-: Details
|
||||
* ns-3 Callbacks::
|
||||
* Simulation Output::
|
||||
* ns-3 routing overview::
|
||||
* Other-network-topologies::
|
||||
* Nonlinear-Thinking::
|
||||
* Summary::
|
||||
* Object-Model::
|
||||
* The-Doxygen-Documentation-System::
|
||||
* How-To-Change-Things::
|
||||
* How-To-Set-Default-Values::
|
||||
* How-To-Write-A-New-Application::
|
||||
@ Troubleshooting
|
||||
@end menu
|
||||
|
||||
@include introduction.texi
|
||||
@include callbacks.texi
|
||||
@include output.texi
|
||||
@include routing.texi
|
||||
@include other.texi
|
||||
@include troubleshoot.texi
|
||||
|
||||
@printindex cp
|
||||
|
||||
@bye
|
||||
@@ -107,9 +107,9 @@ main (int argc, char *argv[])
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
@@ -154,7 +154,7 @@ main (int argc, char *argv[])
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 512 bytes (default) at a rate of 500 Kb/s (default) from n0
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("255.255.255.255", port),
|
||||
"Udp",
|
||||
@@ -165,7 +165,7 @@ main (int argc, char *argv[])
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
Ptr<PacketSink> sink = CreateObject<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
@@ -174,7 +174,7 @@ main (int argc, char *argv[])
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
sink = Create<PacketSink> (
|
||||
sink = CreateObject<PacketSink> (
|
||||
n2,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
|
||||
+10
-10
@@ -106,11 +106,11 @@ main (int argc, char *argv[])
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n4 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n4 = CreateObject<InternetNode> ();
|
||||
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
//
|
||||
@@ -211,7 +211,7 @@ main (int argc, char *argv[])
|
||||
// a fine time to find the interface indices on node two.
|
||||
//
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n2->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4 = n2->GetObject<Ipv4> ();
|
||||
|
||||
uint32_t ifIndexLan0 = ipv4->FindInterfaceForAddr (n2Lan0Addr);
|
||||
uint32_t ifIndexLan1 = ipv4->FindInterfaceForAddr (n2Lan1Addr);
|
||||
@@ -261,7 +261,7 @@ main (int argc, char *argv[])
|
||||
// interface to find the output interface index, and tell node zero to send
|
||||
// its multicast traffic out that interface.
|
||||
//
|
||||
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
uint32_t ifIndexSrc = ipv4->FindInterfaceForAddr (multicastSource);
|
||||
ipv4->SetDefaultMulticastRoute (ifIndexSrc);
|
||||
//
|
||||
@@ -269,7 +269,7 @@ main (int argc, char *argv[])
|
||||
// multicast data. To enable forwarding bits up the protocol stack, we need
|
||||
// to tell the stack to join the multicast group.
|
||||
//
|
||||
ipv4 = n4->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4 = n4->GetObject<Ipv4> ();
|
||||
ipv4->JoinMulticastGroup (multicastSource, multicastGroup);
|
||||
//
|
||||
// Create an OnOff application to send UDP datagrams from node zero to the
|
||||
@@ -281,7 +281,7 @@ main (int argc, char *argv[])
|
||||
|
||||
// Configure a multicast packet generator that generates a packet
|
||||
// every few seconds
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress (multicastGroup, port),
|
||||
"Udp",
|
||||
@@ -298,7 +298,7 @@ main (int argc, char *argv[])
|
||||
// Create an optional packet sink to receive these packets
|
||||
// If you enable logging on this (above) it will print a log statement
|
||||
// for every packet received
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
Ptr<PacketSink> sink = CreateObject<PacketSink> (
|
||||
n4,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
|
||||
@@ -100,10 +100,10 @@ main (int argc, char *argv[])
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
//
|
||||
@@ -165,7 +165,7 @@ main (int argc, char *argv[])
|
||||
//
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.1.2", port),
|
||||
"Udp",
|
||||
@@ -179,7 +179,7 @@ main (int argc, char *argv[])
|
||||
//
|
||||
// Create a similar flow from n3 to n0, starting at time 1.1 seconds
|
||||
//
|
||||
ooff = Create<OnOffApplication> (
|
||||
ooff = CreateObject<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.1.1", port),
|
||||
"Udp",
|
||||
|
||||
@@ -61,7 +61,7 @@ NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample");
|
||||
static Ptr<CsmaNetDevice>
|
||||
CreateCsmaDevice (Ptr<Node> node, Ptr<CsmaChannel> channel)
|
||||
{
|
||||
Ptr<CsmaNetDevice> device = Create<CsmaNetDevice> (node);
|
||||
Ptr<CsmaNetDevice> device = CreateObject<CsmaNetDevice> (node);
|
||||
device->Attach (channel);
|
||||
Ptr<Queue> queue = Queue::CreateDefault ();
|
||||
device->AddQueue (queue);
|
||||
@@ -102,14 +102,14 @@ main (int argc, char *argv[])
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<Node> ();
|
||||
Ptr<Node> n1 = Create<Node> ();
|
||||
Ptr<Node> n2 = Create<Node> ();
|
||||
Ptr<Node> n3 = Create<Node> ();
|
||||
Ptr<Node> n0 = CreateObject<Node> ();
|
||||
Ptr<Node> n1 = CreateObject<Node> ();
|
||||
Ptr<Node> n2 = CreateObject<Node> ();
|
||||
Ptr<Node> n3 = CreateObject<Node> ();
|
||||
|
||||
// create the shared medium used by all csma devices.
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
Ptr<CsmaChannel> channel = Create<CsmaChannel> (DataRate(5000000), MilliSeconds(2));
|
||||
Ptr<CsmaChannel> channel = CreateObject<CsmaChannel> (DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
// use a helper function to connect our nodes to the shared channel.
|
||||
NS_LOG_INFO ("Build Topology.");
|
||||
@@ -134,7 +134,7 @@ main (int argc, char *argv[])
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
// from n0 to n1
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
n0ToN1,
|
||||
"Packet",
|
||||
@@ -145,7 +145,7 @@ main (int argc, char *argv[])
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create a similar flow from n3 to n0, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
ooff = CreateObject<OnOffApplication> (
|
||||
n3,
|
||||
n3ToN0,
|
||||
"Packet",
|
||||
|
||||
@@ -120,13 +120,13 @@ main (int argc, char *argv[])
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n4 = Create<InternetNode> ();
|
||||
Ptr<Node> n5 = Create<InternetNode> ();
|
||||
Ptr<Node> n6 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n4 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n5 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n6 = CreateObject<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
@@ -191,7 +191,7 @@ main (int argc, char *argv[])
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
|
||||
@@ -128,10 +128,10 @@ main (int argc, char *argv[])
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
@@ -182,7 +182,7 @@ main (int argc, char *argv[])
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
// Create a flow from n3 to n1, starting at time 1.1 seconds
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.1.1", port),
|
||||
"Udp",
|
||||
@@ -193,7 +193,7 @@ main (int argc, char *argv[])
|
||||
ooff->Stop (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
Ptr<PacketSink> sink = CreateObject<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/component-manager.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
@@ -97,10 +96,10 @@ main (int argc, char *argv[])
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
@@ -143,7 +142,7 @@ main (int argc, char *argv[])
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
@@ -154,7 +153,7 @@ main (int argc, char *argv[])
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
Ptr<PacketSink> sink = CreateObject<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
@@ -163,7 +162,7 @@ main (int argc, char *argv[])
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
ooff = CreateObject<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
@@ -174,7 +173,7 @@ main (int argc, char *argv[])
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
sink = Create<PacketSink> (
|
||||
sink = CreateObject<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
@@ -186,9 +185,9 @@ main (int argc, char *argv[])
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
NS_LOG_INFO ("Set Default Routes.");
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
|
||||
ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4 = n3->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
|
||||
|
||||
//
|
||||
@@ -205,8 +204,7 @@ main (int argc, char *argv[])
|
||||
NS_ASSERT (em != 0);
|
||||
// Now, query interface on the resulting em pointer to see if a
|
||||
// RateErrorModel interface exists. If so, set the packet error rate
|
||||
Ptr<RateErrorModel> bem = em->QueryInterface<RateErrorModel>
|
||||
(RateErrorModel::iid);
|
||||
Ptr<RateErrorModel> bem = em->GetObject<RateErrorModel> ();
|
||||
if (bem)
|
||||
{
|
||||
bem->SetRandomVariable (UniformVariable ());
|
||||
@@ -222,7 +220,7 @@ main (int argc, char *argv[])
|
||||
sampleList.push_back (11);
|
||||
sampleList.push_back (17);
|
||||
// This time, we'll explicitly create the error model we want
|
||||
Ptr<ListErrorModel> pem = Create<ListErrorModel> ();
|
||||
Ptr<ListErrorModel> pem = CreateObject<ListErrorModel> ();
|
||||
pem->SetList (sampleList);
|
||||
nd2->AddReceiveErrorModel (pem);
|
||||
|
||||
|
||||
@@ -122,10 +122,10 @@ main (int argc, char *argv[])
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
@@ -163,7 +163,7 @@ main (int argc, char *argv[])
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
@@ -175,7 +175,7 @@ main (int argc, char *argv[])
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
// The last argument "true" disables output from the Receive callback
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
Ptr<PacketSink> sink = CreateObject<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
@@ -184,7 +184,7 @@ main (int argc, char *argv[])
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
ooff = CreateObject<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
@@ -195,7 +195,7 @@ main (int argc, char *argv[])
|
||||
ooff->Stop (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
sink = Create<PacketSink> (
|
||||
sink = CreateObject<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 -------------------------n3
|
||||
// n2 -------------------------n3---------n4
|
||||
// /
|
||||
// / 5 Mb/s, 2ms
|
||||
// n1
|
||||
@@ -118,10 +118,11 @@ main (int argc, char *argv[])
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n4 = CreateObject<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
@@ -136,6 +137,10 @@ main (int argc, char *argv[])
|
||||
Ptr<PointToPointChannel> channel2 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n2, n3, DataRate(1500000), MilliSeconds(10));
|
||||
|
||||
Ptr<PointToPointChannel> channel3 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n3, n4, DataRate(1500000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
@@ -151,65 +156,54 @@ main (int argc, char *argv[])
|
||||
channel2, n2, Ipv4Address("10.1.3.1"),
|
||||
n3, Ipv4Address("10.1.3.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel3, n3, Ipv4Address("10.1.4.1"),
|
||||
n4, Ipv4Address("10.1.4.2"));
|
||||
|
||||
// Enable OLSR
|
||||
NS_LOG_INFO ("Enabling OLSR Routing.");
|
||||
olsr::EnableAllNodes ();
|
||||
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
InetSocketAddress ("10.1.4.2", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n3,
|
||||
Ptr<PacketSink> sink = CreateObject<PacketSink> (
|
||||
n4,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
// Create a similar flow from n4 to n1, starting at time 1.1 seconds
|
||||
ooff = CreateObject<OnOffApplication> (
|
||||
n4,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
ooff->Start (Seconds(1.1));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
sink = Create<PacketSink> (
|
||||
sink = CreateObject<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.1));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Here, finish off packet routing configuration
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
NS_LOG_INFO ("Set Default Routes.");
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
|
||||
ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-point-to-point.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
@@ -226,8 +220,8 @@ main (int argc, char *argv[])
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::StopAt (Seconds (10));
|
||||
Simulator::Run ();
|
||||
Simulator::StopAt (Seconds (30));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
|
||||
@@ -72,29 +72,7 @@ main (int argc, char *argv[])
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable ("SimplePointToPointExample", LOG_LEVEL_INFO);
|
||||
|
||||
LogComponentEnable("Object", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Queue", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Channel", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Socket", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable ("SimplePointToPointExample", LOG_LEVEL_ALL);
|
||||
#endif
|
||||
|
||||
// Set up some default values for the simulation. Use the Bind()
|
||||
@@ -108,8 +86,6 @@ main (int argc, char *argv[])
|
||||
DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
|
||||
DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
|
||||
//DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
@@ -117,10 +93,10 @@ main (int argc, char *argv[])
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
@@ -163,27 +139,25 @@ main (int argc, char *argv[])
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
Ptr<OnOffApplication> ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
ooff->Start (Seconds(1.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
Ptr<PacketSink> sink = CreateObject<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
ooff = CreateObject<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
@@ -191,24 +165,43 @@ main (int argc, char *argv[])
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
sink = Create<PacketSink> (
|
||||
sink = CreateObject<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.1));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// TCP
|
||||
// Create a file transfer from n0 to n3, starting at time 1.2
|
||||
uint16_t servPort = 500;
|
||||
|
||||
ooff = CreateObject<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", servPort),
|
||||
"Tcp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start (Seconds(1.2));
|
||||
ooff->Stop (Seconds(1.35));
|
||||
|
||||
// Create a packet sink to receive these TCP packets
|
||||
sink = Create<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort),
|
||||
"Tcp");
|
||||
sink->Start (Seconds (1.2));
|
||||
|
||||
// Here, finish off packet routing configuration
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
NS_LOG_INFO ("Set Default Routes.");
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
|
||||
ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4 = n3->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
@@ -227,7 +220,7 @@ main (int argc, char *argv[])
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::StopAt (Seconds (10));
|
||||
Simulator::StopAt (Seconds (3.0));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 10Mb/s, 10ms 10Mb/s, 10ms
|
||||
// n0-----------------n1-----------------n2
|
||||
//
|
||||
//
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "tcp-large-transfer-errors.tr"
|
||||
// - pcap traces also generated in the following files
|
||||
// "tcp-large-transfer-errors.pcap-$n-$i" where n and i represent node and interface numbers respectively
|
||||
// Usage (e.g.): ./waf --run tcp-large-transfer-errors
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/node-list.h"
|
||||
|
||||
#include "ns3/tcp.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpLargeTransferErrors");
|
||||
|
||||
void
|
||||
ApplicationTraceSink (const TraceContext &context, Ptr<const Packet> packet,
|
||||
const Address &addr)
|
||||
{
|
||||
// g_log is not declared in optimized builds
|
||||
// should convert this to use of some other flag than the logging system
|
||||
#ifdef NS3_LOG_ENABLE
|
||||
if (!g_log.IsNoneEnabled ()) {
|
||||
if (InetSocketAddress::IsMatchingType (addr) )
|
||||
{
|
||||
InetSocketAddress address = InetSocketAddress::ConvertFrom (addr);
|
||||
std::cout << "PacketSink received size " <<
|
||||
packet->GetSize () << " at time " <<
|
||||
Simulator::Now ().GetSeconds () << " from address: " <<
|
||||
address.GetIpv4 () << std::endl;
|
||||
char buf[2000];
|
||||
memcpy(buf, packet->PeekData (), packet->GetSize ());
|
||||
for (uint32_t i=0; i < packet->GetSize (); i++)
|
||||
{
|
||||
std::cout << buf[i];
|
||||
if (i && i % 60 == 0)
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseConnection (Ptr<Socket> localSocket)
|
||||
{
|
||||
//localSocket->Close ();
|
||||
}
|
||||
|
||||
void StartFlow(Ptr<Socket> localSocket, uint32_t nBytes,
|
||||
uint16_t servPort)
|
||||
{
|
||||
// NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ());
|
||||
localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));//connect
|
||||
localSocket->SetConnectCallback (MakeCallback (&CloseConnection),
|
||||
Callback<void, Ptr<Socket> > (),
|
||||
Callback<void, Ptr<Socket> > ());
|
||||
//we want to close as soon as the connection is established
|
||||
//the tcp state machine and outgoing buffer will assure that
|
||||
//all of the data is delivered
|
||||
|
||||
// Perform series of 1040 byte writes (this is a multiple of 26 since
|
||||
// we want to detect data splicing in the output stream)
|
||||
uint32_t writeSize = 1040;
|
||||
uint8_t data[writeSize];
|
||||
while (nBytes > 0) {
|
||||
uint32_t curSize= nBytes > writeSize ? writeSize : nBytes;
|
||||
for(uint32_t i = 0; i < curSize; ++i)
|
||||
{
|
||||
char m = toascii (97 + i % 26);
|
||||
data[i] = m;
|
||||
}
|
||||
localSocket->Send (data, curSize);
|
||||
nBytes -= curSize;
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpSocket", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
|
||||
//LogComponentEnable("TcpLargeTransferErrors", LOG_LEVEL_ALL);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create three nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n1, DataRate(10000000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.3.1"),
|
||||
n1, Ipv4Address("10.1.3.2"));
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(10000000), MilliSeconds(10));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address("10.1.2.1"),
|
||||
n2, Ipv4Address("10.1.2.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Routes(n0, n1, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1);
|
||||
ipv4 = n2->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Simulation 1
|
||||
//
|
||||
// Send 2000000 bytes over a connection to server port 50000 at time 0
|
||||
// Should observe SYN exchange, a lot of data segments, and FIN exchange
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int nBytes = 2000000;
|
||||
uint16_t servPort = 50000;
|
||||
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
n0->GetObject<SocketFactory> ();
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n2,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort),
|
||||
"Tcp");
|
||||
sink->Start (Seconds (0.0));
|
||||
sink->Stop (Seconds (10000.0));
|
||||
|
||||
//
|
||||
// Error models
|
||||
//
|
||||
// We want to add an error model to node 2's NetDevice
|
||||
// We can obtain a handle to the NetDevice via the channel and node
|
||||
// pointers
|
||||
Ptr<PointToPointNetDevice> nd2 = PointToPointTopology::GetNetDevice
|
||||
(n2, channel1);
|
||||
Ptr<RateErrorModel> rem = Create<RateErrorModel> ();
|
||||
// The first data segment for this flow is packet uid=4
|
||||
rem->SetRandomVariable (UniformVariable ());
|
||||
rem->SetUnit (EU_PKT);
|
||||
rem->SetRate (0.05);
|
||||
nd2->AddReceiveErrorModel (rem);
|
||||
|
||||
Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes,
|
||||
servPort);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-examples.tr file
|
||||
AsciiTrace asciitrace ("tcp-large-transfer-errors.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-examples.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("tcp-large-transfer-errors.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink));
|
||||
|
||||
Simulator::StopAt (Seconds(10000));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 10Mb/s, 10ms 10Mb/s, 10ms
|
||||
// n0-----------------n1-----------------n2
|
||||
//
|
||||
//
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "tcp-large-transfer.tr"
|
||||
// - pcap traces also generated in the following files
|
||||
// "tcp-large-transfer.pcap-$n-$i" where n and i represent node and interface numbers respectively
|
||||
// Usage (e.g.): ./waf --run tcp-large-transfer
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/node-list.h"
|
||||
|
||||
#include "ns3/tcp.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpLargeTransfer");
|
||||
|
||||
void
|
||||
ApplicationTraceSink (const TraceContext &context, Ptr<const Packet> packet,
|
||||
const Address &addr)
|
||||
{
|
||||
// g_log is not declared in optimized builds
|
||||
// should convert this to use of some other flag than the logging system
|
||||
#ifdef NS3_LOG_ENABLE
|
||||
if (!g_log.IsNoneEnabled ()) {
|
||||
if (InetSocketAddress::IsMatchingType (addr) )
|
||||
{
|
||||
InetSocketAddress address = InetSocketAddress::ConvertFrom (addr);
|
||||
std::cout << "PacketSink received size " <<
|
||||
packet->GetSize () << " at time " <<
|
||||
Simulator::Now ().GetSeconds () << " from address: " <<
|
||||
address.GetIpv4 () << std::endl;
|
||||
char buf[2000];
|
||||
memcpy(buf, packet->PeekData (), packet->GetSize ());
|
||||
for (uint32_t i=0; i < packet->GetSize (); i++)
|
||||
{
|
||||
std::cout << buf[i];
|
||||
if (i && i % 60 == 0)
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseConnection (Ptr<Socket> localSocket)
|
||||
{
|
||||
//localSocket->Close ();
|
||||
}
|
||||
|
||||
void StartFlow(Ptr<Socket> localSocket, uint32_t nBytes,
|
||||
uint16_t servPort)
|
||||
{
|
||||
// NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ());
|
||||
localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));//connect
|
||||
localSocket->SetConnectCallback (MakeCallback (&CloseConnection),
|
||||
Callback<void, Ptr<Socket> > (),
|
||||
Callback<void, Ptr<Socket> > ());
|
||||
//we want to close as soon as the connection is established
|
||||
//the tcp state machine and outgoing buffer will assure that
|
||||
//all of the data is delivered
|
||||
|
||||
// Perform series of 1040 byte writes (this is a multiple of 26 since
|
||||
// we want to detect data splicing in the output stream)
|
||||
uint32_t writeSize = 1040;
|
||||
uint8_t data[writeSize];
|
||||
while (nBytes > 0) {
|
||||
uint32_t curSize= nBytes > writeSize ? writeSize : nBytes;
|
||||
for(uint32_t i = 0; i < curSize; ++i)
|
||||
{
|
||||
char m = toascii (97 + i % 26);
|
||||
data[i] = m;
|
||||
}
|
||||
localSocket->Send (data, curSize);
|
||||
nBytes -= curSize;
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpSocket", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
|
||||
//LogComponentEnable("TcpLargeTransfer", LOG_LEVEL_ALL);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create three nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n1, DataRate(10000000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.3.1"),
|
||||
n1, Ipv4Address("10.1.3.2"));
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(10000000), MilliSeconds(10));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address("10.1.2.1"),
|
||||
n2, Ipv4Address("10.1.2.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Routes(n0, n1, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1);
|
||||
ipv4 = n2->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Simulation 1
|
||||
//
|
||||
// Send 2000000 bytes over a connection to server port 50000 at time 0
|
||||
// Should observe SYN exchange, a lot of data segments, and FIN exchange
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int nBytes = 2000000;
|
||||
uint16_t servPort = 50000;
|
||||
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
n0->GetObject<SocketFactory> ();
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n2,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort),
|
||||
"Tcp");
|
||||
sink->Start (Seconds (0.0));
|
||||
sink->Stop (Seconds (100.0));
|
||||
|
||||
Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes,
|
||||
servPort);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-examples.tr file
|
||||
AsciiTrace asciitrace ("tcp-large-transfer.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-examples.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("tcp-large-transfer.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink));
|
||||
|
||||
Simulator::StopAt (Seconds(1000));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 100Kb/s, 10ms 1Mb/s, 10ms
|
||||
// n0-----------------n1-----------------n2
|
||||
//
|
||||
//
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "tcp-nonlistening-server.tr"
|
||||
// - pcap traces also generated in the following files
|
||||
// "tcp-nonlistening-server.pcap-$n-$i" where n and i represent node and interface numbers respectively
|
||||
// Usage (e.g.): ./waf --run tcp-nonlistening-server
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/error-model.h"
|
||||
|
||||
#include "ns3/tcp.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpNonListeningServer");
|
||||
|
||||
void ConnectionSucceededCallback (Ptr<Socket> localSocket)
|
||||
{
|
||||
uint32_t nBytes = 2000;
|
||||
uint8_t data[nBytes];
|
||||
for(uint32_t i = 0; i < nBytes; ++i)
|
||||
{
|
||||
char m = 'A';
|
||||
data[i] = m;
|
||||
} //put something interesting in the packets ABCDEF...
|
||||
localSocket->Send (data, nBytes);
|
||||
}
|
||||
|
||||
void ConnectionFailedCallback (Ptr<Socket> localSocket)
|
||||
{
|
||||
NS_LOG_ERROR("Connection failed at time " << Simulator::Now ().GetSeconds ());
|
||||
}
|
||||
|
||||
void StartFlow(Ptr<Socket> localSocket, uint16_t servPort)
|
||||
{
|
||||
NS_LOG_LOGIC(std::endl << "Connection attempt at time " <<
|
||||
Simulator::Now ().GetSeconds () << std::endl);
|
||||
localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));
|
||||
localSocket->SetConnectCallback (
|
||||
MakeCallback (&ConnectionSucceededCallback),
|
||||
MakeCallback (&ConnectionFailedCallback),
|
||||
MakeNullCallback<void, Ptr<Socket> > () );
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
//LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
//LogComponentEnable("TcpSocket", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("TcpNonListeningServer", LOG_LEVEL_ALL);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create three nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n1, DataRate(1000000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.3.1"),
|
||||
n1, Ipv4Address("10.1.3.2"));
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(100000), MilliSeconds(10));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address("10.1.2.1"),
|
||||
n2, Ipv4Address("10.1.2.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Routes(n0, n1, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1);
|
||||
ipv4 = n2->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Simulation 1
|
||||
//
|
||||
// Send 2000 bytes over a connection to server port 500 at time 0
|
||||
// Should observe SYN exchange, two data segments, and FIN exchange
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint16_t servPort = 500;
|
||||
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
n0->GetObject<SocketFactory> ();
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
|
||||
#ifdef NOTFORTHISSCRIPT
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n2,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort),
|
||||
"Tcp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (0.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
#endif
|
||||
|
||||
Simulator::Schedule(Seconds(0), &StartFlow, localSocket, servPort);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-examples.tr file
|
||||
AsciiTrace asciitrace ("tcp-nonlistening-server.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-examples.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("tcp-nonlistening-server.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
|
||||
Simulator::StopAt (Seconds(1000));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 100Kb/s, 10ms 1Mb/s, 10ms
|
||||
// n0-----------------n1-----------------n2
|
||||
//
|
||||
//
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "tcp-small-transfer-oneloss.tr"
|
||||
// - pcap traces also generated in the following files
|
||||
// "tcp-small-transfer-oneloss.pcap-$n-$i" where n and i represent node and interface numbers respectively
|
||||
// Usage (e.g.): ./waf --run tcp-small-transfer-oneloss
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/node-list.h"
|
||||
|
||||
#include "ns3/tcp.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpSmallTransferOneloss");
|
||||
|
||||
void
|
||||
ApplicationTraceSink (const TraceContext &context, Ptr<const Packet> packet,
|
||||
const Address &addr)
|
||||
{
|
||||
// g_log is not declared in optimized builds
|
||||
// should convert this to use of some other flag than the logging system
|
||||
#ifdef NS3_LOG_ENABLE
|
||||
if (!g_log.IsNoneEnabled ()) {
|
||||
if (InetSocketAddress::IsMatchingType (addr) )
|
||||
{
|
||||
InetSocketAddress address = InetSocketAddress::ConvertFrom (addr);
|
||||
std::cout << "PacketSink received size " <<
|
||||
packet->GetSize () << " at time " <<
|
||||
Simulator::Now ().GetSeconds () << " from address: " <<
|
||||
address.GetIpv4 () << std::endl;
|
||||
char buf[2000];
|
||||
memcpy(buf, packet->PeekData (), packet->GetSize ());
|
||||
for (uint32_t i=0; i < packet->GetSize (); i++)
|
||||
{
|
||||
std::cout << buf[i];
|
||||
if (i && i % 60 == 0)
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void StartFlow(Ptr<Socket> localSocket, uint32_t nBytes,
|
||||
uint16_t servPort)
|
||||
{
|
||||
// NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ());
|
||||
localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));
|
||||
uint8_t data[nBytes];
|
||||
for(uint32_t i = 0; i < nBytes; ++i)
|
||||
{
|
||||
char m = toascii (97 + i % 26);
|
||||
data[i] = m;
|
||||
}
|
||||
localSocket->Send (data, nBytes);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpSocket", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("TcpSmallTransferOneloss", LOG_LEVEL_ALL);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create three nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n1, DataRate(1000000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.3.1"),
|
||||
n1, Ipv4Address("10.1.3.2"));
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(100000), MilliSeconds(10));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address("10.1.2.1"),
|
||||
n2, Ipv4Address("10.1.2.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Routes(n0, n1, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1);
|
||||
ipv4 = n2->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Simulation 1
|
||||
//
|
||||
// Send 2000 bytes over a connection to server port 500 at time 0
|
||||
// Should observe SYN exchange, two data segments, and FIN exchange
|
||||
// Force the loss of the first data segment
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int nBytes = 2000;
|
||||
uint16_t servPort = 500;
|
||||
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
n0->GetObject<SocketFactory> ();
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n2,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort),
|
||||
"Tcp");
|
||||
sink->Start (Seconds (0.0));
|
||||
sink->Stop (Seconds (100.0));
|
||||
|
||||
//
|
||||
// Error models
|
||||
//
|
||||
// We want to add an error model to node 2's NetDevice
|
||||
// We can obtain a handle to the NetDevice via the channel and node
|
||||
// pointers
|
||||
Ptr<PointToPointNetDevice> nd2 = PointToPointTopology::GetNetDevice
|
||||
(n2, channel1);
|
||||
Ptr<ListErrorModel> pem = Create<ListErrorModel> ();
|
||||
std::list<uint32_t> sampleList;
|
||||
// The first data segment for this flow is packet uid=4
|
||||
sampleList.push_back (4);
|
||||
pem->SetList (sampleList);
|
||||
nd2->AddReceiveErrorModel (pem);
|
||||
|
||||
Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes,
|
||||
servPort);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-examples.tr file
|
||||
AsciiTrace asciitrace ("tcp-small-transfer-oneloss.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-examples.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("tcp-small-transfer-oneloss.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink));
|
||||
|
||||
Simulator::StopAt (Seconds(1000));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 100Kb/s, 10ms 1Mb/s, 10ms
|
||||
// n0-----------------n1-----------------n2
|
||||
//
|
||||
//
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "tcp-small-transfer.tr"
|
||||
// - pcap traces also generated in the following files
|
||||
// "tcp-small-transfer.pcap-$n-$i" where n and i represent node and interface numbers respectively
|
||||
// Usage (e.g.): ./waf --run tcp-small-transfer
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/node-list.h"
|
||||
|
||||
#include "ns3/tcp.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpSmallTransfer");
|
||||
|
||||
void
|
||||
ApplicationTraceSink (const TraceContext &context, Ptr<const Packet> packet,
|
||||
const Address &addr)
|
||||
{
|
||||
// g_log is not declared in optimized builds
|
||||
// should convert this to use of some other flag than the logging system
|
||||
#ifdef NS3_LOG_ENABLE
|
||||
if (!g_log.IsNoneEnabled ()) {
|
||||
if (InetSocketAddress::IsMatchingType (addr) )
|
||||
{
|
||||
InetSocketAddress address = InetSocketAddress::ConvertFrom (addr);
|
||||
std::cout << "PacketSink received size " <<
|
||||
packet->GetSize () << " at time " <<
|
||||
Simulator::Now ().GetSeconds () << " from address: " <<
|
||||
address.GetIpv4 () << std::endl;
|
||||
char buf[2000];
|
||||
memcpy(buf, packet->PeekData (), packet->GetSize ());
|
||||
for (uint32_t i=0; i < packet->GetSize (); i++)
|
||||
{
|
||||
std::cout << buf[i];
|
||||
if (i && i % 60 == 0)
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseConnection (Ptr<Socket> localSocket)
|
||||
{
|
||||
localSocket->Close ();
|
||||
}
|
||||
|
||||
void StartFlow(Ptr<Socket> localSocket, uint32_t nBytes,
|
||||
uint16_t servPort)
|
||||
{
|
||||
// NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ());
|
||||
localSocket->Connect (InetSocketAddress ("10.1.2.2", servPort));//connect
|
||||
localSocket->SetConnectCallback (MakeCallback (&CloseConnection),
|
||||
MakeNullCallback<void, Ptr<Socket> > (),
|
||||
MakeNullCallback<void, Ptr<Socket> > ());
|
||||
//we want to close as soon as the connection is established
|
||||
//the tcp state machine and outgoing buffer will assure that
|
||||
//all of the data is delivered
|
||||
uint8_t data[nBytes];
|
||||
for(uint32_t i = 0; i < nBytes; ++i)
|
||||
{
|
||||
char m = toascii (97 + i % 26);
|
||||
data[i] = m;
|
||||
}
|
||||
localSocket->Send (data, nBytes);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpSocket", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("TcpSmallTransfer", LOG_LEVEL_ALL);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create three nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n1, DataRate(1000000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.3.1"),
|
||||
n1, Ipv4Address("10.1.3.2"));
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(100000), MilliSeconds(10));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address("10.1.2.1"),
|
||||
n2, Ipv4Address("10.1.2.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Routes(n0, n1, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.2"), 1);
|
||||
ipv4 = n2->GetObject<Ipv4> ();
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.2.1"), 1);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Simulation 1
|
||||
//
|
||||
// Send 2000 bytes over a connection to server port 500 at time 0
|
||||
// Should observe SYN exchange, two data segments, and FIN exchange
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int nBytes = 2000;
|
||||
uint16_t servPort = 500;
|
||||
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
n0->GetObject<SocketFactory> ();
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n2,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort),
|
||||
"Tcp");
|
||||
sink->Start (Seconds (0.0));
|
||||
sink->Stop (Seconds (100.0));
|
||||
|
||||
Simulator::Schedule(Seconds(0), &StartFlow, localSocket, nBytes,
|
||||
servPort);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-examples.tr file
|
||||
AsciiTrace asciitrace ("tcp-small-transfer.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-examples.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("tcp-small-transfer.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NodeList::Connect ("/nodes/*/applications/*/rx", MakeCallback (&ApplicationTraceSink));
|
||||
|
||||
Simulator::StopAt (Seconds(1000));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -100,10 +100,10 @@ main (int argc, char *argv[])
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n1 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n2 = CreateObject<InternetNode> ();
|
||||
Ptr<Node> n3 = CreateObject<InternetNode> ();
|
||||
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
//
|
||||
@@ -167,7 +167,7 @@ main (int argc, char *argv[])
|
||||
//
|
||||
uint16_t port = 9; // well-known echo port number
|
||||
|
||||
Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
|
||||
Ptr<UdpEchoServer> server = CreateObject<UdpEchoServer> (n1, port);
|
||||
//
|
||||
// Create a UdpEchoClient application to send UDP datagrams from node zero to
|
||||
// node one.
|
||||
@@ -176,7 +176,7 @@ main (int argc, char *argv[])
|
||||
uint32_t maxPacketCount = 1;
|
||||
Time interPacketInterval = Seconds (1.);
|
||||
|
||||
Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port,
|
||||
Ptr<UdpEchoClient> client = CreateObject<UdpEchoClient> (n0, "10.1.1.2", port,
|
||||
maxPacketCount, interPacketInterval, packetSize);
|
||||
//
|
||||
// Tell the applications when to start and stop.
|
||||
|
||||
@@ -45,3 +45,25 @@ def build(bld):
|
||||
obj = bld.create_ns3_program('simple-point-to-point-olsr',
|
||||
['point-to-point', 'internet-node', 'olsr'])
|
||||
obj.source = 'simple-point-to-point-olsr.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-large-transfer',
|
||||
['point-to-point', 'internet-node'])
|
||||
obj.source = 'tcp-large-transfer.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-large-transfer-errors',
|
||||
['point-to-point', 'internet-node'])
|
||||
obj.source = 'tcp-large-transfer-errors.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-nonlistening-server',
|
||||
['point-to-point', 'internet-node'])
|
||||
obj.source = 'tcp-nonlistening-server.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-small-transfer',
|
||||
['point-to-point', 'internet-node'])
|
||||
obj.source = 'tcp-small-transfer.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-small-transfer-oneloss',
|
||||
['point-to-point', 'internet-node'])
|
||||
obj.source = 'tcp-small-transfer-oneloss.cc'
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006,2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "ns3/wifi-net-device.h"
|
||||
#include "ns3/wifi-channel.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/packet-socket-address.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/gnuplot.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
static uint32_t g_bytesTotal = 0;
|
||||
static GnuplotDataset *g_output = 0;
|
||||
|
||||
static Ptr<Node>
|
||||
CreateAdhocNode (Ptr<WifiChannel> channel,
|
||||
Vector position, const char *address)
|
||||
{
|
||||
Ptr<Node> node = CreateObject<Node> ();
|
||||
Ptr<AdhocWifiNetDevice> device = CreateObject<AdhocWifiNetDevice> (node, Mac48Address (address));
|
||||
device->Attach (channel);
|
||||
Ptr<MobilityModel> mobility = CreateObject<StaticMobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
node->AggregateObject (mobility);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
SetPosition (Ptr<Node> node, Vector position)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
}
|
||||
|
||||
static Vector
|
||||
GetPosition (Ptr<Node> node)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
return mobility->GetPosition ();
|
||||
}
|
||||
|
||||
static void
|
||||
AdvancePosition (Ptr<Node> node)
|
||||
{
|
||||
Vector pos = GetPosition (node);
|
||||
double mbs = ((g_bytesTotal * 8.0) / 1000000);
|
||||
g_bytesTotal = 0;
|
||||
g_output->Add (pos.x, mbs);
|
||||
pos.x += 1.0;
|
||||
if (pos.x >= 210.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetPosition (node, pos);
|
||||
//std::cout << "x="<<pos.x << std::endl;
|
||||
Simulator::Schedule (Seconds (1.0), &AdvancePosition, node);
|
||||
}
|
||||
|
||||
static void
|
||||
ReceivePacket (Ptr<Socket> socket, Ptr<Packet> packet, const Address &address)
|
||||
{
|
||||
g_bytesTotal += packet->GetSize ();
|
||||
}
|
||||
|
||||
static Ptr<Socket>
|
||||
SetupPacketReceive (Ptr<Node> node, uint16_t port)
|
||||
{
|
||||
TypeId tid = TypeId::LookupByName ("Packet");
|
||||
Ptr<SocketFactory> socketFactory = node->GetObject<SocketFactory> (tid);
|
||||
Ptr<Socket> sink = socketFactory->CreateSocket ();
|
||||
sink->Bind ();
|
||||
sink->SetRecvCallback (MakeCallback (&ReceivePacket));
|
||||
return sink;
|
||||
}
|
||||
|
||||
static void
|
||||
RunOneExperiment (void)
|
||||
{
|
||||
g_bytesTotal = 0;
|
||||
|
||||
Ptr<WifiChannel> channel = CreateObject<WifiChannel> ();
|
||||
|
||||
Ptr<Node> a = CreateAdhocNode (channel,
|
||||
Vector (5.0,0.0,0.0),
|
||||
"00:00:00:00:00:01");
|
||||
Ptr<Node> b = CreateAdhocNode (channel,
|
||||
Vector (0.0, 0.0, 0.0),
|
||||
"00:00:00:00:00:02");
|
||||
|
||||
PacketSocketAddress destination = PacketSocketAddress ();
|
||||
destination.SetProtocol (1);
|
||||
destination.SetSingleDevice (0);
|
||||
destination.SetPhysicalAddress (Mac48Address ("00:00:00:00:00:02"));
|
||||
Ptr<Application> app = CreateObject<OnOffApplication> (a, destination,
|
||||
"Packet",
|
||||
ConstantVariable (250),
|
||||
ConstantVariable (0),
|
||||
DataRate (60000000),
|
||||
2000);
|
||||
|
||||
app->Start (Seconds (0.5));
|
||||
app->Stop (Seconds (250.0));
|
||||
|
||||
Simulator::Schedule (Seconds (1.5), &AdvancePosition, b);
|
||||
Ptr<Socket> recvSink = SetupPacketReceive (b, 10);
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Simulator::SetLinkedList ();
|
||||
|
||||
// disable fragmentation
|
||||
DefaultValue::Bind ("WifiFragmentationThreshold", "2200");
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
Gnuplot gnuplot = Gnuplot ("reference-rates.png");
|
||||
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
|
||||
g_output = new GnuplotDataset ("54mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "54mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("48mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "48mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("36mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "36mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("24mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "24mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("18mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "18mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("12mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "12mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("9mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "9mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("6mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "6mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
gnuplot.GenerateOutput (std::cout);
|
||||
|
||||
gnuplot = Gnuplot ("rate-control.png");
|
||||
|
||||
DefaultValue::Bind ("WifiPhyStandard", "holland");
|
||||
|
||||
g_output = new GnuplotDataset ("arf");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Arf");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("aarf");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Aarf");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("ideal");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Ideal");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
gnuplot.GenerateOutput (std::cout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006,2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "ns3/wifi-net-device.h"
|
||||
#include "ns3/wifi-channel.h"
|
||||
#include "ns3/wifi-phy.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/packet-socket-address.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/node-list.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
void
|
||||
WifiNetDeviceTrace (const TraceContext &context, Ptr<const Packet> p, Mac48Address address)
|
||||
{
|
||||
std::cout << context << " ad=" << address << " p: " << p << std::endl;
|
||||
}
|
||||
void
|
||||
WifiPhyStateTrace (const TraceContext &context, Time start, Time duration, enum WifiPhy::State state)
|
||||
{
|
||||
std::cout << context << " state=";
|
||||
switch (state) {
|
||||
case WifiPhy::TX:
|
||||
std::cout << "tx ";
|
||||
break;
|
||||
case WifiPhy::SYNC:
|
||||
std::cout << "sync ";
|
||||
break;
|
||||
case WifiPhy::CCA_BUSY:
|
||||
std::cout << "cca-busy";
|
||||
break;
|
||||
case WifiPhy::IDLE:
|
||||
std::cout << "idle ";
|
||||
break;
|
||||
}
|
||||
std::cout << " start="<<start<<" duration="<<duration<<std::endl;
|
||||
}
|
||||
|
||||
static Ptr<Node>
|
||||
CreateApNode (Ptr<WifiChannel> channel,
|
||||
Vector position,
|
||||
const char *macAddress,
|
||||
Ssid ssid,
|
||||
Time at)
|
||||
{
|
||||
Ptr<Node> node = CreateObject<Node> ();
|
||||
Ptr<NqapWifiNetDevice> device = CreateObject<NqapWifiNetDevice> (node, Mac48Address (macAddress));
|
||||
device->SetSsid (ssid);
|
||||
Simulator::Schedule (at, &NqapWifiNetDevice::StartBeaconing, device);
|
||||
device->Attach (channel);
|
||||
Ptr<MobilityModel> mobility = CreateObject<StaticMobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
node->AggregateObject (mobility);
|
||||
return node;
|
||||
}
|
||||
|
||||
static Ptr<Node>
|
||||
CreateStaNode (Ptr<WifiChannel> channel,
|
||||
Vector position,
|
||||
const char *macAddress,
|
||||
Ssid ssid)
|
||||
{
|
||||
Ptr<Node> node = CreateObject<Node> ();
|
||||
Ptr<NqstaWifiNetDevice> device = CreateObject<NqstaWifiNetDevice> (node, Mac48Address (macAddress));
|
||||
Simulator::ScheduleNow (&NqstaWifiNetDevice::StartActiveAssociation, device,
|
||||
ssid);
|
||||
device->Attach (channel);
|
||||
Ptr<MobilityModel> mobility = CreateObject<StaticMobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
node->AggregateObject (mobility);
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
SetPosition (Ptr<Node> node, Vector position)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
}
|
||||
|
||||
static Vector
|
||||
GetPosition (Ptr<Node> node)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
return mobility->GetPosition ();
|
||||
}
|
||||
|
||||
static void
|
||||
AdvancePosition (Ptr<Node> node)
|
||||
{
|
||||
Vector pos = GetPosition (node);
|
||||
pos.x += 5.0;
|
||||
if (pos.x >= 210.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetPosition (node, pos);
|
||||
//std::cout << "x="<<pos.x << std::endl;
|
||||
Simulator::Schedule (Seconds (1.0), &AdvancePosition, node);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Simulator::SetLinkedList ();
|
||||
|
||||
Packet::EnableMetadata ();
|
||||
|
||||
//Simulator::EnableLogTo ("80211.log");
|
||||
|
||||
|
||||
// enable rts cts all the time.
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "0");
|
||||
// disable fragmentation
|
||||
DefaultValue::Bind ("WifiFragmentationThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Aarf");
|
||||
//DefaultValue::Bind ("WifiRateControlAlgorithm", "Arf");
|
||||
|
||||
Ptr<WifiChannel> channel = CreateObject<WifiChannel> ();
|
||||
Ssid ssid = Ssid ("mathieu");
|
||||
|
||||
Ptr<Node> a = CreateApNode (channel,
|
||||
Vector (5.0,0.0,0.0),
|
||||
"00:00:00:00:00:01",
|
||||
ssid,
|
||||
Seconds (0.1));
|
||||
Simulator::Schedule (Seconds (1.0), &AdvancePosition, a);
|
||||
|
||||
Ptr<Node> b = CreateStaNode (channel,
|
||||
Vector (0.0, 0.0, 0.0),
|
||||
"00:00:00:00:00:02",
|
||||
ssid);
|
||||
|
||||
Ptr<Node> c = CreateStaNode (channel,
|
||||
Vector (0.0, 0.0, 0.0),
|
||||
"00:00:00:00:00:03",
|
||||
ssid);
|
||||
|
||||
PacketSocketAddress destination = PacketSocketAddress ();
|
||||
destination.SetProtocol (1);
|
||||
destination.SetSingleDevice (0);
|
||||
destination.SetPhysicalAddress (Mac48Address ("00:00:00:00:00:03"));
|
||||
Ptr<Application> app = CreateObject<OnOffApplication> (b, destination,
|
||||
"Packet",
|
||||
ConstantVariable (42),
|
||||
ConstantVariable (0));
|
||||
app->Start (Seconds (0.5));
|
||||
app->Stop (Seconds (43.0));
|
||||
|
||||
//NodeList::Connect ("/nodes/*/devices/*/*", MakeCallback (&WifiNetDeviceTrace));
|
||||
//NodeList::Connect ("/nodes/*/devices/*/phy/state", MakeCallback (&WifiPhyStateTrace));
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 University of Washington
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/drop-tail.h"
|
||||
#include "ns3/layer-connector.h"
|
||||
#include "ns3/channel.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("ChannelSample");
|
||||
|
||||
// ===========================================================================
|
||||
// Cook up a simplistic Internet Node
|
||||
// ===========================================================================
|
||||
class FakeInternetNode : public LayerConnectorUpper
|
||||
{
|
||||
public:
|
||||
FakeInternetNode ();
|
||||
~FakeInternetNode ();
|
||||
|
||||
void Doit (void);
|
||||
|
||||
protected:
|
||||
bool UpperDoSendUp (Packet &p);
|
||||
bool UpperDoPull (Packet &p);
|
||||
|
||||
DropTailQueue m_dtqOutbound;
|
||||
DropTailQueue m_dtqInbound;
|
||||
};
|
||||
|
||||
FakeInternetNode::FakeInternetNode ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
FakeInternetNode::~FakeInternetNode ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
void
|
||||
FakeInternetNode::Doit (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
NS_LOG_INFO ("**** Send outbound packet");
|
||||
Packet p;
|
||||
|
||||
m_dtqOutbound.Enqueue(p);
|
||||
UpperNotify();
|
||||
}
|
||||
|
||||
bool
|
||||
FakeInternetNode::UpperDoSendUp (Packet &p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
NS_LOG_PARAMS (this << &p);
|
||||
NS_LOG_INFO ("**** Receive inbound packet");
|
||||
m_dtqInbound.Enqueue(p);
|
||||
return m_dtqInbound.Dequeue(p);
|
||||
}
|
||||
|
||||
bool
|
||||
FakeInternetNode::UpperDoPull (Packet &p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
NS_LOG_PARAMS (this << &p);
|
||||
|
||||
return m_dtqOutbound.Dequeue(p);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Cook up a simplistic Physical Layer
|
||||
// ===========================================================================
|
||||
class FakePhysicalLayer :
|
||||
public LayerConnectorLower,
|
||||
public LayerConnectorUpper
|
||||
{
|
||||
public:
|
||||
FakePhysicalLayer ();
|
||||
~FakePhysicalLayer ();
|
||||
|
||||
protected:
|
||||
bool LowerDoNotify (LayerConnectorUpper *upper);
|
||||
bool UpperDoSendUp (Packet &p);
|
||||
bool UpperDoPull (Packet &p);
|
||||
|
||||
DropTailQueue m_dtqInbound;
|
||||
DropTailQueue m_dtqOutbound;
|
||||
};
|
||||
|
||||
FakePhysicalLayer::FakePhysicalLayer ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
FakePhysicalLayer::~FakePhysicalLayer ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::LowerDoNotify (LayerConnectorUpper *upper)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
|
||||
Packet p;
|
||||
|
||||
NS_LOG_LOGIC ("Starting pull");
|
||||
|
||||
NS_ASSERT(m_upperPartner);
|
||||
m_upperPartner->UpperPull(p);
|
||||
|
||||
m_dtqOutbound.Enqueue(p);
|
||||
|
||||
NS_LOG_LOGIC ("Got bits, Notify lower");
|
||||
|
||||
NS_ASSERT(m_lowerPartner);
|
||||
return m_lowerPartner->LowerNotify(this);
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::UpperDoSendUp (Packet &p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
NS_LOG_PARAMS (this << &p);
|
||||
|
||||
NS_ASSERT(m_upperPartner);
|
||||
return m_upperPartner->UpperSendUp(p);
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::UpperDoPull (Packet &p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
NS_LOG_PARAMS (this << &p);
|
||||
|
||||
return m_dtqOutbound.Dequeue(p);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Cook up a simplistic Channel, just to add any moby hack we feel like
|
||||
// ===========================================================================
|
||||
class FakeChannel : public Channel
|
||||
{
|
||||
public:
|
||||
FakeChannel ();
|
||||
~FakeChannel ();
|
||||
};
|
||||
|
||||
FakeChannel::FakeChannel ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
FakeChannel::~FakeChannel ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
NS_LOG_INFO ("Channel Hackorama");
|
||||
|
||||
FakeInternetNode node1, node2, node3, node4;
|
||||
FakePhysicalLayer phys1, phys2, phys3, phys4;
|
||||
FakeChannel channel;
|
||||
Packet pkt;
|
||||
|
||||
// all the hassle above lets us do something very simple here
|
||||
|
||||
node1.ConnectToLower(phys1);
|
||||
phys1.ConnectToUpper(node1);
|
||||
phys1.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys1);
|
||||
|
||||
node2.ConnectToLower(phys2);
|
||||
phys2.ConnectToUpper(node2);
|
||||
phys2.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys2);
|
||||
|
||||
node3.ConnectToLower(phys3);
|
||||
phys3.ConnectToUpper(node3);
|
||||
phys3.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys3);
|
||||
|
||||
node4.ConnectToLower(phys4);
|
||||
phys4.ConnectToUpper(node4);
|
||||
phys4.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys4);
|
||||
|
||||
node1.Doit();
|
||||
node2.Doit();
|
||||
node3.Doit();
|
||||
node4.Doit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/component-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
class AnObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
AnObject (int a, double b);
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId AnObject::iid = MakeInterfaceId ("AnObject", Object::iid);
|
||||
const ClassId AnObject::cid = MakeClassId<AnObject, int, double> ("AnObject", AnObject::iid);
|
||||
|
||||
AnObject::AnObject (int a, double b)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnObject::iid);
|
||||
}
|
||||
void
|
||||
AnObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Ptr<AnObject> anObject = ComponentManager::Create<AnObject,int,double> (AnObject::cid, AnObject::iid, 10, 20.0);
|
||||
NS_ASSERT (anObject != 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ int main (int argc, char *argv[])
|
||||
// create an array of empty nodes for testing purposes
|
||||
for (uint32_t i = 0; i < 120; i++)
|
||||
{
|
||||
nodes.push_back (Create<InternetNode> ());
|
||||
nodes.push_back (CreateObject<InternetNode> ());
|
||||
}
|
||||
|
||||
// setup the grid itself: objects are layed out
|
||||
@@ -27,7 +27,7 @@ int main (int argc, char *argv[])
|
||||
GridTopology grid (-100, -100, 20, 5, 20);
|
||||
|
||||
// each object will be attached a static position.
|
||||
grid.SetMobilityModel (StaticMobilityModel::cid);
|
||||
grid.SetMobilityModel (StaticMobilityModel::GetTypeId ());
|
||||
|
||||
// finalize the setup by attaching to each object
|
||||
// in the input array a position and initializing
|
||||
@@ -39,7 +39,7 @@ int main (int argc, char *argv[])
|
||||
j != nodes.end (); j++)
|
||||
{
|
||||
Ptr<Object> object = *j;
|
||||
Ptr<MobilityModel> position = object->QueryInterface<MobilityModel> (MobilityModel::iid);
|
||||
Ptr<MobilityModel> position = object->GetObject<MobilityModel> ();
|
||||
NS_ASSERT (position != 0);
|
||||
Vector pos = position->GetPosition ();
|
||||
std::cout << "x=" << pos.x << ", y=" << pos.y << ", z=" << pos.z << std::endl;
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
#include "ns3/object.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
class AnObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
AnObject ();
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId AnObject::iid = MakeInterfaceId ("AnObject", Object::iid);
|
||||
|
||||
AnObject::AnObject ()
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnObject::iid);
|
||||
}
|
||||
void
|
||||
AnObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
class AnotherObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
AnotherObject (int a);
|
||||
private:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId AnotherObject::iid = MakeInterfaceId ("AnotherObject", Object::iid);
|
||||
|
||||
AnotherObject::AnotherObject (int a)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnotherObject::iid);
|
||||
}
|
||||
void
|
||||
AnotherObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
class YetAnotherObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
YetAnotherObject (int a);
|
||||
private:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId YetAnotherObject::iid = MakeInterfaceId ("YetAnotherObject", Object::iid);
|
||||
|
||||
YetAnotherObject::YetAnotherObject (int a)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (YetAnotherObject::iid);
|
||||
// aggregated directly to another object.
|
||||
AddInterface (Create<AnObject> ());
|
||||
}
|
||||
void
|
||||
YetAnotherObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Ptr<Object> p;
|
||||
Ptr<AnObject> anObject;
|
||||
Ptr<AnotherObject> anotherObject;
|
||||
Ptr<YetAnotherObject> yetAnotherObject;
|
||||
|
||||
p = Create<AnObject> ();
|
||||
// p gives you access to AnObject's interface
|
||||
anObject = p->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject != 0);
|
||||
// p does not give you access to AnotherObject's interface
|
||||
anotherObject = p->QueryInterface<AnotherObject> (AnotherObject::iid);
|
||||
NS_ASSERT (anotherObject == 0);
|
||||
|
||||
anotherObject = Create<AnotherObject> (1);
|
||||
// AnotherObject does not give you access to AnObject's interface
|
||||
anObject = anotherObject->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject == 0);
|
||||
|
||||
// aggregate the two objects
|
||||
p->AddInterface (anotherObject);
|
||||
// p gives you access to AnObject's interface
|
||||
anObject = p->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject != 0);
|
||||
// p gives you access to AnotherObject's interface
|
||||
anotherObject = p->QueryInterface<AnotherObject> (AnotherObject::iid);
|
||||
NS_ASSERT (anotherObject != 0);
|
||||
|
||||
|
||||
yetAnotherObject = Create<YetAnotherObject> (2);
|
||||
// gives you acess to AnObject interface too.
|
||||
anObject = yetAnotherObject->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject != 0);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/header.h"
|
||||
#include <iostream>
|
||||
@@ -105,16 +106,17 @@ int main (int argc, char *argv[])
|
||||
sourceHeader.SetData (2);
|
||||
|
||||
// instantiate a packet
|
||||
Packet p;
|
||||
Ptr<Packet> p = Create<Packet> ();
|
||||
|
||||
// and store my header into the packet.
|
||||
p.AddHeader (sourceHeader);
|
||||
p->AddHeader (sourceHeader);
|
||||
|
||||
// print the content of my packet on the standard output.
|
||||
p.Print (std::cout);
|
||||
p->Print (std::cout);
|
||||
|
||||
// you can now remove the header from the packet:
|
||||
MyHeader destinationHeader;
|
||||
p.RemoveHeader (destinationHeader);
|
||||
p->RemoveHeader (destinationHeader);
|
||||
|
||||
// and check that the destination and source
|
||||
// headers contain the same values.
|
||||
|
||||
@@ -49,7 +49,7 @@ void DefaultPrint (void)
|
||||
{
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
// and add 3 headers to this packet.
|
||||
Packet p (1000);
|
||||
Ptr<Packet> p = Create<Packet> (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
@@ -57,36 +57,36 @@ void DefaultPrint (void)
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
udp.SetPayloadSize (1000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
std::cout << "full packet size=" << p->GetSize () << std::endl;
|
||||
// Here, invoke the default Print routine, directed to std out
|
||||
p.Print (std::cout);
|
||||
p->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// Now, we fragment our packet in 3 consecutive pieces.
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
Ptr<Packet> p1 = p->CreateFragment (0, 2);
|
||||
Ptr<Packet> p2 = p->CreateFragment (2, 1000);
|
||||
Ptr<Packet> p3 = p->CreateFragment (1002, 26);
|
||||
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout);
|
||||
p1->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout);
|
||||
p2->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout);
|
||||
p3->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
// And, finally, we re-aggregate the 3 consecutive pieces.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
Ptr<Packet> aggregate = p1->Copy ();
|
||||
aggregate->AddAtEnd (p2);
|
||||
aggregate->AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout);
|
||||
aggregate->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void NonDefaultPrint (void)
|
||||
|
||||
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
Packet p (1000);
|
||||
Ptr<Packet> p = Create<Packet> (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
@@ -136,35 +136,35 @@ void NonDefaultPrint (void)
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
udp.SetPayloadSize (1000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
p.Print (std::cout, printer);
|
||||
std::cout << "full packet size=" << p->GetSize () << std::endl;
|
||||
p->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// fragment our packet in 3 pieces
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
Ptr<Packet> p1 = p->CreateFragment (0, 2);
|
||||
Ptr<Packet> p2 = p->CreateFragment (2, 1000);
|
||||
Ptr<Packet> p3 = p->CreateFragment (1002, 26);
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout, printer);
|
||||
p1->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout, printer);
|
||||
p2->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout, printer);
|
||||
p3->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
// aggregate all 3 fragments of the original packet
|
||||
// to reconstruct a copy of the original packet.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
Ptr<Packet> aggregate = p1->Copy ();
|
||||
aggregate->AddAtEnd (p2);
|
||||
aggregate->AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout, printer);
|
||||
aggregate->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,20 +116,20 @@ int main (int argc, char *argv[])
|
||||
tag.SetSimpleValue (0x56);
|
||||
|
||||
// store the tag in a packet.
|
||||
Packet p;
|
||||
p.AddTag (tag);
|
||||
Ptr<Packet> p = Create<Packet> ();
|
||||
p->AddTag (tag);
|
||||
|
||||
// create a copy of the packet
|
||||
Packet aCopy = p;
|
||||
Ptr<Packet> aCopy = p->Copy ();
|
||||
|
||||
// read the tag from the packet copy
|
||||
MyTag tagCopy;
|
||||
p.PeekTag (tagCopy);
|
||||
p->PeekTag (tagCopy);
|
||||
|
||||
// the copy and the original are the same !
|
||||
NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
|
||||
|
||||
aCopy.PrintTags (std::cout);
|
||||
aCopy->PrintTags (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
static void
|
||||
PrintOne (double minTxpower, double maxTxpower, double stepTxpower, double min, double max, double step)
|
||||
{
|
||||
Ptr<StaticMobilityModel> a = CreateObject<StaticMobilityModel> ();
|
||||
Ptr<StaticMobilityModel> b = CreateObject<StaticMobilityModel> ();
|
||||
Ptr<PropagationLossModel> model = PropagationLossModel::CreateDefault ();
|
||||
|
||||
a->SetPosition (Vector (0.0, 0.0, 0.0));
|
||||
for (double x = min; x < max; x+= step)
|
||||
{
|
||||
b->SetPosition (Vector (x, 0.0, 0.0));
|
||||
std::cout << x << " ";
|
||||
for (double txpower = minTxpower; txpower < maxTxpower; txpower += stepTxpower)
|
||||
{
|
||||
double rxPowerDbm = model->GetRxPower (txpower, a, b);
|
||||
std::cout << rxPowerDbm << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
#if 0
|
||||
DefaultValue::Bind ("PropagationLossModelType", "Friis");
|
||||
DefaultValue::Bind ("FriisPropagationLossLambda", "0.6");
|
||||
DefaultValue::Bind ("FriisPropagationLossSystemLoss", "1.0");
|
||||
|
||||
PrintOne (-10, 20, 5, 0, 1000, 5);
|
||||
#endif
|
||||
|
||||
DefaultValue::Bind ("PropagationLossModelType", "LogDistance");
|
||||
DefaultValue::Bind ("LogDistancePropagationLossReferenceDistance", "1.0");
|
||||
DefaultValue::Bind ("LogDistancePropagationLossReferenceType", "Random");
|
||||
DefaultValue::Bind ("RandomPropagationLossDistribution", "Constant:10");
|
||||
DefaultValue::Bind ("LogDistancePropagationLossExponent", "4");
|
||||
|
||||
PrintOne (-10, 20, 5, 0, 10000, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+2
-2
@@ -49,7 +49,7 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
// Create a new object of type A, store it in global
|
||||
// variable g_a
|
||||
Ptr<A> a = Create<A> ();
|
||||
Ptr<A> a = CreateObject<A> ();
|
||||
a->Method ();
|
||||
Ptr<A> prev = StoreA (a);
|
||||
NS_ASSERT (prev == 0);
|
||||
@@ -58,7 +58,7 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
// Create a new object of type A, store it in global
|
||||
// variable g_a, get a hold on the previous A object.
|
||||
Ptr<A> a = Create<A> ();
|
||||
Ptr<A> a = CreateObject<A> ();
|
||||
Ptr<A> prev = StoreA (a);
|
||||
// call method on object
|
||||
prev->Method ();
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 University of Washington
|
||||
* Authors: Tom Henderson, Craig Dowell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/component-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
//
|
||||
// This sample file shows examples of how to use QueryInterface.
|
||||
//
|
||||
// QueryInterface is a templated method of class Object, defined in
|
||||
// src/core/object.h. ns-3 objects that derive from class Object
|
||||
// can have QueryInterface invoked on them.
|
||||
//
|
||||
// QueryInterface is a type-safe way to ask an object, at run-time,
|
||||
// "Do you support the interface identified by the given InterfaceId?"
|
||||
// It avoids deprecated techniques of having to downcast pointers to
|
||||
// an object to ask questions about its type. One or more interfaces
|
||||
// may be associated with a given object.
|
||||
//
|
||||
// QueryInterface is of most use when working with base class
|
||||
// pointers of objects that may be subclassed. For instance,
|
||||
// one may have a pointer to a Node, but not know whether it has
|
||||
// an IPv4 stack. Another example might be to determine whether
|
||||
// a Node has an EnergyModel, to which calls to decrement energy
|
||||
// from the node's battery might be made.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// Object is the base class for ns-3 node-related objects used at
|
||||
// the public API. Object provides reference counting implementations
|
||||
// and the QueryInterface.
|
||||
//
|
||||
// A common design paradigm for an ns-3 node object, such as a Queue,
|
||||
// is that we provide an abstract base class that inherits from
|
||||
// Object. This class is assigned an interface ID (iid) and
|
||||
// contains the basic API for objects in this class and subclasses.
|
||||
// This base class is specialized to provide implementations of
|
||||
// the object in question (such as a DropTailQueue).
|
||||
//
|
||||
// The design pattern commonly used is known as the "non-virtual
|
||||
// public interface" pattern, whereby the public API for this
|
||||
// object is a set of public non-virtual functions that forward
|
||||
// to private virtual functions. The forwarding functions can
|
||||
// impose pre- and post-conditions on the forwarding call at
|
||||
// the base class level.
|
||||
//
|
||||
// We'll call this base class "AnInterface" in the example below.
|
||||
//
|
||||
//
|
||||
class AnInterface : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
void methodA (void);
|
||||
private:
|
||||
virtual void domethodA (void) = 0;
|
||||
};
|
||||
|
||||
void
|
||||
AnInterface::methodA (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
// pre-dispatch asserts
|
||||
NS_LOG_LOGIC ("pre-condition");
|
||||
domethodA ();
|
||||
NS_LOG_LOGIC ("post-condition");
|
||||
// post-dispatch asserts
|
||||
}
|
||||
|
||||
//
|
||||
// The below assignment assigns the InterfaceId of the class AnInterface,
|
||||
// and declares that the parent iid is that of class Object.
|
||||
//
|
||||
const InterfaceId AnInterface::iid = MakeInterfaceId ("AnInterface", Object::iid);
|
||||
|
||||
//
|
||||
// AnImplementation is an implementation of the abstract base class
|
||||
// defined above. It provides implementation for the virtual functions
|
||||
// in the base class. It defines one ClassId for each constructor,
|
||||
// and can also provide an interface itself (in this example,
|
||||
// a methodImpl is available)
|
||||
//
|
||||
class AnImplementation : public AnInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
|
||||
AnImplementation ();
|
||||
void methodImpl (void);
|
||||
private:
|
||||
virtual void domethodA (void);
|
||||
};
|
||||
|
||||
void
|
||||
AnImplementation::methodImpl (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
|
||||
AnImplementation::AnImplementation (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
// enable our interface
|
||||
SetInterfaceId (AnImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
AnImplementation::domethodA ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
//
|
||||
// The below assignment assigns the InterfaceId of the class AnImplementation,
|
||||
// and declares that the parent iid is that of class Object.
|
||||
//
|
||||
const InterfaceId AnImplementation::iid =
|
||||
MakeInterfaceId ("AnImplementation", AnInterface::iid);
|
||||
|
||||
//
|
||||
// The next few lines are used by the component manager. They
|
||||
// state that the component manager can create a new object
|
||||
// AnImplementation and return an interface corresponding to
|
||||
// the AnImplementation iid.
|
||||
//
|
||||
const ClassId AnImplementation::cid =
|
||||
MakeClassId<AnImplementation>
|
||||
("AnImplementation", AnImplementation::iid);
|
||||
|
||||
|
||||
//
|
||||
// Extending interfaces
|
||||
// ==================
|
||||
// What if AnInterface doesn't provide enough API for your
|
||||
// object type?
|
||||
// - if you aren't concerned about backward compatibility and
|
||||
// don't mind recompiling, you just add new methods to AnInterface
|
||||
// and recompile.
|
||||
// - if you want to address backward compatibiliy, or allow part
|
||||
// of the system to use the old interface, you have to do more.
|
||||
// You have to declare a new interface with the new functionality.
|
||||
//
|
||||
|
||||
class AnExtendedInterface : public AnInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
void methodB (void);
|
||||
private:
|
||||
virtual void domethodB (void) = 0;
|
||||
};
|
||||
|
||||
const InterfaceId AnExtendedInterface::iid =
|
||||
MakeInterfaceId ("AnExtendedInterface", AnInterface::iid);
|
||||
|
||||
//
|
||||
// Then you need provide an implementation for the virtual
|
||||
// methods. If you are providing a new implementation for
|
||||
// everything, the answer is straightforward
|
||||
//
|
||||
|
||||
class ANewImplementation : public AnExtendedInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
|
||||
ANewImplementation ();
|
||||
void methodImpl (void);
|
||||
private:
|
||||
virtual void domethodA (void) { /* new-implementation-behavior (); */}
|
||||
virtual void domethodB (void) { /* new-implementation-behavior (); */}
|
||||
};
|
||||
|
||||
ANewImplementation::ANewImplementation (void)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (ANewImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
ANewImplementation::methodImpl (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
const InterfaceId ANewImplementation::iid =
|
||||
MakeInterfaceId ("ANewImplementation", AnExtendedInterface::iid);
|
||||
|
||||
//
|
||||
// If you want to extend an existing implementation, you can use
|
||||
// the existing class to instantiate an implementation of its
|
||||
// methods (hasa) and do the following if you can use stuff from
|
||||
// the existing class.
|
||||
//
|
||||
|
||||
class AnExtendedImplementation : public AnExtendedInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
|
||||
AnExtendedImplementation ();
|
||||
void methodImpl (void) { /* pImpl->methodImpl (); */ }
|
||||
void methodExtendedImpl (void);
|
||||
private:
|
||||
virtual void domethodA (void) { /* new-implementation-behavior (); */}
|
||||
virtual void domethodB (void) { /* new-implementation-behavior (); */}
|
||||
Ptr<AnImplementation> pImpl;
|
||||
};
|
||||
|
||||
AnExtendedImplementation::AnExtendedImplementation (void)
|
||||
{
|
||||
pImpl = Create<AnImplementation> ();
|
||||
SetInterfaceId (AnExtendedImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
AnExtendedImplementation::methodExtendedImpl (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
const InterfaceId AnExtendedImplementation::iid =
|
||||
MakeInterfaceId ("AnExtendedImplementation", AnExtendedInterface::iid);
|
||||
|
||||
//
|
||||
// Inheriting from an existing implementation (isa) and an extended
|
||||
// interface is tricky, because of the diamond multiple inheritance
|
||||
// problem. If the pImpl method above is not desirable, it may
|
||||
// be that the implementation extension could be aggregated.
|
||||
//
|
||||
// The extension will not have access to the base implementation,
|
||||
// so this design pattern may be more appropriate if the extension
|
||||
// is very modular (e.g., add an EnergyModel to a wireless interface)
|
||||
//
|
||||
// EXAMPLE NOT YET PROVIDED
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
Ptr<AnInterface> aBase = ComponentManager::Create<AnImplementation>
|
||||
(AnImplementation::cid, AnInterface::iid);
|
||||
NS_ASSERT (aBase != 0);
|
||||
|
||||
aBase->methodA ();
|
||||
//aBase->methodImpl (); // XXX won't compile, aBase not right ptr type
|
||||
|
||||
Ptr<AnImplementation> aBaseImplPtr =
|
||||
aBase-> QueryInterface<AnImplementation> (AnImplementation::iid);
|
||||
aBaseImplPtr->methodImpl ();
|
||||
aBaseImplPtr->methodA();
|
||||
|
||||
// Test symmetric property of QueryInterface
|
||||
Ptr<AnInterface> aBase2 =
|
||||
aBaseImplPtr-> QueryInterface<AnInterface> (AnInterface::iid);
|
||||
aBase2->methodA ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ int main (int argc, char *argv[])
|
||||
std::vector<Ptr<Object> > objects;
|
||||
for (uint32_t i = 0; i < 10000; i++)
|
||||
{
|
||||
Ptr<MobilityModelNotifier> notifier = Create<MobilityModelNotifier> ();
|
||||
Ptr<MobilityModelNotifier> notifier = CreateObject<MobilityModelNotifier> ();
|
||||
notifier->TraceConnect ("/course-change", MakeCallback (&CourseChange));
|
||||
objects.push_back (notifier);
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ int main (int argc, char *argv[])
|
||||
|
||||
for (uint32_t i = 0; i < 100; i++)
|
||||
{
|
||||
Ptr<Node> node = Create<Node> ();
|
||||
node->AddInterface (Create<MobilityModelNotifier> ());
|
||||
Ptr<Node> node = CreateObject<Node> ();
|
||||
node->AggregateObject (CreateObject<MobilityModelNotifier> ());
|
||||
}
|
||||
|
||||
topology.Layout (NodeList::Begin (), NodeList::End ());
|
||||
|
||||
@@ -14,7 +14,7 @@ static void
|
||||
GenerateTraffic (Ptr<Socket> socket, uint32_t size)
|
||||
{
|
||||
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl;
|
||||
socket->Send (Packet (size));
|
||||
socket->Send (Create<Packet> (size));
|
||||
if (size > 0)
|
||||
{
|
||||
Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50);
|
||||
@@ -26,9 +26,9 @@ GenerateTraffic (Ptr<Socket> socket, uint32_t size)
|
||||
}
|
||||
|
||||
static void
|
||||
SocketPrinter (Ptr<Socket> socket, const Packet &packet, const Address &from)
|
||||
SocketPrinter (Ptr<Socket> socket, Ptr<Packet> packet, const Address &from)
|
||||
{
|
||||
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet.GetSize () << std::endl;
|
||||
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet->GetSize () << std::endl;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -40,10 +40,10 @@ PrintTraffic (Ptr<Socket> socket)
|
||||
void
|
||||
RunSimulation (void)
|
||||
{
|
||||
Ptr<Node> a = Create<InternetNode> ();
|
||||
Ptr<Node> a = CreateObject<InternetNode> ();
|
||||
|
||||
InterfaceId iid = InterfaceId::LookupByName ("Udp");
|
||||
Ptr<SocketFactory> socketFactory = a->QueryInterface<SocketFactory> (iid);
|
||||
TypeId tid = TypeId::LookupByName ("Udp");
|
||||
Ptr<SocketFactory> socketFactory = a->GetObject<SocketFactory> (tid);
|
||||
|
||||
Ptr<Socket> sink = socketFactory->CreateSocket ();
|
||||
InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
|
||||
|
||||
@@ -38,6 +38,20 @@ def build(bld):
|
||||
['core', 'simulator', 'mobility'])
|
||||
obj.source = 'main-random-topology.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-adhoc-wifi',
|
||||
['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'main-adhoc-wifi.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-ap-wifi',
|
||||
['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'main-ap-wifi.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-random-walk',
|
||||
['core', 'simulator', 'mobility'])
|
||||
obj.source = 'main-random-walk.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-propagation-loss',
|
||||
['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'main-propagation-loss.cc'
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/composite-trace-resolver.h"
|
||||
#include "onoff-application.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("OnOffApplication");
|
||||
@@ -52,20 +53,20 @@ static NumericDefaultValue<uint32_t> g_defaultSize ("OnOffApplicationPacketSize"
|
||||
|
||||
OnOffApplication::OnOffApplication(Ptr<Node> n,
|
||||
const Address &remote,
|
||||
std::string iid,
|
||||
std::string tid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime)
|
||||
: Application(n),
|
||||
m_cbrRate (g_defaultRate.GetValue ())
|
||||
{
|
||||
Construct (n, remote, iid,
|
||||
Construct (n, remote, tid,
|
||||
ontime, offtime,
|
||||
g_defaultSize.GetValue ());
|
||||
}
|
||||
|
||||
OnOffApplication::OnOffApplication(Ptr<Node> n,
|
||||
const Address &remote,
|
||||
std::string iid,
|
||||
std::string tid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime,
|
||||
DataRate rate,
|
||||
@@ -74,13 +75,13 @@ OnOffApplication::OnOffApplication(Ptr<Node> n,
|
||||
m_cbrRate (rate)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
Construct (n, remote, iid, ontime, offtime, size);
|
||||
Construct (n, remote, tid, ontime, offtime, size);
|
||||
}
|
||||
|
||||
void
|
||||
OnOffApplication::Construct (Ptr<Node> n,
|
||||
const Address &remote,
|
||||
std::string iid,
|
||||
std::string tid,
|
||||
const RandomVariable& onTime,
|
||||
const RandomVariable& offTime,
|
||||
uint32_t size)
|
||||
@@ -90,14 +91,14 @@ OnOffApplication::Construct (Ptr<Node> n,
|
||||
m_socket = 0;
|
||||
m_peer = remote;
|
||||
m_connected = false;
|
||||
m_onTime = onTime.Copy ();
|
||||
m_offTime = offTime.Copy ();
|
||||
m_onTime = onTime;
|
||||
m_offTime = offTime;
|
||||
m_pktSize = size;
|
||||
m_residualBits = 0;
|
||||
m_lastStartTime = Seconds (0);
|
||||
m_maxBytes = 0xffffffff;
|
||||
m_maxBytes = 0;
|
||||
m_totBytes = 0;
|
||||
m_iid = iid;
|
||||
m_tid = tid;
|
||||
}
|
||||
|
||||
OnOffApplication::~OnOffApplication()
|
||||
@@ -135,12 +136,6 @@ OnOffApplication::DoDispose (void)
|
||||
NS_LOG_FUNCTION;
|
||||
|
||||
m_socket = 0;
|
||||
delete m_onTime;
|
||||
delete m_offTime;
|
||||
|
||||
m_onTime = 0;
|
||||
m_offTime = 0;
|
||||
|
||||
// chain up
|
||||
Application::DoDispose ();
|
||||
}
|
||||
@@ -153,8 +148,8 @@ void OnOffApplication::StartApplication() // Called at time specified by Start
|
||||
// Create the socket if not already
|
||||
if (!m_socket)
|
||||
{
|
||||
InterfaceId iid = InterfaceId::LookupByName (m_iid);
|
||||
Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
|
||||
TypeId tid = TypeId::LookupByName (m_tid);
|
||||
Ptr<SocketFactory> socketFactory = GetNode ()->GetObject<SocketFactory> (tid);
|
||||
m_socket = socketFactory->CreateSocket ();
|
||||
m_socket->Bind ();
|
||||
m_socket->Connect (m_peer);
|
||||
@@ -194,6 +189,7 @@ void OnOffApplication::StopSending()
|
||||
NS_LOG_FUNCTION;
|
||||
|
||||
Simulator::Cancel(m_sendEvent);
|
||||
m_socket->Close ();
|
||||
}
|
||||
|
||||
// Private helpers
|
||||
@@ -201,7 +197,7 @@ void OnOffApplication::ScheduleNextTx()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
|
||||
if (m_totBytes < m_maxBytes)
|
||||
if (m_maxBytes == 0 || m_totBytes < m_maxBytes)
|
||||
{
|
||||
uint32_t bits = m_pktSize * 8 - m_residualBits;
|
||||
NS_LOG_LOGIC ("bits = " << bits);
|
||||
@@ -221,7 +217,7 @@ void OnOffApplication::ScheduleStartEvent()
|
||||
{ // Schedules the event to start sending data (switch to the "On" state)
|
||||
NS_LOG_FUNCTION;
|
||||
|
||||
Time offInterval = Seconds(m_offTime->GetValue());
|
||||
Time offInterval = Seconds(m_offTime.GetValue());
|
||||
NS_LOG_LOGIC ("start at " << offInterval);
|
||||
m_startStopEvent = Simulator::Schedule(offInterval, &OnOffApplication::StartSending, this);
|
||||
}
|
||||
@@ -230,7 +226,7 @@ void OnOffApplication::ScheduleStopEvent()
|
||||
{ // Schedules the event to stop sending data (switch to "Off" state)
|
||||
NS_LOG_FUNCTION;
|
||||
|
||||
Time onInterval = Seconds(m_onTime->GetValue());
|
||||
Time onInterval = Seconds(m_onTime.GetValue());
|
||||
Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
|
||||
}
|
||||
|
||||
@@ -240,7 +236,9 @@ void OnOffApplication::SendPacket()
|
||||
NS_LOG_FUNCTION;
|
||||
|
||||
NS_ASSERT (m_sendEvent.IsExpired ());
|
||||
m_socket->Send(Packet (m_pktSize));
|
||||
Ptr<Packet> packet = Create<Packet> (m_pktSize);
|
||||
m_txTrace (packet);
|
||||
m_socket->Send (packet);
|
||||
m_totBytes += m_pktSize;
|
||||
m_lastStartTime = Simulator::Now();
|
||||
m_residualBits = 0;
|
||||
@@ -261,4 +259,17 @@ void OnOffApplication::ConnectionFailed(Ptr<Socket>)
|
||||
cout << "OnOffApplication, Connection Failed" << endl;
|
||||
}
|
||||
|
||||
Ptr<TraceResolver>
|
||||
OnOffApplication::GetTraceResolver (void) const
|
||||
{
|
||||
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
|
||||
resolver->AddSource ("tx",
|
||||
TraceDoc ("A new packet is created and is sent",
|
||||
"Ptr<const Packet>",
|
||||
"The newly-created packet."),
|
||||
m_txTrace);
|
||||
resolver->SetParentResolver (Application::GetTraceResolver ());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
} // Namespace ns3
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/callback-trace-source.h"
|
||||
#include "ns3/random-variable.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -53,20 +55,24 @@ public:
|
||||
/**
|
||||
* \param n node associated to this application
|
||||
* \param remote remote ip address
|
||||
* \param iid
|
||||
* \param tid TypeId of the socket factory to use. Note this
|
||||
* factory should create sockets compatible with the specified
|
||||
* remote address.
|
||||
* \param ontime on time random variable
|
||||
* \param offtime off time random variable
|
||||
*/
|
||||
OnOffApplication(Ptr<Node> n,
|
||||
const Address &remote,
|
||||
std::string iid,
|
||||
std::string tid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime);
|
||||
|
||||
/**
|
||||
* \param n node associated to this application
|
||||
* \param remote remote ip address
|
||||
* \param iid
|
||||
* \param tid TypeId of the socket factory to use. Note this
|
||||
* factory should create sockets compatible with the specified
|
||||
* remote address.
|
||||
* \param ontime on time random variable
|
||||
* \param offtime off time random variable
|
||||
* \param rate data rate when on
|
||||
@@ -74,7 +80,7 @@ public:
|
||||
*/
|
||||
OnOffApplication(Ptr<Node> n,
|
||||
const Address &remote,
|
||||
std::string iid,
|
||||
std::string tid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime,
|
||||
DataRate rate,
|
||||
@@ -109,7 +115,7 @@ private:
|
||||
|
||||
void Construct (Ptr<Node> n,
|
||||
const Address &remote,
|
||||
std::string iid,
|
||||
std::string tid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime,
|
||||
uint32_t size);
|
||||
@@ -123,8 +129,8 @@ private:
|
||||
Ptr<Socket> m_socket; // Associated socket
|
||||
Address m_peer; // Peer address
|
||||
bool m_connected; // True if connected
|
||||
RandomVariable* m_onTime; // rng for On Time
|
||||
RandomVariable* m_offTime; // rng for Off Time
|
||||
RandomVariable m_onTime; // rng for On Time
|
||||
RandomVariable m_offTime; // rng for Off Time
|
||||
DataRate m_cbrRate; // Rate that data is generated
|
||||
uint32_t m_pktSize; // Size of packets
|
||||
uint32_t m_residualBits; // Number of generated, but not sent, bits
|
||||
@@ -134,9 +140,11 @@ private:
|
||||
EventId m_startStopEvent; // Event id for next start or stop event
|
||||
EventId m_sendEvent; // Eventid of pending "send packet" event
|
||||
bool m_sending; // True if currently in sending state
|
||||
std::string m_iid;
|
||||
std::string m_tid;
|
||||
CallbackTraceSource<Ptr<const Packet> > m_txTrace;
|
||||
|
||||
private:
|
||||
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
|
||||
void ScheduleNextTx();
|
||||
void ScheduleStartEvent();
|
||||
void ScheduleStopEvent();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
module = bld.create_ns3_module('onoff', ['core'])
|
||||
module = bld.create_ns3_module('onoff', ['core', 'simulator', 'node'])
|
||||
module.source = [
|
||||
'onoff-application.cc',
|
||||
]
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/composite-trace-resolver.h"
|
||||
#include "packet-sink.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -37,20 +38,20 @@ NS_LOG_COMPONENT_DEFINE ("PacketSinkApplication");
|
||||
|
||||
PacketSink::PacketSink (Ptr<Node> n,
|
||||
const Address &local,
|
||||
std::string iid)
|
||||
std::string tid)
|
||||
: Application(n)
|
||||
{
|
||||
Construct (n, local, iid);
|
||||
Construct (n, local, tid);
|
||||
}
|
||||
|
||||
void
|
||||
PacketSink::Construct (Ptr<Node> n,
|
||||
const Address &local,
|
||||
std::string iid)
|
||||
std::string tid)
|
||||
{
|
||||
m_socket = 0;
|
||||
m_local = local;
|
||||
m_iid = iid;
|
||||
m_tid = tid;
|
||||
}
|
||||
|
||||
PacketSink::~PacketSink()
|
||||
@@ -72,37 +73,62 @@ void PacketSink::StartApplication() // Called at time specified by Start
|
||||
// Create the socket if not already
|
||||
if (!m_socket)
|
||||
{
|
||||
InterfaceId iid = InterfaceId::LookupByName (m_iid);
|
||||
TypeId tid = TypeId::LookupByName (m_tid);
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
GetNode ()->QueryInterface<SocketFactory> (iid);
|
||||
GetNode ()->GetObject<SocketFactory> (tid);
|
||||
m_socket = socketFactory->CreateSocket ();
|
||||
m_socket->Bind (m_local);
|
||||
m_socket->Listen (0);
|
||||
}
|
||||
|
||||
m_socket->SetRecvCallback (MakeCallback(&PacketSink::Receive, this));
|
||||
m_socket->SetAcceptCallback (
|
||||
MakeNullCallback<bool, Ptr<Socket>, const Address &> (),
|
||||
MakeNullCallback<void, Ptr<Socket>, const Address&> (),
|
||||
MakeCallback(&PacketSink::CloseConnection, this) );
|
||||
}
|
||||
|
||||
void PacketSink::StopApplication() // Called at time specified by Stop
|
||||
{
|
||||
if (!m_socket)
|
||||
if (m_socket)
|
||||
{
|
||||
m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket>,
|
||||
const Packet &, const Address &> ());
|
||||
|
||||
Ptr<Packet>, const Address &> ());
|
||||
}
|
||||
}
|
||||
|
||||
// This LOG output inspired by the application on Joseph Kopena's wiki
|
||||
void PacketSink::Receive(Ptr<Socket> socket, const Packet &packet,
|
||||
void PacketSink::Receive(Ptr<Socket> socket, Ptr<Packet> packet,
|
||||
const Address &from)
|
||||
{
|
||||
if (InetSocketAddress::IsMatchingType (from))
|
||||
{
|
||||
InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
|
||||
NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " <<
|
||||
NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " <<
|
||||
address.GetIpv4() << " [" << address << "]---'" <<
|
||||
packet.PeekData() << "'");
|
||||
// TODO: Add a tracing source here
|
||||
packet->PeekData() << "'");
|
||||
}
|
||||
m_rxTrace (packet, from);
|
||||
}
|
||||
|
||||
void PacketSink::CloseConnection (Ptr<Socket> socket)
|
||||
{
|
||||
socket->Close ();
|
||||
}
|
||||
|
||||
Ptr<TraceResolver>
|
||||
PacketSink::GetTraceResolver (void) const
|
||||
{
|
||||
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
|
||||
resolver->AddSource ("rx",
|
||||
TraceDoc ("A new packet has been received",
|
||||
"Ptr<const Packet>",
|
||||
"The newly-received packet.",
|
||||
"const Address &",
|
||||
"The source address of the received packet."),
|
||||
m_rxTrace);
|
||||
resolver->SetParentResolver (Application::GetTraceResolver ());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
} // Namespace ns3
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "ns3/application.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/callback-trace-source.h"
|
||||
#include "ns3/address.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -54,11 +56,11 @@ public:
|
||||
/**
|
||||
* \param n node associated to this application
|
||||
* \param local local address to bind to
|
||||
* \param iid string to identify transport protocol of interest
|
||||
* \param tid string to identify transport protocol of interest
|
||||
*/
|
||||
PacketSink (Ptr<Node> n,
|
||||
const Address &local,
|
||||
std::string iid);
|
||||
std::string tid);
|
||||
|
||||
virtual ~PacketSink ();
|
||||
|
||||
@@ -68,16 +70,20 @@ private:
|
||||
// inherited from Application base class.
|
||||
virtual void StartApplication (void); // Called at time specified by Start
|
||||
virtual void StopApplication (void); // Called at time specified by Stop
|
||||
// inherited from Object base class.
|
||||
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
|
||||
|
||||
void Construct (Ptr<Node> n,
|
||||
const Address &local,
|
||||
std::string iid);
|
||||
std::string tid);
|
||||
|
||||
virtual void Receive (Ptr<Socket> socket, const Packet& packet, const Address& from);
|
||||
virtual void Receive (Ptr<Socket> socket, Ptr<Packet> packet, const Address& from);
|
||||
virtual void CloseConnection (Ptr<Socket> socket);
|
||||
|
||||
Ptr<Socket> m_socket; // Associated socket
|
||||
Address m_local; // Local address to bind to
|
||||
std::string m_iid; // Protocol name (e.g., "Udp")
|
||||
std::string m_tid; // Protocol name (e.g., "Udp")
|
||||
CallbackTraceSource<Ptr<const Packet>, const Address &> m_rxTrace;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -91,16 +91,15 @@ UdpEchoClient::StartApplication (void)
|
||||
|
||||
if (!m_socket)
|
||||
{
|
||||
InterfaceId iid = InterfaceId::LookupByName ("Udp");
|
||||
TypeId tid = TypeId::LookupByName ("Udp");
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
GetNode ()->QueryInterface<SocketFactory> (iid);
|
||||
GetNode ()->GetObject<SocketFactory> (tid);
|
||||
m_socket = socketFactory->CreateSocket ();
|
||||
m_socket->Bind ();
|
||||
m_socket->Connect (m_peer);
|
||||
}
|
||||
|
||||
m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
|
||||
const Address &>) MakeCallback(&UdpEchoClient::Receive, this));
|
||||
m_socket->SetRecvCallback(MakeCallback(&UdpEchoClient::Receive, this));
|
||||
|
||||
ScheduleTransmit (Seconds(0.));
|
||||
}
|
||||
@@ -112,8 +111,8 @@ UdpEchoClient::StopApplication ()
|
||||
|
||||
if (!m_socket)
|
||||
{
|
||||
m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
|
||||
const Address &>) NULL);
|
||||
m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>, Ptr<Packet>,
|
||||
const Address &> ());
|
||||
}
|
||||
|
||||
Simulator::Cancel(m_sendEvent);
|
||||
@@ -133,7 +132,7 @@ UdpEchoClient::Send (void)
|
||||
|
||||
NS_ASSERT (m_sendEvent.IsExpired ());
|
||||
|
||||
Packet p (m_size);
|
||||
Ptr<Packet> p = Create<Packet> (m_size);
|
||||
m_socket->Send (p);
|
||||
++m_sent;
|
||||
|
||||
@@ -148,7 +147,7 @@ UdpEchoClient::Send (void)
|
||||
void
|
||||
UdpEchoClient::Receive(
|
||||
Ptr<Socket> socket,
|
||||
const Packet &packet,
|
||||
Ptr<Packet> packet,
|
||||
const Address &from)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
@@ -157,7 +156,7 @@ UdpEchoClient::Receive(
|
||||
if (InetSocketAddress::IsMatchingType (from))
|
||||
{
|
||||
InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
|
||||
NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " <<
|
||||
NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " <<
|
||||
address.GetIpv4());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ private:
|
||||
void ScheduleTransmit (Time dt);
|
||||
void Send (void);
|
||||
|
||||
void Receive(Ptr<Socket> socket, const Packet &packet, const Address &from);
|
||||
void Receive(Ptr<Socket> socket, Ptr<Packet> packet, const Address &from);
|
||||
|
||||
Ptr<Node> m_node;
|
||||
Ipv4Address m_serverAddress;
|
||||
|
||||
@@ -77,9 +77,9 @@ UdpEchoServer::StartApplication (void)
|
||||
|
||||
if (!m_socket)
|
||||
{
|
||||
InterfaceId iid = InterfaceId::LookupByName ("Udp");
|
||||
TypeId tid = TypeId::LookupByName ("Udp");
|
||||
Ptr<SocketFactory> socketFactory =
|
||||
GetNode ()->QueryInterface<SocketFactory> (iid);
|
||||
GetNode ()->GetObject<SocketFactory> (tid);
|
||||
m_socket = socketFactory->CreateSocket ();
|
||||
m_socket->Bind (m_local);
|
||||
}
|
||||
@@ -94,15 +94,15 @@ UdpEchoServer::StopApplication ()
|
||||
|
||||
if (!m_socket)
|
||||
{
|
||||
m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket>,
|
||||
const Packet &, const Address &> ());
|
||||
m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>,
|
||||
Ptr<Packet>, const Address &> ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UdpEchoServer::Receive(
|
||||
Ptr<Socket> socket,
|
||||
const Packet &packet,
|
||||
Ptr<Packet> packet,
|
||||
const Address &from)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
@@ -111,7 +111,7 @@ UdpEchoServer::Receive(
|
||||
if (InetSocketAddress::IsMatchingType (from))
|
||||
{
|
||||
InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
|
||||
NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " <<
|
||||
NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " <<
|
||||
address.GetIpv4());
|
||||
|
||||
NS_LOG_LOGIC ("Echoing packet");
|
||||
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
virtual void StartApplication (void);
|
||||
virtual void StopApplication (void);
|
||||
|
||||
void Receive(Ptr<Socket> socket, const Packet &packet, const Address &from);
|
||||
void Receive(Ptr<Socket> socket, Ptr<Packet> packet, const Address &from);
|
||||
|
||||
Ptr<Node> m_node;
|
||||
uint16_t m_port;
|
||||
|
||||
@@ -105,7 +105,7 @@ ChunkRegistry::GetName (uint32_t uid, uint8_t *instance)
|
||||
void
|
||||
ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
|
||||
uint32_t packetUid, uint32_t size,
|
||||
Ptr<CallbackImplBase> callback)
|
||||
CallbackBase callback)
|
||||
{
|
||||
InfoVector *vec = GetInfoVector ();
|
||||
NS_ASSERT (uid >= 1 && uid <= vec->size ());
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
static bool IsTrailer (uint32_t uid);
|
||||
static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
|
||||
uint32_t packetUid, uint32_t size,
|
||||
Ptr<CallbackImplBase> callback);
|
||||
CallbackBase callback);
|
||||
private:
|
||||
typedef uint8_t *(*GetStaticInstanceCb) (void);
|
||||
typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
|
||||
@@ -62,7 +62,7 @@ private:
|
||||
typedef std::string (*GetNameCb) (uint8_t *);
|
||||
typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os,
|
||||
uint32_t packetUid, uint32_t size,
|
||||
Ptr<CallbackImplBase> callback);
|
||||
CallbackBase callback);
|
||||
struct Info {
|
||||
std::string uidString;
|
||||
bool isHeader;
|
||||
@@ -85,7 +85,7 @@ private:
|
||||
template <typename T>
|
||||
static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
|
||||
uint32_t packetUid, uint32_t size,
|
||||
Ptr<CallbackImplBase> callback);
|
||||
CallbackBase callback);
|
||||
template <typename T>
|
||||
static uint32_t GetUid (bool isHeader, std::string uidString);
|
||||
|
||||
@@ -167,7 +167,7 @@ template <typename T>
|
||||
void
|
||||
ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
|
||||
uint32_t packetUid, uint32_t size,
|
||||
Ptr<CallbackImplBase> callback)
|
||||
CallbackBase callback)
|
||||
{
|
||||
T *obj = reinterpret_cast<T *> (instance);
|
||||
Callback<void,std::ostream&,uint32_t,uint32_t,const T*> cb;
|
||||
|
||||
+48
-38
@@ -28,22 +28,30 @@
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/type-id-default-value.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("ErrorModel");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
static ClassIdDefaultValue g_classIdErrorModelDefaultValue ("ErrorModel",
|
||||
"Error Model", ErrorModel::iid, "RateErrorModel");
|
||||
static TypeIdDefaultValue g_interfaceIdErrorModelDefaultValue ("ErrorModel",
|
||||
"Error Model",
|
||||
ErrorModel::GetTypeId (),
|
||||
"RateErrorModel");
|
||||
|
||||
const InterfaceId ErrorModel::iid =
|
||||
MakeInterfaceId ("ErrorModel", Object::iid);
|
||||
NS_OBJECT_ENSURE_REGISTERED (ErrorModel);
|
||||
|
||||
TypeId ErrorModel::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ErrorModel")
|
||||
.SetParent<Object> ();
|
||||
return tid;
|
||||
}
|
||||
|
||||
ErrorModel::ErrorModel () :
|
||||
m_enable (true)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
SetInterfaceId (ErrorModel::iid);
|
||||
}
|
||||
|
||||
ErrorModel::~ErrorModel ()
|
||||
@@ -55,14 +63,13 @@ Ptr<ErrorModel>
|
||||
ErrorModel::CreateDefault (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
ClassId classId = g_classIdErrorModelDefaultValue.GetValue ();
|
||||
Ptr<ErrorModel> em = ComponentManager::Create<ErrorModel> (classId,
|
||||
ErrorModel::iid);
|
||||
TypeId interfaceId = g_interfaceIdErrorModelDefaultValue.GetValue ();
|
||||
Ptr<ErrorModel> em = interfaceId.CreateObject ()->GetObject<ErrorModel> ();
|
||||
return em;
|
||||
}
|
||||
|
||||
bool
|
||||
ErrorModel::IsCorrupt (Packet& p)
|
||||
ErrorModel::IsCorrupt (Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
bool result;
|
||||
@@ -104,13 +111,6 @@ ErrorModel::IsEnabled (void) const
|
||||
// RateErrorModel
|
||||
//
|
||||
|
||||
const InterfaceId RateErrorModel::iid =
|
||||
MakeInterfaceId ("RateErrorModel", ErrorModel::iid);
|
||||
|
||||
const ClassId RateErrorModel::cid =
|
||||
MakeClassId<RateErrorModel> ("RateErrorModel", ErrorModel::iid,
|
||||
RateErrorModel::iid);
|
||||
|
||||
// Defaults for rate/size
|
||||
static NumericDefaultValue<double> g_defaultRateErrorModelErrorRate
|
||||
("RateErrorModelErrorRate", "The error rate for the error model", 0.0);
|
||||
@@ -123,20 +123,29 @@ static EnumDefaultValue<enum ErrorUnit>
|
||||
EU_BIT, "EU_BIT",
|
||||
0, (void*)0);
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (RateErrorModel);
|
||||
|
||||
TypeId RateErrorModel::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("RateErrorModel")
|
||||
.SetParent<ErrorModel> ()
|
||||
.AddConstructor<RateErrorModel> ();
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
RateErrorModel::RateErrorModel () :
|
||||
m_unit (g_defaultRateErrorModelErrorUnit.GetValue() ),
|
||||
m_rate (g_defaultRateErrorModelErrorRate.GetValue() )
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
// Assume a uniform random variable if user does not specify
|
||||
m_ranvar = new UniformVariable ();
|
||||
SetInterfaceId (RateErrorModel::iid);
|
||||
m_ranvar = UniformVariable ();
|
||||
}
|
||||
|
||||
RateErrorModel::~RateErrorModel ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
delete m_ranvar;
|
||||
}
|
||||
|
||||
enum ErrorUnit
|
||||
@@ -171,12 +180,11 @@ void
|
||||
RateErrorModel::SetRandomVariable (const RandomVariable &ranvar)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
delete m_ranvar;
|
||||
m_ranvar = ranvar.Copy ();
|
||||
m_ranvar = ranvar;
|
||||
}
|
||||
|
||||
bool
|
||||
RateErrorModel::DoCorrupt (Packet& p)
|
||||
RateErrorModel::DoCorrupt (Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
if (!m_enable)
|
||||
@@ -199,28 +207,28 @@ RateErrorModel::DoCorrupt (Packet& p)
|
||||
}
|
||||
|
||||
bool
|
||||
RateErrorModel::DoCorruptPkt (Packet& p)
|
||||
RateErrorModel::DoCorruptPkt (Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
return (m_ranvar->GetValue () < m_rate);
|
||||
return (m_ranvar.GetValue () < m_rate);
|
||||
}
|
||||
|
||||
bool
|
||||
RateErrorModel::DoCorruptByte (Packet& p)
|
||||
RateErrorModel::DoCorruptByte (Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
// compute pkt error rate, assume uniformly distributed byte error
|
||||
double per = 1 - pow (1.0 - m_rate, p.GetSize ());
|
||||
return (m_ranvar->GetValue () < per);
|
||||
double per = 1 - pow (1.0 - m_rate, p->GetSize ());
|
||||
return (m_ranvar.GetValue () < per);
|
||||
}
|
||||
|
||||
bool
|
||||
RateErrorModel::DoCorruptBit(Packet& p)
|
||||
RateErrorModel::DoCorruptBit(Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
// compute pkt error rate, assume uniformly distributed bit error
|
||||
double per = 1 - pow (1.0 - m_rate, (8 * p.GetSize ()) );
|
||||
return (m_ranvar->GetValue () < per);
|
||||
double per = 1 - pow (1.0 - m_rate, (8 * p->GetSize ()) );
|
||||
return (m_ranvar.GetValue () < per);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -234,17 +242,19 @@ RateErrorModel::DoReset (void)
|
||||
// ListErrorModel
|
||||
//
|
||||
|
||||
const InterfaceId ListErrorModel::iid =
|
||||
MakeInterfaceId ("ListErrorModel", ErrorModel::iid);
|
||||
NS_OBJECT_ENSURE_REGISTERED (ListErrorModel);
|
||||
|
||||
const ClassId ListErrorModel::cid =
|
||||
MakeClassId<ListErrorModel> ("ListErrorModel", ErrorModel::iid,
|
||||
ListErrorModel::iid);
|
||||
TypeId ListErrorModel::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ListErrorModel")
|
||||
.SetParent<ErrorModel> ()
|
||||
.AddConstructor<ListErrorModel> ();
|
||||
return tid;
|
||||
}
|
||||
|
||||
ListErrorModel::ListErrorModel ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
SetInterfaceId (ListErrorModel::iid);
|
||||
}
|
||||
|
||||
ListErrorModel::~ListErrorModel ()
|
||||
@@ -270,14 +280,14 @@ ListErrorModel::SetList (const std::list<uint32_t> &packetlist)
|
||||
// converted to a dynamically-sized array of uint32_t to avoid
|
||||
// list iteration below.
|
||||
bool
|
||||
ListErrorModel::DoCorrupt (Packet& p)
|
||||
ListErrorModel::DoCorrupt (Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
if (!m_enable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint32_t uid = p.GetUid ();
|
||||
uint32_t uid = p->GetUid ();
|
||||
for (PacketListCI i = m_packetList.begin ();
|
||||
i != m_packetList.end (); i++)
|
||||
{
|
||||
|
||||
+15
-18
@@ -23,12 +23,11 @@
|
||||
|
||||
#include <list>
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/component-manager.h"
|
||||
#include "ns3/random-variable.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Packet;
|
||||
class RandomVariable;
|
||||
|
||||
/**
|
||||
* \brief General error model that can be used to corrupt packets
|
||||
@@ -37,7 +36,7 @@ class RandomVariable;
|
||||
* It is part of the Object framework and can be aggregated to
|
||||
* other ns3 objects and handled by the Ptr class.
|
||||
*
|
||||
* The main method is IsCorrupt(Packet& p) which returns true if
|
||||
* The main method is IsCorrupt(Ptr<Packet> p) which returns true if
|
||||
* the packet is to be corrupted according to the underlying model.
|
||||
* Depending on the error model, the packet itself may have its packet
|
||||
* data buffer errored or not, or side information may be returned to
|
||||
@@ -48,11 +47,11 @@ class RandomVariable;
|
||||
* Typical code (simplified) to use an ErrorModel may look something like
|
||||
* this:
|
||||
* \code
|
||||
* Ptr<ErrorModel> rem = Create<RateErrorModel> ();
|
||||
* Ptr<ErrorModel> rem = CreateObject<RateErrorModel> ();
|
||||
* rem->SetRandomVariable (UniformVariable ());
|
||||
* rem->SetRate (0.001);
|
||||
* ...
|
||||
* Packet p;
|
||||
* Ptr<Packet> p;
|
||||
* if (rem->IsCorrupt (p))
|
||||
* {
|
||||
* dropTrace(p);
|
||||
@@ -67,7 +66,7 @@ class RandomVariable;
|
||||
class ErrorModel : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* A factory method to generate a preconfigured default ErrorModel for use
|
||||
* \return an ErrorModel smart pointer that is the default ErrorModel
|
||||
@@ -82,7 +81,7 @@ public:
|
||||
* \returns true if the Packet is to be considered as errored/corrupted
|
||||
* \param pkt Packet to apply error model to
|
||||
*/
|
||||
bool IsCorrupt (Packet& pkt);
|
||||
bool IsCorrupt (Ptr<Packet> pkt);
|
||||
/**
|
||||
* Reset any state associated with the error model
|
||||
*/
|
||||
@@ -107,7 +106,7 @@ private:
|
||||
/*
|
||||
* These methods must be implemented by subclasses
|
||||
*/
|
||||
virtual bool DoCorrupt (Packet&) = 0;
|
||||
virtual bool DoCorrupt (Ptr<Packet>) = 0;
|
||||
virtual void DoReset (void) = 0;
|
||||
|
||||
};
|
||||
@@ -137,8 +136,7 @@ enum ErrorUnit
|
||||
class RateErrorModel : public ErrorModel
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
RateErrorModel ();
|
||||
virtual ~RateErrorModel ();
|
||||
@@ -167,16 +165,16 @@ public:
|
||||
void SetRandomVariable (const RandomVariable &ranvar);
|
||||
|
||||
private:
|
||||
virtual bool DoCorrupt (Packet& p);
|
||||
virtual bool DoCorruptPkt (Packet& p);
|
||||
virtual bool DoCorruptByte (Packet& p);
|
||||
virtual bool DoCorruptBit (Packet& p);
|
||||
virtual bool DoCorrupt (Ptr<Packet> p);
|
||||
virtual bool DoCorruptPkt (Ptr<Packet> p);
|
||||
virtual bool DoCorruptByte (Ptr<Packet> p);
|
||||
virtual bool DoCorruptBit (Ptr<Packet> p);
|
||||
virtual void DoReset (void);
|
||||
|
||||
enum ErrorUnit m_unit;
|
||||
double m_rate;
|
||||
|
||||
RandomVariable* m_ranvar;
|
||||
RandomVariable m_ranvar;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -204,8 +202,7 @@ private:
|
||||
class ListErrorModel : public ErrorModel
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
static TypeId GetTypeId (void);
|
||||
ListErrorModel ();
|
||||
virtual ~ListErrorModel ();
|
||||
|
||||
@@ -221,7 +218,7 @@ public:
|
||||
void SetList (const std::list<uint32_t> &packetlist);
|
||||
|
||||
private:
|
||||
virtual bool DoCorrupt (Packet& p);
|
||||
virtual bool DoCorrupt (Ptr<Packet> p);
|
||||
virtual void DoReset (void);
|
||||
|
||||
typedef std::list<uint32_t> PacketList;
|
||||
|
||||
@@ -199,7 +199,7 @@ class PacketMetadataTest : public Test {
|
||||
public:
|
||||
PacketMetadataTest ();
|
||||
virtual ~PacketMetadataTest ();
|
||||
bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
|
||||
bool CheckHistory (Ptr<Packet> p, const char *file, int line, uint32_t n, ...);
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
template <int N>
|
||||
@@ -217,7 +217,7 @@ private:
|
||||
template <int N>
|
||||
void RegisterTrailer (void);
|
||||
void CleanupPrints (void);
|
||||
Packet DoAddHeader (Packet p);
|
||||
Ptr<Packet> DoAddHeader (Ptr<Packet> p);
|
||||
bool Check (const char *file, int line, std::list<int> expected);
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
|
||||
}
|
||||
|
||||
bool
|
||||
PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
|
||||
PacketMetadataTest::CheckHistory (Ptr<Packet> p, const char *file, int line, uint32_t n, ...)
|
||||
{
|
||||
m_headerError = false;
|
||||
m_trailerError = false;
|
||||
@@ -373,7 +373,7 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t
|
||||
va_end (ap);
|
||||
|
||||
m_printer.PrintForward ();
|
||||
p.Print (Failure (), m_printer);
|
||||
p->Print (Failure (), m_printer);
|
||||
bool ok = Check (file, line, expected);
|
||||
CleanupPrints ();
|
||||
if (!ok)
|
||||
@@ -382,7 +382,7 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t
|
||||
}
|
||||
|
||||
m_printer.PrintBackward ();
|
||||
p.Print (Failure (), m_printer);
|
||||
p->Print (Failure (), m_printer);
|
||||
expected.reverse ();
|
||||
ok = Check (file, line, expected);
|
||||
CleanupPrints ();
|
||||
@@ -393,25 +393,25 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t
|
||||
{ \
|
||||
HistoryHeader<n> header; \
|
||||
RegisterHeader<n> (); \
|
||||
p.AddHeader (header); \
|
||||
p->AddHeader (header); \
|
||||
}
|
||||
#define ADD_TRAILER(p, n) \
|
||||
{ \
|
||||
HistoryTrailer<n> trailer; \
|
||||
RegisterTrailer<n> (); \
|
||||
p.AddTrailer (trailer); \
|
||||
p->AddTrailer (trailer); \
|
||||
}
|
||||
#define REM_HEADER(p, n) \
|
||||
{ \
|
||||
HistoryHeader<n> header; \
|
||||
RegisterHeader<n> (); \
|
||||
p.RemoveHeader (header); \
|
||||
p->RemoveHeader (header); \
|
||||
}
|
||||
#define REM_TRAILER(p, n) \
|
||||
{ \
|
||||
HistoryTrailer<n> trailer; \
|
||||
RegisterTrailer<n> (); \
|
||||
p.RemoveTrailer (trailer); \
|
||||
p->RemoveTrailer (trailer); \
|
||||
}
|
||||
#define CHECK_HISTORY(p, ...) \
|
||||
{ \
|
||||
@@ -421,9 +421,9 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t
|
||||
ok = false; \
|
||||
} \
|
||||
Buffer buffer; \
|
||||
buffer = p.Serialize (); \
|
||||
Packet otherPacket; \
|
||||
otherPacket.Deserialize (buffer); \
|
||||
buffer = p->Serialize (); \
|
||||
Ptr<Packet> otherPacket = Create<Packet> ();\
|
||||
otherPacket->Deserialize (buffer); \
|
||||
if (!CheckHistory (otherPacket, __FILE__, \
|
||||
__LINE__, __VA_ARGS__)) \
|
||||
{ \
|
||||
@@ -432,8 +432,8 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t
|
||||
}
|
||||
|
||||
|
||||
Packet
|
||||
PacketMetadataTest::DoAddHeader (Packet p)
|
||||
Ptr<Packet>
|
||||
PacketMetadataTest::DoAddHeader (Ptr<Packet> p)
|
||||
{
|
||||
ADD_HEADER (p, 10);
|
||||
return p;
|
||||
@@ -446,14 +446,14 @@ PacketMetadataTest::RunTests (void)
|
||||
|
||||
PacketMetadata::Enable ();
|
||||
|
||||
Packet p = Packet (0);
|
||||
Packet p1 = Packet (0);
|
||||
Ptr<Packet> p = Create<Packet> (0);
|
||||
Ptr<Packet> p1 = Create<Packet> (0);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_TRAILER (p, 100);
|
||||
CHECK_HISTORY (p, 2, 10, 100);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 1);
|
||||
ADD_HEADER (p, 2);
|
||||
ADD_HEADER (p, 3);
|
||||
@@ -466,7 +466,7 @@ PacketMetadataTest::RunTests (void)
|
||||
CHECK_HISTORY (p, 6,
|
||||
6, 5, 3, 2, 1, 10);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 1);
|
||||
ADD_HEADER (p, 2);
|
||||
ADD_HEADER (p, 3);
|
||||
@@ -474,7 +474,7 @@ PacketMetadataTest::RunTests (void)
|
||||
CHECK_HISTORY (p, 3,
|
||||
2, 1, 10);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 1);
|
||||
ADD_HEADER (p, 2);
|
||||
ADD_HEADER (p, 3);
|
||||
@@ -483,7 +483,7 @@ PacketMetadataTest::RunTests (void)
|
||||
CHECK_HISTORY (p, 2,
|
||||
1, 10);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 1);
|
||||
ADD_HEADER (p, 2);
|
||||
ADD_HEADER (p, 3);
|
||||
@@ -492,11 +492,11 @@ PacketMetadataTest::RunTests (void)
|
||||
REM_HEADER (p, 1);
|
||||
CHECK_HISTORY (p, 1, 10);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 1);
|
||||
ADD_HEADER (p, 2);
|
||||
ADD_HEADER (p, 3);
|
||||
p1 = p;
|
||||
p1 = p->Copy ();
|
||||
REM_HEADER (p1, 3);
|
||||
REM_HEADER (p1, 2);
|
||||
REM_HEADER (p1, 1);
|
||||
@@ -524,88 +524,88 @@ PacketMetadataTest::RunTests (void)
|
||||
REM_TRAILER (p, 5);
|
||||
CHECK_HISTORY (p, 5,
|
||||
3, 2, 1, 10, 4);
|
||||
p1 = p;
|
||||
p1 = p->Copy ();
|
||||
REM_TRAILER (p, 4);
|
||||
CHECK_HISTORY (p, 4,
|
||||
3, 2, 1, 10);
|
||||
CHECK_HISTORY (p1, 5,
|
||||
3, 2, 1, 10, 4);
|
||||
p1.RemoveAtStart (3);
|
||||
p1->RemoveAtStart (3);
|
||||
CHECK_HISTORY (p1, 4,
|
||||
2, 1, 10, 4);
|
||||
p1.RemoveAtStart (1);
|
||||
p1->RemoveAtStart (1);
|
||||
CHECK_HISTORY (p1, 4,
|
||||
1, 1, 10, 4);
|
||||
p1.RemoveAtStart (1);
|
||||
p1->RemoveAtStart (1);
|
||||
CHECK_HISTORY (p1, 3,
|
||||
1, 10, 4);
|
||||
p1.RemoveAtEnd (4);
|
||||
p1->RemoveAtEnd (4);
|
||||
CHECK_HISTORY (p1, 2,
|
||||
1, 10);
|
||||
p1.RemoveAtStart (1);
|
||||
p1->RemoveAtStart (1);
|
||||
CHECK_HISTORY (p1, 1, 10);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 8);
|
||||
ADD_TRAILER (p, 8);
|
||||
ADD_TRAILER (p, 8);
|
||||
p.RemoveAtStart (8+10+8);
|
||||
p->RemoveAtStart (8+10+8);
|
||||
CHECK_HISTORY (p, 1, 8);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 10);
|
||||
ADD_HEADER (p, 8);
|
||||
ADD_TRAILER (p, 6);
|
||||
ADD_TRAILER (p, 7);
|
||||
ADD_TRAILER (p, 9);
|
||||
p.RemoveAtStart (5);
|
||||
p.RemoveAtEnd (12);
|
||||
p->RemoveAtStart (5);
|
||||
p->RemoveAtEnd (12);
|
||||
CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 10);
|
||||
ADD_TRAILER (p, 6);
|
||||
p.RemoveAtEnd (18);
|
||||
p->RemoveAtEnd (18);
|
||||
ADD_TRAILER (p, 5);
|
||||
ADD_HEADER (p, 3);
|
||||
CHECK_HISTORY (p, 3, 3, 8, 5);
|
||||
p.RemoveAtStart (12);
|
||||
p->RemoveAtStart (12);
|
||||
CHECK_HISTORY (p, 1, 4);
|
||||
p.RemoveAtEnd (2);
|
||||
p->RemoveAtEnd (2);
|
||||
CHECK_HISTORY (p, 1, 2);
|
||||
ADD_HEADER (p, 10);
|
||||
CHECK_HISTORY (p, 2, 10, 2);
|
||||
p.RemoveAtEnd (5);
|
||||
p->RemoveAtEnd (5);
|
||||
CHECK_HISTORY (p, 1, 7);
|
||||
|
||||
Packet p2 = Packet (0);
|
||||
Packet p3 = Packet (0);
|
||||
Ptr<Packet> p2 = Create<Packet> (0);
|
||||
Ptr<Packet> p3 = Create<Packet> (0);
|
||||
|
||||
p = Packet (40);
|
||||
p = Create<Packet> (40);
|
||||
ADD_HEADER (p, 5);
|
||||
ADD_HEADER (p, 8);
|
||||
CHECK_HISTORY (p, 3, 8, 5, 40);
|
||||
p1 = p.CreateFragment (0, 5);
|
||||
p2 = p.CreateFragment (5, 5);
|
||||
p3 = p.CreateFragment (10, 43);
|
||||
p1 = p->CreateFragment (0, 5);
|
||||
p2 = p->CreateFragment (5, 5);
|
||||
p3 = p->CreateFragment (10, 43);
|
||||
CHECK_HISTORY (p1, 1, 5);
|
||||
CHECK_HISTORY (p2, 2, 3, 2);
|
||||
CHECK_HISTORY (p3, 2, 3, 40);
|
||||
p1.AddAtEnd (p2);
|
||||
p1->AddAtEnd (p2);
|
||||
CHECK_HISTORY (p1, 2, 8, 2);
|
||||
CHECK_HISTORY (p2, 2, 3, 2);
|
||||
p1.AddAtEnd (p3);
|
||||
p1->AddAtEnd (p3);
|
||||
CHECK_HISTORY (p1, 3, 8, 5, 40);
|
||||
CHECK_HISTORY (p2, 2, 3, 2);
|
||||
CHECK_HISTORY (p3, 2, 3, 40);
|
||||
p1 = p.CreateFragment (0, 5);
|
||||
p1 = p->CreateFragment (0, 5);
|
||||
CHECK_HISTORY (p1, 1, 5);
|
||||
|
||||
p3 = Packet (50);
|
||||
p3 = Create<Packet> (50);
|
||||
ADD_HEADER (p3, 8);
|
||||
CHECK_HISTORY (p3, 2, 8, 50);
|
||||
CHECK_HISTORY (p1, 1, 5);
|
||||
p1.AddAtEnd (p3);
|
||||
p1->AddAtEnd (p3);
|
||||
CHECK_HISTORY (p1, 3, 5, 8, 50);
|
||||
ADD_HEADER (p1, 5);
|
||||
CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
|
||||
@@ -613,71 +613,71 @@ PacketMetadataTest::RunTests (void)
|
||||
CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
|
||||
REM_HEADER (p1, 5);
|
||||
CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
|
||||
p1.RemoveAtEnd (60);
|
||||
p1->RemoveAtEnd (60);
|
||||
CHECK_HISTORY (p1, 1, 5);
|
||||
p1.AddAtEnd (p2);
|
||||
p1->AddAtEnd (p2);
|
||||
CHECK_HISTORY (p1, 2, 8, 2);
|
||||
CHECK_HISTORY (p2, 2, 3, 2);
|
||||
|
||||
p3 = Packet (40);
|
||||
p3 = Create<Packet> (40);
|
||||
ADD_HEADER (p3, 5);
|
||||
ADD_HEADER (p3, 5);
|
||||
CHECK_HISTORY (p3, 3, 5, 5, 40);
|
||||
p1 = p3.CreateFragment (0, 5);
|
||||
p2 = p3.CreateFragment (5, 5);
|
||||
p1 = p3->CreateFragment (0, 5);
|
||||
p2 = p3->CreateFragment (5, 5);
|
||||
CHECK_HISTORY (p1, 1, 5);
|
||||
CHECK_HISTORY (p2, 1, 5);
|
||||
p1.AddAtEnd (p2);
|
||||
p1->AddAtEnd (p2);
|
||||
CHECK_HISTORY (p1, 2, 5, 5);
|
||||
|
||||
p = Packet (0);
|
||||
p = Create<Packet> (0);
|
||||
CHECK_HISTORY (p, 0);
|
||||
|
||||
p3 = Packet (0);
|
||||
p3 = Create<Packet> (0);
|
||||
ADD_HEADER (p3, 5);
|
||||
ADD_HEADER (p3, 5);
|
||||
CHECK_HISTORY (p3, 2, 5, 5);
|
||||
p1 = p3.CreateFragment (0, 4);
|
||||
p2 = p3.CreateFragment (9, 1);
|
||||
p1 = p3->CreateFragment (0, 4);
|
||||
p2 = p3->CreateFragment (9, 1);
|
||||
CHECK_HISTORY (p1, 1, 4);
|
||||
CHECK_HISTORY (p2, 1, 1);
|
||||
p1.AddAtEnd (p2);
|
||||
p1->AddAtEnd (p2);
|
||||
CHECK_HISTORY (p1, 2, 4, 1);
|
||||
|
||||
|
||||
p = Packet (2000);
|
||||
p = Create<Packet> (2000);
|
||||
CHECK_HISTORY (p, 1, 2000);
|
||||
|
||||
p = Packet ();
|
||||
p = Create<Packet> ();
|
||||
ADD_TRAILER (p, 10);
|
||||
ADD_HEADER (p, 5);
|
||||
p1 = p.CreateFragment (0, 8);
|
||||
p2 = p.CreateFragment (8, 7);
|
||||
p1.AddAtEnd (p2);
|
||||
p1 = p->CreateFragment (0, 8);
|
||||
p2 = p->CreateFragment (8, 7);
|
||||
p1->AddAtEnd (p2);
|
||||
CHECK_HISTORY (p, 2, 5, 10);
|
||||
|
||||
p = Packet ();
|
||||
p = Create<Packet> ();
|
||||
ADD_TRAILER (p, 10);
|
||||
REM_TRAILER (p, 10);
|
||||
ADD_TRAILER (p, 10);
|
||||
CHECK_HISTORY (p, 1, 10);
|
||||
|
||||
p = Packet ();
|
||||
p = Create<Packet> ();
|
||||
ADD_HEADER (p, 10);
|
||||
REM_HEADER (p, 10);
|
||||
ADD_HEADER (p, 10);
|
||||
CHECK_HISTORY (p, 1, 10);
|
||||
|
||||
p = Packet ();
|
||||
p = Create<Packet> ();
|
||||
ADD_HEADER (p, 10);
|
||||
p = DoAddHeader (p);
|
||||
CHECK_HISTORY (p, 2, 10, 10);
|
||||
|
||||
p = Packet (10);
|
||||
p = Create<Packet> (10);
|
||||
ADD_HEADER (p, 8);
|
||||
ADD_TRAILER (p, 8);
|
||||
ADD_TRAILER (p, 8);
|
||||
p.RemoveAtStart (8+10+8);
|
||||
p->RemoveAtStart (8+10+8);
|
||||
CHECK_HISTORY (p, 1, 8);
|
||||
|
||||
return ok;
|
||||
|
||||
@@ -134,7 +134,7 @@ private:
|
||||
struct Printer
|
||||
{
|
||||
uint32_t m_chunkUid;
|
||||
Ptr<CallbackImplBase> m_printer;
|
||||
CallbackBase m_printer;
|
||||
Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,
|
||||
struct PacketPrinter::FragmentInformation> m_fragmentPrinter;
|
||||
};
|
||||
@@ -158,7 +158,7 @@ PacketPrinter::SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,
|
||||
{
|
||||
Printer p;
|
||||
p.m_chunkUid = T::GetUid ();
|
||||
p.m_printer = printer.GetImpl ();
|
||||
p.m_printer = printer;
|
||||
p.m_fragmentPrinter = fragmentPrinter;
|
||||
m_printerList.push_back (p);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ PacketPrinter::SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t
|
||||
{
|
||||
Printer p;
|
||||
p.m_chunkUid = T::GetUid ();
|
||||
p.m_printer = printer.GetImpl ();
|
||||
p.m_printer = printer;
|
||||
p.m_fragmentPrinter = fragmentPrinter;
|
||||
m_printerList.push_back (p);
|
||||
}
|
||||
|
||||
+71
-18
@@ -26,22 +26,72 @@ namespace ns3 {
|
||||
|
||||
uint32_t Packet::m_globalUid = 0;
|
||||
|
||||
void
|
||||
Packet::Ref (void) const
|
||||
{
|
||||
m_refCount++;
|
||||
}
|
||||
void
|
||||
Packet::Unref (void) const
|
||||
{
|
||||
m_refCount--;
|
||||
if (m_refCount == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Packet>
|
||||
Packet::Copy (void) const
|
||||
{
|
||||
// we need to invoke the copy constructor directly
|
||||
// rather than calling Create because the copy constructor
|
||||
// is private.
|
||||
return Ptr<Packet> (new Packet (*this), false);
|
||||
}
|
||||
|
||||
Packet::Packet ()
|
||||
: m_buffer (),
|
||||
m_metadata (m_globalUid, 0)
|
||||
m_tags (),
|
||||
m_metadata (m_globalUid, 0),
|
||||
m_refCount (1)
|
||||
{
|
||||
m_globalUid++;
|
||||
}
|
||||
|
||||
Packet::Packet (const Packet &o)
|
||||
: m_buffer (o.m_buffer),
|
||||
m_tags (o.m_tags),
|
||||
m_metadata (o.m_metadata),
|
||||
m_refCount (1)
|
||||
{}
|
||||
|
||||
Packet &
|
||||
Packet::operator = (const Packet &o)
|
||||
{
|
||||
if (this == &o)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
m_buffer = o.m_buffer;
|
||||
m_tags = o.m_tags;
|
||||
m_metadata = o.m_metadata;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Packet::Packet (uint32_t size)
|
||||
: m_buffer (size),
|
||||
m_metadata (m_globalUid, size)
|
||||
m_tags (),
|
||||
m_metadata (m_globalUid, size),
|
||||
m_refCount (1)
|
||||
{
|
||||
m_globalUid++;
|
||||
}
|
||||
Packet::Packet (uint8_t const*buffer, uint32_t size)
|
||||
: m_buffer (),
|
||||
m_metadata (m_globalUid, size)
|
||||
m_tags (),
|
||||
m_metadata (m_globalUid, size),
|
||||
m_refCount (1)
|
||||
{
|
||||
m_globalUid++;
|
||||
m_buffer.AddAtStart (size);
|
||||
@@ -52,17 +102,20 @@ Packet::Packet (uint8_t const*buffer, uint32_t size)
|
||||
Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
|
||||
: m_buffer (buffer),
|
||||
m_tags (tags),
|
||||
m_metadata (metadata)
|
||||
m_metadata (metadata),
|
||||
m_refCount (1)
|
||||
{}
|
||||
|
||||
Packet
|
||||
Ptr<Packet>
|
||||
Packet::CreateFragment (uint32_t start, uint32_t length) const
|
||||
{
|
||||
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);
|
||||
return Packet (buffer, m_tags, metadata);
|
||||
// again, call the constructor directly rather than
|
||||
// through Create because it is private.
|
||||
return Ptr<Packet> (new Packet (buffer, m_tags, metadata), false);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@@ -72,9 +125,9 @@ Packet::GetSize (void) const
|
||||
}
|
||||
|
||||
void
|
||||
Packet::AddAtEnd (Packet packet)
|
||||
Packet::AddAtEnd (Ptr<const Packet> packet)
|
||||
{
|
||||
Buffer src = packet.m_buffer.CreateFullCopy ();
|
||||
Buffer src = packet->m_buffer.CreateFullCopy ();
|
||||
Buffer dst = m_buffer.CreateFullCopy ();
|
||||
|
||||
dst.AddAtEnd (src.GetSize ());
|
||||
@@ -86,7 +139,7 @@ Packet::AddAtEnd (Packet packet)
|
||||
* XXX: we might need to merge the tag list of the
|
||||
* other packet into the current packet.
|
||||
*/
|
||||
m_metadata.AddAtEnd (packet.m_metadata);
|
||||
m_metadata.AddAtEnd (packet->m_metadata);
|
||||
}
|
||||
void
|
||||
Packet::AddPaddingAtEnd (uint32_t size)
|
||||
@@ -233,20 +286,20 @@ PacketTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
Packet pkt1 (reinterpret_cast<const uint8_t*> ("hello"), 5);
|
||||
Packet pkt2 (reinterpret_cast<const uint8_t*> (" world"), 6);
|
||||
Packet packet;
|
||||
packet.AddAtEnd (pkt1);
|
||||
packet.AddAtEnd (pkt2);
|
||||
Ptr<Packet> pkt1 = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello"), 5);
|
||||
Ptr<Packet> pkt2 = Create<Packet> (reinterpret_cast<const uint8_t*> (" world"), 6);
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
packet->AddAtEnd (pkt1);
|
||||
packet->AddAtEnd (pkt2);
|
||||
|
||||
if (packet.GetSize () != 11)
|
||||
if (packet->GetSize () != 11)
|
||||
{
|
||||
Failure () << "expected size 11, got " << packet.GetSize () << std::endl;
|
||||
Failure () << "expected size 11, got " << packet->GetSize () << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
|
||||
std::string msg = std::string (reinterpret_cast<const char *>(packet.PeekData ()),
|
||||
packet.GetSize ());
|
||||
std::string msg = std::string (reinterpret_cast<const char *>(packet->PeekData ()),
|
||||
packet->GetSize ());
|
||||
if (msg != "hello world")
|
||||
{
|
||||
Failure () << "expected 'hello world', got '" << msg << "'" << std::endl;
|
||||
|
||||
+27
-5
@@ -30,6 +30,7 @@
|
||||
#include "tag.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/ptr.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -74,6 +75,11 @@ class PacketPrinter;
|
||||
*/
|
||||
class Packet {
|
||||
public:
|
||||
void Ref (void) const;
|
||||
void Unref (void) const;
|
||||
|
||||
Ptr<Packet> Copy (void) const;
|
||||
|
||||
/**
|
||||
* Create an empty packet with a new uid (as returned
|
||||
* by getUid).
|
||||
@@ -107,7 +113,7 @@ public:
|
||||
* \param length length of fragment to create
|
||||
* \returns a fragment of the original packet
|
||||
*/
|
||||
Packet CreateFragment (uint32_t start, uint32_t length) const;
|
||||
Ptr<Packet> CreateFragment (uint32_t start, uint32_t length) const;
|
||||
/**
|
||||
* \returns the size in bytes of the packet (including the zero-filled
|
||||
* initial payload)
|
||||
@@ -152,15 +158,27 @@ public:
|
||||
template <typename T>
|
||||
uint32_t RemoveTrailer (T &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.
|
||||
*
|
||||
* \param tag a pointer to the tag to attach to this packet.
|
||||
* Note that adding a tag is a const operation which is pretty
|
||||
* un-intuitive. The rationale is that the content and behavior of
|
||||
* a packet is _not_ changed when a tag is added to a packet: any
|
||||
* code which was not aware of the new tag is going to work just
|
||||
* the same if the new tag is added. The real reason why adding a
|
||||
* tag was made a const operation is to allow a trace sink which gets
|
||||
* a packet to tag the packet, even if the packet is const (and most
|
||||
* trace sources should use const packets because it would be
|
||||
* totally evil to allow a trace sink to modify the content of a
|
||||
* packet).
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
void AddTag (T const &tag);
|
||||
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
|
||||
@@ -210,7 +228,7 @@ public:
|
||||
*
|
||||
* \param packet packet to concatenate
|
||||
*/
|
||||
void AddAtEnd (Packet packet);
|
||||
void AddAtEnd (Ptr<const Packet> packet);
|
||||
/**
|
||||
* \param size number of padding bytes to add.
|
||||
*/
|
||||
@@ -332,15 +350,19 @@ public:
|
||||
void Deserialize (Buffer buffer);
|
||||
private:
|
||||
Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
|
||||
Packet (const Packet &o);
|
||||
Packet &operator = (const Packet &o);
|
||||
Buffer m_buffer;
|
||||
Tags m_tags;
|
||||
PacketMetadata m_metadata;
|
||||
mutable uint32_t m_refCount;
|
||||
static uint32_t m_globalUid;
|
||||
};
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const Packet &packet);
|
||||
|
||||
/**
|
||||
* \ingroup common
|
||||
* \defgroup packetperf Packet Performance
|
||||
* The current implementation of the byte buffers and tag list is based
|
||||
* on COW (Copy On Write. An introduction to COW can be found in Scott
|
||||
@@ -441,7 +463,7 @@ Packet::RemoveTrailer (T &trailer)
|
||||
|
||||
|
||||
template <typename T>
|
||||
void Packet::AddTag (T const& tag)
|
||||
void Packet::AddTag (T const& tag) const
|
||||
{
|
||||
const Tag *parent;
|
||||
// if the following assignment fails, it is because the
|
||||
|
||||
@@ -89,7 +89,7 @@ PcapWriter::WriteHeader (uint32_t network)
|
||||
|
||||
|
||||
void
|
||||
PcapWriter::WritePacket (Packet const packet)
|
||||
PcapWriter::WritePacket (Ptr<const Packet> packet)
|
||||
{
|
||||
if (m_writer != 0)
|
||||
{
|
||||
@@ -98,9 +98,9 @@ PcapWriter::WritePacket (Packet const packet)
|
||||
uint64_t us = current % 1000000;
|
||||
Write32 (s & 0xffffffff);
|
||||
Write32 (us & 0xffffffff);
|
||||
Write32 (packet.GetSize ());
|
||||
Write32 (packet.GetSize ());
|
||||
WriteData (packet.PeekData (), packet.GetSize ());
|
||||
Write32 (packet->GetSize ());
|
||||
Write32 (packet->GetSize ());
|
||||
WriteData (packet->PeekData (), packet->GetSize ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,11 @@
|
||||
|
||||
#include "ns3/callback.h"
|
||||
#include <stdint.h>
|
||||
#include "packet.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* \brief Pcap output for Packet logger
|
||||
*
|
||||
@@ -62,7 +63,7 @@ public:
|
||||
/**
|
||||
* \param packet packet to write to output file
|
||||
*/
|
||||
void WritePacket (Packet const packet);
|
||||
void WritePacket (Ptr<const Packet> packet);
|
||||
|
||||
private:
|
||||
void WriteData (uint8_t const*buffer, uint32_t size);
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@ struct Tags::TagData *Tags::gFree = 0;
|
||||
uint32_t Tags::gN_free = 0;
|
||||
|
||||
struct Tags::TagData *
|
||||
Tags::AllocData (void)
|
||||
Tags::AllocData (void) const
|
||||
{
|
||||
struct Tags::TagData *retval;
|
||||
if (gFree != 0)
|
||||
@@ -47,7 +47,7 @@ Tags::AllocData (void)
|
||||
}
|
||||
|
||||
void
|
||||
Tags::FreeData (struct TagData *data)
|
||||
Tags::FreeData (struct TagData *data) const
|
||||
{
|
||||
if (gN_free > 1000)
|
||||
{
|
||||
@@ -61,7 +61,7 @@ Tags::FreeData (struct TagData *data)
|
||||
}
|
||||
#else
|
||||
struct Tags::TagData *
|
||||
Tags::AllocData (void)
|
||||
Tags::AllocData (void) const
|
||||
{
|
||||
struct Tags::TagData *retval;
|
||||
retval = new struct Tags::TagData ();
|
||||
@@ -69,7 +69,7 @@ Tags::AllocData (void)
|
||||
}
|
||||
|
||||
void
|
||||
Tags::FreeData (struct TagData *data)
|
||||
Tags::FreeData (struct TagData *data) const
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
+14
-6
@@ -44,7 +44,7 @@ public:
|
||||
inline ~Tags ();
|
||||
|
||||
template <typename T>
|
||||
void Add (T const&tag);
|
||||
void Add (T const&tag) const;
|
||||
|
||||
template <typename T>
|
||||
bool Remove (T &tag);
|
||||
@@ -71,8 +71,8 @@ private:
|
||||
};
|
||||
|
||||
bool Remove (uint32_t id);
|
||||
struct Tags::TagData *AllocData (void);
|
||||
void FreeData (struct TagData *data);
|
||||
struct Tags::TagData *AllocData (void) const;
|
||||
void FreeData (struct TagData *data) const;
|
||||
|
||||
static struct Tags::TagData *gFree;
|
||||
static uint32_t gN_free;
|
||||
@@ -96,7 +96,7 @@ namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
Tags::Add (T const&tag)
|
||||
Tags::Add (T const&tag) const
|
||||
{
|
||||
const Tag *parent;
|
||||
// if the following assignment fails, it is because the
|
||||
@@ -116,7 +116,7 @@ Tags::Add (T const&tag)
|
||||
void *buf = &newStart->m_data;
|
||||
new (buf) T (tag);
|
||||
newStart->m_next = m_next;
|
||||
m_next = newStart;
|
||||
const_cast<Tags *> (this)->m_next = newStart;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -128,7 +128,15 @@ Tags::Remove (T &tag)
|
||||
// input to this function is not a subclass of the Tag class.
|
||||
parent = &tag;
|
||||
NS_ASSERT (sizeof (T) <= Tags::SIZE);
|
||||
return Remove (T::GetUid ());
|
||||
if (Peek (tag))
|
||||
{
|
||||
Remove (T::GetUid ());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
|
||||
#include "delay-jitter-estimation.h"
|
||||
#include "ns3/tag.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class TimestampTag : public ns3::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;
|
||||
|
||||
ns3::Time GetTxTime (void) const;
|
||||
private:
|
||||
uint64_t m_creationTime;
|
||||
};
|
||||
|
||||
TimestampTag::TimestampTag ()
|
||||
: m_creationTime (ns3::Simulator::Now ().GetTimeStep ())
|
||||
{}
|
||||
uint32_t
|
||||
TimestampTag::GetUid (void)
|
||||
{
|
||||
static uint32_t uid = ns3::Tag::AllocateUid<TimestampTag> ("mathieu.paper.TimestampTag");
|
||||
return uid;
|
||||
}
|
||||
void
|
||||
TimestampTag::Print (std::ostream &os) const
|
||||
{
|
||||
os << ns3::TimeStep (m_creationTime);
|
||||
}
|
||||
void
|
||||
TimestampTag::Serialize (ns3::Buffer::Iterator start) const
|
||||
{}
|
||||
uint32_t
|
||||
TimestampTag::Deserialize (ns3::Buffer::Iterator start)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint32_t
|
||||
TimestampTag::GetSerializedSize (void) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ns3::Time
|
||||
TimestampTag::GetTxTime (void) const
|
||||
{
|
||||
return ns3::TimeStep (m_creationTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
DelayJitterEstimation::DelayJitterEstimation ()
|
||||
: m_previousRx (Simulator::Now ()),
|
||||
m_previousRxTx (Simulator::Now ()),
|
||||
m_jitter (Seconds (0.0)),
|
||||
m_delay (Seconds (0.0))
|
||||
{}
|
||||
void
|
||||
DelayJitterEstimation::PrepareTx (Ptr<const Packet> packet)
|
||||
{
|
||||
TimestampTag tag;
|
||||
packet->AddTag (tag);
|
||||
}
|
||||
void
|
||||
DelayJitterEstimation::RecordRx (Ptr<const Packet> packet)
|
||||
{
|
||||
TimestampTag tag;
|
||||
bool found;
|
||||
found = packet->PeekTag (tag);
|
||||
if (!found)
|
||||
{
|
||||
return;
|
||||
}
|
||||
tag.GetTxTime ();
|
||||
|
||||
Time delta = (Simulator::Now () - m_previousRx) - (tag.GetTxTime () - m_previousRxTx);
|
||||
m_jitter += (Abs (delta) - m_jitter ) / Scalar (16.0);
|
||||
m_previousRx = Simulator::Now ();
|
||||
m_previousRxTx = tag.GetTxTime ();
|
||||
m_delay = Simulator::Now () - tag.GetTxTime ();
|
||||
}
|
||||
|
||||
Time
|
||||
DelayJitterEstimation::GetLastDelay (void) const
|
||||
{
|
||||
return m_delay;
|
||||
}
|
||||
Time
|
||||
DelayJitterEstimation::GetLastJitter (void) const
|
||||
{
|
||||
return m_jitter;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef DELAY_JITTER_ESTIMATION_H
|
||||
#define DELAY_JITTER_ESTIMATION_H
|
||||
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/packet.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief quick and diry delay and jitter estimation
|
||||
*
|
||||
*/
|
||||
class DelayJitterEstimation
|
||||
{
|
||||
public:
|
||||
DelayJitterEstimation ();
|
||||
|
||||
/**
|
||||
* \param packet the packet to send over a wire
|
||||
*
|
||||
* This method should be invoked once on each packet to
|
||||
* record within the packet the tx time which is used upon
|
||||
* packet reception to calculate the delay and jitter. The
|
||||
* tx time is stored in the packet as an ns3::Tag which means
|
||||
* that it does not use any network ressources and is not
|
||||
* taken into account in transmission delay calculations.
|
||||
*/
|
||||
static void PrepareTx (Ptr<const Packet> packet);
|
||||
/**
|
||||
* \param packet the packet received
|
||||
*
|
||||
* Invoke this method to update the delay and jitter calculations
|
||||
* After a call to this method, \ref GetLastDelay and \ref GetLastJitter
|
||||
* will return an updated delay and jitter.
|
||||
*/
|
||||
void RecordRx (Ptr<const Packet> packet);
|
||||
|
||||
/**
|
||||
* \returns the updated delay.
|
||||
*/
|
||||
Time GetLastDelay (void) const;
|
||||
/**
|
||||
* The jitter is calculated using the RFC 1889 (RTP) jitter
|
||||
* definition.
|
||||
*
|
||||
* \returns the updated jitter.
|
||||
*/
|
||||
Time GetLastJitter (void) const;
|
||||
|
||||
private:
|
||||
Time m_previousRx;
|
||||
Time m_previousRxTx;
|
||||
Time m_jitter;
|
||||
Time m_delay;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* DELAY_JITTER_ESTIMATION_H */
|
||||
@@ -0,0 +1,186 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "gnuplot.h"
|
||||
#include "ns3/assert.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
GnuplotDataset::GnuplotDataset (std::string title)
|
||||
: m_title (title),
|
||||
m_style (LINES),
|
||||
m_errorBars (NONE)
|
||||
{}
|
||||
void
|
||||
GnuplotDataset::SetStyle (enum Style style)
|
||||
{
|
||||
m_style = style;
|
||||
}
|
||||
void
|
||||
GnuplotDataset::SetErrorBars (enum ErrorBars errorBars)
|
||||
{
|
||||
m_errorBars = errorBars;
|
||||
}
|
||||
void
|
||||
GnuplotDataset::Add (double x, double y)
|
||||
{
|
||||
NS_ASSERT (m_errorBars == NONE);
|
||||
struct Data data;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.dx = 0.0;
|
||||
data.dy = 0.0;
|
||||
m_dataset.push_back (data);
|
||||
}
|
||||
void
|
||||
GnuplotDataset::Add (double x, double y, double errorDelta)
|
||||
{
|
||||
NS_ASSERT (m_errorBars == X || m_errorBars == Y);
|
||||
struct Data data;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.dx = errorDelta;
|
||||
data.dy = errorDelta;
|
||||
m_dataset.push_back (data);
|
||||
}
|
||||
|
||||
Gnuplot::Gnuplot (std::string pngFilename)
|
||||
: m_pngFilename (pngFilename)
|
||||
{}
|
||||
|
||||
Gnuplot::~Gnuplot ()
|
||||
{
|
||||
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end (); i++)
|
||||
{
|
||||
delete *i;
|
||||
}
|
||||
m_datasets.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::SetLegend (std::string xLegend, std::string yLegend)
|
||||
{
|
||||
m_xLegend = xLegend;
|
||||
m_yLegend = yLegend;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::AddDataset (const GnuplotDataset &dataset)
|
||||
{
|
||||
m_datasets.push_back (new GnuplotDataset (dataset));
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::GenerateOutput (std::ostream &os)
|
||||
{
|
||||
os << "set terminal png" << std::endl;
|
||||
os << "set output '" << m_pngFilename << "'" << std::endl;
|
||||
os << "set xlabel '" << m_xLegend << "'" << std::endl;
|
||||
os << "set ylabel '" << m_yLegend << "'" << std::endl;
|
||||
os << "plot ";
|
||||
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end ();)
|
||||
{
|
||||
os << "'-' title '" << (*i)->m_title << "'";
|
||||
switch ((*i)->m_style) {
|
||||
case GnuplotDataset::LINES:
|
||||
os << " with lines";
|
||||
break;
|
||||
case GnuplotDataset::POINTS:
|
||||
switch ((*i)->m_errorBars)
|
||||
{
|
||||
case GnuplotDataset::NONE:
|
||||
os << " with points";
|
||||
break;
|
||||
case GnuplotDataset::X:
|
||||
os << " with xerrorbars";
|
||||
break;
|
||||
case GnuplotDataset::Y:
|
||||
os << " with yerrorbars";
|
||||
break;
|
||||
case GnuplotDataset::XY:
|
||||
os << " with xyerrorbars";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GnuplotDataset::LINES_POINTS:
|
||||
switch ((*i)->m_errorBars)
|
||||
{
|
||||
case GnuplotDataset::NONE:
|
||||
os << " with linespoints";
|
||||
break;
|
||||
case GnuplotDataset::X:
|
||||
os << " with xerrorlines";
|
||||
break;
|
||||
case GnuplotDataset::Y:
|
||||
os << " with yerrorlines";
|
||||
break;
|
||||
case GnuplotDataset::XY:
|
||||
os << " with xyerrorlines";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GnuplotDataset::DOTS:
|
||||
os << " with dots";
|
||||
break;
|
||||
case GnuplotDataset::IMPULSES:
|
||||
os << " with impulses";
|
||||
break;
|
||||
case GnuplotDataset::STEPS:
|
||||
os << " with steps";
|
||||
break;
|
||||
case GnuplotDataset::FSTEPS:
|
||||
os << " with fsteps";
|
||||
break;
|
||||
case GnuplotDataset::HISTEPS:
|
||||
os << " with histeps";
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
if (i != m_datasets.end ())
|
||||
{
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
os << std::endl;
|
||||
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end (); i++)
|
||||
{
|
||||
for (GnuplotDataset::Dataset::const_iterator j = (*i)->m_dataset.begin ();
|
||||
j != (*i)->m_dataset.end (); j++)
|
||||
{
|
||||
switch ((*i)->m_errorBars) {
|
||||
case GnuplotDataset::NONE:
|
||||
os << j->x << " " << j->y << std::endl;
|
||||
break;
|
||||
case GnuplotDataset::X:
|
||||
os << j->x << " " << j->y << " " << j->dx << std::endl;
|
||||
break;
|
||||
case GnuplotDataset::Y:
|
||||
os << j->x << " " << j->y << " " << j->dy << std::endl;
|
||||
break;
|
||||
case GnuplotDataset::XY:
|
||||
os << j->x << " " << j->y << " " << j->dx << " " << j->dy << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
os << "e" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -0,0 +1,91 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef GNUPLOT_H
|
||||
#define GNUPLOT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class GnuplotDataset
|
||||
{
|
||||
public:
|
||||
enum Style {
|
||||
LINES,
|
||||
POINTS,
|
||||
LINES_POINTS,
|
||||
DOTS,
|
||||
IMPULSES,
|
||||
STEPS,
|
||||
FSTEPS,
|
||||
HISTEPS,
|
||||
};
|
||||
enum ErrorBars {
|
||||
NONE,
|
||||
X,
|
||||
Y,
|
||||
XY
|
||||
};
|
||||
|
||||
GnuplotDataset (std::string title);
|
||||
void SetStyle (enum Style style);
|
||||
void SetErrorBars (enum ErrorBars errorBars);
|
||||
void Add (double x, double y);
|
||||
void Add (double x, double y, double errorDelta);
|
||||
void Add (double x, double y, double errorDeltaX, double errorDeltaY);
|
||||
private:
|
||||
friend class Gnuplot;
|
||||
struct Data {
|
||||
double x;
|
||||
double y;
|
||||
double dx;
|
||||
double dy;
|
||||
};
|
||||
typedef std::vector<struct Data> Dataset;
|
||||
Dataset m_dataset;
|
||||
std::string m_title;
|
||||
enum Style m_style;
|
||||
enum ErrorBars m_errorBars;
|
||||
};
|
||||
|
||||
class Gnuplot
|
||||
{
|
||||
public:
|
||||
Gnuplot (std::string pngFilename);
|
||||
~Gnuplot ();
|
||||
|
||||
void SetLegend (std::string xLegend, std::string yLegend);
|
||||
|
||||
void AddDataset (const GnuplotDataset &dataset);
|
||||
|
||||
void GenerateOutput (std::ostream &os);
|
||||
private:
|
||||
typedef std::vector<GnuplotDataset *> Datasets;
|
||||
Datasets m_datasets;
|
||||
std::string m_xLegend;
|
||||
std::string m_yLegend;
|
||||
std::string m_pngFilename;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* GNUPLOT_H */
|
||||
@@ -0,0 +1,16 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
module = bld.create_ns3_module('contrib', ['simulator'])
|
||||
module.source = [
|
||||
'event-garbage-collector.cc',
|
||||
'gnuplot.cc',
|
||||
'delay-jitter-estimation.cc',
|
||||
]
|
||||
|
||||
headers = bld.create_obj('ns3header')
|
||||
headers.source = [
|
||||
'event-garbage-collector.h',
|
||||
'gnuplot.h',
|
||||
'delay-jitter-estimation.h',
|
||||
]
|
||||
@@ -0,0 +1,306 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "array-trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
ArrayTraceResolverMatcher::ArrayTraceResolverMatcher (std::string element)
|
||||
: m_element (element)
|
||||
{}
|
||||
bool
|
||||
ArrayTraceResolverMatcher::Matches (uint32_t i) const
|
||||
{
|
||||
if (m_element == "*")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
std::string::size_type tmp;
|
||||
tmp = m_element.find ("|");
|
||||
if (tmp != std::string::npos)
|
||||
{
|
||||
std::string left = m_element.substr (0, tmp-0);
|
||||
std::string right = m_element.substr (tmp+1, m_element.size () - (tmp + 1));
|
||||
ArrayTraceResolverMatcher matcher = ArrayTraceResolverMatcher (left);
|
||||
if (matcher.Matches (i))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
matcher = ArrayTraceResolverMatcher (right);
|
||||
if (matcher.Matches (i))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string::size_type leftBracket = m_element.find ("[");
|
||||
std::string::size_type rightBracket = m_element.find ("]");
|
||||
std::string::size_type dash = m_element.find ("-");
|
||||
if (leftBracket == 0 && rightBracket == m_element.size () - 1 &&
|
||||
dash > leftBracket && dash < rightBracket)
|
||||
{
|
||||
std::string lowerBound = m_element.substr (leftBracket + 1, dash - (leftBracket + 1));
|
||||
std::string upperBound = m_element.substr (dash + 1, rightBracket - (dash + 1));
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
if (StringToUint32 (lowerBound, &min) &&
|
||||
StringToUint32 (upperBound, &max) &&
|
||||
i >= min && i <= max)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
uint32_t value;
|
||||
if (StringToUint32 (m_element, &value) &&
|
||||
i == value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayTraceResolverMatcher::StringToUint32 (std::string str, uint32_t *value) const
|
||||
{
|
||||
std::istringstream iss;
|
||||
iss.str (str);
|
||||
iss >> (*value);
|
||||
return !iss.bad () && !iss.fail ();
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "test.h"
|
||||
#include "object.h"
|
||||
#include "array-trace-resolver.h"
|
||||
#include "callback-trace-source.h"
|
||||
#include "composite-trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class ObjectTraceTesterIndex : public TraceContextElement
|
||||
{
|
||||
public:
|
||||
ObjectTraceTesterIndex ();
|
||||
ObjectTraceTesterIndex (uint32_t index);
|
||||
void Print (std::ostream &os);
|
||||
static uint16_t GetUid (void);
|
||||
uint32_t Get (void) const;
|
||||
std::string GetTypeName (void) const;
|
||||
private:
|
||||
uint32_t m_index;
|
||||
};
|
||||
|
||||
|
||||
ObjectTraceTesterIndex::ObjectTraceTesterIndex ()
|
||||
: m_index (0)
|
||||
{}
|
||||
ObjectTraceTesterIndex::ObjectTraceTesterIndex (uint32_t index)
|
||||
: m_index (index)
|
||||
{}
|
||||
void
|
||||
ObjectTraceTesterIndex::Print (std::ostream &os)
|
||||
{
|
||||
os << "nodeid=" << m_index;
|
||||
}
|
||||
uint16_t
|
||||
ObjectTraceTesterIndex::GetUid (void)
|
||||
{
|
||||
static uint16_t uid = AllocateUid<ObjectTraceTesterIndex> ("ObjectTraceTesterIndex");
|
||||
return uid;
|
||||
}
|
||||
uint32_t
|
||||
ObjectTraceTesterIndex::Get (void) const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
std::string
|
||||
ObjectTraceTesterIndex::GetTypeName (void) const
|
||||
{
|
||||
return "ns3::ObjectTraceTesterIndex";
|
||||
}
|
||||
|
||||
|
||||
class ObjectTraceTester : public Object
|
||||
{
|
||||
public:
|
||||
void Do (uint32_t i);
|
||||
protected:
|
||||
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
|
||||
private:
|
||||
CallbackTraceSource<uint32_t> m_test;
|
||||
};
|
||||
|
||||
void
|
||||
ObjectTraceTester::Do (uint32_t i)
|
||||
{
|
||||
m_test (i);
|
||||
}
|
||||
|
||||
Ptr<TraceResolver>
|
||||
ObjectTraceTester::GetTraceResolver (void) const
|
||||
{
|
||||
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
|
||||
resolver->AddSource ("test",
|
||||
TraceDoc ("Test"),
|
||||
m_test);
|
||||
resolver->SetParentResolver (Object::GetTraceResolver ());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
class ArrayTraceResolverTest : public Test
|
||||
{
|
||||
public:
|
||||
ArrayTraceResolverTest ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
bool RunOne (uint32_t n, std::string str,
|
||||
uint32_t nExpected, ...);
|
||||
void OneItem (const TraceContext &context,
|
||||
uint32_t i);
|
||||
|
||||
typedef std::vector<uint32_t> Got;
|
||||
Got m_got;
|
||||
};
|
||||
|
||||
ArrayTraceResolverTest::ArrayTraceResolverTest ()
|
||||
: Test ("ArrayTraceResolver")
|
||||
{}
|
||||
bool
|
||||
ArrayTraceResolverTest::RunOne (uint32_t n, std::string str,
|
||||
uint32_t nExpected, ...)
|
||||
{
|
||||
bool result = true;
|
||||
std::vector<uint32_t> expected;
|
||||
va_list ap;
|
||||
va_start (ap, nExpected);
|
||||
for (uint32_t k = 0; k < nExpected; k++)
|
||||
{
|
||||
uint32_t v = va_arg (ap, uint32_t);
|
||||
expected.push_back (v);
|
||||
}
|
||||
va_end (ap);
|
||||
std::sort (expected.begin (), expected.end ());
|
||||
std::sort (m_got.begin (), m_got.end ());
|
||||
|
||||
std::vector<Ptr<ObjectTraceTester> > vec;
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
vec.push_back (CreateObject<ObjectTraceTester> ());
|
||||
}
|
||||
ArrayTraceResolver<ObjectTraceTesterIndex> resolver;
|
||||
resolver.SetIterators (vec.begin (), vec.end ());
|
||||
|
||||
TraceContext context;
|
||||
resolver.Connect (str, MakeCallback (&ArrayTraceResolverTest::OneItem, this), context);
|
||||
uint32_t l = 0;
|
||||
for (std::vector<Ptr<ObjectTraceTester> >::const_iterator j = vec.begin (); j != vec.end (); j++)
|
||||
{
|
||||
(*j)->Do (l);
|
||||
l++;
|
||||
}
|
||||
NS_TEST_ASSERT_EQUAL (m_got.size (), expected.size ());
|
||||
for (uint32_t m = 0; m < expected.size (); m++)
|
||||
{
|
||||
NS_TEST_ASSERT_EQUAL (m_got[m], expected[m]);
|
||||
}
|
||||
m_got.clear ();
|
||||
resolver.Disconnect (str, MakeCallback (&ArrayTraceResolverTest::OneItem, this));
|
||||
for (std::vector<Ptr<ObjectTraceTester> >::const_iterator j = vec.begin (); j != vec.end (); j++)
|
||||
{
|
||||
(*j)->Do (l);
|
||||
l++;
|
||||
}
|
||||
NS_TEST_ASSERT_EQUAL (m_got.size (), 0);
|
||||
m_got.clear ();
|
||||
|
||||
return result;
|
||||
}
|
||||
void
|
||||
ArrayTraceResolverTest::OneItem (const TraceContext &context,
|
||||
uint32_t i)
|
||||
{
|
||||
ObjectTraceTesterIndex index;
|
||||
bool found = context.GetElement (index);
|
||||
if (!found)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (index.Get () != i)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_got.push_back (i);
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayTraceResolverTest::RunTests (void)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
NS_TEST_ASSERT (RunOne (0, "/*/test", 0));
|
||||
NS_TEST_ASSERT (RunOne (1, "/*/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (1, "/0/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (1, "/[0-0]/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (1, "/0|0/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (2, "/*/test", 2, 0, 1));
|
||||
NS_TEST_ASSERT (RunOne (2, "/0|1/test", 2, 0, 1));
|
||||
NS_TEST_ASSERT (RunOne (2, "/1/test", 1, 1));
|
||||
NS_TEST_ASSERT (RunOne (2, "/|1|/test", 1, 1));
|
||||
NS_TEST_ASSERT (RunOne (2, "/0/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (2, "/0|/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (2, "/|0/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (2, "/[0-1]/test", 2, 0, 1));
|
||||
NS_TEST_ASSERT (RunOne (2, "/[0-0]/test", 1, 0));
|
||||
NS_TEST_ASSERT (RunOne (2, "/[1-1]/test", 1, 1));
|
||||
NS_TEST_ASSERT (RunOne (2, "/0|[1-1]/test", 2, 0, 1));
|
||||
NS_TEST_ASSERT (RunOne (3, "/1|0/test", 2, 0, 1));
|
||||
NS_TEST_ASSERT (RunOne (3, "/2|0/test", 2, 0, 2));
|
||||
NS_TEST_ASSERT (RunOne (3, "/2|1/test", 2, 1, 2));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[0-1]/test", 2, 0, 1));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[1-2]/test", 2, 1, 2));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[0-2]/test", 3, 0, 1, 2));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[1-2]|0/test", 3, 0, 1, 2));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[1-1]|0|[2-2]/test", 3, 0, 1, 2));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[1-2]||/test", 2, 1, 2));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[1-2]||/test", 2, 2, 1));
|
||||
NS_TEST_ASSERT (RunOne (3, "/||||/test", 0));
|
||||
NS_TEST_ASSERT (RunOne (20, "/[5-10]|[2-3]|[15-17]/test", 11, 2, 3, 5, 6, 7, 8, 9, 10, 15, 16, 17));
|
||||
NS_TEST_ASSERT (RunOne (3, "/[1-2]|[0-1]/test", 3, 0, 1, 2));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ArrayTraceResolverTest g_arrayTraceResolverTest;
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "callback.h"
|
||||
#include "trace-resolver.h"
|
||||
#include "object.h"
|
||||
@@ -78,6 +79,17 @@ private:
|
||||
};
|
||||
IteratorBase *m_iter;
|
||||
};
|
||||
|
||||
class ArrayTraceResolverMatcher
|
||||
{
|
||||
public:
|
||||
ArrayTraceResolverMatcher (std::string element);
|
||||
bool Matches (uint32_t i) const;
|
||||
bool StringToUint32 (std::string str, uint32_t *value) const;
|
||||
private:
|
||||
std::string m_element;
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
|
||||
@@ -133,19 +145,20 @@ ArrayTraceResolver<INDEX>::Connect (std::string path, CallbackBase const &cb, co
|
||||
}
|
||||
std::string id = GetElement (path);
|
||||
std::string subpath = GetSubpath (path);
|
||||
if (id == "*")
|
||||
{
|
||||
uint32_t j = 0;
|
||||
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
|
||||
{
|
||||
TraceContext tmp = context;
|
||||
INDEX index = j;
|
||||
tmp.AddElement (index);
|
||||
Ptr<Object> obj = m_iter->Get ();
|
||||
obj->GetTraceResolver ()->Connect (subpath, cb, tmp);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
ArrayTraceResolverMatcher matcher = ArrayTraceResolverMatcher (id);
|
||||
uint32_t i = 0;
|
||||
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
|
||||
{
|
||||
if (matcher.Matches (i))
|
||||
{
|
||||
TraceContext tmp = context;
|
||||
INDEX index = i;
|
||||
tmp.AddElement (index);
|
||||
Ptr<Object> obj = m_iter->Get ();
|
||||
obj->GetTraceResolver ()->Connect (subpath, cb, tmp);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
template <typename INDEX>
|
||||
void
|
||||
@@ -157,14 +170,17 @@ ArrayTraceResolver<INDEX>::Disconnect (std::string path, CallbackBase const &cb)
|
||||
}
|
||||
std::string id = GetElement (path);
|
||||
std::string subpath = GetSubpath (path);
|
||||
if (id == "*")
|
||||
{
|
||||
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
|
||||
{
|
||||
Ptr<Object> obj = m_iter->Get ();
|
||||
obj->TraceDisconnect (subpath, cb);
|
||||
}
|
||||
}
|
||||
ArrayTraceResolverMatcher matcher = ArrayTraceResolverMatcher (id);
|
||||
uint32_t i = 0;
|
||||
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
|
||||
{
|
||||
if (matcher.Matches (i))
|
||||
{
|
||||
Ptr<Object> obj = m_iter->Get ();
|
||||
obj->TraceDisconnect (subpath, cb);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
template <typename INDEX>
|
||||
void
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "breakpoint.h"
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup assert Assert
|
||||
* \brief assert functions and macros
|
||||
*
|
||||
|
||||
@@ -72,7 +72,20 @@ void TestFRFour (int &, int &, int &, int &) {}
|
||||
void TestFRFive (int &, int &, int &, int &, int &) {}
|
||||
void TestFRSix (int &, int &, int &, int &, int &, int &) {}
|
||||
|
||||
class CallbackTest : public ns3::Test {
|
||||
class X : public ns3::Test
|
||||
{
|
||||
public:
|
||||
X () : Test ("Callback") {}
|
||||
void PublicParent (void) {}
|
||||
protected:
|
||||
static void StaticProtectedParent (void) {}
|
||||
void ProtectedParent (void) {}
|
||||
private:
|
||||
void PrivateParent (void) {}
|
||||
};
|
||||
|
||||
class CallbackTest : public X
|
||||
{
|
||||
private:
|
||||
bool m_test1;
|
||||
bool m_test2;
|
||||
@@ -107,8 +120,7 @@ public:
|
||||
};
|
||||
|
||||
CallbackTest::CallbackTest ()
|
||||
: ns3::Test ("Callback"),
|
||||
m_test1 (false),
|
||||
: m_test1 (false),
|
||||
m_test2 (false),
|
||||
m_test3 (false),
|
||||
m_test4 (false)
|
||||
@@ -294,6 +306,14 @@ CallbackTest::RunTests (void)
|
||||
MakeBoundCallback (&TestFRFive, 1);
|
||||
|
||||
|
||||
MakeCallback (&X::StaticProtectedParent);
|
||||
MakeCallback (&X::PublicParent, this);
|
||||
MakeCallback (&CallbackTest::ProtectedParent, this);
|
||||
// as expected, fails.
|
||||
//MakeCallback (&X::PrivateParent, this);
|
||||
// unexpected, but fails too.
|
||||
// It does fumble me.
|
||||
//MakeCallback (&X::ProtectedParent, this);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
+47
-53
@@ -75,18 +75,18 @@ public:
|
||||
CallbackImplBase ()
|
||||
: m_count (1) {}
|
||||
virtual ~CallbackImplBase () {}
|
||||
void Ref (void) {
|
||||
void Ref (void) const {
|
||||
m_count++;
|
||||
}
|
||||
void Unref (void) {
|
||||
void Unref (void) const {
|
||||
m_count--;
|
||||
if (m_count == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const = 0;
|
||||
virtual bool IsEqual (Ptr<const CallbackImplBase> other) const = 0;
|
||||
private:
|
||||
uint32_t m_count;
|
||||
mutable uint32_t m_count;
|
||||
};
|
||||
|
||||
// declare the CallbackImpl class
|
||||
@@ -171,9 +171,9 @@ public:
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
|
||||
return m_functor (a1,a2,a3,a4,a5,a6);
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const {
|
||||
virtual bool IsEqual (Ptr<const CallbackImplBase> other) const {
|
||||
FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *otherDerived =
|
||||
dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *> (other);
|
||||
dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *> (PeekPointer(other));
|
||||
if (otherDerived == 0)
|
||||
{
|
||||
return false;
|
||||
@@ -216,9 +216,9 @@ public:
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const {
|
||||
virtual bool IsEqual (Ptr<const CallbackImplBase> other) const {
|
||||
MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *otherDerived =
|
||||
dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *> (other);
|
||||
dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *> (PeekPointer (other));
|
||||
if (otherDerived == 0)
|
||||
{
|
||||
return false;
|
||||
@@ -237,9 +237,11 @@ private:
|
||||
|
||||
class CallbackBase {
|
||||
public:
|
||||
virtual ~CallbackBase () {}
|
||||
virtual CallbackImplBase *PeekImpl (void) const = 0;
|
||||
virtual Ptr<CallbackImplBase> GetImpl (void) const = 0;
|
||||
CallbackBase () : m_impl () {}
|
||||
Ptr<CallbackImplBase> GetImpl (void) const {return m_impl;}
|
||||
protected:
|
||||
CallbackBase (Ptr<CallbackImplBase> impl) : m_impl (impl) {}
|
||||
Ptr<CallbackImplBase> m_impl;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -277,59 +279,69 @@ template<typename R,
|
||||
typename T5 = empty, typename T6 = empty>
|
||||
class Callback : public CallbackBase {
|
||||
public:
|
||||
Callback () {}
|
||||
|
||||
// There are two dummy args below to ensure that this constructor is
|
||||
// always properly disambiguited by the c++ compiler
|
||||
template <typename FUNCTOR>
|
||||
Callback (FUNCTOR const &functor, bool, bool)
|
||||
: m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5,T6> > (functor))
|
||||
: CallbackBase (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5,T6> > (functor))
|
||||
{}
|
||||
|
||||
template <typename OBJ_PTR, typename MEM_PTR>
|
||||
Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr)
|
||||
: m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> > (objPtr, mem_ptr))
|
||||
: CallbackBase (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> > (objPtr, mem_ptr))
|
||||
{}
|
||||
|
||||
Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > const &impl)
|
||||
: m_impl (impl)
|
||||
: CallbackBase (impl)
|
||||
{}
|
||||
|
||||
bool IsNull (void) const {
|
||||
return (PeekImpl () == 0)?true:false;
|
||||
return (DoPeekImpl () == 0)?true:false;
|
||||
}
|
||||
void Nullify (void) {
|
||||
m_impl = 0;
|
||||
}
|
||||
|
||||
Callback () : m_impl () {}
|
||||
R operator() (void) const {
|
||||
return (*(PeekImpl ())) ();
|
||||
return (*(DoPeekImpl ())) ();
|
||||
}
|
||||
R operator() (T1 a1) const {
|
||||
return (*(PeekImpl ())) (a1);
|
||||
return (*(DoPeekImpl ())) (a1);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2) const {
|
||||
return (*(PeekImpl ())) (a1,a2);
|
||||
return (*(DoPeekImpl ())) (a1,a2);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3) const {
|
||||
return (*(PeekImpl ())) (a1,a2,a3);
|
||||
return (*(DoPeekImpl ())) (a1,a2,a3);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3, T4 a4) const {
|
||||
return (*(PeekImpl ())) (a1,a2,a3,a4);
|
||||
return (*(DoPeekImpl ())) (a1,a2,a3,a4);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const {
|
||||
return (*(PeekImpl ())) (a1,a2,a3,a4,a5);
|
||||
return (*(DoPeekImpl ())) (a1,a2,a3,a4,a5);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6) const {
|
||||
return (*(PeekImpl ())) (a1,a2,a3,a4,a5,a6);
|
||||
return (*(DoPeekImpl ())) (a1,a2,a3,a4,a5,a6);
|
||||
}
|
||||
|
||||
bool IsEqual (CallbackBase const &other) const {
|
||||
return PeekImpl ()->IsEqual (other.PeekImpl ());
|
||||
bool IsEqual (const CallbackBase &other) const {
|
||||
return m_impl->IsEqual (other.GetImpl ());
|
||||
}
|
||||
|
||||
bool CheckType (CallbackBase const& other) const {
|
||||
CallbackImplBase *otherBase = other.PeekImpl ();
|
||||
if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (otherBase) != 0)
|
||||
bool CheckType (const CallbackBase & other) const {
|
||||
return DoCheckType (other.GetImpl ());
|
||||
}
|
||||
void Assign (const CallbackBase &other) {
|
||||
DoAssign (other.GetImpl ());
|
||||
}
|
||||
private:
|
||||
CallbackImpl<R,T1,T2,T3,T4,T5,T6> *DoPeekImpl (void) const {
|
||||
return static_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (PeekPointer (m_impl));
|
||||
}
|
||||
bool DoCheckType (Ptr<const CallbackImplBase> other) const {
|
||||
if (dynamic_cast<const CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (PeekPointer (other)) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -338,37 +350,19 @@ public:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void Assign (CallbackBase const &other) {
|
||||
if (!CheckType (other))
|
||||
void DoAssign (Ptr<const CallbackImplBase> other) {
|
||||
if (!DoCheckType (other))
|
||||
{
|
||||
NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
|
||||
" got=" << typeid (other).name () <<
|
||||
" got=" << typeid (*other).name () <<
|
||||
", expected=" << typeid (*this).name ());
|
||||
}
|
||||
const Callback<R, T1,T2,T3,T4,T5,T6> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5,T6> *> (&other);
|
||||
*this = *goodType;
|
||||
m_impl = const_cast<CallbackImplBase *> (PeekPointer (other));
|
||||
}
|
||||
void Assign (Ptr<CallbackImplBase> other) {
|
||||
CallbackImpl<R,T1,T2,T3,T4,T5,T6> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (PeekPointer (other));
|
||||
if (other == 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
|
||||
" got=" << typeid (other).name () <<
|
||||
", expected=" << typeid (*impl).name ());
|
||||
}
|
||||
*this = Callback<R,T1,T2,T3,T4,T5,T6> (impl);
|
||||
}
|
||||
virtual Ptr<CallbackImplBase>GetImpl (void) const {
|
||||
return m_impl;
|
||||
}
|
||||
private:
|
||||
virtual CallbackImpl<R,T1,T2,T3,T4,T5,T6> *PeekImpl (void) const {
|
||||
return PeekPointer (m_impl);
|
||||
}
|
||||
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > m_impl;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup MakeCallback MakeCallback
|
||||
*
|
||||
*/
|
||||
@@ -675,9 +669,9 @@ public:
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
|
||||
return m_functor (m_a,a1,a2,a3,a4,a5);
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const {
|
||||
virtual bool IsEqual (Ptr<const CallbackImplBase> other) const {
|
||||
BoundFunctorCallbackImpl<T,R,TX,T1,T2,T3,T4,T5> const *otherDerived =
|
||||
dynamic_cast<BoundFunctorCallbackImpl<T,R,TX,T1,T2,T3,T4,T5> const *> (other);
|
||||
dynamic_cast<BoundFunctorCallbackImpl<T,R,TX,T1,T2,T3,T4,T5> const *> (PeekPointer (other));
|
||||
if (otherDerived == 0)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -188,45 +188,45 @@ public:
|
||||
std::ostringstream nullout;
|
||||
std::streambuf *origcerr = std::cerr.rdbuf (nullout.rdbuf ());
|
||||
{
|
||||
char *argv[] = {"run-tests", "--loops", "bad-value", NULL};
|
||||
const char *argv[] = {"run-tests", "--loops", "bad-value", NULL};
|
||||
int argc = sizeof (argv) / sizeof (argv[0]) - 1;
|
||||
|
||||
uint32_t loops = 123;
|
||||
CommandLine::AddArgValue ("loops","a test of the command line", loops);
|
||||
CommandLine::Parse (argc, argv);
|
||||
CommandLine::Parse (argc, const_cast<char **> (argv));
|
||||
|
||||
NS_TEST_ASSERT_EQUAL (loops, 123);
|
||||
}
|
||||
|
||||
{
|
||||
char *argv[] = {"run-tests", "--loops=bad-value", NULL};
|
||||
const char *argv[] = {"run-tests", "--loops=bad-value", NULL};
|
||||
int argc = sizeof (argv) / sizeof (argv[0]) - 1;
|
||||
|
||||
uint32_t loops = 123;
|
||||
CommandLine::AddArgValue ("loops","a test of the command line", loops);
|
||||
CommandLine::Parse (argc, argv);
|
||||
CommandLine::Parse (argc, const_cast<char **> (argv));
|
||||
|
||||
NS_TEST_ASSERT_EQUAL (loops, 123);
|
||||
}
|
||||
|
||||
{
|
||||
char *argv[] = {"run-tests", "--loops", "456", NULL};
|
||||
const char *argv[] = {"run-tests", "--loops", "456", NULL};
|
||||
int argc = sizeof (argv) / sizeof (argv[0]) - 1;
|
||||
|
||||
uint32_t loops = 123;
|
||||
CommandLine::AddArgValue ("loops","a test of the command line", loops);
|
||||
CommandLine::Parse (argc, argv);
|
||||
CommandLine::Parse (argc, const_cast<char **> (argv));
|
||||
|
||||
NS_TEST_ASSERT_EQUAL (loops, 456);
|
||||
}
|
||||
|
||||
{
|
||||
char *argv[] = {"run-tests", "--loops=456", NULL};
|
||||
const char *argv[] = {"run-tests", "--loops=456", NULL};
|
||||
int argc = sizeof (argv) / sizeof (argv[0]) - 1;
|
||||
|
||||
uint32_t loops = 123;
|
||||
CommandLine::AddArgValue ("loops","a test of the command line", loops);
|
||||
CommandLine::Parse (argc, argv);
|
||||
CommandLine::Parse (argc, const_cast<char **> (argv));
|
||||
|
||||
NS_TEST_ASSERT_EQUAL (loops, 456);
|
||||
}
|
||||
|
||||
@@ -1,402 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "component-manager.h"
|
||||
#include "uid-manager.h"
|
||||
#include "singleton.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
// we redefine a UidManager type for the class id singleton below.
|
||||
// otherwise, we would have to share the same id singleton instance
|
||||
// with the Iids.
|
||||
class CidManager : public UidManager
|
||||
{};
|
||||
|
||||
ClassId::ClassId (std::string name)
|
||||
: m_classId (Singleton<CidManager>::Get ()->Allocate (name))
|
||||
{}
|
||||
|
||||
ClassId::ClassId (uint32_t classId)
|
||||
: m_classId (classId)
|
||||
{}
|
||||
|
||||
std::string
|
||||
ClassId::GetName (void) const
|
||||
{
|
||||
return Singleton<CidManager>::Get ()->LookupByUid (m_classId);
|
||||
}
|
||||
|
||||
bool operator == (const ClassId &a, const ClassId &b)
|
||||
{
|
||||
return a.m_classId == b.m_classId;
|
||||
}
|
||||
|
||||
ComponentManager::ClassIdEntry::ClassIdEntry (ClassId classId)
|
||||
: m_classId (classId)
|
||||
{}
|
||||
|
||||
Ptr<Object>
|
||||
ComponentManager::Create (ClassId classId)
|
||||
{
|
||||
Callback<Ptr<Object> > callback = DoGetCallback<empty,empty,empty,empty,empty> (classId);
|
||||
return callback ();
|
||||
}
|
||||
|
||||
CallbackBase *
|
||||
ComponentManager::Lookup (ClassId classId)
|
||||
{
|
||||
List *list = Singleton<List>::Get ();
|
||||
for (List::const_iterator i = list->begin (); i != list->end (); i++)
|
||||
{
|
||||
if (i->m_classId == classId)
|
||||
{
|
||||
return i->m_callback;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ClassId
|
||||
ComponentManager::LookupByName (std::string name)
|
||||
{
|
||||
return ClassId (Singleton<CidManager>::Get ()->LookupByName (name));
|
||||
}
|
||||
ClassId
|
||||
ComponentManager::LookupByName (std::string name, bool *ok)
|
||||
{
|
||||
uint32_t cid = Singleton<CidManager>::Get ()->LookupByName (name);
|
||||
if (cid == 0)
|
||||
{
|
||||
*ok = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ok = true;
|
||||
}
|
||||
return ClassId (cid);
|
||||
}
|
||||
std::vector<ClassId>
|
||||
ComponentManager::LookupByInterfaceId (InterfaceId iid)
|
||||
{
|
||||
std::vector<ClassId> classIdList;
|
||||
List *list = Singleton<List>::Get ();
|
||||
for (List::const_iterator i = list->begin (); i != list->end (); i++)
|
||||
{
|
||||
for (std::vector<const InterfaceId *>::const_iterator j = i->m_supportedInterfaces.begin ();
|
||||
j != i->m_supportedInterfaces.end (); j++)
|
||||
{
|
||||
if (*(*j) == iid)
|
||||
{
|
||||
classIdList.push_back (i->m_classId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
unique (classIdList.begin (), classIdList.end ());
|
||||
return classIdList;
|
||||
}
|
||||
|
||||
void
|
||||
ComponentManager::Register (ClassId classId, CallbackBase *callback,
|
||||
std::vector<const InterfaceId *> supportedInterfaces)
|
||||
{
|
||||
List *list = Singleton<List>::Get ();
|
||||
struct ClassIdEntry entry = ClassIdEntry (classId);
|
||||
entry.m_callback = callback;
|
||||
bool foundObject = false;
|
||||
for (std::vector<const InterfaceId *>::iterator i = supportedInterfaces.begin ();
|
||||
i != supportedInterfaces.end (); i++)
|
||||
{
|
||||
if (*i == &Object::iid)
|
||||
{
|
||||
foundObject = true;
|
||||
}
|
||||
}
|
||||
if (!foundObject)
|
||||
{
|
||||
supportedInterfaces.push_back (&Object::iid);
|
||||
}
|
||||
entry.m_supportedInterfaces = supportedInterfaces;
|
||||
list->push_back (entry);
|
||||
}
|
||||
|
||||
void
|
||||
RegisterCallback (ClassId classId, CallbackBase *callback, std::vector<const InterfaceId *> supportedInterfaces)
|
||||
{
|
||||
return ComponentManager::Register (classId, callback, supportedInterfaces);
|
||||
}
|
||||
|
||||
|
||||
ClassIdDefaultValue::ClassIdDefaultValue (std::string name,
|
||||
std::string help,
|
||||
const InterfaceId &iid,
|
||||
std::string defaultValue)
|
||||
: DefaultValueBase (name, help),
|
||||
m_defaultName (defaultValue),
|
||||
m_name (defaultValue),
|
||||
m_interfaceId (&iid)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
}
|
||||
ClassId
|
||||
ClassIdDefaultValue::GetValue (void) const
|
||||
{
|
||||
return ComponentManager::LookupByName (m_name);
|
||||
}
|
||||
void
|
||||
ClassIdDefaultValue::SetValue (ClassId classId)
|
||||
{
|
||||
m_name = classId.GetName ();
|
||||
}
|
||||
void
|
||||
ClassIdDefaultValue::SetValue (std::string name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
bool
|
||||
ClassIdDefaultValue::DoParseValue (const std::string &value)
|
||||
{
|
||||
bool ok;
|
||||
ClassId classId = ComponentManager::LookupByName (value, &ok);
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::vector<ClassId> classIdList = ComponentManager::LookupByInterfaceId (*m_interfaceId);
|
||||
for (std::vector<ClassId>::const_iterator i = classIdList.begin ();
|
||||
i != classIdList.end (); i++)
|
||||
{
|
||||
if (*i == classId)
|
||||
{
|
||||
m_name = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string
|
||||
ClassIdDefaultValue::DoGetType (void) const
|
||||
{
|
||||
std::vector<ClassId> classIdList = ComponentManager::LookupByInterfaceId (*m_interfaceId);
|
||||
std::ostringstream oss;
|
||||
oss << "(";
|
||||
for (std::vector<ClassId>::const_iterator i = classIdList.begin ();
|
||||
i != classIdList.end (); i++)
|
||||
{
|
||||
if (i != classIdList.begin ())
|
||||
{
|
||||
oss << "|";
|
||||
}
|
||||
oss << i->GetName ();
|
||||
}
|
||||
oss << ")";
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
std::string
|
||||
ClassIdDefaultValue::DoGetDefaultValue (void) const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "test.h"
|
||||
#include "object.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
class B : public ns3::Object
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
B ();
|
||||
};
|
||||
|
||||
const ns3::InterfaceId B::iid = MakeInterfaceId ("B", Object::iid);
|
||||
|
||||
B::B ()
|
||||
{
|
||||
SetInterfaceId (B::iid);
|
||||
}
|
||||
|
||||
|
||||
class A : public ns3::Object
|
||||
{
|
||||
public:
|
||||
static const ns3::ClassId cidZero;
|
||||
static const ns3::ClassId cidOneBool;
|
||||
static const ns3::ClassId cidOneUi32;
|
||||
static const ns3::ClassId cidOther;
|
||||
static const ns3::InterfaceId iid;
|
||||
|
||||
A ();
|
||||
A (bool);
|
||||
A (uint32_t);
|
||||
|
||||
bool m_zeroInvoked;
|
||||
bool m_oneBoolInvoked;
|
||||
bool m_oneUi32Invoked;
|
||||
|
||||
bool m_bool;
|
||||
int m_ui32;
|
||||
};
|
||||
|
||||
const ns3::ClassId A::cidZero = ns3::MakeClassId<A> ("A", A::iid);
|
||||
const ns3::ClassId A::cidOneBool = ns3::MakeClassId <A,bool> ("ABool", A::iid);
|
||||
const ns3::ClassId A::cidOneUi32 = ns3::MakeClassId <A,uint32_t> ("AUi32", A::iid);
|
||||
const ns3::InterfaceId A::iid = ns3::MakeInterfaceId ("A", Object::iid);
|
||||
|
||||
A::A ()
|
||||
: m_zeroInvoked (true),
|
||||
m_oneBoolInvoked (false),
|
||||
m_oneUi32Invoked (false)
|
||||
{
|
||||
SetInterfaceId (A::iid);
|
||||
ns3::Ptr<B> b = ns3::Create<B> ();
|
||||
AddInterface (b);
|
||||
}
|
||||
|
||||
A::A (bool bo)
|
||||
: m_zeroInvoked (false),
|
||||
m_oneBoolInvoked (true),
|
||||
m_oneUi32Invoked (false),
|
||||
m_bool (bo)
|
||||
{
|
||||
SetInterfaceId (A::iid);
|
||||
ns3::Ptr<B> b = ns3::Create<B> ();
|
||||
AddInterface (b);
|
||||
}
|
||||
|
||||
A::A (uint32_t i)
|
||||
: m_zeroInvoked (false),
|
||||
m_oneBoolInvoked (false),
|
||||
m_oneUi32Invoked (true),
|
||||
m_ui32 (i)
|
||||
{
|
||||
SetInterfaceId (A::iid);
|
||||
ns3::Ptr<B> b = ns3::Create<B> ();
|
||||
AddInterface (b);
|
||||
}
|
||||
|
||||
class X : public A
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
};
|
||||
class C : public X
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
};
|
||||
class D : public C
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
static const ns3::ClassId cid;
|
||||
};
|
||||
|
||||
const ns3::InterfaceId X::iid = ns3::MakeInterfaceId ("X", A::iid);
|
||||
const ns3::InterfaceId C::iid = ns3::MakeInterfaceId ("C", X::iid);
|
||||
const ns3::InterfaceId D::iid = ns3::MakeInterfaceId ("D", C::iid);
|
||||
const ns3::ClassId D::cid = ns3::MakeClassId<D> ("D", A::iid, X::iid, C::iid, D::iid);
|
||||
|
||||
}
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class ComponentManagerTest : public Test
|
||||
{
|
||||
public:
|
||||
ComponentManagerTest ();
|
||||
virtual bool RunTests (void);
|
||||
};
|
||||
|
||||
ComponentManagerTest::ComponentManagerTest ()
|
||||
: Test ("ComponentManager")
|
||||
{}
|
||||
bool
|
||||
ComponentManagerTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
Ptr<A> a = 0;
|
||||
a = ComponentManager::Create<A> (A::cidZero, A::iid);
|
||||
if (a == 0 ||
|
||||
!a->m_zeroInvoked)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
a = ComponentManager::Create<A,bool> (A::cidOneBool, A::iid, true);
|
||||
if (a == 0 ||
|
||||
!a->m_oneBoolInvoked ||
|
||||
!a->m_bool)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
a = ComponentManager::Create<A,bool> (A::cidOneBool, A::iid, false);
|
||||
if (a == 0 ||
|
||||
!a->m_oneBoolInvoked ||
|
||||
a->m_bool)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
a = ComponentManager::Create<A,uint32_t> (A::cidOneUi32, A::iid, 10);
|
||||
if (a == 0 ||
|
||||
!a->m_oneUi32Invoked ||
|
||||
a->m_ui32 != 10)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
a = ComponentManager::Create<A> (A::cidOneUi32, A::iid, (uint32_t)10);
|
||||
if (a == 0 ||
|
||||
!a->m_oneUi32Invoked ||
|
||||
a->m_ui32 != 10)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
Ptr<B> b = ComponentManager::Create<B,uint32_t> (A::cidOneUi32, B::iid, 10);
|
||||
if (b == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
static ComponentManagerTest g_unknownManagerTest;
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -1,686 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef COMPONENT_MANAGER_H
|
||||
#define COMPONENT_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include "callback.h"
|
||||
#include "object.h"
|
||||
#include "fatal-error.h"
|
||||
#include "ptr.h"
|
||||
#include "empty.h"
|
||||
#include "default-value.h"
|
||||
|
||||
namespace {
|
||||
// anonymous namespace for implementation code.
|
||||
template <typename T, typename T1 = ns3::empty, typename T2 = ns3::empty,
|
||||
typename T3 = ns3::empty, typename T4 = ns3::empty, typename T5 = ns3::empty>
|
||||
struct ObjectMaker;
|
||||
}
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Unique Identifier for class constructors.
|
||||
*
|
||||
* Instances of this type must be allocated through
|
||||
* the ns3::MakeClassId class.
|
||||
*/
|
||||
class ClassId
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \returns the symbolic name associated to this class id
|
||||
*
|
||||
* This name is the name which was associated to this class id
|
||||
* by the ns3::Ns3UnknownManager::RegisterConstructor methods.
|
||||
* This name is also the name which is expected to be input
|
||||
* to ns3::UnknownManager::LookupByName.
|
||||
*/
|
||||
std::string GetName (void) const;
|
||||
protected:
|
||||
ClassId (std::string name);
|
||||
private:
|
||||
ClassId (uint32_t classId);
|
||||
friend class ComponentManager;
|
||||
friend ClassId AllocateClassId (std::string name);
|
||||
friend bool operator == (const ClassId &a, const ClassId &b);
|
||||
uint32_t m_classId;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief a class used to create ClassIds
|
||||
*
|
||||
*
|
||||
*/
|
||||
template <typename T, typename T1 = empty, typename T2 = empty,
|
||||
typename T3 = empty, typename T4 = empty, typename T5 = empty>
|
||||
class MakeClassId : public ClassId
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name name of ClassId
|
||||
*
|
||||
* Create a ClassId with specified name.
|
||||
*/
|
||||
MakeClassId (std::string name);
|
||||
/**
|
||||
* \param name name of ClassId
|
||||
* \param iid interface id
|
||||
*
|
||||
* Create a ClassId with specified name. Register iid
|
||||
* as a supported interface.
|
||||
*/
|
||||
MakeClassId (std::string name,
|
||||
const InterfaceId &iid);
|
||||
/**
|
||||
* \param name name of ClassId
|
||||
* \param iid0 interface id
|
||||
* \param iid1 interface id
|
||||
*
|
||||
* Create a ClassId with specified name. Register iid0 and iid1
|
||||
* as supported interfaces.
|
||||
*/
|
||||
MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId iid1);
|
||||
/**
|
||||
* \param name name of ClassId
|
||||
* \param iid0 interface id
|
||||
* \param iid1 interface id
|
||||
* \param iid2 interface id
|
||||
*
|
||||
* Create a ClassId with specified name. Register iid0, iid1
|
||||
* and iid2 as supported interfaces.
|
||||
*/
|
||||
MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId &iid1,
|
||||
const InterfaceId &iid2);
|
||||
/**
|
||||
* \param name name of ClassId
|
||||
* \param iid0 interface id
|
||||
* \param iid1 interface id
|
||||
* \param iid2 interface id
|
||||
* \param iid3 interface id
|
||||
*
|
||||
* Create a ClassId with specified name. Register iid0, iid1
|
||||
* iid2, and iid3 as supported interfaces.
|
||||
*/
|
||||
MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId &iid1,
|
||||
const InterfaceId &iid2,
|
||||
const InterfaceId &iid3);
|
||||
/**
|
||||
* \param name name of ClassId
|
||||
* \param iid0 interface id
|
||||
* \param iid1 interface id
|
||||
* \param iid2 interface id
|
||||
* \param iid3 interface id
|
||||
* \param iid4 interface id
|
||||
*
|
||||
* Create a ClassId with specified name. Register iid0, iid1
|
||||
* iid2, iid3, and iid4 as supported interfaces.
|
||||
*/
|
||||
MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId &iid1,
|
||||
const InterfaceId &iid2,
|
||||
const InterfaceId &iid3,
|
||||
const InterfaceId &iid4);
|
||||
private:
|
||||
typedef ObjectMaker<T,T1,T2,T3,T4,T5> MakerType;
|
||||
static Callback<Ptr<Object>,T1,T2,T3,T4,T5> m_callback;
|
||||
void Register (const InterfaceId *array [], uint32_t n);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Create any Interface
|
||||
*
|
||||
* This class keeps track of a set of ClassId, each
|
||||
* of which uniquely identifies the constructor of an
|
||||
* object which derives from the Interface base class.
|
||||
* This class can also create an instance of any of
|
||||
* the objects tracked through any of their tracked
|
||||
* constructor/ClassId.
|
||||
*/
|
||||
class ComponentManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name the symbolic name to lookup
|
||||
* \returns the ClassId associated to the input name.
|
||||
*/
|
||||
static ClassId LookupByName (std::string name);
|
||||
static ClassId LookupByName (std::string name, bool *ok);
|
||||
/**
|
||||
* \param iid interface id to lookup
|
||||
* \returns the list of ClassId which can be used to
|
||||
* create objects which support the requested
|
||||
* interface.
|
||||
*
|
||||
* Note that this method will not necessarily return the
|
||||
* complete list of objects which support a given interface
|
||||
* since dynamic aggregation of objects is not under
|
||||
* the control of this class.
|
||||
*/
|
||||
static std::vector<ClassId> LookupByInterfaceId (InterfaceId iid);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId. This method invokes the default constructor.
|
||||
*/
|
||||
static Ptr<Object> Create (ClassId classId);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param a1 argument to pass to the constructor.
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId.
|
||||
*/
|
||||
template <typename T1>
|
||||
static Ptr<Object> Create (ClassId classId, T1 a1);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param a1 first argument to pass to the constructor.
|
||||
* \param a2 second argument to pass to the constructor.
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId.
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
static Ptr<Object> Create (ClassId classId, T1 a1, T2 a2);
|
||||
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param a1 first argument to pass to the constructor.
|
||||
* \param a2 second argument to pass to the constructor.
|
||||
* \param a3 third argument to pass to the constructor.
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId.
|
||||
*/
|
||||
template <typename T1, typename T2, typename T3>
|
||||
static Ptr<Object> Create (ClassId classId, T1 a1, T2 a2, T3 a3);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param a1 first argument to pass to the constructor.
|
||||
* \param a2 second argument to pass to the constructor.
|
||||
* \param a3 third argument to pass to the constructor.
|
||||
* \param a4 fourth argument to pass to the constructor.
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId.
|
||||
*/
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
static Ptr<Object> Create (ClassId classId, T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param a1 first argument to pass to the constructor.
|
||||
* \param a2 second argument to pass to the constructor.
|
||||
* \param a3 third argument to pass to the constructor.
|
||||
* \param a4 fourth argument to pass to the constructor.
|
||||
* \param a5 fifth argument to pass to the constructor.
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId.
|
||||
*/
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static Ptr<Object> Create (ClassId classId, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param iid interface id to query for
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId, call QueryInterface on it, and return the
|
||||
* result.
|
||||
*/
|
||||
template <typename T>
|
||||
static Ptr<T> Create (ClassId classId, InterfaceId iid);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param iid interface id to query for
|
||||
* \param a1 first argument to pass to constructor
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId, call QueryInterface on it, and return the
|
||||
* result.
|
||||
*/
|
||||
template <typename T, typename T1>
|
||||
static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param iid interface id to query for
|
||||
* \param a1 first argument to pass to constructor
|
||||
* \param a2 second argument to pass to constructor
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId, call QueryInterface on it, and return the
|
||||
* result.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2>
|
||||
static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param iid interface id to query for
|
||||
* \param a1 first argument to pass to constructor
|
||||
* \param a2 second argument to pass to constructor
|
||||
* \param a3 third argument to pass to constructor
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId, call QueryInterface on it, and return the
|
||||
* result.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param iid interface id to query for
|
||||
* \param a1 first argument to pass to constructor
|
||||
* \param a2 second argument to pass to constructor
|
||||
* \param a3 third argument to pass to constructor
|
||||
* \param a4 fourth argument to pass to constructor
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId, call QueryInterface on it, and return the
|
||||
* result.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
|
||||
/**
|
||||
* \param classId class id of the constructor to invoke.
|
||||
* \param iid interface id to query for
|
||||
* \param a1 first argument to pass to constructor
|
||||
* \param a2 second argument to pass to constructor
|
||||
* \param a3 third argument to pass to constructor
|
||||
* \param a4 fourth argument to pass to constructor
|
||||
* \param a5 fifth argument to pass to constructor
|
||||
* \return a pointer to the instance created.
|
||||
*
|
||||
* Create an instance of the object identified by its
|
||||
* ClassId, call QueryInterface on it, and return the
|
||||
* result.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
|
||||
private:
|
||||
friend void RegisterCallback (ClassId classId, CallbackBase *callback,
|
||||
std::vector<const InterfaceId *> supportedInterfaces);
|
||||
static void Register (ClassId classId, CallbackBase *callback,
|
||||
std::vector<const InterfaceId *> supportedInterfaces);
|
||||
|
||||
template <typename T1, typename T2,
|
||||
typename T3, typename T4,
|
||||
typename T5>
|
||||
static Callback<Ptr<Object>,T1,T2,T3,T4,T5> DoGetCallback (ClassId classId);
|
||||
|
||||
struct ClassIdEntry {
|
||||
ClassIdEntry (ClassId classId);
|
||||
ClassId m_classId;
|
||||
CallbackBase *m_callback;
|
||||
std::vector<const InterfaceId *> m_supportedInterfaces;
|
||||
};
|
||||
|
||||
typedef std::vector<struct ClassIdEntry> List;
|
||||
static List *GetList (void);
|
||||
static CallbackBase *Lookup (ClassId classId);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief a DefaultValue class to handle ClassIds
|
||||
*
|
||||
* This class provides the necessary glue to allow
|
||||
* the Bind function and the command-line arguments
|
||||
* to control the type of an object to create.
|
||||
*/
|
||||
class ClassIdDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name the name of this default value.
|
||||
* \param help the help text associated to this default value
|
||||
* \param iid the interface id which all objects created
|
||||
* through this "default value" must support.
|
||||
* \param defaultValue the name of the object to create
|
||||
* by default.
|
||||
*/
|
||||
ClassIdDefaultValue (std::string name,
|
||||
std::string help,
|
||||
const InterfaceId &iid,
|
||||
std::string defaultValue);
|
||||
/**
|
||||
* \returns the ClassId of the object selected by the user.
|
||||
*/
|
||||
ClassId GetValue (void) const;
|
||||
/**
|
||||
* \param classId the new ClassId selected.
|
||||
*
|
||||
* Override the currently-selected value.
|
||||
*/
|
||||
void SetValue (ClassId classId);
|
||||
/**
|
||||
* \param name the new object selected.
|
||||
*
|
||||
* Override the currently-selected value.
|
||||
*/
|
||||
void SetValue (std::string name);
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
std::string m_defaultName;
|
||||
std::string m_name;
|
||||
const InterfaceId *m_interfaceId;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
struct ObjectMaker<T,ns3::empty,ns3::empty,ns3::empty,ns3::empty,ns3::empty> {
|
||||
static ns3::Ptr<ns3::Object>
|
||||
MakeObject (void) {
|
||||
return ns3::Create<T> ();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename T1>
|
||||
struct ObjectMaker<T,T1,ns3::empty,ns3::empty,ns3::empty,ns3::empty> {
|
||||
static ns3::Ptr<ns3::Object>
|
||||
MakeObject (T1 a1) {
|
||||
return ns3::Create<T> (a1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
struct ObjectMaker<T,T1,T2,ns3::empty,ns3::empty,ns3::empty> {
|
||||
static ns3::Ptr<ns3::Object>
|
||||
MakeObject (T1 a1, T2 a2) {
|
||||
return ns3::Create<T> (a1, a2);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
struct ObjectMaker<T,T1,T2,T3,ns3::empty,ns3::empty> {
|
||||
static ns3::Ptr<ns3::Object>
|
||||
MakeObject (T1 a1, T2 a2, T3 a3) {
|
||||
return ns3::Create<T> (a1, a2, a3);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3,
|
||||
typename T4>
|
||||
struct ObjectMaker<T,T1,T2,T3,T4,ns3::empty> {
|
||||
static ns3::Ptr<ns3::Object>
|
||||
MakeObject (T1 a1, T2 a2, T3 a3, T4 a4) {
|
||||
return ns3::Create<T> (a1, a2, a3, a4);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3,
|
||||
typename T4, typename T5>
|
||||
struct ObjectMaker {
|
||||
static ns3::Ptr<ns3::Object>
|
||||
MakeObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
|
||||
return ns3::Create<T> (a1, a2, a3, a4, a5);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
void RegisterCallback (ClassId classId, ns3::CallbackBase *callback,
|
||||
std::vector<const InterfaceId *> supportedInterfaces);
|
||||
|
||||
|
||||
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
void
|
||||
MakeClassId<T,T1,T2,T3,T4,T5>::Register (const InterfaceId *array [], uint32_t n)
|
||||
{
|
||||
std::vector<const InterfaceId *> supportedInterfaces;
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
supportedInterfaces.push_back (array[i]);
|
||||
}
|
||||
RegisterCallback (*this, &m_callback, supportedInterfaces);
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
MakeClassId<T,T1,T2,T3,T4,T5>::MakeClassId (std::string name)
|
||||
: ClassId (name)
|
||||
{
|
||||
const InterfaceId *array[] = {};
|
||||
Register (array, sizeof (array)/sizeof(InterfaceId *));
|
||||
}
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
MakeClassId<T,T1,T2,T3,T4,T5>::MakeClassId (std::string name,
|
||||
const InterfaceId &iid)
|
||||
: ClassId (name)
|
||||
{
|
||||
const InterfaceId *array[] = {&iid};
|
||||
Register (array, sizeof (array)/sizeof(InterfaceId *));
|
||||
}
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
MakeClassId<T,T1,T2,T3,T4,T5>::MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId iid1)
|
||||
: ClassId (name)
|
||||
{
|
||||
const InterfaceId *array[] = {&iid0, &iid1};
|
||||
Register (array, sizeof (array)/sizeof(InterfaceId *));
|
||||
}
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
MakeClassId<T,T1,T2,T3,T4,T5>::MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId &iid1,
|
||||
const InterfaceId &iid2)
|
||||
: ClassId (name)
|
||||
{
|
||||
const InterfaceId *array[] = {&iid0, &iid1, &iid2};
|
||||
Register (array, sizeof (array)/sizeof(InterfaceId *));
|
||||
}
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
MakeClassId<T,T1,T2,T3,T4,T5>::MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId &iid1,
|
||||
const InterfaceId &iid2,
|
||||
const InterfaceId &iid3)
|
||||
: ClassId (name)
|
||||
{
|
||||
const InterfaceId *array[] = {&iid0, &iid1, &iid2, &iid3};
|
||||
Register (array, sizeof (array)/sizeof(InterfaceId *));
|
||||
}
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
MakeClassId<T,T1,T2,T3,T4,T5>::MakeClassId (std::string name,
|
||||
const InterfaceId &iid0,
|
||||
const InterfaceId &iid1,
|
||||
const InterfaceId &iid2,
|
||||
const InterfaceId &iid3,
|
||||
const InterfaceId &iid4)
|
||||
: ClassId (name)
|
||||
{
|
||||
const InterfaceId *array[] = {&iid0, &iid1, iid2, &iid3, &iid4};
|
||||
Register (array, sizeof (array)/sizeof(InterfaceId *));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2,
|
||||
typename T3, typename T4, typename T5>
|
||||
Callback<Ptr<Object>,T1,T2,T3,T4,T5> MakeClassId<T,T1,T2,T3,T4,T5>::m_callback =
|
||||
MakeCallback (&MakeClassId::MakerType::MakeObject);
|
||||
|
||||
|
||||
|
||||
template <typename T1, typename T2,
|
||||
typename T3, typename T4,
|
||||
typename T5>
|
||||
Callback<Ptr<Object>,T1,T2,T3,T4,T5>
|
||||
ComponentManager::DoGetCallback (ClassId classId)
|
||||
{
|
||||
CallbackBase *callback = Lookup (classId);
|
||||
if (callback == 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("Invalid Class Id.");
|
||||
}
|
||||
Callback<Ptr<Object>,T1,T2,T3,T4,T5> reference;
|
||||
reference.Assign (*callback);
|
||||
return reference;
|
||||
}
|
||||
|
||||
|
||||
template <typename T1>
|
||||
Ptr<Object>
|
||||
ComponentManager::Create (ClassId classId, T1 a1)
|
||||
{
|
||||
Callback<Ptr<Object>,T1> callback = DoGetCallback<T1,empty,empty,empty,empty> (classId);
|
||||
return callback (a1);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
Ptr<Object>
|
||||
ComponentManager::Create (ClassId classId, T1 a1, T2 a2)
|
||||
{
|
||||
Callback<Ptr<Object>,T1,T2> callback = DoGetCallback<T1,T2,empty,empty,empty> (classId);
|
||||
return callback (a1, a2);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
Ptr<Object>
|
||||
ComponentManager::Create (ClassId classId, T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
Callback<Ptr<Object>,T1,T2,T3> callback = DoGetCallback<T1,T2,T3,empty,empty> (classId);
|
||||
return callback (a1, a2, a3);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
Ptr<Object>
|
||||
ComponentManager::Create (ClassId classId, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
Callback<Ptr<Object>,T1,T2,T3,T4> callback = DoGetCallback<T1,T2,T3,T4,empty> (classId);
|
||||
return callback (a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Ptr<Object>
|
||||
ComponentManager::Create (ClassId classId, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
Callback<Ptr<Object>,T1,T2,T3,T4,T5> callback = DoGetCallback<T1,T2,T3,T4,T5> (classId);
|
||||
return callback (a1, a2, a3, a4, a5);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
Ptr<T>
|
||||
ComponentManager::Create (ClassId classId, InterfaceId iid)
|
||||
{
|
||||
Ptr<Object> obj = Create (classId);
|
||||
Ptr<T> i = obj->QueryInterface<T> (iid);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename T, typename T1>
|
||||
Ptr<T>
|
||||
ComponentManager::Create (ClassId classId, InterfaceId iid, T1 a1)
|
||||
{
|
||||
Ptr<Object> obj = Create (classId, a1);
|
||||
Ptr<T> i = obj->QueryInterface<T> (iid);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
Ptr<T>
|
||||
ComponentManager::Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2)
|
||||
{
|
||||
Ptr<Object> obj = Create (classId, a1, a2);
|
||||
Ptr<T> i = obj->QueryInterface<T> (iid);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
Ptr<T>
|
||||
ComponentManager::Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
Ptr<Object> obj = Create (classId, a1, a2, a3);
|
||||
Ptr<T> i = obj->QueryInterface<T> (iid);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
Ptr<T>
|
||||
ComponentManager::Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
Ptr<Object> obj = Create (classId, a1, a2, a3, a4);
|
||||
Ptr<T> i = obj->QueryInterface<T> (iid);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Ptr<T>
|
||||
ComponentManager::Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
Ptr<Object> obj = Create (classId, a1, a2, a3, a4, a5);
|
||||
Ptr<T> i = obj->QueryInterface<T> (iid);
|
||||
return i;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* COMPONENT_MANAGER_H */
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "callback.h"
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup config Simulation configuration
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup error Error
|
||||
* \brief fatal error handling
|
||||
*
|
||||
|
||||
+37
-23
@@ -39,6 +39,12 @@ namespace ns3 {
|
||||
typedef std::list<std::pair <std::string, LogComponent *> > ComponentList;
|
||||
typedef std::list<std::pair <std::string, LogComponent *> >::iterator ComponentListI;
|
||||
|
||||
static class PrintList
|
||||
{
|
||||
public:
|
||||
PrintList ();
|
||||
} g_printList;
|
||||
|
||||
static
|
||||
ComponentList *GetComponentList (void)
|
||||
{
|
||||
@@ -46,6 +52,35 @@ ComponentList *GetComponentList (void)
|
||||
return &components;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PrintList::PrintList ()
|
||||
{
|
||||
#ifdef HAVE_GETENV
|
||||
char *envVar = getenv("NS_LOG");
|
||||
if (envVar == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::string env = envVar;
|
||||
std::string::size_type cur = 0;
|
||||
std::string::size_type next = 0;
|
||||
while (next != std::string::npos)
|
||||
{
|
||||
next = env.find_first_of (";", cur);
|
||||
std::string tmp = std::string (env, cur, next-cur);
|
||||
if (tmp == "print-list")
|
||||
{
|
||||
LogComponentPrintList ();
|
||||
exit (0);
|
||||
break;
|
||||
}
|
||||
cur = next + 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
LogComponent::LogComponent (char const * name)
|
||||
: m_levels (0), m_name (name)
|
||||
{
|
||||
@@ -75,23 +110,10 @@ LogComponent::EnvVarCheck (char const * name)
|
||||
|
||||
std::string::size_type cur = 0;
|
||||
std::string::size_type next = 0;
|
||||
while (true)
|
||||
while (next != std::string::npos)
|
||||
{
|
||||
next = env.find_first_of (";", cur);
|
||||
std::string tmp = std::string (env, cur, next);
|
||||
{
|
||||
/* The following code is a workaround for a bug in the g++
|
||||
* c++ string library. Its goal is to remove any trailing ';'
|
||||
* from the string even though there should not be any in
|
||||
* it. This code should be safe even if the bug is not there.
|
||||
*/
|
||||
std::string::size_type trailing = tmp.find_first_of (";");
|
||||
tmp = tmp.substr (0, trailing);
|
||||
}
|
||||
if (tmp.size () == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::string tmp = std::string (env, cur, next-cur);
|
||||
std::string::size_type equal = tmp.find ("=");
|
||||
std::string component;
|
||||
if (equal == std::string::npos)
|
||||
@@ -189,15 +211,7 @@ LogComponent::EnvVarCheck (char const * name)
|
||||
Enable ((enum LogLevel)level);
|
||||
}
|
||||
}
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
cur = next + 1;
|
||||
if (cur >= env.size ())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+5
-4
@@ -25,6 +25,7 @@
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup logging Logging
|
||||
* \brief Logging functions and macros
|
||||
*
|
||||
@@ -116,6 +117,9 @@ public:
|
||||
switch (m_itemNumber)
|
||||
{
|
||||
case 0: // first item is actually the function name
|
||||
std::clog << param << " (";
|
||||
break;
|
||||
case 1: // first parameter
|
||||
if (m_parameterName)
|
||||
{
|
||||
std::clog << m_parameterName << "=" << param;
|
||||
@@ -126,7 +130,7 @@ public:
|
||||
std::clog << param;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
default: // parameter following a previous parameter
|
||||
if (m_parameterName)
|
||||
{
|
||||
std::clog << ", " << m_parameterName << "=" << param;
|
||||
@@ -137,9 +141,6 @@ public:
|
||||
std::clog << ", " << param;
|
||||
}
|
||||
break;
|
||||
default: // parameter following a previous parameter
|
||||
std::clog << ", " << param;
|
||||
break;
|
||||
}
|
||||
m_itemNumber++;
|
||||
return *this;
|
||||
|
||||
+347
-139
@@ -21,49 +21,177 @@
|
||||
#include "object.h"
|
||||
#include "assert.h"
|
||||
#include "singleton.h"
|
||||
#include "uid-manager.h"
|
||||
#include "trace-resolver.h"
|
||||
#include "log.h"
|
||||
#include <vector>
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Object");
|
||||
|
||||
/*********************************************************************
|
||||
* Helper code
|
||||
*********************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
class IidManager : public ns3::UidManager
|
||||
{};
|
||||
|
||||
class IidTree
|
||||
class IidManager
|
||||
{
|
||||
public:
|
||||
void SetParent (uint16_t child, const uint16_t *parent);
|
||||
uint16_t LookupParent (uint16_t child);
|
||||
|
||||
uint16_t AllocateUid (std::string name);
|
||||
void SetParent (uint16_t uid, uint16_t parent);
|
||||
void AddConstructor (uint16_t uid, ns3::CallbackBase callback, uint32_t nArguments);
|
||||
uint16_t GetUid (std::string name) const;
|
||||
std::string GetName (uint16_t uid) const;
|
||||
uint16_t GetParent (uint16_t uid) const;
|
||||
ns3::CallbackBase GetConstructor (uint16_t uid, uint32_t nArguments);
|
||||
bool HasConstructor (uint16_t uid);
|
||||
uint32_t GetRegisteredN (void);
|
||||
uint16_t GetRegistered (uint32_t i);
|
||||
private:
|
||||
std::vector<const uint16_t *> m_parents;
|
||||
struct ConstructorInformation {
|
||||
ns3::CallbackBase cb;
|
||||
uint32_t nArguments;
|
||||
};
|
||||
struct IidInformation {
|
||||
std::string name;
|
||||
uint16_t parent;
|
||||
std::vector<struct ConstructorInformation> constructors;
|
||||
};
|
||||
typedef std::vector<struct IidInformation>::const_iterator Iterator;
|
||||
|
||||
struct IidManager::IidInformation *LookupInformation (uint16_t uid) const;
|
||||
|
||||
std::vector<struct IidInformation> m_information;
|
||||
};
|
||||
|
||||
void
|
||||
IidTree::SetParent (uint16_t child, const uint16_t *parent)
|
||||
uint16_t
|
||||
IidManager::AllocateUid (std::string name)
|
||||
{
|
||||
m_parents.resize (child+1);
|
||||
m_parents[child] = parent;
|
||||
uint16_t j = 1;
|
||||
for (Iterator i = m_information.begin (); i != m_information.end (); i++)
|
||||
{
|
||||
if (i->name == name)
|
||||
{
|
||||
NS_FATAL_ERROR ("Trying to allocate twice the same uid: " << name);
|
||||
return 0;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
struct IidInformation information;
|
||||
information.name = name;
|
||||
information.parent = 0;
|
||||
m_information.push_back (information);
|
||||
uint32_t uid = m_information.size ();
|
||||
NS_ASSERT (uid <= 0xffff);
|
||||
return uid;
|
||||
}
|
||||
|
||||
struct IidManager::IidInformation *
|
||||
IidManager::LookupInformation (uint16_t uid) const
|
||||
{
|
||||
NS_ASSERT (uid <= m_information.size ());
|
||||
return const_cast<struct IidInformation *> (&m_information[uid-1]);
|
||||
}
|
||||
|
||||
void
|
||||
IidManager::SetParent (uint16_t uid, uint16_t parent)
|
||||
{
|
||||
NS_ASSERT (parent <= m_information.size ());
|
||||
struct IidInformation *information = LookupInformation (uid);
|
||||
information->parent = parent;
|
||||
}
|
||||
void
|
||||
IidManager::AddConstructor (uint16_t uid, ns3::CallbackBase callback, uint32_t nArguments)
|
||||
{
|
||||
struct IidInformation *information = LookupInformation (uid);
|
||||
struct ConstructorInformation constructor;
|
||||
constructor.cb = callback;
|
||||
constructor.nArguments = nArguments;
|
||||
for (std::vector<struct ConstructorInformation>::const_iterator i = information->constructors.begin ();
|
||||
i != information->constructors.end (); i++)
|
||||
{
|
||||
if (i->nArguments == nArguments)
|
||||
{
|
||||
NS_FATAL_ERROR ("registered two constructors on the same type with the same number of arguments.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
information->constructors.push_back (constructor);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
IidManager::GetUid (std::string name) const
|
||||
{
|
||||
uint32_t j = 1;
|
||||
for (Iterator i = m_information.begin (); i != m_information.end (); i++)
|
||||
{
|
||||
if (i->name == name)
|
||||
{
|
||||
NS_ASSERT (j <= 0xffff);
|
||||
return j;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
std::string
|
||||
IidManager::GetName (uint16_t uid) const
|
||||
{
|
||||
struct IidInformation *information = LookupInformation (uid);
|
||||
return information->name;
|
||||
}
|
||||
uint16_t
|
||||
IidTree::LookupParent (uint16_t child)
|
||||
IidManager::GetParent (uint16_t uid) const
|
||||
{
|
||||
NS_ASSERT (child < m_parents.size ());
|
||||
return *(m_parents[child]);
|
||||
struct IidInformation *information = LookupInformation (uid);
|
||||
return information->parent;
|
||||
}
|
||||
ns3::CallbackBase
|
||||
IidManager::GetConstructor (uint16_t uid, uint32_t nArguments)
|
||||
{
|
||||
struct IidInformation *information = LookupInformation (uid);
|
||||
for (std::vector<struct ConstructorInformation>::const_iterator i = information->constructors.begin ();
|
||||
i != information->constructors.end (); i++)
|
||||
{
|
||||
if (i->nArguments == nArguments)
|
||||
{
|
||||
return i->cb;
|
||||
}
|
||||
}
|
||||
NS_FATAL_ERROR ("Requested constructor with "<<nArguments<<" arguments not found");
|
||||
return ns3::CallbackBase ();
|
||||
}
|
||||
|
||||
bool
|
||||
IidManager::HasConstructor (uint16_t uid)
|
||||
{
|
||||
struct IidInformation *information = LookupInformation (uid);
|
||||
return !information->constructors.empty ();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
IidManager::GetRegisteredN (void)
|
||||
{
|
||||
return m_information.size ();
|
||||
}
|
||||
uint16_t
|
||||
IidManager::GetRegistered (uint32_t i)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*********************************************************************
|
||||
* The TypeId TraceResolver
|
||||
*********************************************************************/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class InterfaceIdTraceResolver : public TraceResolver
|
||||
class TypeIdTraceResolver : public TraceResolver
|
||||
{
|
||||
public:
|
||||
InterfaceIdTraceResolver (Ptr<const Object> aggregate);
|
||||
TypeIdTraceResolver (Ptr<const Object> aggregate);
|
||||
virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
|
||||
virtual void Disconnect (std::string path, CallbackBase const &cb);
|
||||
virtual void CollectSources (std::string path, const TraceContext &context,
|
||||
@@ -74,11 +202,11 @@ private:
|
||||
Ptr<const Object> m_aggregate;
|
||||
};
|
||||
|
||||
InterfaceIdTraceResolver::InterfaceIdTraceResolver (Ptr<const Object> aggregate)
|
||||
TypeIdTraceResolver::TypeIdTraceResolver (Ptr<const Object> aggregate)
|
||||
: m_aggregate (aggregate)
|
||||
{}
|
||||
Ptr<const Object>
|
||||
InterfaceIdTraceResolver::ParseForInterface (std::string path)
|
||||
TypeIdTraceResolver::ParseForInterface (std::string path)
|
||||
{
|
||||
std::string element = GetElement (path);
|
||||
std::string::size_type dollar_pos = element.find ("$");
|
||||
@@ -87,12 +215,12 @@ InterfaceIdTraceResolver::ParseForInterface (std::string path)
|
||||
return 0;
|
||||
}
|
||||
std::string interfaceName = element.substr (1, std::string::npos);
|
||||
InterfaceId interfaceId = InterfaceId::LookupByName (interfaceName);
|
||||
Ptr<Object> interface = m_aggregate->QueryInterface<Object> (interfaceId);
|
||||
TypeId interfaceId = TypeId::LookupByName (interfaceName);
|
||||
Ptr<Object> interface = m_aggregate->GetObject<Object> (interfaceId);
|
||||
return interface;
|
||||
}
|
||||
void
|
||||
InterfaceIdTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
|
||||
void
|
||||
TypeIdTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
|
||||
{
|
||||
Ptr<const Object> interface = ParseForInterface (path);
|
||||
if (interface != 0)
|
||||
@@ -101,7 +229,7 @@ InterfaceIdTraceResolver::Connect (std::string path, CallbackBase const &cb, con
|
||||
}
|
||||
}
|
||||
void
|
||||
InterfaceIdTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
|
||||
TypeIdTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
|
||||
{
|
||||
Ptr<const Object> interface = ParseForInterface (path);
|
||||
if (interface != 0)
|
||||
@@ -110,77 +238,136 @@ InterfaceIdTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
|
||||
}
|
||||
}
|
||||
void
|
||||
InterfaceIdTraceResolver::CollectSources (std::string path, const TraceContext &context,
|
||||
TypeIdTraceResolver::CollectSources (std::string path, const TraceContext &context,
|
||||
SourceCollection *collection)
|
||||
{
|
||||
m_aggregate->DoCollectSources (path, context, collection);
|
||||
}
|
||||
void
|
||||
InterfaceIdTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
|
||||
TypeIdTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
|
||||
{
|
||||
m_aggregate->DoTraceAll (os, context);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* The TypeId class
|
||||
*********************************************************************/
|
||||
|
||||
InterfaceId::InterfaceId (uint16_t iid)
|
||||
: m_iid (iid)
|
||||
{}
|
||||
InterfaceId::~InterfaceId ()
|
||||
{}
|
||||
InterfaceId
|
||||
InterfaceId::LookupByName (std::string name)
|
||||
TypeId::TypeId (std::string name)
|
||||
{
|
||||
uint32_t uid = Singleton<IidManager>::Get ()->LookupByName (name);
|
||||
NS_ASSERT (uid != 0 && uid <= 0xffff);
|
||||
return InterfaceId (uid);
|
||||
uint16_t uid = Singleton<IidManager>::Get ()->AllocateUid (name);
|
||||
NS_ASSERT (uid != 0);
|
||||
m_tid = uid;
|
||||
}
|
||||
InterfaceId
|
||||
InterfaceId::LookupParent (InterfaceId iid)
|
||||
|
||||
|
||||
TypeId::TypeId (uint16_t tid)
|
||||
: m_tid (tid)
|
||||
{}
|
||||
TypeId::~TypeId ()
|
||||
{}
|
||||
TypeId
|
||||
TypeId::LookupByName (std::string name)
|
||||
{
|
||||
return Singleton<IidTree>::Get ()->LookupParent (iid.m_iid);
|
||||
uint16_t uid = Singleton<IidManager>::Get ()->GetUid (name);
|
||||
NS_ASSERT (uid != 0);
|
||||
return TypeId (uid);
|
||||
}
|
||||
uint32_t
|
||||
TypeId::GetRegisteredN (void)
|
||||
{
|
||||
return Singleton<IidManager>::Get ()->GetRegisteredN ();
|
||||
}
|
||||
TypeId
|
||||
TypeId::GetRegistered (uint32_t i)
|
||||
{
|
||||
return TypeId (Singleton<IidManager>::Get ()->GetRegistered (i));
|
||||
}
|
||||
|
||||
TypeId
|
||||
TypeId::SetParent (TypeId tid)
|
||||
{
|
||||
Singleton<IidManager>::Get ()->SetParent (m_tid, tid.m_tid);
|
||||
return *this;
|
||||
}
|
||||
TypeId
|
||||
TypeId::GetParent (void) const
|
||||
{
|
||||
uint16_t parent = Singleton<IidManager>::Get ()->GetParent (m_tid);
|
||||
return TypeId (parent);
|
||||
}
|
||||
std::string
|
||||
InterfaceId::GetName (void) const
|
||||
TypeId::GetName (void) const
|
||||
{
|
||||
std::string name = Singleton<IidManager>::Get ()->LookupByUid (m_iid);
|
||||
std::string name = Singleton<IidManager>::Get ()->GetName (m_tid);
|
||||
return name;
|
||||
}
|
||||
|
||||
bool operator == (const InterfaceId &a, const InterfaceId &b)
|
||||
bool
|
||||
TypeId::HasConstructor (void) const
|
||||
{
|
||||
return a.m_iid == b.m_iid;
|
||||
bool hasConstructor = Singleton<IidManager>::Get ()->HasConstructor (m_tid);
|
||||
return hasConstructor;
|
||||
}
|
||||
|
||||
bool operator != (const InterfaceId &a, const InterfaceId &b)
|
||||
void
|
||||
TypeId::DoAddConstructor (CallbackBase cb, uint32_t nArguments)
|
||||
{
|
||||
return a.m_iid != b.m_iid;
|
||||
Singleton<IidManager>::Get ()->AddConstructor (m_tid, cb, nArguments);
|
||||
}
|
||||
|
||||
InterfaceId
|
||||
MakeInterfaceId (std::string name, const InterfaceId &parent)
|
||||
CallbackBase
|
||||
TypeId::LookupConstructor (uint32_t nArguments)
|
||||
{
|
||||
uint32_t uid = Singleton<IidManager>::Get ()->Allocate (name);
|
||||
NS_ASSERT (uid <= 0xffff);
|
||||
InterfaceId iid = uid;
|
||||
Singleton<IidTree>::Get ()->SetParent (iid.m_iid, &parent.m_iid);
|
||||
return iid;
|
||||
CallbackBase constructor = Singleton<IidManager>::Get ()->GetConstructor (m_tid, nArguments);
|
||||
return constructor;
|
||||
}
|
||||
|
||||
InterfaceId
|
||||
MakeObjectInterfaceId (void)
|
||||
Ptr<Object>
|
||||
TypeId::CreateObject (void)
|
||||
{
|
||||
InterfaceId iid = Singleton<IidManager>::Get ()->Allocate ("Object");
|
||||
Singleton<IidTree>::Get ()->SetParent (iid.m_iid, &iid.m_iid);
|
||||
return iid;
|
||||
CallbackBase cb = LookupConstructor (0);
|
||||
Callback<Ptr<Object> > realCb;
|
||||
realCb.Assign (cb);
|
||||
Ptr<Object> object = realCb ();
|
||||
return object;
|
||||
}
|
||||
|
||||
bool operator == (TypeId a, TypeId b)
|
||||
{
|
||||
return a.m_tid == b.m_tid;
|
||||
}
|
||||
|
||||
const InterfaceId Object::iid = MakeObjectInterfaceId ();
|
||||
bool operator != (TypeId a, TypeId b)
|
||||
{
|
||||
return a.m_tid != b.m_tid;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* The Object implementation
|
||||
*********************************************************************/
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (Object);
|
||||
|
||||
static TypeId
|
||||
GetObjectIid (void)
|
||||
{
|
||||
TypeId tid = TypeId ("Object");
|
||||
tid.SetParent (tid);
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
Object::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = GetObjectIid ();
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
Object::Object ()
|
||||
: m_count (1),
|
||||
m_iid (Object::iid),
|
||||
m_tid (Object::GetTypeId ()),
|
||||
m_disposed (false),
|
||||
m_collecting (false),
|
||||
m_next (this)
|
||||
@@ -190,18 +377,18 @@ Object::~Object ()
|
||||
m_next = 0;
|
||||
}
|
||||
Ptr<Object>
|
||||
Object::DoQueryInterface (InterfaceId iid) const
|
||||
Object::DoGetObject (TypeId tid) const
|
||||
{
|
||||
NS_ASSERT (CheckLoose ());
|
||||
const Object *currentObject = this;
|
||||
do {
|
||||
NS_ASSERT (currentObject != 0);
|
||||
InterfaceId cur = currentObject->m_iid;
|
||||
while (cur != iid && cur != Object::iid)
|
||||
TypeId cur = currentObject->m_tid;
|
||||
while (cur != tid && cur != Object::GetTypeId ())
|
||||
{
|
||||
cur = InterfaceId::LookupParent (cur);
|
||||
cur = cur.GetParent ();
|
||||
}
|
||||
if (cur == iid)
|
||||
if (cur == tid)
|
||||
{
|
||||
return const_cast<Object *> (currentObject);
|
||||
}
|
||||
@@ -223,7 +410,7 @@ Object::Dispose (void)
|
||||
}
|
||||
|
||||
void
|
||||
Object::AddInterface (Ptr<Object> o)
|
||||
Object::AggregateObject (Ptr<Object> o)
|
||||
{
|
||||
NS_ASSERT (!m_disposed);
|
||||
NS_ASSERT (!o->m_disposed);
|
||||
@@ -251,10 +438,10 @@ Object::TraceDisconnect (std::string path, const CallbackBase &cb) const
|
||||
}
|
||||
|
||||
void
|
||||
Object::SetInterfaceId (InterfaceId iid)
|
||||
Object::SetTypeId (TypeId tid)
|
||||
{
|
||||
NS_ASSERT (Check ());
|
||||
m_iid = iid;
|
||||
m_tid = tid;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -267,8 +454,8 @@ Ptr<TraceResolver>
|
||||
Object::GetTraceResolver (void) const
|
||||
{
|
||||
NS_ASSERT (CheckLoose ());
|
||||
Ptr<InterfaceIdTraceResolver> resolver =
|
||||
Create<InterfaceIdTraceResolver> (this);
|
||||
Ptr<TypeIdTraceResolver> resolver =
|
||||
Create<TypeIdTraceResolver> (this);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
@@ -348,8 +535,8 @@ Object::DoCollectSources (std::string path, const TraceContext &context,
|
||||
{
|
||||
NS_ASSERT (current != 0);
|
||||
NS_LOG_LOGIC ("collect current=" << current);
|
||||
InterfaceId cur = current->m_iid;
|
||||
while (cur != Object::iid)
|
||||
TypeId cur = current->m_tid;
|
||||
while (cur != Object::GetTypeId ())
|
||||
{
|
||||
std::string name = cur.GetName ();
|
||||
std::string fullpath = path;
|
||||
@@ -357,7 +544,7 @@ Object::DoCollectSources (std::string path, const TraceContext &context,
|
||||
fullpath.append (name);
|
||||
NS_LOG_LOGIC("collect: " << fullpath);
|
||||
current->GetTraceResolver ()->CollectSources (fullpath, context, collection);
|
||||
cur = InterfaceId::LookupParent (cur);
|
||||
cur = cur.GetParent ();
|
||||
}
|
||||
current = current->m_next;
|
||||
}
|
||||
@@ -404,11 +591,14 @@ namespace {
|
||||
class BaseA : public ns3::Object
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
BaseA ()
|
||||
{
|
||||
SetInterfaceId (BaseA::iid);
|
||||
static ns3::TypeId GetTypeId (void) {
|
||||
static ns3::TypeId tid = ns3::TypeId ("BaseA")
|
||||
.SetParent (Object::GetTypeId ())
|
||||
.AddConstructor<BaseA> ();
|
||||
return tid;
|
||||
}
|
||||
BaseA ()
|
||||
{}
|
||||
void BaseGenerateTrace (int16_t v)
|
||||
{ m_source = v; }
|
||||
virtual void Dispose (void) {}
|
||||
@@ -426,11 +616,14 @@ public:
|
||||
class DerivedA : public BaseA
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
DerivedA (int v)
|
||||
{
|
||||
SetInterfaceId (DerivedA::iid);
|
||||
static ns3::TypeId GetTypeId (void) {
|
||||
static ns3::TypeId tid = ns3::TypeId ("DerivedA")
|
||||
.SetParent (BaseA::GetTypeId ())
|
||||
.AddConstructor<DerivedA,int> ();
|
||||
return tid;
|
||||
}
|
||||
DerivedA (int v)
|
||||
{}
|
||||
void DerivedGenerateTrace (int16_t v)
|
||||
{ m_sourceDerived = v; }
|
||||
virtual void Dispose (void) {
|
||||
@@ -447,19 +640,17 @@ public:
|
||||
ns3::SVTraceSource<int16_t> m_sourceDerived;
|
||||
};
|
||||
|
||||
const ns3::InterfaceId BaseA::iid =
|
||||
ns3::MakeInterfaceId ("BaseA", Object::iid);
|
||||
const ns3::InterfaceId DerivedA::iid =
|
||||
ns3::MakeInterfaceId ("DerivedA", BaseA::iid);;
|
||||
|
||||
class BaseB : public ns3::Object
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
BaseB ()
|
||||
{
|
||||
SetInterfaceId (BaseB::iid);
|
||||
static ns3::TypeId GetTypeId (void) {
|
||||
static ns3::TypeId tid = ns3::TypeId ("BaseB")
|
||||
.SetParent (Object::GetTypeId ())
|
||||
.AddConstructor<BaseB> ();
|
||||
return tid;
|
||||
}
|
||||
BaseB ()
|
||||
{}
|
||||
void BaseGenerateTrace (int16_t v)
|
||||
{ m_source = v; }
|
||||
virtual void Dispose (void) {}
|
||||
@@ -477,11 +668,17 @@ public:
|
||||
class DerivedB : public BaseB
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
DerivedB (int v)
|
||||
{
|
||||
SetInterfaceId (DerivedB::iid);
|
||||
static ns3::TypeId GetTypeId (void) {
|
||||
static ns3::TypeId tid = ns3::TypeId ("DerivedB")
|
||||
.SetParent (BaseB::GetTypeId ())
|
||||
.AddConstructor<DerivedB,int> ()
|
||||
.AddConstructor<DerivedB,int,int &> ();
|
||||
return tid;
|
||||
}
|
||||
DerivedB (int v)
|
||||
{}
|
||||
DerivedB (int v1, int &v2)
|
||||
{}
|
||||
void DerivedGenerateTrace (int16_t v)
|
||||
{ m_sourceDerived = v; }
|
||||
virtual void Dispose (void) {
|
||||
@@ -498,10 +695,10 @@ public:
|
||||
ns3::SVTraceSource<int16_t> m_sourceDerived;
|
||||
};
|
||||
|
||||
const ns3::InterfaceId BaseB::iid =
|
||||
ns3::MakeInterfaceId ("BaseB", Object::iid);
|
||||
const ns3::InterfaceId DerivedB::iid =
|
||||
ns3::MakeInterfaceId ("DerivedB", BaseB::iid);;
|
||||
NS_OBJECT_ENSURE_REGISTERED (BaseA);
|
||||
NS_OBJECT_ENSURE_REGISTERED (DerivedA);
|
||||
NS_OBJECT_ENSURE_REGISTERED (BaseB);
|
||||
NS_OBJECT_ENSURE_REGISTERED (DerivedB);
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
@@ -553,63 +750,63 @@ ObjectTest::RunTests (void)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
Ptr<BaseA> baseA = Create<BaseA> ();
|
||||
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
|
||||
baseA = Create<DerivedA> (10);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), baseA);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
|
||||
Ptr<BaseA> baseA = CreateObject<BaseA> ();
|
||||
NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (), baseA);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->GetObject<DerivedA> (), 0);
|
||||
baseA = CreateObject<DerivedA> (10);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (), baseA);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), baseA);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<DerivedA> (), 0);
|
||||
|
||||
baseA = Create<BaseA> ();
|
||||
Ptr<BaseB> baseB = Create<BaseB> ();
|
||||
baseA = CreateObject<BaseA> ();
|
||||
Ptr<BaseB> baseB = CreateObject<BaseB> ();
|
||||
Ptr<BaseB> baseBCopy = baseB;
|
||||
baseA->AddInterface (baseB);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
|
||||
baseA->AggregateObject (baseB);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<BaseA> (), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->GetObject<DerivedA> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<BaseB> (), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseA->GetObject<DerivedB> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseB->GetObject<DerivedB> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseA> (), 0);
|
||||
NS_TEST_ASSERT_EQUAL (baseB->GetObject<DerivedA> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<BaseA> (), 0);
|
||||
|
||||
baseA = Create<DerivedA> (1);
|
||||
baseB = Create<DerivedB> (1);
|
||||
baseA = CreateObject<DerivedA> (1);
|
||||
baseB = CreateObject<DerivedB> (1);
|
||||
baseBCopy = baseB;
|
||||
baseA->AddInterface (baseB);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0)
|
||||
baseA->AggregateObject (baseB);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<DerivedB> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<BaseB> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<DerivedA> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseA> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<DerivedA> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<BaseA> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<DerivedB> (), 0);
|
||||
NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0)
|
||||
|
||||
baseA = Create<BaseA> ();
|
||||
baseB = Create<BaseB> ();
|
||||
baseA->AddInterface (baseB);
|
||||
baseA = CreateObject<BaseA> ();
|
||||
baseB = CreateObject<BaseB> ();
|
||||
baseA->AggregateObject (baseB);
|
||||
baseA = 0;
|
||||
baseA = baseB->QueryInterface<BaseA> (BaseA::iid);
|
||||
baseA = baseB->GetObject<BaseA> ();
|
||||
|
||||
baseA = Create<BaseA> ();
|
||||
baseA = CreateObject<BaseA> ();
|
||||
baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
|
||||
m_baseATrace = false;
|
||||
baseA->BaseGenerateTrace (1);
|
||||
NS_TEST_ASSERT (m_baseATrace);
|
||||
baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
|
||||
|
||||
baseB = Create<BaseB> ();
|
||||
baseB = CreateObject<BaseB> ();
|
||||
baseB->TraceConnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
|
||||
m_baseBTrace = false;
|
||||
baseB->BaseGenerateTrace (2);
|
||||
NS_TEST_ASSERT (m_baseBTrace);
|
||||
baseB->TraceDisconnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
|
||||
|
||||
baseA->AddInterface (baseB);
|
||||
baseA->AggregateObject (baseB);
|
||||
|
||||
baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
|
||||
m_baseATrace = false;
|
||||
@@ -639,9 +836,9 @@ ObjectTest::RunTests (void)
|
||||
baseA->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
|
||||
|
||||
Ptr<DerivedA> derivedA;
|
||||
derivedA = Create<DerivedA> (1);
|
||||
baseB = Create<BaseB> ();
|
||||
derivedA->AddInterface (baseB);
|
||||
derivedA = CreateObject<DerivedA> (1);
|
||||
baseB = CreateObject<BaseB> ();
|
||||
derivedA->AggregateObject (baseB);
|
||||
baseB->TraceConnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::DerivedATrace, this));
|
||||
baseB->TraceConnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
|
||||
m_derivedATrace = false;
|
||||
@@ -664,6 +861,17 @@ ObjectTest::RunTests (void)
|
||||
NS_TEST_ASSERT (m_derivedATrace);
|
||||
baseB->TraceDisconnect ("/$DerivedA/*", MakeCallback (&ObjectTest::BaseATrace, this));
|
||||
|
||||
// Test the object creation code of TypeId
|
||||
Ptr<Object> a = BaseA::GetTypeId ().CreateObject ();
|
||||
NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (), a);
|
||||
NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (DerivedA::GetTypeId ()), 0);
|
||||
NS_TEST_ASSERT_EQUAL (a->GetObject<DerivedA> (), 0);
|
||||
a = DerivedA::GetTypeId ().CreateObject (10);
|
||||
NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (), a);
|
||||
NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (DerivedA::GetTypeId ()), a);
|
||||
NS_TEST_ASSERT_UNEQUAL (a->GetObject<DerivedA> (), 0);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+354
-53
@@ -25,21 +25,30 @@
|
||||
#include <string>
|
||||
#include "ptr.h"
|
||||
#include "trace-resolver.h"
|
||||
#include "callback.h"
|
||||
#include "empty.h"
|
||||
|
||||
#define NS_OBJECT_ENSURE_REGISTERED(type) \
|
||||
static struct X##type##RegistrationClass \
|
||||
{ \
|
||||
X##type##RegistrationClass () { \
|
||||
ns3::TypeId tid = type::GetTypeId (); \
|
||||
tid.GetParent (); \
|
||||
} \
|
||||
} x_##type##RegistrationVariable
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class TraceContext;
|
||||
class CallbackBase;
|
||||
class Object;
|
||||
|
||||
/**
|
||||
* \brief a unique identifier for an interface.
|
||||
*
|
||||
* Instances of this class can be created only through
|
||||
* calls to ns3::MakeInterfaceId.
|
||||
*
|
||||
* Note: This class is quite similar to COM's UUIDs.
|
||||
*/
|
||||
class InterfaceId
|
||||
class TypeId
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -50,55 +59,85 @@ public:
|
||||
* This method cannot fail: it will crash if the input
|
||||
* name is not a valid interface name.
|
||||
*/
|
||||
static InterfaceId LookupByName (std::string name);
|
||||
static TypeId LookupByName (std::string name);
|
||||
static uint32_t GetRegisteredN (void);
|
||||
static TypeId GetRegistered (uint32_t i);
|
||||
/**
|
||||
* \param iid a unique id
|
||||
* \returns the parent of the requested id, as registered
|
||||
* by ns3::MakeInterfaceId.
|
||||
* \returns the parent of this TypeId
|
||||
*
|
||||
* This method cannot fail: it will crash if the input
|
||||
* id is not a valid interface id.
|
||||
* This method cannot fail. It will return itself
|
||||
* if this TypeId has no parent. i.e., it is at the top
|
||||
* of the TypeId hierarchy. Currently, this is the
|
||||
* case for the TypeId associated to the Object class
|
||||
* only.
|
||||
*/
|
||||
static InterfaceId LookupParent (InterfaceId iid);
|
||||
TypeId GetParent (void) const;
|
||||
|
||||
/**
|
||||
* \returns the name of this interface.
|
||||
*/
|
||||
std::string GetName (void) const;
|
||||
~InterfaceId ();
|
||||
private:
|
||||
InterfaceId (uint16_t iid);
|
||||
friend InterfaceId MakeInterfaceId (std::string name, const InterfaceId &parent);
|
||||
friend InterfaceId MakeObjectInterfaceId (void);
|
||||
friend bool operator == (const InterfaceId &a, const InterfaceId &b);
|
||||
friend bool operator != (const InterfaceId &a, const InterfaceId &b);
|
||||
uint16_t m_iid;
|
||||
};
|
||||
|
||||
/**
|
||||
* \param name of the new InterfaceId to create.
|
||||
* \param parent the "parent" of the InterfaceId to create.
|
||||
* \returns a new InterfaceId
|
||||
* \relates InterfaceId
|
||||
*
|
||||
* Every InterfaceId is a child of another InterfaceId. The
|
||||
* top-most InterfaceId is Object::iid and its parent is
|
||||
* itself.
|
||||
*/
|
||||
InterfaceId
|
||||
MakeInterfaceId (std::string name, const InterfaceId &parent);
|
||||
/**
|
||||
* \returns true if this TypeId has a constructor
|
||||
*/
|
||||
bool HasConstructor (void) const;
|
||||
|
||||
TypeId (std::string);
|
||||
|
||||
TypeId SetParent (TypeId tid);
|
||||
template <typename T>
|
||||
TypeId SetParent (void);
|
||||
|
||||
template <typename T>
|
||||
TypeId AddConstructor (void);
|
||||
template <typename T, typename T1>
|
||||
TypeId AddConstructor (void);
|
||||
template <typename T, typename T1, typename T2>
|
||||
TypeId AddConstructor (void);
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
TypeId AddConstructor (void);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
TypeId AddConstructor (void);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
TypeId AddConstructor (void);
|
||||
|
||||
|
||||
Ptr<Object> CreateObject (void);
|
||||
template <typename T1>
|
||||
Ptr<Object> CreateObject (T1 a1);
|
||||
template <typename T1, typename T2>
|
||||
Ptr<Object> CreateObject (T1 a1, T2 a2);
|
||||
template <typename T1, typename T2, typename T3>
|
||||
Ptr<Object> CreateObject (T1 a1, T2 a2, T3 a3);
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
Ptr<Object> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Ptr<Object> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
|
||||
~TypeId ();
|
||||
private:
|
||||
friend bool operator == (TypeId a, TypeId b);
|
||||
friend bool operator != (TypeId a, TypeId b);
|
||||
|
||||
explicit TypeId (uint16_t tid);
|
||||
void DoAddConstructor (CallbackBase callback, uint32_t nArguments);
|
||||
CallbackBase LookupConstructor (uint32_t nArguments);
|
||||
|
||||
uint16_t m_tid;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief a base class which provides memory management and object aggregation
|
||||
*
|
||||
* Note: This base class is quite similar in spirit to IUnknown in COM or
|
||||
* BonoboObject in Bonobo: it provides three main methods: Ref, Unref and
|
||||
* QueryInterface.
|
||||
* GetObject.
|
||||
*/
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
Object ();
|
||||
virtual ~Object ();
|
||||
@@ -117,12 +156,16 @@ public:
|
||||
*/
|
||||
inline void Unref (void) const;
|
||||
/**
|
||||
* \param iid the interface requested
|
||||
* \returns a pointer to the requested interface or zero if it could not be found.
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
Ptr<T> QueryInterface (InterfaceId iid) const;
|
||||
Ptr<T> GetObject (void) const;
|
||||
/**
|
||||
* \param tid the interface id of the requested interface
|
||||
* \returns a pointer to the requested interface or zero if it could not be found.
|
||||
*/
|
||||
template <typename T>
|
||||
Ptr<T> GetObject (TypeId tid) const;
|
||||
/**
|
||||
* Run the DoDispose methods of this object and all the
|
||||
* objects aggregated to it.
|
||||
@@ -136,10 +179,10 @@ public:
|
||||
* \param other another object pointer
|
||||
*
|
||||
* This method aggregates the two objects together: after this
|
||||
* method returns, it becomes possible to call QueryInterface
|
||||
* method returns, it becomes possible to call GetObject
|
||||
* on one to get the other, and vice-versa.
|
||||
*/
|
||||
void AddInterface (Ptr<Object> other);
|
||||
void AggregateObject (Ptr<Object> other);
|
||||
|
||||
/**
|
||||
* \param path the path to match for the callback
|
||||
@@ -165,14 +208,6 @@ public:
|
||||
*/
|
||||
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
|
||||
protected:
|
||||
/**
|
||||
* \param iid an InterfaceId
|
||||
*
|
||||
* Every subclass which defines a new InterfaceId for itself
|
||||
* should register this InterfaceId by calling this method
|
||||
* from its constructor.
|
||||
*/
|
||||
void SetInterfaceId (InterfaceId iid);
|
||||
/**
|
||||
* This method is called by Object::Dispose.
|
||||
* Subclasses are expected to override this method and chain
|
||||
@@ -180,25 +215,214 @@ protected:
|
||||
*/
|
||||
virtual void DoDispose (void);
|
||||
private:
|
||||
friend class InterfaceIdTraceResolver;
|
||||
Ptr<Object> DoQueryInterface (InterfaceId iid) const;
|
||||
friend class TypeIdTraceResolver;
|
||||
template <typename T>
|
||||
friend Ptr<T> CreateObject (void);
|
||||
template <typename T, typename T1>
|
||||
friend Ptr<T> CreateObject (T1 a1);
|
||||
template <typename T, typename T1, typename T2>
|
||||
friend Ptr<T> CreateObject (T1 a1, T2 a2);
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
friend Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
friend Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
friend Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
|
||||
friend Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
||||
friend Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7);
|
||||
|
||||
Ptr<Object> DoGetObject (TypeId tid) const;
|
||||
void DoCollectSources (std::string path, const TraceContext &context,
|
||||
TraceResolver::SourceCollection *collection) const;
|
||||
void DoTraceAll (std::ostream &os, const TraceContext &context) const;
|
||||
bool Check (void) const;
|
||||
bool CheckLoose (void) const;
|
||||
void MaybeDelete (void) const;
|
||||
/**
|
||||
* \param tid an TypeId
|
||||
*
|
||||
* Every subclass which defines a new TypeId for itself
|
||||
* should register this TypeId by calling this method
|
||||
* from its constructor.
|
||||
*/
|
||||
void SetTypeId (TypeId tid);
|
||||
|
||||
mutable uint32_t m_count;
|
||||
InterfaceId m_iid;
|
||||
TypeId m_tid;
|
||||
bool m_disposed;
|
||||
mutable bool m_collecting;
|
||||
Object *m_next;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Ptr<T> CreateObject (void);
|
||||
|
||||
template <typename T, typename T1>
|
||||
Ptr<T> CreateObject (T1 a1);
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2);
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3);
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6);
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7);
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
TypeId
|
||||
TypeId::SetParent (void)
|
||||
{
|
||||
return SetParent (T::GetTypeId ());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TypeId
|
||||
TypeId::AddConstructor (void)
|
||||
{
|
||||
struct Maker {
|
||||
static Ptr<Object> Create (void) {
|
||||
return ns3::CreateObject<T> ();
|
||||
}
|
||||
};
|
||||
CallbackBase cb = MakeCallback (&Maker::Create);
|
||||
DoAddConstructor (cb, 0);
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename T1>
|
||||
TypeId
|
||||
TypeId::AddConstructor (void)
|
||||
{
|
||||
struct Maker {
|
||||
static Ptr<Object> Create (T1 a1) {
|
||||
return ns3::CreateObject<T,T1> (a1);
|
||||
}
|
||||
};
|
||||
CallbackBase cb = MakeCallback (&Maker::Create);
|
||||
DoAddConstructor (cb, 1);
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename T1, typename T2>
|
||||
TypeId
|
||||
TypeId::AddConstructor (void)
|
||||
{
|
||||
struct Maker {
|
||||
static Ptr<Object> Create (T1 a1, T2 a2) {
|
||||
return ns3::CreateObject<T,T1,T2> (a1, a2);
|
||||
}
|
||||
};
|
||||
CallbackBase cb = MakeCallback (&Maker::Create);
|
||||
DoAddConstructor (cb, 2);
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
TypeId
|
||||
TypeId::AddConstructor (void)
|
||||
{
|
||||
struct Maker {
|
||||
static Ptr<Object> Create (T1 a1, T2 a2, T3 a3) {
|
||||
return ns3::CreateObject<T,T1,T2,T3> (a1, a2, a3);
|
||||
}
|
||||
};
|
||||
CallbackBase cb = MakeCallback (&Maker::Create);
|
||||
DoAddConstructor (cb, 3);
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
TypeId
|
||||
TypeId::AddConstructor (void)
|
||||
{
|
||||
struct Maker {
|
||||
static Ptr<Object> Create (T1 a1, T2 a2, T3 a3, T4 a4) {
|
||||
return ns3::CreateObject<T,T1,T2,T3,T4> (a1, a2, a3, a4);
|
||||
}
|
||||
};
|
||||
CallbackBase cb = MakeCallback (&Maker::Create);
|
||||
DoAddConstructor (cb, 4);
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
TypeId
|
||||
TypeId::AddConstructor (void)
|
||||
{
|
||||
struct Maker {
|
||||
static Ptr<Object> Create (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
|
||||
return ns3::CreateObject<T,T1,T2,T3,T4,T5> (a1, a2, a3, a4, a5);
|
||||
}
|
||||
};
|
||||
CallbackBase cb = MakeCallback (&Maker::Create);
|
||||
DoAddConstructor (cb, 5);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
Ptr<Object>
|
||||
TypeId::CreateObject (T1 a1)
|
||||
{
|
||||
CallbackBase cb = LookupConstructor (1);
|
||||
Callback<Ptr<Object>,T1> realCb;
|
||||
realCb.Assign (cb);
|
||||
Ptr<Object> object = realCb (a1);
|
||||
return object;
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
Ptr<Object>
|
||||
TypeId::CreateObject (T1 a1, T2 a2)
|
||||
{
|
||||
CallbackBase cb = LookupConstructor (2);
|
||||
Callback<Ptr<Object>,T1,T2> realCb;
|
||||
realCb.Assign (cb);
|
||||
Ptr<Object> object = realCb (a1,a2);
|
||||
return object;
|
||||
}
|
||||
template <typename T1, typename T2, typename T3>
|
||||
Ptr<Object>
|
||||
TypeId::CreateObject (T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
CallbackBase cb = LookupConstructor (3);
|
||||
Callback<Ptr<Object>,T1,T2,T3> realCb;
|
||||
realCb.Assign (cb);
|
||||
Ptr<Object> object = realCb (a1,a2,a3);
|
||||
return object;
|
||||
}
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
Ptr<Object>
|
||||
TypeId::CreateObject (T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
CallbackBase cb = LookupConstructor (4);
|
||||
Callback<Ptr<Object>,T1,T2,T3,T4> realCb;
|
||||
realCb.Assign (cb);
|
||||
Ptr<Object> object = realCb (a1,a2,a3,a4);
|
||||
return object;
|
||||
}
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Ptr<Object>
|
||||
TypeId::CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
CallbackBase cb = LookupConstructor (5);
|
||||
Callback<Ptr<Object>,T1,T2,T3,T4,T5> realCb;
|
||||
realCb.Assign (cb);
|
||||
Ptr<Object> object = realCb (a1,a2,a3,a4,a5);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Object::Ref (void) const
|
||||
{
|
||||
@@ -217,9 +441,9 @@ Object::Unref (void) const
|
||||
|
||||
template <typename T>
|
||||
Ptr<T>
|
||||
Object::QueryInterface (InterfaceId iid) const
|
||||
Object::GetObject () const
|
||||
{
|
||||
Ptr<Object> found = DoQueryInterface (iid);
|
||||
Ptr<Object> found = DoGetObject (T::GetTypeId ());
|
||||
if (found != 0)
|
||||
{
|
||||
return Ptr<T> (dynamic_cast<T *> (PeekPointer (found)));
|
||||
@@ -227,6 +451,83 @@ Object::QueryInterface (InterfaceId iid) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Ptr<T>
|
||||
Object::GetObject (TypeId tid) const
|
||||
{
|
||||
Ptr<Object> found = DoGetObject (tid);
|
||||
if (found != 0)
|
||||
{
|
||||
return Ptr<T> (dynamic_cast<T *> (PeekPointer (found)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Ptr<T> CreateObject (void)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, typename T1>
|
||||
Ptr<T> CreateObject (T1 a1)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (a1), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (a1, a2), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (a1, a2, a3), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (a1, a2, a3, a4), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (a1, a2, a3, a4, a5), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (a1, a2, a3, a4, a5, a6), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
||||
Ptr<T> CreateObject (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
|
||||
{
|
||||
Ptr<T> p = Ptr<T> (new T (a1, a2, a3, a4, a5, a6, a7), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* OBJECT_H */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user