Compare commits
924 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c813805e7 | |||
| 0583ab3bc8 | |||
| ae8f10ae47 | |||
| b6c0155487 | |||
| 42d93b9872 | |||
| d757f69479 | |||
| 5629eae3ae | |||
| 496313f56b | |||
| 67fa3a8c82 | |||
| 3ce169b4e2 | |||
| 441a8868a0 | |||
| 65f894b7ac | |||
| de608e90c1 | |||
| 0b32b0109f | |||
| 0f246d7f69 | |||
| d30f4d66de | |||
| 8b7716b380 | |||
| 96a92d230e | |||
| 7bed39940e | |||
| 5625551898 | |||
| fd479088ec | |||
| bedbfd18d7 | |||
| 2756732458 | |||
| 3bb28c049f | |||
| ce57b5d156 | |||
| 23f4e85f87 | |||
| b937ec5a87 | |||
| 103a2527ce | |||
| 18e53720d1 | |||
| 35f80fc5c3 | |||
| 993dc85f8f | |||
| 99bd5418bc | |||
| 7c1e148ffa | |||
| ffa52a935a | |||
| 4b4b121366 | |||
| 2964b90925 | |||
| 50f2fc5a16 | |||
| d879c3c54a | |||
| 3012f74206 | |||
| 91aa5250de | |||
| 75d762c0b9 | |||
| 67454b117b | |||
| 3b96881ba2 | |||
| 87c5cb5706 | |||
| f4911e544b | |||
| 10d053a838 | |||
| c4ab5ba8ff | |||
| 75bc2e9b0b | |||
| c2fda9ce09 | |||
| 8e2ee88b93 | |||
| d27fe9ac8e | |||
| 0d7b0e26ee | |||
| da531b4aef | |||
| 4772e79fee | |||
| 72622c0755 | |||
| 55f2084e86 | |||
| f34463d1cc | |||
| 76b31adc2f | |||
| 641ecb2736 | |||
| 3dbf735aeb | |||
| 33a493fe5d | |||
| 1ec3ab4a1f | |||
| 005d9c9877 | |||
| 102dcfd4bc | |||
| e89ad0a86b | |||
| b7ded4e595 | |||
| b61417101f | |||
| 6e2d898443 | |||
| 1ba5c01281 | |||
| c6f42b1cff | |||
| 2b3882fb1a | |||
| 12476595ad | |||
| 8435bfc4fe | |||
| 9cec524f88 | |||
| fb3786c137 | |||
| 40e654dd22 | |||
| d5087e2d90 | |||
| adf49bbc32 | |||
| 8361cbab71 | |||
| 49abdbd009 | |||
| 4b95d67bea | |||
| a6382422df | |||
| e77c211955 | |||
| 8a3e4b7b14 | |||
| a0901958a8 | |||
| 8e0ccbb45a | |||
| 1608934b89 | |||
| 02763bf7cb | |||
| e5b63ce34d | |||
| 4ed6463d22 | |||
| f348fc4fbc | |||
| 07489e7e9c | |||
| eb6eea0f72 | |||
| b0a30b32bb | |||
| 2caaf90037 | |||
| 929ea4dab0 | |||
| f5ce4791d2 | |||
| 5698e745c9 | |||
| 8c03ce9e0c | |||
| 113e6255ea | |||
| cbac246ffb | |||
| e829515b02 | |||
| 3e511d1457 | |||
| aabed928b1 | |||
| 6816e303ec | |||
| 1bbf7ce1a2 | |||
| 969ff1267e | |||
| 3634046dc7 | |||
| c3ff0ad584 | |||
| ebfe75384c | |||
| bd1dcf3f97 | |||
| d5e147d400 | |||
| 35dbade0a9 | |||
| dc62fabc0b | |||
| 47f2db1e23 | |||
| 967b3f34e9 | |||
| 09ed1c9575 | |||
| f71d6fd74f | |||
| b9c4fa85f1 | |||
| c32fa46161 | |||
| d0bd4ea161 | |||
| 7b6d5c4e97 | |||
| 0459737b00 | |||
| 372ecb8430 | |||
| 9a852e442e | |||
| 92757ef5c3 | |||
| 297692d88b | |||
| 4ead4618e6 | |||
| 96f1c67bfe | |||
| 9db1449b4b | |||
| 9421bfcfee | |||
| a5a1152e95 | |||
| 3a97fce182 | |||
| e8ab5afb41 | |||
| 1d0658dc85 | |||
| 01f37ccb65 | |||
| 4d5a66d6e5 | |||
| c4234041bc | |||
| 359a2f98a8 | |||
| 1225b1623e | |||
| 62aa29999b | |||
| a4f727f68d | |||
| a6c8a11881 | |||
| ce4bcba2e6 | |||
| a88ff1f2c4 | |||
| a986e81353 | |||
| b9899de6df | |||
| bebb4eb281 | |||
| 03ca60cd50 | |||
| 1c46ed54e5 | |||
| 34c6957f95 | |||
| 8a62c228b2 | |||
| 4c92dfe914 | |||
| 5f2b952521 | |||
| 3485d9829c | |||
| 00d6bb5c8a | |||
| 89fc9310db | |||
| 26e52f0da4 | |||
| 99c235760e | |||
| 0dfdcfbdc3 | |||
| 5f48c4e7f3 | |||
| 5e703c70f7 | |||
| e9ae18f809 | |||
| 396c76892c | |||
| c329d7dd4e | |||
| ca3871e4f6 | |||
| d1c6c9a348 | |||
| d5260811dc | |||
| ce155b4d35 | |||
| 65aca43f3f | |||
| 96418f577d | |||
| 2ee9064175 | |||
| 4042681e83 | |||
| cdf13df87d | |||
| 50037ae611 | |||
| e38244e7c0 | |||
| 4f0eae4a6d | |||
| 438e58cc1c | |||
| 4bfd1c4a2a | |||
| abfdb4befc | |||
| 5a1ffabd03 | |||
| 66bf48b6e6 | |||
| bf7acebc30 | |||
| 975c1dc46f | |||
| 8cf2162121 | |||
| 9980528f1e | |||
| 0e34f6cfb8 | |||
| 581b34b586 | |||
| 20581afe80 | |||
| 3861a96d5a | |||
| af44bde349 | |||
| 4736067ed2 | |||
| 2e686bcca7 | |||
| 8eef599aa6 | |||
| afb85320bf | |||
| 4b8dabddae | |||
| ab5c0a43bd | |||
| 65f215eee2 | |||
| e7abed2def | |||
| 66c3a25fe1 | |||
| d9f03cafbe | |||
| 639231388c | |||
| fe44d27cde | |||
| b71248e0f3 | |||
| 4db6e9a69a | |||
| a6d6859aab | |||
| 55f8e04570 | |||
| a1f206804c | |||
| 18c3f768a3 | |||
| 0e277a28d8 | |||
| 081e70c7f3 | |||
| 44007809fd | |||
| 827e1c879e | |||
| 1a7e6629fb | |||
| 4164903d0e | |||
| 5bedcf0a1c | |||
| f1db331e5d | |||
| 3df39a1f78 | |||
| 59459fc6ca | |||
| 83dcd91223 | |||
| ca530216ec | |||
| c2ac40ca00 | |||
| 14e59ca91a | |||
| 643522774e | |||
| cb3ec490a5 | |||
| 4358b2fd71 | |||
| 6c6a0073bf | |||
| f86cf8b9c3 | |||
| 0444eb1f80 | |||
| 45d2ebfc69 | |||
| acbfbc29b3 | |||
| 923f4aeb8f | |||
| 381103678d | |||
| 80247a993d | |||
| 29026f00db | |||
| 25c6350a88 | |||
| c0af811d13 | |||
| 01d21b3ea2 | |||
| df1cd3d5da | |||
| 1bab5a3625 | |||
| 911daba417 | |||
| 9b4e7f4cfc | |||
| 8c4e057c91 | |||
| cd0c502986 | |||
| 7436c51592 | |||
| 95863b81a3 | |||
| 49fbbec138 | |||
| cc2d1399ab | |||
| fcf02a427c | |||
| 73a66e5b1a | |||
| 8b48c39675 | |||
| 055f6d06ae | |||
| 23ab5ba436 | |||
| a655f02fcc | |||
| 92aa47e0bc | |||
| 8cdcda24e1 | |||
| a28dd7dbc3 | |||
| cd7fdcf026 | |||
| 81b081c67d | |||
| fb07f84709 | |||
| 0c0f992a5c | |||
| 64663cf3bd | |||
| e518ba5de5 | |||
| 2dc08498c4 | |||
| f3135499c2 | |||
| 5e093d105a | |||
| b09393e580 | |||
| 43c9310f2e | |||
| b862b62fb9 | |||
| e8d95c4e7e | |||
| 234aafe368 | |||
| 418ceadc2b | |||
| 12840fd46c | |||
| 8dd140d50d | |||
| 81da9b6187 | |||
| fdfcb95711 | |||
| 8d9a65d226 | |||
| 777438f7fc | |||
| d386be9d5d | |||
| 78f81de607 | |||
| b3b7a98b8e | |||
| b1bc31ae0e | |||
| 4c68aff164 | |||
| b3d1e90132 | |||
| 6e7e5822fb | |||
| 237de8786b | |||
| 6f9b937819 | |||
| 96535936a5 | |||
| f2c02fe3bb | |||
| 38ab245727 | |||
| 447de493d3 | |||
| f03a672ac0 | |||
| 6a4d33e3e6 | |||
| aa0d967512 | |||
| fd0a70f87e | |||
| 12ed9958e5 | |||
| 58f1af736e | |||
| 256582455b | |||
| b852e0492e | |||
| 37aa2a4bd2 | |||
| 6736b56964 | |||
| 41b12f96a5 | |||
| 12fa2d9178 | |||
| 7c4b2d67f6 | |||
| 487867d3aa | |||
| 29ba1c1c64 | |||
| 6c93b818af | |||
| 9d2216d84f | |||
| 093b8557ce | |||
| cf9674a713 | |||
| ddeb64e4dd | |||
| 109139b07f | |||
| ec9215fbc1 | |||
| 222f309be5 | |||
| 0ae24ebd1b | |||
| 94c5cf7457 | |||
| 1a70acc7c5 | |||
| 866c4cd4ec | |||
| bae023c075 | |||
| a6d24b73bd | |||
| 791a45c3da | |||
| b3375209c0 | |||
| 3c3bea853e | |||
| ee02cd1a23 | |||
| 4ac0069541 | |||
| 0d9f136298 | |||
| 1b0dbb2b34 | |||
| 01f945c459 | |||
| 58651f9ff6 | |||
| 7aacb7d136 | |||
| ca2416f431 | |||
| 19696ec37f | |||
| ec20424afb | |||
| a9ffc5d23b | |||
| 36b2223600 | |||
| 52d60ea049 | |||
| 88c5dfecb0 | |||
| 1f454dd36e | |||
| f1612bbc2c | |||
| a8bc213609 | |||
| d83bde7b0f | |||
| 293fb90057 | |||
| 05b444ae8a | |||
| b1574fba1a | |||
| 87112f46f7 | |||
| 26c628e81a | |||
| a37a156977 | |||
| bca528b89a | |||
| dc01b2136e | |||
| 5c5ad7b16a | |||
| 3834d248de | |||
| b3aee2deb2 | |||
| 5cb92847c4 | |||
| 666e00b097 | |||
| e22e6188cf | |||
| 6495c220a9 | |||
| e47155fe77 | |||
| 95280cac61 | |||
| 9be459e22f | |||
| 6c2e4c823c | |||
| 2d8ed8d400 | |||
| 24d19e29c0 | |||
| bc15f7157e | |||
| 720fae1bbe | |||
| d82a6d11f9 | |||
| 0e1388a2fd | |||
| 4bd2abebd2 | |||
| 349f970d82 | |||
| 01a20c0a82 | |||
| db94cb6941 | |||
| 2d66e7e804 | |||
| 60734cd2db | |||
| f5451f5bce | |||
| e322d7f1df | |||
| 96f4b45eab | |||
| 11d883f2a6 | |||
| 66bc2db9d1 | |||
| 96e58ed708 | |||
| ad8424e6d1 | |||
| 817876d6fe | |||
| 4d1c0647c8 | |||
| 5bd6229ac1 | |||
| b67d398976 | |||
| c12d5a1142 | |||
| 90a0cb3ad2 | |||
| 2eb20b5743 | |||
| a70e279787 | |||
| a82cf78743 | |||
| 80854a2c39 | |||
| bd73c92bb5 | |||
| de3b9c78f3 | |||
| ecfcfa977d | |||
| 4e32c8f56e | |||
| 5461e0a056 | |||
| b2a87732c9 | |||
| ea55c60fe3 | |||
| a6f05a05e0 | |||
| 8819fdde7a | |||
| 1808ad3c6d | |||
| 440479be65 | |||
| d35f6e80df | |||
| 0bd8f12c64 | |||
| 9e269500d2 | |||
| 658cc9cd23 | |||
| aa4cf039bf | |||
| 4b68e3f7fe | |||
| 6e437f5103 | |||
| ccd6f5b640 | |||
| c7db73ec6b | |||
| 4f05b2b2fc | |||
| b4810cc153 | |||
| 2f1189d766 | |||
| b1eccbe7bf | |||
| c2bd604574 | |||
| b15d1043d1 | |||
| e89d1692e5 | |||
| b0399a9f9c | |||
| 69ffe8defb | |||
| 0e11e9f7f4 | |||
| 20d0136449 | |||
| 3e3d180edb | |||
| 5b4433d50b | |||
| 0db7be7cb8 | |||
| 37434dca9c | |||
| 3ec8e09b8a | |||
| db843fd786 | |||
| 97f57a698b | |||
| 62a6143de1 | |||
| 5c9a4d2328 | |||
| 66780ca8aa | |||
| 4a90819ba6 | |||
| 08e8dbec66 | |||
| 77a1488dd2 | |||
| e5d10e4bf7 | |||
| 5528c400d0 | |||
| 43154a6a64 | |||
| 34160210b4 | |||
| b31f827d9b | |||
| 3dbf9f25e1 | |||
| a158a93198 | |||
| 2d41f0a3c1 | |||
| 9021652bd3 | |||
| 48899c0ba7 | |||
| e24a6a189a | |||
| b20e550e89 | |||
| ad230ae351 | |||
| 0ee24c204f | |||
| 43adf5863d | |||
| c5193f1e74 | |||
| 1893fea2ea | |||
| acf2d25cd5 | |||
| 3cc6ff972b | |||
| c82b51d8da | |||
| 3b476dbd6c | |||
| a6e2a3fc30 | |||
| 767fceb6f0 | |||
| 54e9226bdd | |||
| 0c235e8edd | |||
| 9bb706c627 | |||
| 6d4e502109 | |||
| 1eeab81136 | |||
| 5f7f31e7c9 | |||
| b7ad24cea9 | |||
| 6e03b80cd0 | |||
| d4814abf5f | |||
| cdee56670e | |||
| 63a732f71e | |||
| 8c580647fd | |||
| fb6b984be4 | |||
| 9eaf9191d8 | |||
| d4ddfc18f5 | |||
| 4206fd3bce | |||
| e8633acdca | |||
| 47c1f224dc | |||
| a49c5e804c | |||
| 399ba068e1 | |||
| f3febd91ac | |||
| 4873ff5f39 | |||
| 52646de997 | |||
| f311b5f77b | |||
| 4219858cc2 | |||
| 50e9149f90 | |||
| bb58b03aef | |||
| cd2fabe2f1 | |||
| e63689a66f | |||
| 6bc3146a79 | |||
| 327c365a41 | |||
| 75c78de2b3 | |||
| 7f228cc6f4 | |||
| 48dee43f04 | |||
| c0f7585f95 | |||
| 363c64c04f | |||
| 207976b5fe | |||
| 50728fecb3 | |||
| 859ea21294 | |||
| f3a623dbbc | |||
| dd8efc774c | |||
| a5d4a39e6d | |||
| f7017e22a0 | |||
| 504a77f44d | |||
| b1135d3e02 | |||
| 35ae37acb5 | |||
| 7beaa02443 | |||
| e3b2ac5313 | |||
| 642ffe507f | |||
| cf2e2f54c7 | |||
| b37e67aec2 | |||
| 5979e2483e | |||
| 173dbba314 | |||
| 403f2419d6 | |||
| b83e6d9dfc | |||
| 6aba69af41 | |||
| 967740726a | |||
| aeed4279d7 | |||
| 3af7a78855 | |||
| fbb179e7a6 | |||
| 90107197c7 | |||
| 9bc94d7f80 | |||
| 04a6e02b58 | |||
| 80edf00e0d | |||
| 0932fee6b2 | |||
| b6c62d5650 | |||
| 99c79ebf7e | |||
| 4f3783760b | |||
| 65ffa3827a | |||
| 035a670993 | |||
| adfedc643b | |||
| 11d19f32e1 | |||
| 2584c78959 | |||
| f83f28eacc | |||
| a94fb22965 | |||
| 119eebe3ca | |||
| 3fd6c7d28c | |||
| 55d3a13b59 | |||
| 467b3d3161 | |||
| e9ba4fb43c | |||
| 3563f218ec | |||
| f4b1b82f47 | |||
| 51d7f89ece | |||
| 73e6a7aef6 | |||
| 98c97c8047 | |||
| da52245cc8 | |||
| 6b461f0f8a | |||
| 66b7a217c6 | |||
| e51debfab5 | |||
| 2caa234d78 | |||
| dc1a82772b | |||
| 2d13252e7f | |||
| 5233780b1c | |||
| f1cd4984a1 | |||
| 6bf9d35ba8 | |||
| 6af1c8bb1f | |||
| 994c7be384 | |||
| 1a65d66361 | |||
| 3d8f778457 | |||
| a3663bc40c | |||
| 39d15f6f7e | |||
| fd92794e43 | |||
| be28cb56ff | |||
| 8a2cff0607 | |||
| c2a49fc1c2 | |||
| dd986b3340 | |||
| 00960518d3 | |||
| f62c2ad8e5 | |||
| ad941f038c | |||
| 4edddaeb2d | |||
| 5bb49ff82b | |||
| 3ed3fab322 | |||
| 0827230559 | |||
| 8b9fb7b105 | |||
| ac13b5523f | |||
| d52242c4ae | |||
| 9e86e12f6f | |||
| d456baf82e | |||
| 1441c54100 | |||
| b9e6974c8e | |||
| a0f6d0c326 | |||
| 8cc849de4f | |||
| d156b4ab86 | |||
| cd132b39ed | |||
| 07cdc040b9 | |||
| 3e2f129922 | |||
| 0689d2c0d7 | |||
| 327949573d | |||
| 79568bde6f | |||
| 0fad10f942 | |||
| e4f68cc58d | |||
| 4b39fb88ae | |||
| 7868600d6b | |||
| c6bb8b9b64 | |||
| 6f4566aec7 | |||
| 31adc9851a | |||
| c2460c024a | |||
| e7e003521d | |||
| 7d3e9538f0 | |||
| c276aab07b | |||
| 796b5d4a3f | |||
| e69f129532 | |||
| 1a279cc652 | |||
| f099a24c94 | |||
| 2218e346ae | |||
| 2a994cb96e | |||
| f07316cd2c | |||
| ac25315862 | |||
| b95ce71aaf | |||
| 29b2db3a67 | |||
| a9d2b13fa1 | |||
| 904c8f5a8a | |||
| 62ff2e87b3 | |||
| b3e2607291 | |||
| 6efb114f27 | |||
| 76322a79de | |||
| 390d3d8089 | |||
| d2064f1190 | |||
| 234b1490cb | |||
| f6e33b54b7 | |||
| 82e86038c1 | |||
| 379e7ffd5f | |||
| 97af81500b | |||
| a8a939e65e | |||
| cc8286b25e | |||
| c320f9ea81 | |||
| 0523df8827 | |||
| ac3a5df3b5 | |||
| 76311fe551 | |||
| 6c7109309f | |||
| 3326fdba35 | |||
| 847aca86cf | |||
| 17a41557f2 | |||
| f0d12b6e81 | |||
| f0793fbae6 | |||
| 957462263f | |||
| 848e50c5b5 | |||
| 715c72fac2 | |||
| d7efedefde | |||
| 114c1a93d2 | |||
| c2e3d19e06 | |||
| d7a398bc11 | |||
| e4166af294 | |||
| 873bbd4ba1 | |||
| d9318db068 | |||
| 342ada342a | |||
| 7f5d4a1a79 | |||
| 2fafcce00c | |||
| 9e99f617ec | |||
| f2533a7645 | |||
| a49fb6556a | |||
| ded5b872b9 | |||
| 07b9fc12aa | |||
| 8cf0f1f4b4 | |||
| 50a1e7d737 | |||
| 421fe63583 | |||
| ff0432af99 | |||
| 69f8408b04 | |||
| db2795f4b1 | |||
| 95f07a831b | |||
| 465c2daa6b | |||
| 06788bac27 | |||
| 42ea8aabe0 | |||
| b2c8866cbf | |||
| 310f67b835 | |||
| cb102a5d0b | |||
| f5fee4c7af | |||
| bd19595461 | |||
| 604f7b13e7 | |||
| f4617ef46a | |||
| 53ed89a9e0 | |||
| e63da149b5 | |||
| ed1e87c051 | |||
| fdae8028d6 | |||
| c76a89d22a | |||
| 3d32a4d0d2 | |||
| 608862b8d2 | |||
| df35898657 | |||
| 380b55a1f1 | |||
| ef8e255fd9 | |||
| 5f559b47f8 | |||
| da3bdd9824 | |||
| 12cf66da2b | |||
| 5b05f21261 | |||
| 85025db6dd | |||
| 3c434977f0 | |||
| 8c31ac1950 | |||
| 5d68fb13ea | |||
| 9a899b14b1 | |||
| ea343befaf | |||
| 96d809c983 | |||
| ec6e1ff8bc | |||
| 1df1c2d0c2 | |||
| 738a39cc0d | |||
| 758963eff5 | |||
| 70e5b37f4f | |||
| 9609fe68f0 | |||
| e73ac88cf2 | |||
| 0d9305c70a | |||
| 7abd854183 | |||
| 95778d9453 | |||
| 8cfa657d89 | |||
| 84bdfa4ac5 | |||
| 7de56dad44 | |||
| 02d1e1f2e9 | |||
| 1cc14d25dc | |||
| 392e51924b | |||
| 4094a5bb2c | |||
| 9df3f18084 | |||
| bcad837abd | |||
| 37b5380332 | |||
| d876bcc5ec | |||
| a32774f7c9 | |||
| fe5bf44c65 | |||
| 2e4ee67fea | |||
| 48ae43c61e | |||
| 57b398139b | |||
| 548b20f75a | |||
| 99848bfcd9 | |||
| 9665e33445 | |||
| 19e32b1d0c | |||
| 8ef4881f88 | |||
| 6bb4175d83 | |||
| 041fcd1752 | |||
| b37a9d44e8 | |||
| 735a076eb3 | |||
| 3a88bb5f32 | |||
| 4c0c225a19 | |||
| 8138e1f91c | |||
| 05852215dc | |||
| 311c6ce026 | |||
| fb50c9bf5e | |||
| a9e5c1ee3a | |||
| e28e55aea8 | |||
| 6aa35066f2 | |||
| 3cab375630 | |||
| 9052010557 | |||
| bdc613c1df | |||
| 262d09de55 | |||
| 6e0bc0ef9b | |||
| 873367522a | |||
| cd7c70b0a1 | |||
| 671b1cdf4e | |||
| 19d2e21aaf | |||
| 3473e1cb60 | |||
| b34af189e6 | |||
| 3fb6ed332a | |||
| 2fe5076375 | |||
| 394c26b05b | |||
| 0dacd8bfda | |||
| a29dd08cd0 | |||
| 5540a3de6d | |||
| c2a68da13e | |||
| dcd8c74ae8 | |||
| 7d8437b78f | |||
| 5993280585 | |||
| 776392cee4 | |||
| 25fa4c6c83 | |||
| 40c7810080 | |||
| ad9f80c1c5 | |||
| b6acf05f80 | |||
| a912bad39d | |||
| 5d99ccd05a | |||
| 90d2fc50e9 | |||
| 16e62faea8 | |||
| 54003d6fd0 | |||
| d9485fce89 | |||
| 8e928e75e4 | |||
| 0018ebb50b | |||
| 04e6f0dfa0 | |||
| fa04c0e0df | |||
| ac043f3e9d | |||
| b4e41a481b | |||
| a499791366 | |||
| 48c5381ac1 | |||
| bb29989cac | |||
| 9593f026a9 | |||
| 13b6868242 | |||
| 7c28f1cf7b | |||
| a0a93e6f8d | |||
| c4084caf1e | |||
| a4b9296639 | |||
| 3cd499c1a7 | |||
| 4c969e8fbe | |||
| e24d630008 | |||
| 72d9b91ce5 | |||
| aa2ba3ea27 | |||
| 0fade9d7af | |||
| 5a2a57e052 | |||
| fbdca3413b | |||
| a958188e19 | |||
| fecf0c1494 | |||
| ebd16ea6fc | |||
| 35eab87f76 | |||
| ef639a6e17 | |||
| 4449e8b51d | |||
| ab50c87bf2 | |||
| 099633a180 | |||
| 7f101b2f41 | |||
| defa1e3a91 | |||
| df7747bbe6 | |||
| 7ea80521bb | |||
| 676dc8b5ac | |||
| 90df8d054b | |||
| b89772f06b | |||
| ac4aeaca3d | |||
| a535e12b9e | |||
| f0b9b4c165 | |||
| 504d4ad8bd | |||
| 174843047b | |||
| 4eda06b7e8 | |||
| 9e4cfc42bf | |||
| 7f8eb2c50b | |||
| 729c3f373b | |||
| cf41608a09 | |||
| 17233b9d8b | |||
| 6e9a43cb92 | |||
| 7937fef2f7 | |||
| c3a9fb96d2 | |||
| 3d64c8d0b6 | |||
| 77b66f56e1 | |||
| bc51c0576c | |||
| f4c2f82da9 | |||
| bbcf953d34 | |||
| 9f93b7fb53 | |||
| a405ffd68d | |||
| a1f245126e | |||
| 21039d13d2 | |||
| a11e85066f | |||
| 4cabbc027a | |||
| 4809217dc0 | |||
| 4d69c43531 | |||
| 4ef43ab1c8 | |||
| eb94e8ca83 | |||
| 049eb78586 | |||
| 797df745cd | |||
| af72e72dc7 | |||
| fecc1ded2a | |||
| 90235f36b8 | |||
| d663c4a254 | |||
| 6892171fee | |||
| bd97522a7c | |||
| 3e88c0eb3a | |||
| b61c5a3a18 | |||
| 1a510b4a26 | |||
| 40dac3634e | |||
| bc2dfd243a | |||
| 40b66b8383 | |||
| 7be84aded8 | |||
| c6e4b8811d | |||
| 0aeb4faa87 | |||
| 54649b315a | |||
| d13d83d81a | |||
| 842015ef19 | |||
| d0f62fbb87 | |||
| 4fa19c35b5 | |||
| fede074f3a | |||
| 73b1489fbc | |||
| 48200e2976 | |||
| 51cea233f1 | |||
| 71426c90f9 | |||
| 2f85a9e691 | |||
| a129ff2a7d | |||
| 501829319e | |||
| 0364386fa7 | |||
| 16602f09c4 | |||
| 8602baa246 | |||
| a10eccf11f | |||
| db1ffacc10 | |||
| 55fe398822 | |||
| 8e10651026 | |||
| fc294f6e01 | |||
| f22af44dd1 | |||
| f19b51afe0 | |||
| 495c246850 | |||
| 9f1957be9d | |||
| 5f560144b7 | |||
| 653fcde142 | |||
| 12c001afe7 | |||
| 36dc7c5b99 | |||
| f935fe02bd | |||
| e57dd3faa5 | |||
| 778ca40af3 | |||
| 2329966acc | |||
| dacf6d146c | |||
| fc15c8d04d | |||
| f811daf33b | |||
| 57880bc9da | |||
| 1ebee07e78 | |||
| 1cfa43cf3b | |||
| 5b02e3bc1b | |||
| 62e1051d4c | |||
| 05cbced73d | |||
| 00d7f1810c | |||
| f9a13fdbfd | |||
| 70be235d03 | |||
| 79ba177ba4 | |||
| d6048b8a61 | |||
| a222d1b8da | |||
| b77c4b2bdd | |||
| 554cb205f4 | |||
| 0e8ba3a194 | |||
| 67064f85dc | |||
| aac8571003 | |||
| ac62098a81 | |||
| b335fe1455 | |||
| e5a94ff402 | |||
| a8ece76eac | |||
| 6f7c87a070 | |||
| 02fa792b81 | |||
| fd43aa8bdf | |||
| 490a08af92 | |||
| 2097de0a7e | |||
| cb8352f9c2 | |||
| a525ec46e5 | |||
| 5ffcea26af | |||
| 56f3965e91 | |||
| 0ad28e0595 | |||
| 28c0b86278 | |||
| 37eabeed61 | |||
| e54c17ecd7 | |||
| 344fe9eb0a | |||
| a95a257ae9 | |||
| 9c46cb37df | |||
| a91bbbc401 | |||
| 5c90e561b4 | |||
| ae6d55badc | |||
| 41deba522f |
@@ -0,0 +1,9 @@
|
||||
.*.orig$
|
||||
.*\.o$
|
||||
.*~$
|
||||
build-dir
|
||||
build
|
||||
.*\.sconsign
|
||||
doc/html.*
|
||||
doc/latex.*
|
||||
.lock-wscript
|
||||
@@ -0,0 +1,4 @@
|
||||
56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1
|
||||
7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2
|
||||
0dc81e76166c56aaae64da48b673b62155943aad packet-history-working
|
||||
38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
|
||||
@@ -1 +1,6 @@
|
||||
Bilbo The Hobbit
|
||||
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)
|
||||
Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
|
||||
George F. Riley (riley@ece.gatech.edu)
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -1,3 +1,171 @@
|
||||
empty README
|
||||
|
||||
random test
|
||||
The Network Simulator, Version 3
|
||||
--------------------------------
|
||||
|
||||
Table of Contents:
|
||||
------------------
|
||||
|
||||
1) An Open Source project
|
||||
2) An overview of the ns-3 project
|
||||
3) Building ns-3
|
||||
4) Running ns-3
|
||||
5) Getting access to the ns-3 documentation
|
||||
6) Working with the development version of ns-3
|
||||
|
||||
|
||||
1) An Open Source project
|
||||
-------------------------
|
||||
|
||||
ns-3 is an Open Source project. We intend to make this
|
||||
project a successful collaborative project: we hope that
|
||||
the missing pieces of the models we have not yet implemented
|
||||
will be contributed by the community in an open collaboration
|
||||
process.
|
||||
|
||||
Contributing to the ns-3 project is still a very informal
|
||||
process because that process depends heavily on the background
|
||||
of the people involved, the amount of time they can invest
|
||||
and the type of model they want to work on.
|
||||
|
||||
Despite this lack of a formal process, there are a number of
|
||||
steps which naturally stem from the open-source roots of the
|
||||
project. These steps are described in doc/contributing.txt
|
||||
|
||||
2) An overview of the ns-3 project
|
||||
----------------------------------
|
||||
|
||||
This package contains the latest version of ns-3 which aims
|
||||
at being a replacement for ns-2. Currently, ns-3 provides a
|
||||
number of very simple network simulation models:
|
||||
- an ipv4 and udp stack
|
||||
- arp support at the bottom of the stack
|
||||
- point-to-point physical-layer links
|
||||
- OnOff traffic generator
|
||||
|
||||
Our focus to date has been on getting an overall software
|
||||
framework in place. The framework is there to make adding
|
||||
new models as simple as possible:
|
||||
- an extensive tracing system can be used to connect
|
||||
any number of arbitrary trace sources to any number
|
||||
of trace sinks. This tracing system is decoupled
|
||||
from the act of serializing the trace events to a
|
||||
file: users can and should provide their own
|
||||
trace handling routines.
|
||||
|
||||
- simple file trace serialization support is included
|
||||
to both text and pcap files.
|
||||
|
||||
- adding new MAC-level models simply requires subclassing
|
||||
the pair of classes NetDevice and Channel.
|
||||
|
||||
- adding new traffic generation algorithms is also very
|
||||
simple through the Application and the Socket classes.
|
||||
|
||||
3) Building ns-3
|
||||
----------------
|
||||
|
||||
The code for the framework and the default models provided
|
||||
by ns-3 is built as a set of libraries. User simulations
|
||||
are expected to be written as simple programs that make
|
||||
use of these ns-3 libraries.
|
||||
|
||||
To build the set of default libraries and the example
|
||||
programs included in this package, you need to use the
|
||||
tool 'scons'. Detailed information on how to install
|
||||
and use scons is included in the file doc/build.txt
|
||||
|
||||
However, the real quick and dirty way to get started is to
|
||||
type the command "scons" the the directory which contains
|
||||
this README file. The files built will be copied in the
|
||||
build-dir/dbg-shared/bin and build-dir/dbg-shared/lib
|
||||
directories. build-dir/dbg-shared/bin will contain
|
||||
one binary for each of the sample code in the 'samples'
|
||||
directory and one binary for each of the detailed examples
|
||||
found in the 'examples' directory.
|
||||
|
||||
The current codebase is expected to build and run on the
|
||||
following set of platforms:
|
||||
- linux x86 gcc 4.2, 4.1, and, 3.4.
|
||||
- linux x86_64 gcc 4.0
|
||||
- MacOS X ppc and x86
|
||||
|
||||
The current codebase is expected to fail to build on
|
||||
the following platforms:
|
||||
- gcc 3.3 and earlier
|
||||
- optimized builds on linux x86 gcc 4.0
|
||||
- cygwin
|
||||
|
||||
Other platforms may or may not work: we welcome
|
||||
patches to improve the portability of the code to these
|
||||
other platforms.
|
||||
|
||||
4) Running ns-3
|
||||
---------------
|
||||
|
||||
On recent Linux systems, once you have built ns-3, it
|
||||
should be easy to run the sample programs with the
|
||||
following command:
|
||||
|
||||
./build-dir/dbg-shared/bin/simple-p2p
|
||||
|
||||
or:
|
||||
|
||||
cd build-dir/dbg-shared/bin
|
||||
./simple-p2p
|
||||
|
||||
That program should generate a simple-p2p.tr text
|
||||
trace file and a set of simple-p2p-xx-xx.pcap binary
|
||||
pcap trace files, which can be read by tcpdump.
|
||||
|
||||
5) Getting access to the ns-3 documentation
|
||||
-------------------------------------------
|
||||
|
||||
Once you have verified that your build of ns-3 works by running
|
||||
the simple-p2p example as outlined in 4) above, it is
|
||||
quite likely that you will want to get started on reading
|
||||
some ns-3 documentation.
|
||||
|
||||
All of that documentation should always be available from
|
||||
the ns-3 website: http:://www.nsnam.org/ but we
|
||||
include some of it in this release for ease of use.
|
||||
|
||||
This documentation includes:
|
||||
|
||||
- an architecture document which describes a very
|
||||
high-level view of ns-3: it tries to explain the
|
||||
use-cases the ns-3 developers really focused on when
|
||||
doing the initial design and then goes on to explain
|
||||
the structure of the resulting framework.
|
||||
See the file doc/architecture.pdf
|
||||
|
||||
- a wiki for user-contributed tips: http://www.nsnam.org/wiki/
|
||||
|
||||
- an API documentation generated using doxygen: this is
|
||||
a reference manual, most likely not very well suited
|
||||
as introductory text:
|
||||
http://www.nsnam.org/doxygen/index.html
|
||||
|
||||
If you want to re-generate this documentation, you can
|
||||
easily do so:
|
||||
|
||||
- doc/architecture.pdf is generated from the architecture.tex
|
||||
file in http://code.nsnam.org/docs
|
||||
|
||||
- the doxygen documentation is generated from the doc/doxygen.conf
|
||||
configuration file. The command "scons doc" will generate it
|
||||
as doc/html/index.html if you have installed the doxygen tools
|
||||
(see http://www.doxygen.org)
|
||||
|
||||
6) Working with the development version of ns-3
|
||||
-----------------------------------------------
|
||||
|
||||
If you want to download and use the development version
|
||||
of ns-3, you need to use the tool 'mercurial'. A quick and
|
||||
dirty cheat sheet is included in doc/mercurial.txt but
|
||||
reading through the mercurial tutorials included on the
|
||||
mercurial website is usually a good idea if you are not
|
||||
familiar with it.
|
||||
|
||||
If you have successfully installed mercurial, you can get
|
||||
a copy of the development version with the following command:
|
||||
"hg clone http://code.nsnam.org/ns-3-dev"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
ns-3 RELEASE NOTES
|
||||
|
||||
This file contains ns-3 release notes (most recent releases first).
|
||||
|
||||
Release 3.0.4 (2007/07/15)
|
||||
========================
|
||||
|
||||
- Enable waf as the default build system.
|
||||
- Per-packet metadata: a system to track which headers and trailers
|
||||
are added to a packet
|
||||
- Simplifications to point-to-point devices and channel
|
||||
|
||||
Release 3.0.3 (2007/06/15)
|
||||
========================
|
||||
|
||||
- Enable Waf for release tarballs: users can now build ns-3
|
||||
with the "waf" tool. See doc/build-waf.txt.
|
||||
- Add support for variable time precision: it is now possible
|
||||
to run a simulation with an accuracy which is higher or lower
|
||||
than a nanosecond: seconds, milliseconds, microseconds,
|
||||
femtoseconds and picoseconds are supported.
|
||||
- Optimize and rework the COM framework, solidify the component
|
||||
manager
|
||||
- Many small API cleanups
|
||||
|
||||
Release 3.0.2 (2007/05/18)
|
||||
========================
|
||||
|
||||
- Implement a new memory management infrastructure based
|
||||
on reference counting and smart pointers (the latter being
|
||||
optional)
|
||||
|
||||
- Implement a COM-like framework with support for QueryInterface
|
||||
to provide object extensibility
|
||||
|
||||
- Add support for a BSD-style socket API for user applications
|
||||
|
||||
Release 3.0.1 (2007/03/31)
|
||||
========================
|
||||
|
||||
- First public release; not yet pre-alpha.
|
||||
|
||||
- Simple UDP-based simulation script (examples/simple-p2p.cc)
|
||||
+484
@@ -0,0 +1,484 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
import os.path
|
||||
import build
|
||||
|
||||
version_file = open ('VERSION', 'r')
|
||||
version = version_file.readline ()
|
||||
version_file.close ()
|
||||
version = version.strip ()
|
||||
|
||||
ns3 = build.Ns3()
|
||||
ns3.build_dir = 'build-dir'
|
||||
ns3.version = version
|
||||
ns3.name = 'ns3'
|
||||
ns3.distname = 'ns'
|
||||
ns3.doxygen_config = os.path.join('doc', 'doxygen.conf')
|
||||
ns3.add_extra_dist(os.path.join('doc', 'main.txt'))
|
||||
ns3.add_extra_dist ('doc/architecture.pdf')
|
||||
ns3.add_extra_dist ('doc/contributing.txt')
|
||||
ns3.add_extra_dist ('doc/build.txt')
|
||||
ns3.add_extra_dist ('doc/codingstd.txt')
|
||||
ns3.add_extra_dist ('doc/mercurial.txt')
|
||||
ns3.add_extra_dist ('README')
|
||||
ns3.add_extra_dist ('RELEASE_NOTES')
|
||||
ns3.add_extra_dist ('AUTHORS')
|
||||
ns3.add_extra_dist ('VERSION')
|
||||
|
||||
ns3.add_extra_dist('ns3/_placeholder_')
|
||||
for wscript in [
|
||||
"src/core/wscript",
|
||||
"src/node/wscript",
|
||||
"src/devices/p2p/wscript",
|
||||
"src/common/wscript",
|
||||
"src/applications/wscript",
|
||||
"src/simulator/wscript",
|
||||
"src/internet-node/wscript",
|
||||
"src/wscript",
|
||||
"utils/wscript",
|
||||
"samples/wscript",
|
||||
"examples/wscript",
|
||||
"wscript",
|
||||
]:
|
||||
ns3.add_extra_dist(wscript)
|
||||
ns3.add_extra_dist('waf.bat')
|
||||
|
||||
|
||||
|
||||
#
|
||||
# The Core module
|
||||
#
|
||||
core = build.Ns3Module('core', 'src/core')
|
||||
ns3.add(core)
|
||||
core.add_sources([
|
||||
'callback-test.cc',
|
||||
'debug.cc',
|
||||
'assert.cc',
|
||||
'ptr.cc',
|
||||
'object.cc',
|
||||
'test.cc',
|
||||
'random-variable.cc',
|
||||
'rng-stream.cc',
|
||||
'uid-manager.cc',
|
||||
'default-value.cc',
|
||||
'command-line.cc',
|
||||
'type-name.cc',
|
||||
'component-manager.cc',
|
||||
])
|
||||
env = Environment()
|
||||
if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin':
|
||||
core.add_external_dep('pthread')
|
||||
core.add_sources([
|
||||
'unix-system-wall-clock-ms.cc',
|
||||
])
|
||||
elif env['PLATFORM'] == 'win32':
|
||||
core.add_sources([
|
||||
'win32-system-wall-clock-ms.cc',
|
||||
])
|
||||
core.add_headers ([
|
||||
'uid-manager.h',
|
||||
'singleton.h',
|
||||
])
|
||||
core.add_inst_headers([
|
||||
'system-wall-clock-ms.h',
|
||||
'empty.h',
|
||||
'callback.h',
|
||||
'ptr.h',
|
||||
'object.h',
|
||||
'debug.h',
|
||||
'assert.h',
|
||||
'fatal-error.h',
|
||||
'test.h',
|
||||
'random-variable.h',
|
||||
'rng-stream.h',
|
||||
'default-value.h',
|
||||
'command-line.h',
|
||||
'type-name.h',
|
||||
'component-manager.h',
|
||||
])
|
||||
|
||||
def config_core (env, config):
|
||||
retval = []
|
||||
# XXX This check is primitive but it should be
|
||||
# good enough for now.
|
||||
if config.CheckCHeader ('stdlib.h') == 1:
|
||||
retval.append ('#define HAVE_STDLIB_H 1')
|
||||
retval.append ('#define HAVE_GETENV 1')
|
||||
else:
|
||||
retval.append ('#undef HAVE_STDLIB_H')
|
||||
retval.append ('#undef HAVE_GETENV')
|
||||
return retval
|
||||
core.add_config (config_core)
|
||||
|
||||
#
|
||||
# The Simu module
|
||||
#
|
||||
simu = build.Ns3Module('simulator', 'src/simulator')
|
||||
ns3.add(simu)
|
||||
simu.add_dep('core')
|
||||
simu.add_external_dep('m')
|
||||
simu.add_sources([
|
||||
'high-precision.cc',
|
||||
'time.cc',
|
||||
'event-id.cc',
|
||||
'scheduler.cc',
|
||||
'scheduler-factory.cc',
|
||||
'scheduler-list.cc',
|
||||
'scheduler-heap.cc',
|
||||
'scheduler-map.cc',
|
||||
'event-impl.cc',
|
||||
'simulator.cc',
|
||||
])
|
||||
simu.add_headers([
|
||||
'scheduler-heap.h',
|
||||
'scheduler-map.h',
|
||||
'scheduler-list.h'
|
||||
])
|
||||
simu.add_inst_headers([
|
||||
'high-precision.h',
|
||||
'nstime.h',
|
||||
'event-id.h',
|
||||
'event-impl.h',
|
||||
'simulator.h',
|
||||
'scheduler.h',
|
||||
'scheduler-factory.h',
|
||||
'simulation-singleton.h',
|
||||
])
|
||||
high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
|
||||
if high_precision_as_double == 'y':
|
||||
simu.add_inst_header ('high-precision-double.h')
|
||||
simu.add_source ('high-precision-double.cc')
|
||||
else:
|
||||
simu.add_inst_headers ([
|
||||
'high-precision-128.h',
|
||||
'cairo-wideint-private.h'
|
||||
])
|
||||
simu.add_sources ([
|
||||
'high-precision-128.cc',
|
||||
'cairo-wideint.c',
|
||||
])
|
||||
|
||||
def config_simulator (env, config):
|
||||
retval = []
|
||||
high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
|
||||
if high_precision_as_double == 'y':
|
||||
retval.append ('#define USE_HIGH_PRECISION_DOUBLE 1')
|
||||
else:
|
||||
retval.append ('#undef USE_HIGH_PRECISION_DOUBLE')
|
||||
if config.CheckCHeader ('stdint.h') == 1:
|
||||
retval.append ('#define HAVE_STDINT_H 1')
|
||||
elif config.CheckCHeader ('inttypes.h') == 1:
|
||||
retval.append ('#define HAVE_INTTYPES_H 1')
|
||||
elif config.CheckCHeader ('sys/inttypes.h') == 1:
|
||||
retval.append ('#define HAVE_SYS_INT_TYPES_H 1')
|
||||
return retval
|
||||
simu.add_config (config_simulator)
|
||||
|
||||
|
||||
#
|
||||
# The Common module
|
||||
#
|
||||
common = build.Ns3Module('common', 'src/common')
|
||||
common.add_deps(['core', 'simulator'])
|
||||
ns3.add(common)
|
||||
common.add_sources([
|
||||
'buffer.cc',
|
||||
'chunk.cc',
|
||||
'header.cc',
|
||||
'trailer.cc',
|
||||
'packet-printer.cc',
|
||||
'packet-metadata.cc',
|
||||
'packet.cc',
|
||||
'tags.cc',
|
||||
'pcap-writer.cc',
|
||||
'variable-tracer-test.cc',
|
||||
'trace-context.cc',
|
||||
'trace-resolver.cc',
|
||||
'callback-trace-source.cc',
|
||||
'empty-trace-resolver.cc',
|
||||
'composite-trace-resolver.cc',
|
||||
'trace-root.cc',
|
||||
'data-rate.cc',
|
||||
])
|
||||
common.add_headers ([
|
||||
])
|
||||
common.add_inst_headers([
|
||||
'buffer.h',
|
||||
'chunk.h',
|
||||
'header.h',
|
||||
'trailer.h',
|
||||
'tags.h',
|
||||
'packet.h',
|
||||
'packet-printer.h',
|
||||
'packet-metadata.h',
|
||||
'uv-trace-source.h',
|
||||
'sv-trace-source.h',
|
||||
'fv-trace-source.h',
|
||||
'pcap-writer.h',
|
||||
'callback-trace-source.h',
|
||||
'trace-context.h',
|
||||
'trace-resolver.h',
|
||||
'empty-trace-resolver.h',
|
||||
'composite-trace-resolver.h',
|
||||
'array-trace-resolver.h',
|
||||
'trace-root.h',
|
||||
'terminal-trace-resolver.h',
|
||||
'data-rate.h',
|
||||
])
|
||||
|
||||
node = build.Ns3Module ('node', 'src/node')
|
||||
ns3.add (node)
|
||||
node.add_deps (['core', 'common', 'simulator'])
|
||||
node.add_sources ([
|
||||
'node.cc',
|
||||
'ipv4-address.cc',
|
||||
'net-device.cc',
|
||||
'mac-address.cc',
|
||||
'llc-snap-header.cc',
|
||||
'ipv4-route.cc',
|
||||
'queue.cc',
|
||||
'drop-tail-queue.cc',
|
||||
'channel.cc',
|
||||
'node-list.cc',
|
||||
'socket.cc',
|
||||
'socket-factory.cc',
|
||||
'udp.cc',
|
||||
'ipv4.cc',
|
||||
'application.cc',
|
||||
])
|
||||
node.add_inst_headers ([
|
||||
'node.h',
|
||||
'ipv4-address.h',
|
||||
'net-device.h',
|
||||
'mac-address.h',
|
||||
'ipv4-route.h',
|
||||
'queue.h',
|
||||
'drop-tail-queue.h',
|
||||
'llc-snap-header.h',
|
||||
'channel.h',
|
||||
'node-list.h',
|
||||
'socket.h',
|
||||
'socket-factory.h',
|
||||
'udp.h',
|
||||
'ipv4.h',
|
||||
'application.h',
|
||||
])
|
||||
|
||||
applications = build.Ns3Module ('applications', 'src/applications')
|
||||
ns3.add (applications)
|
||||
applications.add_deps (['node'])
|
||||
applications.add_sources ([
|
||||
'onoff-application.cc',
|
||||
])
|
||||
applications.add_inst_headers ([
|
||||
'onoff-application.h',
|
||||
])
|
||||
|
||||
inode = build.Ns3Module ('internet-node', 'src/internet-node')
|
||||
ns3.add (inode)
|
||||
inode.add_deps (['node'])
|
||||
inode.add_sources ([
|
||||
'internet-node.cc',
|
||||
'l3-demux.cc',
|
||||
'l3-protocol.cc',
|
||||
'ipv4-l4-demux.cc',
|
||||
'ipv4-l4-protocol.cc',
|
||||
'ipv4-header.cc',
|
||||
'udp-header.cc',
|
||||
'ipv4-checksum.cc',
|
||||
'ipv4-interface.cc',
|
||||
'ipv4-l3-protocol.cc',
|
||||
'ipv4-end-point.cc',
|
||||
'udp-l4-protocol.cc',
|
||||
'arp-header.cc',
|
||||
'arp-cache.cc',
|
||||
'arp-ipv4-interface.cc',
|
||||
'arp-l3-protocol.cc',
|
||||
'ipv4-loopback-interface.cc',
|
||||
'header-utils.cc',
|
||||
'udp-socket.cc',
|
||||
'ipv4-end-point-demux.cc',
|
||||
'arp-private.cc',
|
||||
'ipv4-impl.cc',
|
||||
'ipv4-private.cc',
|
||||
'ascii-trace.cc',
|
||||
'pcap-trace.cc',
|
||||
'udp-impl.cc',
|
||||
])
|
||||
inode.add_headers ([
|
||||
'ipv4-checksum.h',
|
||||
'arp-header.h',
|
||||
'arp-cache.h',
|
||||
'arp-l3-protocol.h',
|
||||
'ipv4-loopback-interface.h',
|
||||
'l3-demux.h',
|
||||
'header-utils.h',
|
||||
'arp-ipv4-interface.h',
|
||||
'udp-socket.h',
|
||||
'udp-l4-protocol.h',
|
||||
'arp-private.h',
|
||||
'ipv4-impl.h',
|
||||
'ipv4-private.h',
|
||||
'ipv4-l3-protocol.h',
|
||||
'l3-protocol.h',
|
||||
'ipv4-l4-protocol.h',
|
||||
'ipv4-l4-demux.h',
|
||||
'ipv4-end-point-demux.h',
|
||||
'ipv4-end-point.h',
|
||||
'ipv4-header.h',
|
||||
'udp-header.h',
|
||||
'ipv4-interface.h',
|
||||
'sgi-hashmap.h',
|
||||
'udp-impl.h',
|
||||
])
|
||||
inode.add_inst_headers ([
|
||||
'internet-node.h',
|
||||
'ascii-trace.h',
|
||||
'pcap-trace.h',
|
||||
'ipv4-header.h',
|
||||
'udp-header.h',
|
||||
])
|
||||
|
||||
|
||||
|
||||
p2p = build.Ns3Module ('p2p', 'src/devices/p2p')
|
||||
ns3.add (p2p)
|
||||
p2p.add_deps (['node'])
|
||||
p2p.add_sources ([
|
||||
'p2p-net-device.cc',
|
||||
'p2p-channel.cc',
|
||||
'p2p-topology.cc',
|
||||
])
|
||||
p2p.add_inst_headers ([
|
||||
'p2p-net-device.h',
|
||||
'p2p-channel.h',
|
||||
'p2p-topology.h',
|
||||
])
|
||||
|
||||
|
||||
# utils
|
||||
run_tests = build.Ns3Module('run-tests', 'utils')
|
||||
ns3.add(run_tests)
|
||||
run_tests.set_executable()
|
||||
run_tests.add_deps(['core', 'simulator', 'common'])
|
||||
run_tests.add_source('run-tests.cc')
|
||||
|
||||
bench_object = build.Ns3Module('bench-object', 'utils')
|
||||
ns3.add(bench_object)
|
||||
bench_object.set_executable()
|
||||
bench_object.add_deps(['core'])
|
||||
bench_object.add_source('bench-object.cc')
|
||||
|
||||
bench_packets = build.Ns3Module('bench-packets', 'utils')
|
||||
ns3.add(bench_packets)
|
||||
bench_packets.set_executable()
|
||||
bench_packets.add_deps (['core', 'common'])
|
||||
bench_packets.add_source('bench-packets.cc')
|
||||
|
||||
bench_simu = build.Ns3Module('bench-simulator', 'utils')
|
||||
ns3.add(bench_simu)
|
||||
bench_simu.set_executable()
|
||||
bench_simu.add_dep('simulator')
|
||||
bench_simu.add_source('bench-simulator.cc')
|
||||
|
||||
replay_simu = build.Ns3Module('replay-simulation', 'utils')
|
||||
ns3.add(replay_simu)
|
||||
replay_simu.set_executable()
|
||||
replay_simu.add_dep('simulator')
|
||||
replay_simu.add_source('replay-simulation.cc')
|
||||
|
||||
|
||||
# samples
|
||||
sample_debug = build.Ns3Module('sample-debug', 'samples')
|
||||
sample_debug.set_executable()
|
||||
ns3.add(sample_debug)
|
||||
sample_debug.add_dep('core')
|
||||
sample_debug.add_source('main-debug.cc')
|
||||
sample_debug.add_source('main-debug-other.cc')
|
||||
|
||||
sample_packet_printer = build.Ns3Module('sample-packet-printer', 'samples')
|
||||
sample_packet_printer.set_executable()
|
||||
ns3.add(sample_packet_printer)
|
||||
sample_packet_printer.add_deps (['common', 'internet-node'])
|
||||
sample_packet_printer.add_source('main-packet-printer.cc')
|
||||
|
||||
|
||||
sample_callback = build.Ns3Module('sample-callback', 'samples')
|
||||
sample_callback.set_executable()
|
||||
ns3.add(sample_callback)
|
||||
sample_callback.add_dep('core')
|
||||
sample_callback.add_source('main-callback.cc')
|
||||
|
||||
sample_ptr = build.Ns3Module('sample-ptr', 'samples')
|
||||
sample_ptr.set_executable()
|
||||
ns3.add(sample_ptr)
|
||||
sample_ptr.add_dep('core')
|
||||
sample_ptr.add_source('main-ptr.cc')
|
||||
|
||||
sample_trace = build.Ns3Module('sample-trace', 'samples')
|
||||
#ns3.add(sample_trace)
|
||||
sample_trace.add_dep('common')
|
||||
sample_trace.set_executable()
|
||||
sample_trace.add_source('main-trace.cc')
|
||||
|
||||
sample_query_interface = build.Ns3Module('sample-query-interface', 'samples')
|
||||
ns3.add(sample_query_interface)
|
||||
sample_query_interface.add_dep('common')
|
||||
sample_query_interface.set_executable()
|
||||
sample_query_interface.add_source('main-query-interface.cc')
|
||||
|
||||
sample_simu = build.Ns3Module('sample-simulator', 'samples')
|
||||
ns3.add(sample_simu)
|
||||
sample_simu.set_executable()
|
||||
sample_simu.add_dep('simulator')
|
||||
sample_simu.add_source('main-simulator.cc')
|
||||
|
||||
sample_packet = build.Ns3Module('sample-packet', 'samples')
|
||||
ns3.add(sample_packet)
|
||||
sample_packet.set_executable()
|
||||
sample_packet.add_dep('common')
|
||||
sample_packet.add_source('main-packet.cc')
|
||||
|
||||
sample_test = build.Ns3Module('sample-test', 'samples')
|
||||
sample_test.set_executable()
|
||||
ns3.add(sample_test)
|
||||
sample_test.add_dep('core')
|
||||
sample_test.add_source('main-test.cc')
|
||||
|
||||
sample_simple = build.Ns3Module('sample-simple', 'samples')
|
||||
sample_simple.set_executable()
|
||||
ns3.add(sample_simple)
|
||||
sample_simple.add_deps(['core', 'simulator', 'node', 'internet-node'])
|
||||
sample_simple.add_source('main-simple.cc')
|
||||
|
||||
sample_sp2p = build.Ns3Module('sample-simple-p2p', 'samples')
|
||||
sample_sp2p.set_executable()
|
||||
#n3.add(sample_sp2p)
|
||||
sample_sp2p.add_deps(['core', 'simulator', 'node', 'internet-node', 'p2p'])
|
||||
sample_sp2p.add_source('main-simple-p2p.cc')
|
||||
|
||||
sample_default_value = build.Ns3Module('sample-default-value', 'samples')
|
||||
sample_default_value.set_executable()
|
||||
ns3.add(sample_default_value)
|
||||
sample_default_value.add_deps(['core', 'simulator', 'node', 'p2p'])
|
||||
sample_default_value.add_source('main-default-value.cc')
|
||||
|
||||
sample_object = build.Ns3Module('sample-object', 'samples')
|
||||
sample_object.set_executable()
|
||||
ns3.add(sample_object)
|
||||
sample_object.add_deps(['core'])
|
||||
sample_object.add_source('main-object.cc')
|
||||
|
||||
sample_component_manager = build.Ns3Module('sample-component-manager', 'samples')
|
||||
sample_component_manager.set_executable()
|
||||
ns3.add(sample_component_manager)
|
||||
sample_component_manager.add_deps(['core'])
|
||||
sample_component_manager.add_source('main-component-manager.cc')
|
||||
|
||||
# examples
|
||||
example_simple_p2p = build.Ns3Module('simple-p2p', 'examples')
|
||||
example_simple_p2p.set_executable()
|
||||
ns3.add(example_simple_p2p)
|
||||
example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications'])
|
||||
example_simple_p2p.add_source('simple-p2p.cc')
|
||||
|
||||
ns3.generate_dependencies()
|
||||
@@ -0,0 +1,561 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
# Copyright (c) 2006 INRIA
|
||||
# All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation;
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
from SCons.Environment import Environment
|
||||
from SCons.Builder import Builder
|
||||
from SCons.Action import Action
|
||||
import SCons
|
||||
|
||||
# hack stolen from wengo
|
||||
# to get an ARGUMENTS defined correctly
|
||||
try:
|
||||
ARGUMENTS = SCons.Script.ARGUMENTS
|
||||
COMMAND_LINE_TARGETS = SCons.Script.COMMAND_LINE_TARGETS
|
||||
except AttributeError:
|
||||
from SCons.Script.SConscript import Arguments
|
||||
from SCons.Script.SConscript import CommandLineTargets
|
||||
ARGUMENTS = Arguments
|
||||
COMMAND_LINE_TARGETS = CommandLineTargets
|
||||
|
||||
class Ns3Module:
|
||||
def __init__(self, name, dir):
|
||||
self.sources = []
|
||||
self.inst_headers = []
|
||||
self.headers = []
|
||||
self.extra_dist = []
|
||||
self.deps = []
|
||||
self.external_deps = []
|
||||
self.config = []
|
||||
self.name = name
|
||||
self.dir = dir
|
||||
self.executable = False
|
||||
self.library = True
|
||||
self.ldflags = []
|
||||
self.header_inst_dir = ''
|
||||
def set_library(self):
|
||||
self.library = True
|
||||
self.executable = False
|
||||
def set_executable(self):
|
||||
self.library = False
|
||||
self.executable = True
|
||||
def add_config(self, config_fn):
|
||||
self.config.append(config_fn)
|
||||
def add_extra_dist(self, dist):
|
||||
self.extra_dist.append(dist)
|
||||
def add_external_dep(self, dep):
|
||||
self.external_deps.append(dep)
|
||||
def add_dep(self, dep):
|
||||
self.deps.append(dep)
|
||||
def add_deps(self, deps):
|
||||
self.deps.extend(deps)
|
||||
def add_source(self, source):
|
||||
self.sources.append(source)
|
||||
def add_sources(self, sources):
|
||||
self.sources.extend(sources)
|
||||
def add_header(self, header):
|
||||
self.headers.append(header)
|
||||
def add_headers(self, headers):
|
||||
self.headers.extend(headers)
|
||||
def add_inst_header(self, header):
|
||||
self.inst_headers.append(header)
|
||||
def add_inst_headers(self, headers):
|
||||
self.inst_headers.extend(headers)
|
||||
def add_ldflags (self, ldflags):
|
||||
self.ldflags.extend (ldflags)
|
||||
def add_ldflag (self, ldflag):
|
||||
self.add_ldflags ([ldflag])
|
||||
def set_header_inst_dir (self, inst_dir):
|
||||
self.header_inst_dir = inst_dir
|
||||
|
||||
|
||||
def MyCopyAction(target, source, env):
|
||||
try:
|
||||
if len(target) == len(source):
|
||||
for i in range(len(target)):
|
||||
shutil.copy(source[i].path, target[i].path)
|
||||
return 0
|
||||
else:
|
||||
return 'invalid target/source match'
|
||||
except:
|
||||
print
|
||||
return 'exception'
|
||||
def MyCopyActionPrint(target, source, env):
|
||||
if len(target) == len(source):
|
||||
output = ''
|
||||
for i in range(len(target)):
|
||||
output = output + 'copy \'' + source[i].path + '\' to \'' + target[i].path + '\''
|
||||
if i < len(target) - 1:
|
||||
output = output + '\n'
|
||||
return output
|
||||
else:
|
||||
return 'error in copy'
|
||||
def GcxxEmitter(target, source, env):
|
||||
if os.path.exists(source[0].path):
|
||||
return [target, source]
|
||||
else:
|
||||
return [[], []]
|
||||
def MyRmTree(target, source, env):
|
||||
shutil.rmtree(env['RM_DIR'])
|
||||
return 0
|
||||
def MyRmTreePrint(target, source, env):
|
||||
return ''
|
||||
def print_cmd_line(s, target, src, env):
|
||||
print 'Building ' + (' and '.join([str(x) for x in target])) + '...'
|
||||
|
||||
class Ns3BuildVariant:
|
||||
def __init__(self):
|
||||
self.static = False
|
||||
self.gcxx_deps = False
|
||||
self.gcxx_root = ''
|
||||
self.build_root = ''
|
||||
self.env = None
|
||||
|
||||
class Ns3:
|
||||
def __init__(self):
|
||||
self.__modules = []
|
||||
self.extra_dist = []
|
||||
self.build_dir = 'build'
|
||||
self.version = '0.0.1'
|
||||
self.name = 'noname'
|
||||
self.distname = 'noname'
|
||||
self.doxygen_config = ''
|
||||
def add(self, module):
|
||||
self.__modules.append(module)
|
||||
def add_extra_dist(self, dist):
|
||||
self.extra_dist.append(dist)
|
||||
def __get_module(self, name):
|
||||
for module in self.__modules:
|
||||
if module.name == name:
|
||||
return module
|
||||
return None
|
||||
def get_mod_output(self, module, variant):
|
||||
if module.executable:
|
||||
suffix = variant.env.subst(variant.env['PROGSUFFIX'])
|
||||
filename = os.path.join(variant.build_root, 'bin',
|
||||
module.name + suffix)
|
||||
else:
|
||||
if variant.static:
|
||||
prefix = variant.env['LIBPREFIX']
|
||||
suffix = variant.env['LIBSUFFIX']
|
||||
else:
|
||||
prefix = variant.env['SHLIBPREFIX']
|
||||
suffix = variant.env['SHLIBSUFFIX']
|
||||
prefix = variant.env.subst(prefix)
|
||||
suffix = variant.env.subst(suffix)
|
||||
filename = os.path.join(variant.build_root, 'lib',
|
||||
prefix + module.name + suffix)
|
||||
return filename
|
||||
def get_obj_builders(self, variant, module):
|
||||
env = variant.env.Copy ()
|
||||
objects = []
|
||||
hash = {}
|
||||
self.get_internal_deps (module, hash)
|
||||
for dep in hash.values ():
|
||||
if dep.header_inst_dir != '':
|
||||
inc_dir = os.path.join(variant.build_root, 'include',
|
||||
self.name, dep.header_inst_dir)
|
||||
env.Append (CPPPATH = [inc_dir])
|
||||
|
||||
if len(module.config) > 0:
|
||||
src_config_file = os.path.join(self.build_dir, 'config', module.name + '-config.h')
|
||||
tgt_config_file = os.path.join(variant.build_root, 'include',
|
||||
self.name, module.name + '-config.h')
|
||||
|
||||
for source in module.sources:
|
||||
obj_file = os.path.splitext(source)[0] + '.o'
|
||||
tgt = os.path.join(variant.build_root, module.dir, obj_file)
|
||||
src = os.path.join(module.dir, source)
|
||||
if variant.static:
|
||||
obj_builder = env.StaticObject(target = tgt, source = src)
|
||||
else:
|
||||
obj_builder = env.SharedObject(target = tgt, source = src)
|
||||
if len(module.config) > 0:
|
||||
config_file = env.MyCopyBuilder(target = [tgt_config_file],
|
||||
source = [src_config_file])
|
||||
env.Depends(obj_builder, config_file)
|
||||
if variant.gcxx_deps:
|
||||
gcno_tgt = os.path.join(variant.build_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcno')
|
||||
gcda_tgt = os.path.join(variant.build_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcda')
|
||||
gcda_src = os.path.join(variant.gcxx_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcda')
|
||||
gcno_src = os.path.join(variant.gcxx_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcno')
|
||||
gcno_builder = env.CopyGcxxBuilder(target = gcno_tgt, source = gcno_src)
|
||||
gcda_builder = env.CopyGcxxBuilder(target = gcda_tgt, source = gcda_src)
|
||||
env.Depends(obj_builder, gcda_builder)
|
||||
env.Depends(obj_builder, gcno_builder)
|
||||
objects.append(obj_builder)
|
||||
return objects
|
||||
def get_internal_deps(self, module, hash):
|
||||
for dep_name in module.deps:
|
||||
dep = self.__get_module(dep_name)
|
||||
hash[dep_name] = dep
|
||||
self.get_internal_deps(dep, hash)
|
||||
def get_external_deps(self, module):
|
||||
hash = {}
|
||||
self.get_internal_deps(module, hash)
|
||||
ext_hash = {}
|
||||
for mod in hash.values():
|
||||
for ext_dep in mod.external_deps:
|
||||
ext_hash[ext_dep] = 1
|
||||
return ext_hash.keys()
|
||||
def get_sorted_deps(self, module):
|
||||
h = {}
|
||||
self.get_internal_deps(module, h)
|
||||
modules = []
|
||||
for dep in h.keys():
|
||||
deps_copy = []
|
||||
mod = h[dep]
|
||||
deps_copy.extend(mod.deps)
|
||||
modules.append([mod, deps_copy])
|
||||
sorted = []
|
||||
while len(modules) > 0:
|
||||
to_remove = []
|
||||
for item in modules:
|
||||
if len(item[1]) == 0:
|
||||
to_remove.append(item[0].name)
|
||||
for item in to_remove:
|
||||
for i in modules:
|
||||
if item in i[1]:
|
||||
i[1].remove(item)
|
||||
new_modules = []
|
||||
for mod in modules:
|
||||
found = False
|
||||
for i in to_remove:
|
||||
if i == mod[0].name:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
new_modules.append(mod)
|
||||
modules = new_modules
|
||||
sorted.extend(to_remove)
|
||||
sorted.reverse()
|
||||
# append external deps
|
||||
ext_deps = self.get_external_deps(module)
|
||||
for dep in ext_deps:
|
||||
sorted.append(dep)
|
||||
return sorted
|
||||
|
||||
def gen_mod_dep(self, variant):
|
||||
build_root = variant.build_root
|
||||
cpp_path = os.path.join(variant.build_root, 'include')
|
||||
env = variant.env
|
||||
env.Append(CPPPATH = [cpp_path])
|
||||
header_dir = os.path.join(build_root, 'include', self.name)
|
||||
lib_path = os.path.join(build_root, 'lib')
|
||||
env.Append (LIBPATH = [lib_path])
|
||||
module_builders = []
|
||||
for module in self.__modules:
|
||||
my_env = env.Copy ();
|
||||
objects = self.get_obj_builders(variant, module)
|
||||
libs = self.get_sorted_deps(module)
|
||||
my_env.Append (LIBS = libs)
|
||||
my_env.Append (LINKFLAGS = module.ldflags)
|
||||
|
||||
filename = self.get_mod_output(module, variant)
|
||||
if module.executable:
|
||||
module_builder = my_env.Program(target=filename, source=objects)
|
||||
else:
|
||||
if variant.static:
|
||||
module_builder = my_env.StaticLibrary(target=filename, source=objects)
|
||||
else:
|
||||
module_builder = my_env.SharedLibrary(target=filename, source=objects)
|
||||
|
||||
for dep_name in module.deps:
|
||||
dep = self.__get_module(dep_name)
|
||||
my_env.Depends(module_builder, self.get_mod_output(dep, variant))
|
||||
|
||||
for header in module.inst_headers:
|
||||
if module.header_inst_dir != '':
|
||||
tgt = os.path.join(header_dir, module.header_inst_dir, header)
|
||||
else:
|
||||
tgt = os.path.join(header_dir, header)
|
||||
src = os.path.join(module.dir, header)
|
||||
#builder = env.Install(target = tgt, source = src)
|
||||
header_builder = my_env.MyCopyBuilder(target=tgt, source=src)
|
||||
my_env.Depends(module_builder, header_builder)
|
||||
|
||||
module_builders.append(module_builder)
|
||||
return module_builders
|
||||
def gen_mod_config(self, env):
|
||||
config_dir = os.path.join(self.build_dir, 'config')
|
||||
for module in self.__modules:
|
||||
if len(module.config) > 0:
|
||||
config_file = os.path.join(config_dir, module.name + '-config.h')
|
||||
config_file_guard = module.name + '_CONFIG_H'
|
||||
config_file_guard.upper()
|
||||
if not os.path.isfile(config_file):
|
||||
if not os.path.isdir(config_dir):
|
||||
os.makedirs(config_dir)
|
||||
outfile = open(config_file, 'w')
|
||||
outfile.write('#ifndef ' + config_file_guard + '\n')
|
||||
outfile.write('#define ' + config_file_guard + '\n')
|
||||
config = env.Configure()
|
||||
for fn in module.config:
|
||||
output = fn(env, config)
|
||||
for o in output:
|
||||
outfile.write(o)
|
||||
outfile.write('\n')
|
||||
outfile.write('#endif /*' + config_file_guard + '*/\n')
|
||||
config.Finish()
|
||||
def generate_dependencies(self):
|
||||
inheritenv = (ARGUMENTS.get('inheritenv', 'n') in 'yY1')
|
||||
if inheritenv:
|
||||
env = Environment(ENV=os.environ)
|
||||
else:
|
||||
env = Environment()
|
||||
self.gen_mod_config(env)
|
||||
cc = env['CC']
|
||||
cxx = env.subst(env['CXX'])
|
||||
if cc == '':
|
||||
print "Missing C compiler."
|
||||
env.Exit (1);
|
||||
if cxx == '':
|
||||
print "Missing C++ compiler."
|
||||
env.Exit (1);
|
||||
common_flags = ARGUMENTS.get('cflags', '').split(' ')
|
||||
cxxflags = ARGUMENTS.get('cxxflags', '').split(' ')
|
||||
ldflags = ARGUMENTS.get('ldflags', '').split(' ')
|
||||
if cc == 'cl' and cxx == 'cl':
|
||||
env = Environment(tools=['mingw'])
|
||||
cc = env['CC']
|
||||
cxx = env.subst(env['CXX'])
|
||||
if cc == 'gcc' and cxx == 'g++':
|
||||
common_flags.extend(['-g3', '-Wall', '-Werror'])
|
||||
debug_flags = []
|
||||
opti_flags = ['-O3']
|
||||
elif cc == 'cl' and cxx == 'cl':
|
||||
env = Environment(ENV=os.environ)
|
||||
debug_flags = ['-W1', '-GX', '-EHsc', '-D_DEBUG', '/MDd']
|
||||
opti_flags = ['-O2', '-EHsc', '-DNDEBUG', '/MD']
|
||||
cc = ARGUMENTS.get ('cc', '')
|
||||
cxx = ARGUMENTS.get ('cxx', '')
|
||||
if cc != '':
|
||||
env.Replace (CC = cc)
|
||||
if cxx != '':
|
||||
env.Replace (CXX = cxx)
|
||||
env.Append(CCFLAGS = common_flags,
|
||||
CPPDEFINES = ['RUN_SELF_TESTS'],
|
||||
TARFLAGS = '-c -z',
|
||||
CPPFLAGS = cxxflags,
|
||||
LINKFLAGS = ldflags)
|
||||
if env['PLATFORM'] == 'posix':
|
||||
env.Append(LINKFLAGS = ' -z origin')
|
||||
env.Append(RPATH=env.Literal(os.path.join('\\$$ORIGIN', os.pardir, 'lib')))
|
||||
verbose = ARGUMENTS.get('verbose', 'n')
|
||||
if verbose == 'n':
|
||||
env['PRINT_CMD_LINE_FUNC'] = print_cmd_line
|
||||
header_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint))
|
||||
env.Append(BUILDERS = {'MyCopyBuilder':header_builder})
|
||||
gcxx_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint),
|
||||
emitter = GcxxEmitter)
|
||||
env.Append(BUILDERS = {'CopyGcxxBuilder':gcxx_builder})
|
||||
variant = Ns3BuildVariant()
|
||||
builders = []
|
||||
|
||||
|
||||
gcov_env = env.Copy()
|
||||
gcov_env.Append(CFLAGS = ['-fprofile-arcs', '-ftest-coverage'],
|
||||
CXXFLAGS = ['-fprofile-arcs', '-ftest-coverage'],
|
||||
LINKFLAGS = ['-fprofile-arcs'])
|
||||
# code coverage analysis
|
||||
variant.static = False
|
||||
variant.env = gcov_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'gcov')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
gcov_env.Alias('gcov', builder)
|
||||
gcov_env.Alias('lcov-report')
|
||||
if 'lcov-report' in COMMAND_LINE_TARGETS:
|
||||
lcov_report_dir = os.path.join(self.build_dir, 'lcov-report')
|
||||
create_dir_command = "rm -rf " + lcov_report_dir
|
||||
create_dir_command += " && mkdir " + lcov_report_dir + ";"
|
||||
gcov_env.Execute(create_dir_command)
|
||||
info_file = os.path.join(lcov_report_dir, self.name + '.info')
|
||||
lcov_command = "utils/lcov/lcov -c -d . -o " + info_file
|
||||
lcov_command += " --source-dirs=" + os.getcwd()
|
||||
lcov_command += ":" + os.path.join(os.getcwd(),
|
||||
variant.build_root,
|
||||
'include')
|
||||
gcov_env.Execute(lcov_command)
|
||||
genhtml_command = "utils/lcov/genhtml -o " + lcov_report_dir
|
||||
genhtml_command += " " + info_file
|
||||
gcov_env.Execute(genhtml_command)
|
||||
|
||||
|
||||
|
||||
opt_env = env.Copy()
|
||||
opt_env.Append(CFLAGS=opti_flags,
|
||||
CXXFLAGS=opti_flags,
|
||||
CPPDEFINES=['NDEBUG'])
|
||||
# optimized static support
|
||||
variant.static = True
|
||||
variant.env = opt_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-static')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
opt_env.Alias('opt-static', builder)
|
||||
|
||||
|
||||
opt_env = env.Copy()
|
||||
opt_env.Append(CFLAGS = opti_flags,
|
||||
CXXFLAGS = opti_flags,
|
||||
CPPDEFINES = ['NDEBUG'])
|
||||
# optimized shared support
|
||||
variant.static = False
|
||||
variant.env = opt_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-shared')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
opt_env.Alias('opt-shared', builder)
|
||||
|
||||
|
||||
arc_env = env.Copy()
|
||||
arc_env.Append(CFLAGS=opti_flags,
|
||||
CXXFLAGS=opti_flags,
|
||||
CPPDEFINES=['NDEBUG'])
|
||||
arc_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-generate'],
|
||||
CXXFLAGS=['-frandom-seed=0', '-fprofile-generate'],
|
||||
LINKFLAGS=['-frandom-seed=0', '-fprofile-generate'])
|
||||
# arc profiling
|
||||
variant.static = False
|
||||
variant.env = arc_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-arc')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
arc_env.Alias('opt-arc', builder)
|
||||
|
||||
|
||||
arcrebuild_env = env.Copy()
|
||||
arcrebuild_env.Append(CFLAGS=opti_flags,
|
||||
CXXFLAGS=opti_flags,
|
||||
CPPDEFINES=['NDEBUG'])
|
||||
arcrebuild_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-use'],
|
||||
CXXFLAGS=['-frandom-seed=0', '-fprofile-use'],
|
||||
LINKFLAGS=['-frandom-seed=0', '-fprofile-use'])
|
||||
# arc rebuild
|
||||
variant.static = False
|
||||
variant.env = arcrebuild_env
|
||||
variant.gcxx_deps = True
|
||||
variant.gcxx_root = os.path.join(self.build_dir, 'opt-arc')
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-arc-rebuild')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
arcrebuild_env.Alias('opt-arc-rebuild', builder)
|
||||
variant.gcxx_deps = False
|
||||
|
||||
|
||||
|
||||
|
||||
dbg_env = env.Copy()
|
||||
dbg_env.Append(CFLAGS = debug_flags,
|
||||
CXXFLAGS = debug_flags,
|
||||
CPPDEFINES = ['NS3_DEBUG_ENABLE',
|
||||
'NS3_ASSERT_ENABLE'])
|
||||
# debug static support
|
||||
variant.static = True
|
||||
variant.env = dbg_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'dbg-static')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
dbg_env.Alias('dbg-static', builder)
|
||||
|
||||
dbg_env = env.Copy()
|
||||
dbg_env.Append(CFLAGS=debug_flags,
|
||||
CXXFLAGS=debug_flags,
|
||||
CPPDEFINES = ['NS3_DEBUG_ENABLE',
|
||||
'NS3_ASSERT_ENABLE'])
|
||||
# debug shared support
|
||||
variant.static = False
|
||||
variant.env = dbg_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'dbg-shared')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
dbg_env.Alias('dbg-shared', builder)
|
||||
|
||||
env.Alias('dbg', 'dbg-shared')
|
||||
env.Alias('opt', 'opt-shared')
|
||||
env.Default('dbg')
|
||||
env.Alias('all', ['dbg-shared', 'dbg-static', 'opt-shared', 'opt-static'])
|
||||
|
||||
|
||||
# dist support
|
||||
dist_env = env.Copy()
|
||||
if dist_env['PLATFORM'] == 'posix' or dist_env['PLATFORM'] == 'darwin':
|
||||
dist_list = []
|
||||
for module in self.__modules:
|
||||
for f in module.sources:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in module.headers:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in module.inst_headers:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in module.extra_dist:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in self.extra_dist:
|
||||
dist_list.append(f)
|
||||
dist_list.append (self.doxygen_config)
|
||||
dist_list.append('SConstruct')
|
||||
dist_list.append('build.py')
|
||||
|
||||
targets = []
|
||||
basename = self.distname + '-' + self.version
|
||||
for src in dist_list:
|
||||
tgt = os.path.join(basename, src)
|
||||
targets.append(dist_env.MyCopyBuilder(target=tgt, source=src))
|
||||
tar = basename + '.tar.gz'
|
||||
zip = basename + '.zip'
|
||||
tmp_tar = os.path.join(self.build_dir, tar)
|
||||
tmp_zip = os.path.join(self.build_dir, zip)
|
||||
dist_tgt = [tar, zip]
|
||||
dist_src = [tmp_tar, tmp_zip]
|
||||
dist_env.Tar(tmp_tar, targets)
|
||||
dist_env.Zip(tmp_zip, targets)
|
||||
dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
|
||||
dist_env.Alias('dist', dist_builder)
|
||||
dist_env.Append(RM_DIR=basename)
|
||||
dist_env.AddPostAction(dist_builder, dist_env.Action(MyRmTree,
|
||||
strfunction=MyRmTreePrint))
|
||||
dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
|
||||
dist_env.Alias('fastdist', dist_tgt)
|
||||
|
||||
# distcheck
|
||||
distcheck_list = []
|
||||
for src in dist_list:
|
||||
tgt = os.path.join(self.build_dir, basename, src)
|
||||
distcheck_list.append(tgt)
|
||||
untar = env.Command(distcheck_list, tar,
|
||||
['cd ' + self.build_dir + ' && tar -zxf ../' + tar])
|
||||
scons_dir = os.path.join(self.build_dir, basename)
|
||||
distcheck_builder = env.Command('x', distcheck_list,
|
||||
['cd ' + scons_dir + ' && scons'])
|
||||
env.AlwaysBuild(distcheck_builder)
|
||||
env.Alias('distcheck', distcheck_builder)
|
||||
if self.doxygen_config != '':
|
||||
doxy = env.Command('doc/html/*', self.doxygen_config,
|
||||
['doxygen ' + self.doxygen_config])
|
||||
env.AlwaysBuild(doxy)
|
||||
env.Alias('doc', doxy)
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
The Waf build system is used to build ns-3. Waf is a Python-based
|
||||
build system (http://www.freehackers.org/~tnagy/waf.html)
|
||||
|
||||
=== Installing Waf ===
|
||||
|
||||
If this file is part of a development release tarball, the top-level
|
||||
ns-3 directory should contain a current waf script.
|
||||
|
||||
However, the ns-3 Mercurial code repository does not contain the waf
|
||||
script. Instead, developers should check it out from a subversion
|
||||
repository:
|
||||
|
||||
svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
|
||||
|
||||
[ note: 'tags/ns3' is a tag that represents the last svn version
|
||||
tested to work correctly with ns3, although 'trunk' will likely work
|
||||
as well ]
|
||||
|
||||
Then it can be installed system-wide with 'sudo waf-light install'.
|
||||
When preparing a distribution, the resulting 'waf' script, which is
|
||||
self contained (no external files needed), can be easily included in
|
||||
the tarball so that users downloading ns-3 can easily build it without
|
||||
having Waf installed (although Python >= 2.3 is still needed).
|
||||
|
||||
=== Building with Waf ===
|
||||
|
||||
To build ns-3 with waf type the commands:
|
||||
1. waf configure [options]
|
||||
2. waf
|
||||
|
||||
To see valid configure options, type waf --help. The most important
|
||||
option is -d <debug level>. Valid debug levels (which are listed in
|
||||
waf --help) are: ultradebug, debug, release, and optimized. It is
|
||||
also possible to change the flags used for compilation with (e.g.):
|
||||
CXXFLAGS="-O3" waf configure.
|
||||
|
||||
[ Note: Unlike some other build tools, to change the build target,
|
||||
the option must be supplied during the configure stage rather than
|
||||
the build stage (i.e., "waf -d optimized" will not work; instead, do
|
||||
"waf -d optimized configure; waf" ]
|
||||
|
||||
The resulting binaries are placed in build/<debuglevel>/srcpath.
|
||||
|
||||
Other waf usages include:
|
||||
|
||||
1. waf check
|
||||
Runs the unit tests
|
||||
|
||||
2. waf --doxygen
|
||||
Run doxygen to generate documentation
|
||||
|
||||
3. waf --lcov-report
|
||||
Run code coverage analysis (assuming the project was configured
|
||||
with --enable-gcov)
|
||||
|
||||
4. waf --run "program [args]"
|
||||
Run a ns3 program, given its target name, with the given
|
||||
arguments. This takes care of automatically modifying the the
|
||||
path for finding the ns3 dynamic libraries in the environment
|
||||
before running the program. Note: the "program [args]" string is
|
||||
parsed using POSIX shell rules.
|
||||
|
||||
5. waf --shell
|
||||
Starts a nested system shell with modified environment to run ns3 programs.
|
||||
|
||||
6. waf distclean
|
||||
Cleans out the entire build/ directory
|
||||
|
||||
7. waf dist
|
||||
The command 'waf dist' can be used to create a distribution tarball.
|
||||
It includes all files in the source directory, except some particular
|
||||
extensions that are blacklisted, such as back files (ending in ~).
|
||||
|
||||
|
||||
=== Extending ns-3 ===
|
||||
|
||||
To add new modules:
|
||||
1. Create the module directory under src (or src/devices, or whatever);
|
||||
2. Add the source files to it;
|
||||
3. Add a 'wscript' describing it;
|
||||
4. Add the module subdirectory name to the all_modules list in src/wscript.
|
||||
|
||||
A module's wscript file is basically a regular Waf script. A ns-3
|
||||
module is created as a cpp/shlib object, like this:
|
||||
|
||||
def build(bld):
|
||||
obj = bld.create_obj('cpp', 'shlib')
|
||||
|
||||
## set module name; by convention it starts with ns3-
|
||||
obj.name = 'ns3-mymodule'
|
||||
obj.target = obj.name
|
||||
|
||||
## list dependencies to other modules
|
||||
obj.uselib_local = ['ns3-core']
|
||||
|
||||
## list source files (private or public header files excluded)
|
||||
obj.source = [
|
||||
'mymodule.cc',
|
||||
]
|
||||
|
||||
## list module public header files
|
||||
headers = bld.create_obj('ns3header')
|
||||
headers.source = [
|
||||
'mymodule-header.h',
|
||||
]
|
||||
|
||||
@@ -1,612 +0,0 @@
|
||||
\documentclass[11pt]{article}
|
||||
\usepackage{times}
|
||||
\setlength{\textwidth}{6.5in}
|
||||
\setlength{\textheight}{9in}
|
||||
\setlength{\oddsidemargin}{0.0in}
|
||||
\setlength{\evensidemargin}{0.0in}
|
||||
\setlength{\topmargin}{-0.5in}
|
||||
\def\nst{{\em ns--3}}
|
||||
\newcommand{\code}[1]{\texttt{#1}}
|
||||
|
||||
\begin{document}
|
||||
\begin{center}
|
||||
{\Large Coding Standard for ns--3}\\
|
||||
August 22, 2005
|
||||
|
||||
\end{center}
|
||||
\section{Introduction}
|
||||
|
||||
The purpose of the \nst\ project is to build software which will last
|
||||
many years: making sure that the code is readable and stays so is
|
||||
one of the most important items required to achieve this goal. This
|
||||
document thus outlines guidelines we plan to enforce on each component
|
||||
integrated in \nst to ensure uniformity of the codebase which is
|
||||
a first step towards readable code.
|
||||
|
||||
\section{Recommendations}
|
||||
|
||||
The following recommendations are not strict rules and some of them
|
||||
are conflicting but the point here is to outline the fact that we
|
||||
value more common-sense than strict adherence to the coding style
|
||||
defined in this document.
|
||||
|
||||
\subsection{naming}
|
||||
|
||||
Types, methods, functions and variable names should be self-descriptive.
|
||||
Avoid using acronyms, expand them, do not hesitate to use long names,
|
||||
Avoid shortcuts such as \code{sz} for \code{size}. Long names sometimes get in the
|
||||
way of being able to read the code:
|
||||
\begin{verbatim}
|
||||
for (int loopCount = 0; loopCount < max; loopCount++)
|
||||
{
|
||||
// code
|
||||
}
|
||||
\end{verbatim}
|
||||
loopCount should be renamed to something shorter such as
|
||||
\code{i}, \code{j}, \code{k}, \code{l}, \code{m}, and \code{n}
|
||||
which are widely used names which identify loop counters:
|
||||
\begin{verbatim}
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
// code
|
||||
}
|
||||
\end{verbatim}
|
||||
Similarly, \code{tmp} is a common way to denote temporary variables. On
|
||||
the other hand, \code{foo} is not an appropriate name: it says nothing
|
||||
about the purpose of the variable.
|
||||
|
||||
If you use predicates (that is, functions, variables or methods
|
||||
which return a single boolean value), prefix the
|
||||
name with \code{is} or \code{has}.
|
||||
|
||||
\subsection{Memory management}
|
||||
|
||||
As much as possible, try to pass around objects
|
||||
by value and allocate them on the stack. If you need to allocate
|
||||
objects on the heap with new, make sure that the corresponding
|
||||
call to delete happens where the new took place. i.e., avoid
|
||||
passing around pointer ownership.
|
||||
Avoid the use of reference counting and, more generaly, strive to
|
||||
keep the memory-management model simple.
|
||||
|
||||
\subsection{Templates}
|
||||
|
||||
For now, templates are defined only in the simulator
|
||||
core and are used everywhere else. Try to keep it that way by
|
||||
avoiding defining new templates in model-specific code.
|
||||
|
||||
|
||||
\section{Standards}
|
||||
\subsection{General}
|
||||
\begin{enumerate}
|
||||
\item There will be no {\em tab} characters in the code. Rather, repeated
|
||||
spaces are used to separate the characters as needed.
|
||||
\item No line of code will be longer than 80 characters in length, to
|
||||
prevent lines wrapping in the {\tt emacs} or {\tt vi} editors. For both
|
||||
of these linux text editing tools, the default is a window that is
|
||||
exactly 80 characters wide, so if none of the lines wrap when editing
|
||||
in {\tt emacs} or {\tt vi} this requirement is met.
|
||||
|
||||
\item Each C++ statement will be on a separate line. The only exception
|
||||
is when an {\tt if}, {\tt else}, {\tt for} or {\tt while}
|
||||
statement has a single
|
||||
statement sub--block these can be on the same line.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
int i = 0; // Right\\
|
||||
i = 10; j = 20; // Wrong. Two statements same line\\
|
||||
Sub1(k); Sub2(k); // Wrong. Two statements same line\\
|
||||
if (done) break; // Right. If statement with single statement sub-block
|
||||
\end{tt}
|
||||
|
||||
\item Each variable declaration will be on a separate line.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
int c, d; \=// Wrong. c and d defined on same line.\\
|
||||
int a = 0; \\
|
||||
int b = 0; \>// Right. a and b on different lines\\
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item Variables should be declared at the point in the code
|
||||
where they are needed, and should be assigned an initial value
|
||||
at the time of declaration.
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
int a = 0; \=// Right, a is assigned in initial value.\\
|
||||
int b; \> Wrong, b is not assigned an initial value.\\
|
||||
int c = 0; \\
|
||||
int d = Sub1(a, b);\\
|
||||
c = Sub2(d); \> // Wrong, c should be declared here, not above
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item Excepting when used in a {\tt switch} statement, the open
|
||||
and close curly braces (\{ and \}) are always on a separate line.
|
||||
|
||||
Examples:
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
for (int i = 0; i < MAX\_COUNT; ++i) \\
|
||||
\>\{ // Right. Open brace on separate line \\
|
||||
\>\>sum += i; \\
|
||||
\>\>prod *= i; \\
|
||||
\>\} // Right. Close brace on separate line
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
for (int i = 0; i < 10; ++i) \{ // Wrong. Open brace on same line\\
|
||||
\>sum += i; \\
|
||||
\>prod *= i; \} // Wrong. Close brace on same line
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item The C++ {\tt goto} statement is not to be used.
|
||||
\end{enumerate}
|
||||
\subsection{Commenting}
|
||||
In general, comments should be use liberally throughout the program to
|
||||
increase readability. Specifically:
|
||||
|
||||
\begin{enumerate}
|
||||
\item C++ style comments using the {\tt //} delimeter
|
||||
are to be used, rather than C style comments with the {\tt /*}
|
||||
and {\tt */} delimieters.
|
||||
|
||||
\item Variable declaration should have a short, one or two line comment
|
||||
describing the purpose of the variable, unless it is a
|
||||
local variable whose use is obvious from the context. The short
|
||||
comment should be on the same line as the variable declaration, unless it
|
||||
is too long, in which case it should be on the preceding lines.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
int averageGrade; // Computed average grade for this project \\
|
||||
// Note. The above comment likely qualifies as \\
|
||||
// obvious from context, and could be omitted.
|
||||
\\
|
||||
// Counts the total number of students completing the project, but\\
|
||||
// does not include those not turning in the project. \\
|
||||
int projectCount = 0;
|
||||
\end{tt}
|
||||
\item Every function should be preceded by a detailed comment block
|
||||
describing what the function does, what the formal parameters are, and
|
||||
what the return value is (if any).
|
||||
|
||||
\item Every class declaration should be preceded by a comment block
|
||||
describing what the class is to be used for.
|
||||
|
||||
\item Unless obvious from context, each {\tt if} statement should
|
||||
include a one--line comment on the open curly brace following describing
|
||||
the {\tt TRUE} condition and the {\tt FALSE} condition.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (iter == students.end()) \\
|
||||
\>\{ // Student not found, add him \\
|
||||
\>\>students.push\_back(thisStudent); \\
|
||||
\>\} \\
|
||||
else \\
|
||||
\>\{ // Student exists, modify existing data \\
|
||||
\>\>iter->grade += thisGrade; \\
|
||||
\>\}
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
\item Class and function comments should adhere to the Doxygen standard
|
||||
format, for automated extraction by the Doxygen tool. {\em Note from
|
||||
GFR. We need a bit more here, as Doxygen has several possible methods
|
||||
for commenting. I'll look them over and suggest an approach, for later
|
||||
discussion}
|
||||
|
||||
\end{enumerate}
|
||||
\subsection{Naming Conventions}
|
||||
\begin{enumerate}
|
||||
\item {\bf Variable Names}. All variables, including global variables,
|
||||
local variables, formal parameters,
|
||||
and member variables in classes will start with a
|
||||
lower case letter, and consist of only alphabetic characters and numeric
|
||||
digits. Capital letters are to be used when appropriate between words
|
||||
in a variable name for increased readability.
|
||||
Variable names should not contain the underscore character.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt int i;}\\
|
||||
{\tt int nextIndexValue;}\\
|
||||
{\tt int sum1;}\\
|
||||
{\tt int loopCount10;}
|
||||
|
||||
\item {\bf Class Member and Global Variables}. To be able to distinguish
|
||||
local variables from class member and global variables, prepend the
|
||||
\code{m\_} prefix to class member variables and the \code{g\_} prefix
|
||||
to global variables.
|
||||
|
||||
Examples:
|
||||
\begin{verbatim}
|
||||
class Foo {
|
||||
private:
|
||||
int m_myPrivateVar;
|
||||
};
|
||||
static int g_myGlobalVar;
|
||||
\end{verbatim}
|
||||
|
||||
\item {\bf Subroutine Names}. All subroutine names, including global
|
||||
routines and member functions in classes, will start with an upper case
|
||||
letter, and consist of only alphabetic characters and numeric digits
|
||||
(although digits should be rarely needed).
|
||||
As in variable names, upper case letters are to be used between words as needed
|
||||
to increase readability.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt int ComputeNextIterator()}\\
|
||||
{\tt int Calculate()}\\
|
||||
{\tt int TransmitPacket()}\\
|
||||
{\tt int Dummy()}
|
||||
|
||||
\item {\bf Defined Constants}. All defined constants will be all upper
|
||||
case letters or numeric digits, with the underscore character separating
|
||||
words.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt typedef enum \{ PACKET\_RX, PACKET\_FIRST\_BIT\_RX, PACKET\_TX\} }\\
|
||||
{\tt \#define NUMBER\_ELEMENTS 10}\\
|
||||
{\tt const int LOOP\_COUNT = 100}
|
||||
|
||||
\item {\bf Defined Types}. All user defined types will end start with
|
||||
an upper case letter, consist of upper and lower case letters only, and
|
||||
end in {\tt \_t}.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt typedef double Time\_t; // Simulation time}\\
|
||||
{\tt typedef unsigned long SimulatorUid\_t; // Unique ID for each event}\\
|
||||
{\tt typedef unsigned long Event\_t; // Idenifies events in handler}\\
|
||||
|
||||
\item {\bf Class Names}. Class names will start with an upper case letter,
|
||||
consist of only alphabetic characters, and include capital letters as
|
||||
needed to increase readability.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt class DropTailQueue \{}\\
|
||||
{\tt class Ferrari \{}\\
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
%\newpage % Adjust as needed
|
||||
\subsection{Statement Formatting}
|
||||
\begin{enumerate}
|
||||
\item {\bf Indention}. The basic indention level for all code
|
||||
is four character positions. In some cases, indention to ``one--half''
|
||||
level, is required as described below.
|
||||
\item {\bf Continuation statements}. Frequently a single statement
|
||||
is too long to fit within a single 80 column line. In this case, the
|
||||
statement is simply continued on the next one or more lines. Each
|
||||
continuation line must be indented at least one--half indention level,
|
||||
and more as necessary to increase readability.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
longVariableName = \=(anotherLongName * shorterName) + (loopIndex2 * i) + \\
|
||||
\>(k * j); // Correct, indented for neatness
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
a\=a\=a\= \kill
|
||||
for (LongTypeName\_t longLoopIndexName = aLongExpression; \\
|
||||
\>longLoopIndexName < MAX\_VALUE; \\
|
||||
\>longLoopIndexName++) // Wrong, continuations not indented far enough
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
for (\=LongTypeName\_t longLoopIndexName = aLongExpression; \\
|
||||
\>longLoopIndexName < MAX\_VALUE; \\
|
||||
\>longLoopIndexName++) // Right, indented for readability
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf {\tt IF} Statements}.
|
||||
The open curly brace following an {\tt IF} statement must be on the
|
||||
following line, indented by one--half indention level.
|
||||
The subsequent lines must
|
||||
indented an additional one--half indention level.
|
||||
{\tt IF} statements with only
|
||||
one statement in either the {\tt TRUE} of {\tt FALSE} sub--blocks
|
||||
may omit the curly braces. The {\tt ELSE} statement (if present)
|
||||
must be on a line by itself.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (someCondition) \\
|
||||
\>\{ // Describe TRUE condition here\\
|
||||
\>\>i = k;\\
|
||||
\>\>k = i + 2;\\
|
||||
\>\} // Right, curly block indented one-half, statements one-half more
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (someCondition) \\
|
||||
\>\{ // Describe TRUE condition here\\
|
||||
\>\>i = k;\\
|
||||
\>\>k = i + 2;\\
|
||||
\>\} \\
|
||||
else // Right, ELSE statement on separate line, same indent as IF \\
|
||||
\>\{ // Describe FALSE condition here\\
|
||||
\>\>i = k * 2; \\
|
||||
\>\>k = i + 4; \\
|
||||
\>\} // Right, closing curly brace lined up with open brace
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (someCondition) // Describe TRUE condition here\\
|
||||
\>i = k; // Right, single line block need not have curly braces \\
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
if (someCondition) i = k; // Right, single statement may be on same line
|
||||
\end{tt}
|
||||
|
||||
\item {\bf {\tt FOR} Statements}.
|
||||
The open brace following a {\tt for} statement is indented
|
||||
one-half level from the {\tt for} statement itself. Each statement
|
||||
in the sub--block is indented one--half level from the curly brace.
|
||||
If the sub--block is a single statement, the curly braces can be
|
||||
omitted and the statement indented one level, or optionally appear
|
||||
on the same line as the {\tt for} statement.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
for (int i = 0; i < MAX\_COUNT; ++i) \\
|
||||
\>\{ // Curly brace indented one-half level \\
|
||||
\>\>sum += i; // Statements indented another one-half level \\
|
||||
\>\>prod *= i; \\
|
||||
\>\} // Close brace on same column as open brace \\
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
for (int i = 0; i < MAX\_COUNT; ++i) Sub1(i); // Right, single statement\\
|
||||
\end{tt}
|
||||
|
||||
\item {\bf {\tt WHILE} Statements}.
|
||||
{\tt While} statements are formatted similarly to {\tt IF} statements,
|
||||
with curly braces indented one-half level on separate lines, and the
|
||||
inner statements indented another half-level. If the sub--block has only
|
||||
a single line, the curly braces can be omitted, and the statement may
|
||||
appear on the same line as the {\tt WHILE} statement.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
while (someCondition) \\
|
||||
\>\{ // Right, open brace indented one-half level \\
|
||||
\>\>i = k; // Right, statements indented one-half level from open brace \\
|
||||
\>\>k = i + 2;\\
|
||||
\>\} // Right, close brace lines up with open brace
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
while (someCondition) i = i + 2; // Right, single stmt on same line
|
||||
\end{tt}
|
||||
|
||||
\item {\bf Infinite Loops}.
|
||||
Any loop intended to be infinite (of course with a {\tt break} statement
|
||||
somewhere) should be of the form:
|
||||
|
||||
\begin{tt}
|
||||
while(true) \\
|
||||
{ // Loop until sentinel found\\
|
||||
...code here \\
|
||||
}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf {\tt SWITCH} Statements}.
|
||||
The open curly brace for a {\tt switch} statement will be on the same
|
||||
line as the {\tt switch} statement itself. Each {\tt case} statement
|
||||
following is indented two columns from the switch statement. Each
|
||||
statement in the {\tt case} block is indented two column from the
|
||||
{\tt case} statement. The closing curly brace is on a separate line
|
||||
by itself, indented two columns from the {\tt switch} statement.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
switch(someCondition) \{ Right, open brace on same line as switch\\
|
||||
\>case 0 : // Right, case indented two columns from switch\\
|
||||
\>\>i = k; // Right, statements indented two columns from case \\
|
||||
\>\>k = i + 2;\\
|
||||
\>\>break;\\
|
||||
\>case 1 : // Right, case indented two columns from switch\\
|
||||
\>\>i = k + 2; // Right, statements indented two columns from case \\
|
||||
\>\>k = i + 4;\\
|
||||
\>\>break;\\
|
||||
\>\} // Right, close brace lines up with case statements
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf Functions}. Since C and C++ do not allow nested functions,
|
||||
all functions start with no indentation at column 0. The open curly
|
||||
brace is on a line by itself immediately following the function header
|
||||
and formal parameters, also in column 0. Any local variable declarations
|
||||
immediately following the open curly brace also start at column 0.
|
||||
One blank line follows the initial local variable declarations (if any).
|
||||
The statements in the function body are indented one-half level
|
||||
from the curly brace. Any variable declarations after the start of the
|
||||
statements are indented at the same level as the preceding statement.
|
||||
The closing brace is at column 0.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\=aa\= \kill
|
||||
void Function1(int arg1, double arg2)\\
|
||||
\{ // Right, curly brace at column 0\\
|
||||
int local1 = 0; // Right, local variable at column 0\\
|
||||
int local2;\\
|
||||
\>\\
|
||||
\>local2 = local1 + arg1 + arg2; // Right, indented two columns\\
|
||||
\>int local3; // Right, variable at same level\\
|
||||
\>local3 = Function2(local2);\\
|
||||
\>if (someCondition)\\
|
||||
\>\>\{\\
|
||||
\>\>\>local3 = 0;\\
|
||||
\>\>\>local2 = local1;\\
|
||||
\>\>\>int local4 = local1 + 1; // Right, variable at same level\\
|
||||
\>\>\>Function3(local4);\\
|
||||
\>\>\}\\
|
||||
\} // Right, close brace at column 0
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf Expressions}. Spaces should be used liberally in expressions
|
||||
to increase readability. One space before and after each operator,
|
||||
excepting the increment and decrement operators, leads to easy--to--read
|
||||
expressions. Continued expressions should be indented as far as needed
|
||||
for neatness and readability.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
i = k * 2 + 3 / var1++; // Right, spacing separating terms \\
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
i = k*2+2/var1++; // Wrong, crowded together and hard to read
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
someLongVariableName = \=anotherLongVariableName * shorterName + \\
|
||||
\>anotherName; // Right, indented to line up
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\end{enumerate}
|
||||
\subsection{Header Files}
|
||||
\begin{enumerate}
|
||||
\item All header files will have a file name ending with {\tt .h}.
|
||||
\item All header files should have a one line comment describing
|
||||
the purpose of the header, and comments identifying the
|
||||
author and the (approximate) date the file was created.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
// ns3 Network Simulator - TCP Base Class Declaration \\
|
||||
// George F. Riley. riley@ece.gatech.edu. \\
|
||||
// Georgia Tech, Fall 2006
|
||||
\end{tt}
|
||||
|
||||
\item All header files should have an ``include guard'' to prevent accidental
|
||||
inclusion of the file multiple times in a single compilation unit. The include
|
||||
guard should be named after the file name. If the file name is \code{foo-bar.h}, then the
|
||||
include guard should be named \code{FOO\_BAR\_H}
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\#ifndef FOO\_BAR\_H \\
|
||||
\#define FOO\_BAR\_H \\
|
||||
|
||||
// (Contents of foo-bar.h here
|
||||
|
||||
\#endif
|
||||
\end{tt}
|
||||
\item Header files should avoid including other files whenever possible.
|
||||
This can often be avoided with judicious use of the
|
||||
{\tt class ClassName;} forward declaration.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
// excerpt from application.h \\
|
||||
class L4Protocol; \\
|
||||
|
||||
class Application \{ \\
|
||||
.... \\
|
||||
AddL4Proto(const L4Protocol\&); \\
|
||||
.... \\
|
||||
L4Protocol* l4Proto; \\
|
||||
\};
|
||||
\end{tt}
|
||||
|
||||
In the above example, the use of the forward declaration for {\tt L4Protocol}
|
||||
obviates the need to include {\tt l4proto.h} in the application header
|
||||
file.
|
||||
|
||||
\end{enumerate}
|
||||
\subsection{Source Code Files}
|
||||
\begin{enumerate}
|
||||
\item All souce code files will have a file name ending with {\tt .cc}.
|
||||
\item All source code files should have a one line comment describing
|
||||
the purpose of the code, and comments identifying the
|
||||
author and the (approximate) date the file was created.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
// ns3 Network Simulator - TCP Base Class Implementation \\
|
||||
// George F. Riley. riley@ece.gatech.edu. \\
|
||||
// Georgia Tech, Fall 2006
|
||||
\end{tt}
|
||||
|
||||
\item All {\tt \#include} directives should be grouped with {\em system}
|
||||
files listed first (eg. {\tt \#include <iostream>}), followed by
|
||||
\nst\ defined files (eg. {\tt \#include "tcp.h"}). Within a group,
|
||||
the includes should be sorted in alphabetical order.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\#include <iostream> \\
|
||||
\#include <list> \\
|
||||
\#include <vector> \\
|
||||
|
||||
\#include "application.h" \\
|
||||
\#include "dumbbell.h" \\
|
||||
\#include "simulator.h" \\
|
||||
\#include "tcp.h.h"
|
||||
|
||||
\end{tt}
|
||||
\end{enumerate}
|
||||
\end{document}
|
||||
@@ -0,0 +1,210 @@
|
||||
The Ns-3 Coding Style
|
||||
|
||||
/*
|
||||
* Note: This file is incomplete and will be converted to non-text (html,pdf)
|
||||
* formats at a future date
|
||||
*/
|
||||
|
||||
1) Code layout
|
||||
-----------
|
||||
|
||||
The code layout follows the GNU coding standard layout for C and extends
|
||||
it to C++. Do not use tabs for indentation. Indentation spacing is 2
|
||||
spaces as outlined below:
|
||||
|
||||
void
|
||||
Foo (void)
|
||||
{
|
||||
if (test)
|
||||
{
|
||||
// do stuff here
|
||||
}
|
||||
else
|
||||
{
|
||||
// do other stuff here
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// do loop
|
||||
}
|
||||
|
||||
while (test)
|
||||
{
|
||||
// do while
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// do stuff
|
||||
} while ();
|
||||
}
|
||||
|
||||
The following is not recommended:
|
||||
|
||||
if (test) statement
|
||||
|
||||
if (test)
|
||||
statement
|
||||
|
||||
for (...) statement
|
||||
|
||||
Each statement should be put on a separate line to increase readability.
|
||||
Short one-line comments can use the C++ comment style, that is, '//'
|
||||
but longer comments should use C-style comments:
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
2) Naming Patterns
|
||||
---------------
|
||||
|
||||
2.1) Name encoding
|
||||
-------------
|
||||
Function, Method, and Type names should follow the CamelCase convention:
|
||||
words are joined without spaces and are capitalized. For example,
|
||||
"my computer" is transformed into MyComputer. Do not use all capital
|
||||
letters such as MAC or, PHY, but choose instead Mac or Phy. Do not use
|
||||
all capital letters, even for acronyms such as EDCA: use Edca instead.
|
||||
The goal of the CamelCase convention is to ensure that the words which
|
||||
make up a name can be separated by the eye: the initial Caps fills
|
||||
that role.
|
||||
|
||||
Variable names should follow a slight variation on the base CamelCase
|
||||
convention: camelBack. For example, the variable "user name" would be
|
||||
named "userName". This variation on the basic naming pattern is used to
|
||||
allow a reader to distinguish a variable name from its type. For example,
|
||||
"UserName userName;" would be used to declare a variable named userName
|
||||
of type UserName.
|
||||
|
||||
Global variables should be prefixed with a "g_" and member variables
|
||||
(including static member variables) should be prefixed with a "m_". The
|
||||
goal of that prefix is to give a reader a sense of where a variable of
|
||||
a given name is declared to allow the reader to locate the variable
|
||||
declaration and infer the variable type from that declaration. For example
|
||||
you could declare in your class header my-class.h:
|
||||
|
||||
class MyClass
|
||||
{
|
||||
void MyMethod (int aVar);
|
||||
int m_aVar;
|
||||
static int m_anotherVar;
|
||||
};
|
||||
|
||||
and implement in your class file my-class.cc:
|
||||
|
||||
int MyClass::m_anotherVar = 10;
|
||||
static int g_aStaticVar = 100;
|
||||
int g_aGlobalVar = 1000;
|
||||
|
||||
void
|
||||
MyClass::MyMethod (int aVar)
|
||||
{
|
||||
m_aVar = aVar;
|
||||
}
|
||||
|
||||
2.2) Choosing names
|
||||
|
||||
Variable, function, method, and type names should be based on the
|
||||
english language. Furthermore, always try to choose descriptive
|
||||
names for them. Types are often english names such as: Packet,
|
||||
Buffer, Mac, or Phy. Functions and Methods are often named
|
||||
based on verbs and adjectives: GetX, DoDispose, ClearArray, etc.
|
||||
|
||||
A long descriptive name which requires a lot of typing is always
|
||||
better than a short name which is hard to decipher. Do not use
|
||||
abbreviations in names unless the abbreviation is really unambiguous
|
||||
and obvious to everyone. Do not use short inapropriate names such
|
||||
as foo, bar, or baz. The name of an item should always match its
|
||||
purpose. As such, names such as tmp to identify a temporary
|
||||
variable or such as 'i' to identify a loop index are ok.
|
||||
|
||||
3) File layout and code organization
|
||||
---------------------------------
|
||||
|
||||
A class named MyClass should be declared in a header named my-class.h
|
||||
and implemented in a source file named my-class.cc. The goal of this
|
||||
naming pattern is to allow a reader to quickly navigate through
|
||||
the ns-3 codebase to locate the source file relevant to a specific
|
||||
type.
|
||||
|
||||
Each my-class.h header should start with the following comments: the
|
||||
first line ensures that developers who use the emacs editor will be
|
||||
able to indent your code correctly. The following lines ensure that
|
||||
your code is licensed under the GPL, that the copyright holders
|
||||
are properly identified (typically, you or your employer), and
|
||||
that the actual author of the code is identified. The latter is
|
||||
purely informational and we use it to try to track the most
|
||||
appropriate person to review a patch or fix a bug.
|
||||
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) YEAR COPYRIGHTHOLDER
|
||||
*
|
||||
* 3-paragran GPL blurb
|
||||
*
|
||||
* Author: MyName <myemail@foo.com>
|
||||
*/
|
||||
|
||||
Below these C-style comments, always include the following which
|
||||
defines a set of header guards (MY_CLASS_H) used to avoid multiple
|
||||
header includes, which ensures that your code is included
|
||||
in the "ns3" namespace and which provides a set of doxygen comments
|
||||
for the public part of your class API. Detailed information
|
||||
on the set of tags available for doxygen documentation is described
|
||||
in the doxygen website: http://www.doxygen.org.
|
||||
|
||||
#ifndef MY_CLASS_H
|
||||
#define MY_CLASS_H
|
||||
|
||||
namespace n3 {
|
||||
|
||||
/**
|
||||
* \brief short one-line description of the purpose of your class
|
||||
*
|
||||
* A longer description of the purpose of your class after a blank
|
||||
* empty line.
|
||||
*/
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
MyClass ();
|
||||
/**
|
||||
* \param firstParam a short description of the purpose of this parameter
|
||||
* \returns a short description of what is returned from this function.
|
||||
*
|
||||
* A detailed description of the purpose of the method.
|
||||
*/
|
||||
int DoFoo (int firstParam);
|
||||
private:
|
||||
void MyPrivateMethod (void);
|
||||
int m_myPrivateMemberVariable;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* MY_CLASS_H */
|
||||
|
||||
The my-class.cc file is structured similarly:
|
||||
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) YEAR COPYRIGHTHOLDER
|
||||
*
|
||||
* 3-paragran GPL blurb
|
||||
*
|
||||
* Author: MyName <myemail@foo.com>
|
||||
*/
|
||||
#include "my-class.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
MyClass::MyClass ()
|
||||
{}
|
||||
|
||||
...
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
Contributing to the ns-3 project
|
||||
--------------------------------
|
||||
|
||||
ns-3 is an open source project backed by an NSF CISE CRI grant.
|
||||
Although the NSF PIs have specific aims to fulfill, we want others to
|
||||
contribute, and we'd like to have a broad community of users and
|
||||
developers, with the goal of a self-sustaining project downstream.
|
||||
The project is currently in a bootstrapping phase, but we welcome
|
||||
ambitious developers who might want to help shape the early design.
|
||||
|
||||
Despite the lack of a formal contribution process to the ns-3
|
||||
project, there are a number of steps which we expect every
|
||||
potential contributor to follow. These naturally stem from
|
||||
the open-source roots of the project:
|
||||
|
||||
- first, you should subscribe to the ns-developers
|
||||
mailing-list (see http://www.nsnam.org/mailing_lists.html)
|
||||
|
||||
- then, you should send an email there stating your interest
|
||||
in working on a specific part of the models and trying
|
||||
to explain how you would like to implement it, what
|
||||
resources you have, etc.
|
||||
|
||||
- you should be prepared to work together with the other
|
||||
potential contributors who want to work on the same models.
|
||||
|
||||
- you should be prepared to go through code reviews with the
|
||||
ns-3 development team prior to integration. The goal of these
|
||||
code reviews is to:
|
||||
- ensure adherence to the coding style of the project
|
||||
(see doc/codingstyle.html)
|
||||
- ensure that the structure of your code has a certain
|
||||
coherence with regard to the rest of the ns-3 codebase
|
||||
- improve the quality of the code: we strongly believe in
|
||||
the old saying: "many eyes make all bugs shallow".
|
||||
- increase code reuse by trying to generalize certain
|
||||
useful pieces of your code to make them available to
|
||||
other models.
|
||||
|
||||
- you should be prepared to try to integrate as many tests
|
||||
in the codebase as possible: we understand that writing
|
||||
tests is not sexy and that not everyone is convinced that
|
||||
they improve the code-writing poductivity which is why
|
||||
we do not enforce strict rules about testing. However,
|
||||
we expect model authors to answer basic questions about
|
||||
how they plan to test and validate their models.
|
||||
|
||||
- you should be prepared to maintain your model once it is
|
||||
integrated: while we consider every bug filed against the
|
||||
simulator as being a bug we must deal with and while we
|
||||
will try to fix as many bugs as humanly possible, we
|
||||
also expect model authors to act as responsible maintainers
|
||||
and be reactive to bug reports concerning their models.
|
||||
|
||||
- The project has decided upon GNU GPLv2 as the licensing structure.
|
||||
All simulation software in the ns-3 repositories will be GNU GPLv2
|
||||
or GNU GPLv2-compatible (with non-GPLv2 licensing reserved for
|
||||
ports of pre-existing code under a different license, such as BSD).
|
||||
You do not have to assign your copyright to the ns-3 project but
|
||||
you must accept the terms of the GPLv2 and attest that your
|
||||
contributions can be licensed under those terms. See the
|
||||
following link:
|
||||
http://www.fsf.org/licensing/licenses/info/GPLv2.html
|
||||
+1231
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* \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 debugging, \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 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 "common" module contains:
|
||||
* - a packet class to create and manipulate simulation packets: ns3::Packet, ns3::Header,
|
||||
* and ns3::Trailer. This packet class also supports per-packet ns3::Tag which are
|
||||
* globs of data which can be attached to any packet.
|
||||
* - a set of low-level trace facilities: \ref lowleveltracing
|
||||
*
|
||||
* The "node" module contains:
|
||||
* - a ns3::Node base class which should be subclassed by any new type of
|
||||
* 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
|
||||
*/
|
||||
@@ -0,0 +1,45 @@
|
||||
Introduction
|
||||
------------
|
||||
|
||||
ns-3 uses the Mercurial software revision control system which
|
||||
is a replacement for tools liks cvs or subversion. Thus, to get
|
||||
access to the development versions of ns-3, you need to install
|
||||
mercurial first. See http://www.selenic.com/mercurial/wiki/
|
||||
|
||||
Mercurial cheat sheet
|
||||
---------------------
|
||||
|
||||
Look at our project history and source code:
|
||||
-------------------------------------------
|
||||
http://code.nsnam.org/ns-3-dev
|
||||
|
||||
clone this repository:
|
||||
---------------------
|
||||
hg clone http://code.nsnam.org/ns-3-dev
|
||||
|
||||
commit locally:
|
||||
--------------
|
||||
hg status
|
||||
hg add <new files, if any>
|
||||
hg ci -m "message"
|
||||
|
||||
pull development tree changes to your local repository:
|
||||
------------------------------------------------------
|
||||
hg ci -m "my local changes are recorded"
|
||||
hg pull http://code.nsnam.org/ns-3-dev
|
||||
hg update (apply the changes) OR
|
||||
hg merge (if you've made local changes)
|
||||
|
||||
view the change log:
|
||||
-------------------
|
||||
hg log <file>
|
||||
|
||||
push upwards (developers access only):
|
||||
--------------------------------------
|
||||
To the main repository:
|
||||
hg push ssh://code@code.nsnam.org/repos/ns-3-dev
|
||||
|
||||
To your private repository:
|
||||
hg push ssh://username@code.nsnam.org//home/username/repositories/username/repository
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
Steps in doing an ns-3 release
|
||||
|
||||
1. prepare the source files
|
||||
- revise and check in AUTHORS, if needed
|
||||
- revise and check in RELEASE_NOTES
|
||||
- update and check in VERSION to the latest release number
|
||||
2. make a new "architecture.pdf" document and place it in the doc/ directory
|
||||
3. scons dist
|
||||
4. test tarball on release platforms (run-tests and simple-p2p)
|
||||
5. tag ns-3-dev with "release ns-3.0.X"
|
||||
6. clone the ns-3-dev and place it on the repository
|
||||
7. upload "ns-3.0.x.tar.gz" to the releases/ directory on the server
|
||||
8. update web page
|
||||
- add link to news.html
|
||||
- update download.html
|
||||
- update roadmap.html
|
||||
- build and update Doxygen directory on the server
|
||||
- update and upload software architecture document (PDF, HTML)
|
||||
9. announce to ns-developers, with summary of release notes
|
||||
@@ -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
|
||||
*
|
||||
* ns-2 simple.tcl script (ported from ns-2)
|
||||
* Originally authored by Steve McCanne, 12/19/1996
|
||||
*/
|
||||
|
||||
// Port of ns-2/tcl/ex/simple.tcl to ns-3
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 -------------------------n3
|
||||
// /
|
||||
// / 5 Mb/s, 2ms
|
||||
// n1
|
||||
//
|
||||
// - all links are p2p links with indicated one-way BW/delay
|
||||
// - CBR/UDP flows from n0 to n3, and from n3 to n1
|
||||
// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
|
||||
// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
|
||||
// (i.e., DataRate of 448,000 bps)
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "simple-p2p.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/p2p-channel.h"
|
||||
#include "ns3/p2p-net-device.h"
|
||||
#include "ns3/mac-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/p2p-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
DebugComponentEnable("Object");
|
||||
DebugComponentEnable("Queue");
|
||||
DebugComponentEnable("DropTailQueue");
|
||||
DebugComponentEnable("Channel");
|
||||
DebugComponentEnable("PointToPointChannel");
|
||||
DebugComponentEnable("PointToPointNetDevice");
|
||||
#endif
|
||||
|
||||
// Set up some default values for the simulation. Use the Bind()
|
||||
// technique to tell the system what subclass of Queue to use,
|
||||
// and what the queue limit is
|
||||
|
||||
// The below Bind command tells the queue factory which class to
|
||||
// instantiate, when the queue factory is invoked in the topology code
|
||||
Bind ("Queue", "DropTailQueue");
|
||||
|
||||
Bind ("OnOffApplicationPacketSize", "210");
|
||||
Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
|
||||
//Bind ("DropTailQueue::m_maxPackets", 30);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n2, DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
Ptr<PointToPointChannel> channel2 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n2, n3, DataRate(1500000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.1.1"),
|
||||
n2, Ipv4Address("10.1.1.2"));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address("10.1.2.1"),
|
||||
n2, Ipv4Address("10.1.2.2"));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel2, n2, Ipv4Address("10.1.3.1"),
|
||||
n3, Ipv4Address("10.1.3.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Routes(n0, n2, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
PointToPointTopology::AddIpv4Routes(n2, n3, channel2);
|
||||
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
Ipv4Address("10.1.3.2"),
|
||||
80,
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
Ipv4Address("10.1.2.1"),
|
||||
80,
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Here, finish off packet routing configuration
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
|
||||
ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-p2p.tr file
|
||||
AsciiTrace asciitrace ("simple-p2p.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("simple-p2p.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
import Params
|
||||
|
||||
def build(bld):
|
||||
def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
|
||||
obj = bld.create_obj('cpp', 'program')
|
||||
obj.target = name
|
||||
obj.uselib_local = ["ns3-%s" % dep for dep in deps]
|
||||
obj.source = source
|
||||
return obj
|
||||
|
||||
obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', deps=['p2p', 'internet-node'])
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
This is a placeholder file used only to keep the ns3 directory present (needed for the WAF build system).
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/assert.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
static double
|
||||
CbOne (double a, double b)
|
||||
{
|
||||
std::cout << "invoke cbOne a=" << a << ", b=" << b << std::endl;
|
||||
return a;
|
||||
}
|
||||
|
||||
class MyCb {
|
||||
public:
|
||||
int CbTwo (double a) {
|
||||
std::cout << "invoke cbTwo a=" << a << std::endl;
|
||||
return -5;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// return type: double
|
||||
// first arg type: double
|
||||
// second arg type: double
|
||||
Callback<double, double, double> one;
|
||||
// build callback instance which points to cbOne function
|
||||
one = MakeCallback (&CbOne);
|
||||
// this is not a null callback
|
||||
NS_ASSERT (!one.IsNull ());
|
||||
// invoke cbOne function through callback instance
|
||||
double retOne;
|
||||
retOne = one (10.0, 20.0);
|
||||
|
||||
// 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);
|
||||
// this is not a null callback
|
||||
NS_ASSERT (!two.IsNull ());
|
||||
// invoke MyCb::cbTwo through callback instance
|
||||
int retTwo;
|
||||
retTwo = two (10.0);
|
||||
|
||||
two = MakeNullCallback<int, double> ();
|
||||
// invoking a null callback is just like
|
||||
// invoking a null function pointer:
|
||||
// it will crash.
|
||||
//int retTwoNull = two (20.0);
|
||||
NS_ASSERT (two.IsNull ());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/* -*- 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/debug.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;
|
||||
|
||||
// ===========================================================================
|
||||
// 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_DEBUG_UNCOND("FakeInternetNode::FakeInternetNode ()");
|
||||
}
|
||||
|
||||
FakeInternetNode::~FakeInternetNode ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::~FakeInternetNode ()");
|
||||
}
|
||||
|
||||
void
|
||||
FakeInternetNode::Doit (void)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::Doit ()");
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::Doit (): **** Send outbound packet");
|
||||
Packet p;
|
||||
|
||||
m_dtqOutbound.Enqueue(p);
|
||||
UpperNotify();
|
||||
}
|
||||
|
||||
bool
|
||||
FakeInternetNode::UpperDoSendUp (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (" << &p << ")");
|
||||
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (): **** Receive inbound packet");
|
||||
m_dtqInbound.Enqueue(p);
|
||||
return m_dtqInbound.Dequeue(p);
|
||||
}
|
||||
|
||||
bool
|
||||
FakeInternetNode::UpperDoPull (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::DoPull (" << &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_DEBUG_UNCOND("FakePhysicalLayer::FakePhysicalLayer ()");
|
||||
}
|
||||
|
||||
FakePhysicalLayer::~FakePhysicalLayer ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::~FakePhysicalLayer ()");
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::LowerDoNotify (LayerConnectorUpper *upper)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify ()");
|
||||
|
||||
Packet p;
|
||||
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Starting pull");
|
||||
|
||||
NS_ASSERT(m_upperPartner);
|
||||
m_upperPartner->UpperPull(p);
|
||||
|
||||
m_dtqOutbound.Enqueue(p);
|
||||
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Got bits, Notify lower");
|
||||
|
||||
NS_ASSERT(m_lowerPartner);
|
||||
return m_lowerPartner->LowerNotify(this);
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::UpperDoSendUp (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::UpperDoSendUp (" << &p << ")");
|
||||
|
||||
NS_ASSERT(m_upperPartner);
|
||||
return m_upperPartner->UpperSendUp(p);
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::UpperDoPull (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::DoPull (" << &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_DEBUG_UNCOND("FakeChannel::FakeChannel ()");
|
||||
}
|
||||
|
||||
FakeChannel::~FakeChannel ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeChannel::~FakeChannel ()");
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
NS_DEBUG_UNCOND("Channel Hackorama");
|
||||
|
||||
#if 0
|
||||
DebugComponentEnable("Queue");
|
||||
DebugComponentEnable("DropTailQueue");
|
||||
DebugComponentEnable("LayerConnector");
|
||||
DebugComponentEnable("Channel");
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/debug.h"
|
||||
|
||||
NS_DEBUG_COMPONENT_DEFINE ("MyComponentB");
|
||||
|
||||
namespace foo {
|
||||
|
||||
void OneFunction (void)
|
||||
{
|
||||
NS_DEBUG ("OneFunction debug");
|
||||
}
|
||||
|
||||
}; // namespace foo
|
||||
@@ -0,0 +1,27 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/debug.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
NS_DEBUG_COMPONENT_DEFINE ("MyComponentA");
|
||||
|
||||
// declare other function
|
||||
namespace foo {
|
||||
void OneFunction (void);
|
||||
}
|
||||
|
||||
int main (int argc, int argv)
|
||||
{
|
||||
NS_DEBUG ("nargc="<<argc);
|
||||
|
||||
foo::OneFunction ();
|
||||
|
||||
NS_DEBUG ("other debug output");
|
||||
|
||||
int a;
|
||||
a = 0;
|
||||
|
||||
NS_ASSERT (a == 0);
|
||||
NS_ASSERT_MSG (a == 0, "my msg");
|
||||
NS_ASSERT (a != 0);
|
||||
NS_ASSERT_MSG (a != 0, "my 2 msg");
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include <string>
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/debug.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
//
|
||||
// This sample file demonstrates how to take some simple member
|
||||
// variables and hook them into the default variable system
|
||||
// Typically, you will establish a static variable to maintain the current
|
||||
// value of the default parameter. Then as other code require the values of
|
||||
// the defaults, they query them with GetValue() to get the present value.
|
||||
static BooleanDefaultValue defaultTestBool1 ("testBool1", "helpBool", true);
|
||||
static IntegerDefaultValue<int> defaultTestInt1 ("testInt1", "helpInt1", 33);
|
||||
static IntegerDefaultValue<uint32_t> defaultTestInt2 ("testInt2", "helpInt2", 47);
|
||||
|
||||
//
|
||||
// This test class demonstrates the declaration of variables that
|
||||
// may be overridden by the default-value system
|
||||
//
|
||||
// You will see in the core ns-3 modules that many member variables
|
||||
// can be overridden in this manner
|
||||
//
|
||||
class TestClass {
|
||||
public:
|
||||
TestClass();
|
||||
virtual ~TestClass () {}
|
||||
|
||||
bool m_testBool1;
|
||||
int m_testInt1;
|
||||
uint32_t m_testInt2;
|
||||
};
|
||||
|
||||
//
|
||||
// In the constructor, you can assign default values in the initializer
|
||||
// list such as below; note that the instance of the created TestClass
|
||||
// will have the values as dictated by the current value of the default.
|
||||
// This means that the behavior of this class can be changed on the fly with
|
||||
// calls to bind.
|
||||
//
|
||||
TestClass::TestClass () :
|
||||
m_testBool1(defaultTestBool1.GetValue()),
|
||||
m_testInt1(defaultTestInt1.GetValue()),
|
||||
m_testInt2(defaultTestInt2.GetValue())
|
||||
{
|
||||
}
|
||||
using std::cout;
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
//The following allows the default values established so far to be hooked
|
||||
//into the command line argument processing unit. Essentially, the command
|
||||
//line processor is aware of the DefaultValues that have been registered, and
|
||||
//will accept command line overrides of these. The call automatically
|
||||
//provides a --help option in addition to allowing overrides of defaults.
|
||||
uint32_t loops = 0;
|
||||
CommandLine::AddArgValue("loops","a test of the command line",loops);
|
||||
CommandLine::Parse(argc,argv);
|
||||
|
||||
//utilize the loops variable to show that it can be read from the command line
|
||||
if(loops>0)
|
||||
{
|
||||
cout<<"You requested "<<loops<<" iterations of a loop";
|
||||
for(uint32_t i=0;i<loops;++i)
|
||||
cout<<"iteration "<<i;
|
||||
}
|
||||
|
||||
// Before objects are instantiated in your simulation script, you have
|
||||
// the opportunity to overwrite any default value in the system.
|
||||
// The Bind () method allows you to specify the name (string) of the
|
||||
// global variable and value (string) to overwrite the default.
|
||||
// Here, the default value of 33 for testInt1 is overwritten with 57
|
||||
//
|
||||
Bind("testInt1", "57");
|
||||
|
||||
TestClass* testclass = new TestClass ();
|
||||
NS_DEBUG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
|
||||
NS_DEBUG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")");
|
||||
NS_DEBUG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")");
|
||||
delete testclass;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006,2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/header.h"
|
||||
#include "ns3/packet-printer.h"
|
||||
#include "ns3/ipv4-header.h"
|
||||
#include "ns3/udp-header.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
// This sample file shows how to use the Packet metadata facility
|
||||
//
|
||||
// Packets are stored as ``packed'' data structures, to facilitate
|
||||
// fragmentation and network emulation. However, when debugging a program,
|
||||
// or for certain tracing applications, it may be convenient to dump out
|
||||
// the contents of a packet header in a human-friendly form.
|
||||
//
|
||||
// To do this, a few things are needed:
|
||||
// i) enable the metadata facility (disabled by default, because it causes
|
||||
// a small performance hit
|
||||
// ii) decide on whether you want to use a default or customized (you
|
||||
// provide your own) routine to dump a particular header
|
||||
//
|
||||
// This sample steps through two routines; one to use the default
|
||||
// printing of IPv4 and UDP headers, and one to show a non-default case.
|
||||
// There is a lot of emphasis in this sample of how this facility
|
||||
// interacts with packet fragmentation.
|
||||
|
||||
void DefaultPrint (void)
|
||||
{
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
// and add 3 headers to this packet.
|
||||
Packet p (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
udp.SetPayloadSize (1000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
// Here, invoke the default Print routine, directed to std out
|
||||
p.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// Now, we fragment our packet in 3 consecutive pieces.
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
// And, finally, we re-aggregate the 3 consecutive pieces.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// The below functions are used in place of default versions, in the
|
||||
// non-default case below. For instance, DoPrintIpv4Header will print
|
||||
// out less IPv4 header information than the default print function
|
||||
void
|
||||
DoPrintDefault (std::ostream &os,uint32_t packetUid, uint32_t size,
|
||||
std::string &name, struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << name <<" (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
|
||||
}
|
||||
void
|
||||
DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << "PAYLOAD (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
|
||||
}
|
||||
void
|
||||
DoPrintIpv4Header (std::ostream &os, uint32_t packetUid, uint32_t size, const Ipv4Header *ipv4)
|
||||
{
|
||||
os << "IPV4 " << ipv4->GetSource () << " > " << ipv4->GetDestination ();
|
||||
}
|
||||
void
|
||||
DoPrintIpv4HeaderFragment (std::ostream &os, uint32_t packetUid, uint32_t size,
|
||||
std::string &name, struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << "IPV4 fragment";
|
||||
}
|
||||
|
||||
// This function walks through a non-default case. A few features of
|
||||
// the API (defined in common/packet-printer.h) are shown.
|
||||
//
|
||||
void NonDefaultPrint (void)
|
||||
{
|
||||
// create an adhoc packet printer.
|
||||
PacketPrinter printer;
|
||||
// print from first header to last trailer
|
||||
printer.PrintForward ();
|
||||
// set a string separator automatically inserted
|
||||
// between each call to a printing function.
|
||||
printer.SetSeparator (" - ");
|
||||
// set the default print function: invoked if no
|
||||
// specialized function has been provided for a header
|
||||
// or trailer
|
||||
printer.AddDefaultPrinter (MakeCallback (&DoPrintDefault));
|
||||
// set the payload print function
|
||||
printer.AddPayloadPrinter (MakeCallback (&DoPrintPayload));
|
||||
// set the print function for the header type Ipv4Header.
|
||||
printer.AddHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
|
||||
MakeCallback (&DoPrintIpv4HeaderFragment));
|
||||
|
||||
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
Packet p (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
udp.SetPayloadSize (1000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
p.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// fragment our packet in 3 pieces
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
// aggregate all 3 fragments of the original packet
|
||||
// to reconstruct a copy of the original packet.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Packet::EnableMetadata ();
|
||||
|
||||
std::cout << "DefaultPrint()" << std::endl;
|
||||
DefaultPrint ();
|
||||
|
||||
std::cout << std::endl << "NonDefaultPrint()" << std::endl;
|
||||
NonDefaultPrint ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/header.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
/* A sample Header implementation
|
||||
*/
|
||||
class MyHeader : public Header {
|
||||
public:
|
||||
MyHeader ();
|
||||
virtual ~MyHeader ();
|
||||
|
||||
void SetData (uint16_t data);
|
||||
uint16_t GetData (void) const;
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
virtual uint32_t DeserializeFrom (Buffer::Iterator start);
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
|
||||
uint16_t m_data;
|
||||
};
|
||||
|
||||
MyHeader::MyHeader ()
|
||||
{}
|
||||
MyHeader::~MyHeader ()
|
||||
{}
|
||||
std::string
|
||||
MyHeader::DoGetName (void) const
|
||||
{
|
||||
return "MyHeader";
|
||||
}
|
||||
void
|
||||
MyHeader::PrintTo (std::ostream &os) const
|
||||
{
|
||||
os << "MyHeader data=" << m_data << std::endl;
|
||||
}
|
||||
uint32_t
|
||||
MyHeader::GetSerializedSize (void) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
void
|
||||
MyHeader::SerializeTo (Buffer::Iterator start) const
|
||||
{
|
||||
// serialize in head of buffer
|
||||
start.WriteHtonU16 (m_data);
|
||||
}
|
||||
uint32_t
|
||||
MyHeader::DeserializeFrom (Buffer::Iterator start)
|
||||
{
|
||||
// deserialize from head of buffer
|
||||
m_data = start.ReadNtohU16 ();
|
||||
return GetSerializedSize ();
|
||||
}
|
||||
|
||||
void
|
||||
MyHeader::SetData (uint16_t data)
|
||||
{
|
||||
m_data = data;
|
||||
}
|
||||
uint16_t
|
||||
MyHeader::GetData (void) const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
/* A sample Tag implementation
|
||||
*/
|
||||
struct MyTag {
|
||||
uint16_t m_streamId;
|
||||
};
|
||||
|
||||
static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
|
||||
|
||||
|
||||
static void
|
||||
Receive (Packet p)
|
||||
{
|
||||
MyHeader my;
|
||||
p.RemoveHeader (my);
|
||||
std::cout << "received data=" << my.GetData () << std::endl;
|
||||
struct MyTag myTag;
|
||||
p.PeekTag (myTag);
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Packet p;
|
||||
MyHeader my;
|
||||
my.SetData (2);
|
||||
std::cout << "send data=2" << std::endl;
|
||||
p.AddHeader (my);
|
||||
struct MyTag myTag;
|
||||
myTag.m_streamId = 5;
|
||||
p.AddTag (myTag);
|
||||
Receive (p);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/object.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
class A : public Object
|
||||
{
|
||||
public:
|
||||
A ();
|
||||
~A ();
|
||||
void Method (void);
|
||||
};
|
||||
A::A ()
|
||||
{
|
||||
std::cout << "A constructor" << std::endl;
|
||||
}
|
||||
A::~A()
|
||||
{
|
||||
std::cout << "A destructor" << std::endl;
|
||||
}
|
||||
void
|
||||
A::Method (void)
|
||||
{
|
||||
std::cout << "A method" << std::endl;
|
||||
}
|
||||
|
||||
static Ptr<A> g_a = 0;
|
||||
|
||||
static Ptr<A>
|
||||
StoreA (Ptr<A> a)
|
||||
{
|
||||
Ptr<A> prev = g_a;
|
||||
g_a = a;
|
||||
return prev;
|
||||
}
|
||||
|
||||
static void
|
||||
ClearA (void)
|
||||
{
|
||||
g_a = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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> ();
|
||||
a->Method ();
|
||||
Ptr<A> prev = StoreA (a);
|
||||
NS_ASSERT (prev == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// 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> prev = StoreA (a);
|
||||
// call method on object
|
||||
prev->Method ();
|
||||
// Clear the currently-stored object
|
||||
ClearA ();
|
||||
// get the raw pointer and release it.
|
||||
A *raw = GetPointer (prev);
|
||||
prev = 0;
|
||||
raw->Method ();
|
||||
raw->Unref ();
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
/* -*- 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/debug.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)
|
||||
{
|
||||
// pre-dispatch asserts
|
||||
NS_DEBUG_UNCOND("AnInterface pre-condition::methodA");
|
||||
domethodA ();
|
||||
NS_DEBUG_UNCOND("AnInterface post-condition::methodA\n");
|
||||
// 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_DEBUG_UNCOND("AnImplementation::methodImpl\n");
|
||||
}
|
||||
|
||||
|
||||
AnImplementation::AnImplementation (void)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
AnImplementation::domethodA ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("AnImplementation::domethodA");
|
||||
}
|
||||
|
||||
//
|
||||
// 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_DEBUG_UNCOND("ANewImplementation::methodImpl\n");
|
||||
}
|
||||
|
||||
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_DEBUG_UNCOND("AnExtendedImplementation::methodExtendedImpl\n");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
static void
|
||||
GenerateTraffic (Ptr<Socket> socket, uint32_t size)
|
||||
{
|
||||
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl;
|
||||
socket->Send (0, size);
|
||||
if (size > 0)
|
||||
{
|
||||
Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50);
|
||||
}
|
||||
else
|
||||
{
|
||||
socket->Close ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SocketPrinter (Ptr<Socket> socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort)
|
||||
{
|
||||
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl;
|
||||
}
|
||||
|
||||
static void
|
||||
PrintTraffic (Ptr<Socket> socket)
|
||||
{
|
||||
socket->RecvDummy (MakeCallback (&SocketPrinter));
|
||||
}
|
||||
|
||||
void
|
||||
RunSimulation (void)
|
||||
{
|
||||
Ptr<Node> a = Create<InternetNode> ();
|
||||
|
||||
InterfaceId iid = InterfaceId::LookupByName ("Udp");
|
||||
Ptr<SocketFactory> socketFactory = a->QueryInterface<SocketFactory> (iid);
|
||||
|
||||
Ptr<Socket> sink = socketFactory->CreateSocket ();
|
||||
sink->Bind (80);
|
||||
|
||||
Ptr<Socket> source = socketFactory->CreateSocket ();
|
||||
source->Connect (Ipv4Address::GetLoopback (), 80);
|
||||
|
||||
GenerateTraffic (source, 500);
|
||||
PrintTraffic (sink);
|
||||
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
RunSimulation ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
class MyModel {
|
||||
public:
|
||||
void Start (void);
|
||||
private:
|
||||
void DealWithEvent (double eventValue);
|
||||
};
|
||||
|
||||
void
|
||||
MyModel::Start (void)
|
||||
{
|
||||
Simulator::Schedule (Seconds (10.0),
|
||||
&MyModel::DealWithEvent,
|
||||
this, Simulator::Now ().GetSeconds ());
|
||||
}
|
||||
void
|
||||
MyModel::DealWithEvent (double value)
|
||||
{
|
||||
std::cout << "Member method received event at " << Simulator::Now ().GetSeconds ()
|
||||
<< "s started at " << value << "s" << std::endl;
|
||||
}
|
||||
|
||||
static void
|
||||
random_function (MyModel *model)
|
||||
{
|
||||
std::cout << "random function received event at " <<
|
||||
Simulator::Now ().GetSeconds () << "s" << std::endl;
|
||||
model->Start ();
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
MyModel model;
|
||||
|
||||
Simulator::Schedule (Seconds (10.0), &random_function, &model);
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include "ns3/test.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
// declare subclass of base class Test
|
||||
class MyTest : public Test {
|
||||
public:
|
||||
MyTest (bool ok);
|
||||
virtual ~MyTest ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
bool m_ok;
|
||||
};
|
||||
|
||||
// implement MyTest
|
||||
MyTest::MyTest (bool ok)
|
||||
: Test ("My"),
|
||||
m_ok (ok)
|
||||
{}
|
||||
MyTest::~MyTest ()
|
||||
{}
|
||||
bool
|
||||
MyTest::RunTests (void)
|
||||
{
|
||||
return m_ok;
|
||||
}
|
||||
|
||||
// instantiate MyTest once
|
||||
static MyTest g_my_test = MyTest (true);
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// run tests
|
||||
TestManager::EnableVerbose ();
|
||||
TestManager::RunTests ();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/trace-container.h"
|
||||
#include "ns3/ui-variable-tracer.h"
|
||||
#include "ns3/callback-tracer.h"
|
||||
#include "ns3/stream-tracer.h"
|
||||
#include "ns3/pcap-writer.h"
|
||||
#include "ns3/packet.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
CallbackTraceSourcer<Packet> a;
|
||||
UiVariableTracer<unsigned short> b;
|
||||
StreamTracer c;
|
||||
CallbackTraceSourcer<double, int> d;
|
||||
|
||||
void
|
||||
RegisterAllTraceSources (TraceContainer *container)
|
||||
{
|
||||
container->RegisterCallback ("source-a", &a);
|
||||
container->RegisterUiVariable ("source-b", &b);
|
||||
container->RegisterStream ("source-c", &c);
|
||||
container->RegisterCallback ("source-d", &d);
|
||||
}
|
||||
void
|
||||
GenerateTraceEvents (void)
|
||||
{
|
||||
// log en empty packet
|
||||
a (Packet ());
|
||||
b = 10;
|
||||
b += 100;
|
||||
b += 50;
|
||||
b = (unsigned short) -20;
|
||||
c << "this is a simple test b=" << b << std::endl;
|
||||
d (3.1415, 3);
|
||||
}
|
||||
|
||||
void
|
||||
VariableEvent (uint64_t old, uint64_t cur)
|
||||
{}
|
||||
|
||||
void
|
||||
CallbackEvent (double a, int b)
|
||||
{}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
TraceContainer traces;
|
||||
RegisterAllTraceSources (&traces);
|
||||
PcapWriter pcap;
|
||||
pcap.Open ("trace-test.log");
|
||||
pcap.WriteHeaderEthernet ();
|
||||
traces.SetCallback ("source-a",
|
||||
MakeCallback (&PcapWriter::WritePacket, &pcap));
|
||||
traces.SetUiVariableCallback ("source-b", MakeCallback (&VariableEvent));
|
||||
traces.SetStream ("source-c", &std::cout);
|
||||
traces.SetCallback ("source-d", MakeCallback (&CallbackEvent));
|
||||
GenerateTraceEvents ();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- 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/debug.h"
|
||||
#include "ns3/trace-writer.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
NS_DEBUG_UNCOND("TraceWriter Test")
|
||||
|
||||
TraceWriter writer1;
|
||||
writer1.Open("trace-writer-test.txt");
|
||||
writer1.Write("writer1.char*\n");
|
||||
writer1.Write(std::string("writer1.string\n"));
|
||||
writer1.Close();
|
||||
|
||||
TraceWriter writer2;
|
||||
writer2.Open(std::string("trace-writer-test.txt"));
|
||||
writer2.Write("writer2.char*\n");
|
||||
writer2.Write(std::string("writer2.string\n"));
|
||||
writer2.Close();
|
||||
|
||||
TraceWriter writer3("trace-writer-test.txt");
|
||||
writer3.Write("writer3.char*\n");
|
||||
writer3.Write(std::string("writer3.string\n"));
|
||||
writer3.Close();
|
||||
|
||||
TraceWriter writer4(std::string("trace-writer-test.txt"));
|
||||
writer4.Write("writer4.char*\n");
|
||||
writer4.Write(std::string("writer4.string\n"));
|
||||
writer4.Close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
import Params
|
||||
|
||||
def build(bld):
|
||||
def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
|
||||
obj = bld.create_obj('cpp', 'program')
|
||||
obj.target = name
|
||||
obj.uselib_local = ["ns3-%s" % dep for dep in deps]
|
||||
obj.source = source
|
||||
return obj
|
||||
|
||||
obj = create_ns_prog('main-debug', ['main-debug.cc', 'main-debug-other.cc'])
|
||||
obj = create_ns_prog('main-callback', 'main-callback.cc')
|
||||
obj = create_ns_prog('main-ptr', 'main-ptr.cc')
|
||||
#obj = create_ns_prog('main-trace', 'main-trace.cc')
|
||||
obj = create_ns_prog('main-simulator', 'main-simulator.cc')
|
||||
obj = create_ns_prog('main-packet', 'main-packet.cc')
|
||||
obj = create_ns_prog('main-test', 'main-test.cc')
|
||||
obj = create_ns_prog('main-simple', 'main-simple.cc',
|
||||
deps=['node', 'internet-node', 'applications'])
|
||||
#obj = create_ns_prog('main-simple-p2p', 'main-simple-p2p.cc', deps=['node', 'p2p'])
|
||||
obj = create_ns_prog('main-default-value', 'main-default-value.cc',
|
||||
deps=['core', 'simulator', 'node', 'p2p'])
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
//
|
||||
// Copyright (c) 2006 Georgia Tech Research Corporation
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation;
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Author: George F. Riley<riley@ece.gatech.edu>
|
||||
//
|
||||
|
||||
// ns3 - On/Off Data Source Application class
|
||||
// George F. Riley, Georgia Tech, Spring 2007
|
||||
// Adapted from ApplicationOnOff in GTNetS.
|
||||
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "onoff-application.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
// Defaults for rate/size
|
||||
static DataRateDefaultValue g_defaultRate ("OnOffApplicationDataRate",
|
||||
"The data rate in on state for OnOffApplication",
|
||||
DataRate ("500kb/s"));
|
||||
static IntegerDefaultValue<uint32_t> g_defaultSize ("OnOffApplicationPacketSize",
|
||||
"The size of packets sent in on state for OnOffApplication",
|
||||
512, 1);
|
||||
// Constructors
|
||||
|
||||
OnOffApplication::OnOffApplication(Ptr<Node> n,
|
||||
const Ipv4Address rip,
|
||||
uint16_t rport,
|
||||
std::string iid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime)
|
||||
: Application(n),
|
||||
m_cbrRate (g_defaultRate.GetValue ())
|
||||
{
|
||||
Construct (n, rip, rport, iid,
|
||||
ontime, offtime,
|
||||
g_defaultSize.GetValue ());
|
||||
}
|
||||
|
||||
OnOffApplication::OnOffApplication(Ptr<Node> n,
|
||||
const Ipv4Address rip,
|
||||
uint16_t rport,
|
||||
std::string iid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime,
|
||||
DataRate rate,
|
||||
uint32_t size)
|
||||
: Application(n),
|
||||
m_cbrRate (rate)
|
||||
{
|
||||
Construct (n, rip, rport, iid,
|
||||
ontime, offtime, size);
|
||||
}
|
||||
|
||||
void
|
||||
OnOffApplication::Construct (Ptr<Node> n,
|
||||
const Ipv4Address rip,
|
||||
uint16_t rport,
|
||||
std::string iid,
|
||||
const RandomVariable& onTime,
|
||||
const RandomVariable& offTime,
|
||||
uint32_t size)
|
||||
{
|
||||
m_socket = 0;
|
||||
m_peerIp = rip;
|
||||
m_peerPort = rport;
|
||||
m_connected = false;
|
||||
m_onTime = onTime.Copy ();
|
||||
m_offTime = offTime.Copy ();
|
||||
m_pktSize = size;
|
||||
m_residualBits = 0;
|
||||
m_lastStartTime = Seconds (0);
|
||||
m_maxBytes = 0xffffffff;
|
||||
m_totBytes = 0;
|
||||
m_iid = iid;
|
||||
}
|
||||
|
||||
|
||||
OnOffApplication::~OnOffApplication()
|
||||
{}
|
||||
|
||||
void
|
||||
OnOffApplication::SetMaxBytes(uint32_t maxBytes)
|
||||
{
|
||||
m_maxBytes = maxBytes;
|
||||
}
|
||||
|
||||
void
|
||||
OnOffApplication::SetDefaultRate (const DataRate &rate)
|
||||
{
|
||||
g_defaultRate.SetValue (rate);
|
||||
}
|
||||
void
|
||||
OnOffApplication::SetDefaultSize (uint32_t size)
|
||||
{
|
||||
g_defaultSize.SetValue (size);
|
||||
}
|
||||
|
||||
void
|
||||
OnOffApplication::DoDispose (void)
|
||||
{
|
||||
m_socket = 0;
|
||||
delete m_onTime;
|
||||
delete m_offTime;
|
||||
|
||||
m_onTime = 0;
|
||||
m_offTime = 0;
|
||||
|
||||
// chain up
|
||||
Application::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
// Application Methods
|
||||
void OnOffApplication::StartApplication() // Called at time specified by Start
|
||||
{
|
||||
// Create the socket if not already
|
||||
if (!m_socket)
|
||||
{
|
||||
InterfaceId iid = InterfaceId::LookupByName (m_iid);
|
||||
Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
|
||||
m_socket = socketFactory->CreateSocket ();
|
||||
m_socket->Bind ();
|
||||
m_socket->Connect (m_peerIp, m_peerPort);
|
||||
}
|
||||
// Insure no pending event
|
||||
StopApplication();
|
||||
// If we are not yet connected, there is nothing to do here
|
||||
// The ConnectionComplete upcall will start timers at that time
|
||||
//if (!m_connected) return;
|
||||
ScheduleStartEvent();
|
||||
}
|
||||
|
||||
void OnOffApplication::StopApplication() // Called at time specified by Stop
|
||||
{
|
||||
if (m_sendEvent.IsRunning ())
|
||||
{ // Cancel the pending send packet event
|
||||
// Calculate residual bits since last packet sent
|
||||
Time delta(Simulator::Now() - m_lastStartTime);
|
||||
m_residualBits += (uint32_t)(m_cbrRate.GetBitRate() * delta.GetSeconds());
|
||||
}
|
||||
Simulator::Cancel(m_sendEvent);
|
||||
Simulator::Cancel(m_startStopEvent);
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
void OnOffApplication::StartSending()
|
||||
{
|
||||
ScheduleNextTx(); // Schedule the send packet event
|
||||
}
|
||||
|
||||
void OnOffApplication::StopSending()
|
||||
{
|
||||
Simulator::Cancel(m_sendEvent);
|
||||
}
|
||||
|
||||
// Private helpers
|
||||
void OnOffApplication::ScheduleNextTx()
|
||||
{
|
||||
if (m_totBytes < m_maxBytes)
|
||||
{
|
||||
uint32_t bits = m_pktSize * 8 - m_residualBits;
|
||||
Time nextTime(Seconds (bits /
|
||||
static_cast<double>(m_cbrRate.GetBitRate()))); // Time till next packet
|
||||
m_sendEvent = Simulator::Schedule(nextTime, &OnOffApplication::SendPacket, this);
|
||||
}
|
||||
else
|
||||
{ // All done, cancel any pending events
|
||||
StopApplication();
|
||||
}
|
||||
}
|
||||
|
||||
void OnOffApplication::ScheduleStartEvent()
|
||||
{ // Schedules the event to start sending data (switch to the "On" state)
|
||||
Time offInterval = Seconds(m_offTime->GetValue());
|
||||
m_startStopEvent = Simulator::Schedule(offInterval, &OnOffApplication::StartSending, this);
|
||||
}
|
||||
|
||||
void OnOffApplication::ScheduleStopEvent()
|
||||
{ // Schedules the event to stop sending data (switch to "Off" state)
|
||||
Time onInterval = Seconds(m_onTime->GetValue());
|
||||
Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
|
||||
}
|
||||
|
||||
|
||||
void OnOffApplication::SendPacket()
|
||||
{
|
||||
NS_ASSERT (m_sendEvent.IsExpired ());
|
||||
m_socket->Send(0, m_pktSize);
|
||||
m_totBytes += m_pktSize;
|
||||
m_lastStartTime = Simulator::Now();
|
||||
m_residualBits = 0;
|
||||
ScheduleNextTx();
|
||||
}
|
||||
|
||||
void OnOffApplication::ConnectionSucceeded(Ptr<Socket>)
|
||||
{
|
||||
m_connected = true;
|
||||
ScheduleStartEvent();
|
||||
}
|
||||
|
||||
void OnOffApplication::ConnectionFailed(Ptr<Socket>)
|
||||
{
|
||||
cout << "OnOffApplication, Connection Failed" << endl;
|
||||
}
|
||||
|
||||
} // Namespace ns3
|
||||
@@ -0,0 +1,157 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
//
|
||||
// Copyright (c) 2006 Georgia Tech Research Corporation
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation;
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Author: George F. Riley<riley@ece.gatech.edu>
|
||||
//
|
||||
|
||||
// ns3 - On/Off Data Source Application class
|
||||
// George F. Riley, Georgia Tech, Spring 2007
|
||||
// Adapted from ApplicationOnOff in GTNetS.
|
||||
|
||||
#ifndef __onoff_application_h__
|
||||
#define __onoff_application_h__
|
||||
|
||||
#include "ns3/application.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/ptr.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Ipv4Address;
|
||||
class RandomVariable;
|
||||
class Socket;
|
||||
class DataRate;
|
||||
|
||||
/**
|
||||
* \brief Generate traffic to a single destination according to an
|
||||
* OnOff pattern.
|
||||
*
|
||||
* This traffic follows an On/Off pattern: after Application::StartApplication
|
||||
* is called, "On" and "Off" states alternate. The duration of each of
|
||||
* these states is determined with the onTime and the offTime random
|
||||
* variables. During the "Off" state, no traffic is generated.
|
||||
* During the "On" state, cbr traffic is generated. This cbr traffic is
|
||||
* characterized by the specified "data rate" and "packet size".
|
||||
*/
|
||||
class OnOffApplication : public Application
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param n node associated to this application
|
||||
* \param rip remote ip address
|
||||
* \param rport remove port number
|
||||
* \param iid
|
||||
* \param ontime on time random variable
|
||||
* \param offtime off time random variable
|
||||
*/
|
||||
OnOffApplication(Ptr<Node> n,
|
||||
const Ipv4Address rip,
|
||||
uint16_t rport,
|
||||
std::string iid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime);
|
||||
|
||||
/**
|
||||
* \param n node associated to this application
|
||||
* \param rip remote ip address
|
||||
* \param rport remove port number
|
||||
* \param iid
|
||||
* \param ontime on time random variable
|
||||
* \param offtime off time random variable
|
||||
* \param rate data rate when on
|
||||
* \param size size of packets when sending data.
|
||||
*/
|
||||
OnOffApplication(Ptr<Node> n,
|
||||
const Ipv4Address rip,
|
||||
uint16_t rport,
|
||||
std::string iid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime,
|
||||
DataRate rate,
|
||||
uint32_t size);
|
||||
|
||||
virtual ~OnOffApplication();
|
||||
|
||||
void SetMaxBytes(uint32_t maxBytes);
|
||||
|
||||
/**
|
||||
* \param r the data rate
|
||||
*
|
||||
* Set the data rate to use for every OnOffApplication for which
|
||||
* the user does not specify an explicit data rate.
|
||||
*/
|
||||
static void SetDefaultRate(const DataRate & r);
|
||||
|
||||
/**
|
||||
* \param size the packet size
|
||||
*
|
||||
* Set the packet size to use for every OnOffApplication for
|
||||
* which the user does not specify an explicit packet size.
|
||||
*/
|
||||
static void SetDefaultSize (uint32_t size);
|
||||
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
private:
|
||||
// inherited from Application base class.
|
||||
virtual void StartApplication (void); // Called at time specified by Start
|
||||
virtual void StopApplication (void); // Called at time specified by Stop
|
||||
|
||||
void Construct (Ptr<Node> n,
|
||||
const Ipv4Address rip,
|
||||
uint16_t rport,
|
||||
std::string iid,
|
||||
const RandomVariable& ontime,
|
||||
const RandomVariable& offtime,
|
||||
uint32_t size);
|
||||
|
||||
|
||||
// Event handlers
|
||||
void StartSending();
|
||||
void StopSending();
|
||||
void SendPacket();
|
||||
|
||||
Ptr<Socket> m_socket; // Associated socket
|
||||
Ipv4Address m_peerIp; // Peer IP address
|
||||
uint16_t m_peerPort; // Peer port
|
||||
bool m_connected; // True if connected
|
||||
RandomVariable* m_onTime; // rng for On Time
|
||||
RandomVariable* m_offTime; // rng for Off Time
|
||||
DataRate m_cbrRate; // Rate that data is generated
|
||||
uint32_t m_pktSize; // Size of packets
|
||||
uint32_t m_residualBits; // Number of generated, but not sent, bits
|
||||
Time m_lastStartTime;// Time last packet sent
|
||||
uint32_t m_maxBytes; // Limit total number of bytes sent
|
||||
uint32_t m_totBytes; // Total bytes sent so far
|
||||
EventId m_startStopEvent; // Event id for next start or stop event
|
||||
EventId m_sendEvent; // Eventid of pending "send packet" event
|
||||
bool m_sending; // True if currently in sending state
|
||||
std::string m_iid;
|
||||
|
||||
private:
|
||||
void ScheduleNextTx();
|
||||
void ScheduleStartEvent();
|
||||
void ScheduleStopEvent();
|
||||
void ConnectionSucceeded(Ptr<Socket>);
|
||||
void ConnectionFailed(Ptr<Socket>);
|
||||
void Ignore(Ptr<Socket>);
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
obj = bld.create_obj('cpp', 'shlib')
|
||||
obj.name = 'ns3-applications'
|
||||
obj.target = obj.name
|
||||
obj.uselib_local = ['ns3-node']
|
||||
obj.source = [
|
||||
'onoff-application.cc',
|
||||
]
|
||||
|
||||
headers = bld.create_obj('ns3header')
|
||||
headers.source = [
|
||||
'onoff-application.h',
|
||||
]
|
||||
@@ -0,0 +1,137 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef ARRAY_TRACE_RESOLVER_H
|
||||
#define ARRAY_TRACE_RESOLVER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "ns3/callback.h"
|
||||
#include "trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief a helper class to offer trace resolution for an array of objects.
|
||||
* \ingroup lowleveltracing
|
||||
*/
|
||||
template <typename T>
|
||||
class ArrayTraceResolver : public TraceResolver
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief array index trace context
|
||||
*
|
||||
* During namespace parsing, ns3::ArrayTraceResolver will
|
||||
* embed an instance of this class in the TraceContext
|
||||
* associated to every child object of the object stored
|
||||
* at the index.
|
||||
*
|
||||
* The reason why this class exists is to ensure that we
|
||||
* need to ensure that we can store a unique type as context
|
||||
* into the TraceContext associated to this trace resolver.
|
||||
*/
|
||||
class Index
|
||||
{
|
||||
public:
|
||||
Index ();
|
||||
Index (uint32_t index);
|
||||
/**
|
||||
* The Index is automatically convertible to the
|
||||
* uin32_t type such that it really behaves like a uint32_t
|
||||
* array index for the user.
|
||||
*
|
||||
* \returns the index itself
|
||||
*/
|
||||
operator uint32_t ();
|
||||
private:
|
||||
uint32_t m_index;
|
||||
};
|
||||
/**
|
||||
* \param context trace context associated to this trace resolver
|
||||
* \param getSize callback which returns dynamically the size of underlying array
|
||||
* \param get callback which returns any element in the underlying array
|
||||
*
|
||||
* Construct a trace resolver which can match any input integer
|
||||
* against an element in an array. The array is accessed using a
|
||||
* pair of callbacks. It is the responsability of the user to
|
||||
* provide two such callbacks whose job is to adapt the array
|
||||
* API to the resolver needs. Each element of the array is expected
|
||||
* to provide a method named CreateTraceResolver which takes as
|
||||
* only argument a reference to a const TraceContext and returns
|
||||
* a pointer to a TraceResolver. i.e. the signature is:
|
||||
* TraceResolver * (*) (TraceContext const &)
|
||||
*/
|
||||
ArrayTraceResolver (TraceContext const &context,
|
||||
Callback<uint32_t> getSize,
|
||||
Callback<T *, uint32_t> get);
|
||||
private:
|
||||
virtual TraceResolverList DoLookup (std::string id) const;
|
||||
Callback<uint32_t> m_getSize;
|
||||
Callback<T *, uint32_t> m_get;
|
||||
};
|
||||
}//namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
ArrayTraceResolver<T>::Index::Index ()
|
||||
: m_index ()
|
||||
{}
|
||||
template <typename T>
|
||||
ArrayTraceResolver<T>::Index::Index (uint32_t index)
|
||||
: m_index (index)
|
||||
{}
|
||||
template <typename T>
|
||||
ArrayTraceResolver<T>::Index::operator uint32_t ()
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ArrayTraceResolver<T>::ArrayTraceResolver (TraceContext const &context,
|
||||
Callback<uint32_t> getSize,
|
||||
Callback<T *, uint32_t> get)
|
||||
: TraceResolver (context),
|
||||
m_getSize (getSize),
|
||||
m_get (get)
|
||||
{}
|
||||
template <typename T>
|
||||
TraceResolver::TraceResolverList
|
||||
ArrayTraceResolver<T>::DoLookup (std::string id) const
|
||||
{
|
||||
TraceResolverList list;
|
||||
if (id == "*")
|
||||
{
|
||||
for (uint32_t i = 0; i < m_getSize (); i++)
|
||||
{
|
||||
TraceContext context = GetContext ();
|
||||
typename ArrayTraceResolver<T>::Index index = typename ArrayTraceResolver<T>::Index (i);
|
||||
context.Add (index);
|
||||
list.push_back (m_get (i)->CreateTraceResolver (context));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* ARRAY_TRACE_RESOLVER_H */
|
||||
@@ -0,0 +1,683 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "buffer.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
#include <iostream>
|
||||
//#define TRACE(x) std::cout << x << std::endl;
|
||||
#define TRACE(x)
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
Buffer::BufferDataList Buffer::m_freeList;
|
||||
uint32_t Buffer::m_maxTotalAddStart = 0;
|
||||
uint32_t Buffer::m_maxTotalAddEnd = 0;
|
||||
|
||||
struct Buffer::BufferData *
|
||||
Buffer::Allocate (uint32_t reqSize, uint32_t reqStart)
|
||||
{
|
||||
if (reqSize == 0)
|
||||
{
|
||||
reqSize = 1;
|
||||
}
|
||||
NS_ASSERT (reqSize >= 1);
|
||||
uint32_t size = reqSize - 1 + sizeof (struct Buffer::BufferData);
|
||||
uint8_t *b = new uint8_t [size];
|
||||
struct BufferData *data = reinterpret_cast<struct Buffer::BufferData*>(b);
|
||||
data->m_size = reqSize;
|
||||
data->m_initialStart = reqStart;
|
||||
data->m_dirtyStart = reqStart;
|
||||
data->m_dirtySize = 0;
|
||||
data->m_count = 1;
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
Buffer::Deallocate (struct Buffer::BufferData *data)
|
||||
{
|
||||
uint8_t *buf = reinterpret_cast<uint8_t *> (data);
|
||||
delete [] buf;
|
||||
}
|
||||
#ifdef USE_FREE_LIST
|
||||
void
|
||||
Buffer::Recycle (struct Buffer::BufferData *data)
|
||||
{
|
||||
NS_ASSERT (data->m_count == 0);
|
||||
/* get rid of it if it is too small for later reuse. */
|
||||
if (data->m_size < (Buffer::m_maxTotalAddStart + Buffer::m_maxTotalAddEnd))
|
||||
{
|
||||
Buffer::Deallocate (data);
|
||||
return;
|
||||
}
|
||||
/* feed into free list */
|
||||
if (Buffer::m_freeList.size () > 1000)
|
||||
{
|
||||
Buffer::Deallocate (data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer::m_freeList.push_back (data);
|
||||
}
|
||||
}
|
||||
|
||||
Buffer::BufferData *
|
||||
Buffer::Create (void)
|
||||
{
|
||||
/* try to find a buffer correctly sized. */
|
||||
while (!Buffer::m_freeList.empty ())
|
||||
{
|
||||
struct Buffer::BufferData *data = Buffer::m_freeList.back ();
|
||||
Buffer::m_freeList.pop_back ();
|
||||
if (data->m_size >= (m_maxTotalAddStart + m_maxTotalAddEnd))
|
||||
{
|
||||
data->m_initialStart = m_maxTotalAddStart;
|
||||
data->m_dirtyStart = m_maxTotalAddStart;
|
||||
data->m_dirtySize = 0;
|
||||
data->m_count = 1;
|
||||
return data;
|
||||
}
|
||||
Buffer::Deallocate (data);
|
||||
}
|
||||
struct Buffer::BufferData *data = Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
|
||||
m_maxTotalAddStart);
|
||||
NS_ASSERT (data->m_count == 1);
|
||||
return data;
|
||||
}
|
||||
#else
|
||||
void
|
||||
Buffer::Recycle (struct Buffer::BufferData *data)
|
||||
{
|
||||
Buffer::Deallocate (data);
|
||||
}
|
||||
|
||||
Buffer::BufferData *
|
||||
Buffer::Create (void)
|
||||
{
|
||||
return Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
|
||||
m_maxTotalAddStart);
|
||||
}
|
||||
#endif
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
void
|
||||
Buffer::AddAtStart (uint32_t start)
|
||||
{
|
||||
NS_ASSERT (m_start <= m_data->m_initialStart);
|
||||
bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
|
||||
if (m_start >= start && !isDirty)
|
||||
{
|
||||
/* enough space in the buffer and not dirty. */
|
||||
m_start -= start;
|
||||
m_size += start;
|
||||
}
|
||||
else if (m_size + start <= m_data->m_size && !isDirty)
|
||||
{
|
||||
/* enough space but need to move data around to fit new data */
|
||||
memmove (m_data->m_data + start, GetStart (), m_size);
|
||||
NS_ASSERT (start > m_start);
|
||||
m_data->m_initialStart += start - m_start;
|
||||
m_start = 0;
|
||||
m_size += start;
|
||||
}
|
||||
else if (m_start < start)
|
||||
{
|
||||
/* not enough space in buffer */
|
||||
uint32_t newSize = m_size + start;
|
||||
struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
|
||||
memcpy (newData->m_data + start, GetStart (), m_size);
|
||||
newData->m_initialStart = m_data->m_initialStart + start;
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
Buffer::Deallocate (m_data);
|
||||
}
|
||||
m_data = newData;
|
||||
m_start = 0;
|
||||
m_size = newSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* enough space in the buffer but it is dirty ! */
|
||||
NS_ASSERT (isDirty);
|
||||
struct Buffer::BufferData *newData = Buffer::Create ();
|
||||
memcpy (newData->m_data + m_start, GetStart (), m_size);
|
||||
newData->m_initialStart = m_data->m_initialStart;
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
Recycle (m_data);
|
||||
}
|
||||
m_data = newData;
|
||||
m_start -= start;
|
||||
m_size += start;
|
||||
}
|
||||
// update dirty area
|
||||
m_data->m_dirtyStart = m_start;
|
||||
m_data->m_dirtySize = m_size;
|
||||
// update m_maxTotalAddStart
|
||||
uint32_t addedAtStart;
|
||||
if (m_data->m_initialStart > m_start)
|
||||
{
|
||||
addedAtStart = m_data->m_initialStart - m_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
addedAtStart = 0;
|
||||
}
|
||||
if (addedAtStart > m_maxTotalAddStart)
|
||||
{
|
||||
m_maxTotalAddStart = addedAtStart;
|
||||
}
|
||||
TRACE ("start add="<<start<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
|
||||
", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
|
||||
", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
|
||||
}
|
||||
void
|
||||
Buffer::AddAtEnd (uint32_t end)
|
||||
{
|
||||
NS_ASSERT (m_start <= m_data->m_initialStart);
|
||||
bool isDirty = m_data->m_count > 1 &&
|
||||
m_start + m_size < m_data->m_dirtyStart + m_data->m_dirtySize;
|
||||
if (m_start + m_size + end <= m_data->m_size && !isDirty)
|
||||
{
|
||||
/* enough space in buffer and not dirty */
|
||||
m_size += end;
|
||||
}
|
||||
else if (m_size + end <= m_data->m_size && !isDirty)
|
||||
{
|
||||
/* enough space but need to move data around to fit the extra data */
|
||||
uint32_t newStart = m_data->m_size - (m_size + end);
|
||||
memmove (m_data->m_data + newStart, GetStart (), m_size);
|
||||
NS_ASSERT (newStart < m_start);
|
||||
m_data->m_initialStart -= m_start - newStart;
|
||||
m_start = newStart;
|
||||
m_size += end;
|
||||
}
|
||||
else if (m_start + m_size + end > m_data->m_size)
|
||||
{
|
||||
/* not enough space in buffer */
|
||||
uint32_t newSize = m_size + end;
|
||||
struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
|
||||
memcpy (newData->m_data, GetStart (), m_size);
|
||||
newData->m_initialStart = m_data->m_initialStart - m_start;
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
Buffer::Deallocate (m_data);
|
||||
}
|
||||
m_data = newData;
|
||||
m_size = newSize;
|
||||
m_start = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* enough space in the buffer but it is dirty ! */
|
||||
NS_ASSERT (isDirty);
|
||||
struct Buffer::BufferData *newData = Buffer::Create ();
|
||||
memcpy (newData->m_data + m_start, GetStart (), m_size);
|
||||
newData->m_initialStart = m_data->m_initialStart;
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
Recycle (m_data);
|
||||
}
|
||||
m_data = newData;
|
||||
m_size += end;
|
||||
}
|
||||
// update dirty area
|
||||
m_data->m_dirtyStart = m_start;
|
||||
m_data->m_dirtySize = m_size;
|
||||
// update m_maxTotalAddEnd
|
||||
uint32_t endLoc = m_start + m_size;
|
||||
uint32_t addedAtEnd;
|
||||
if (m_data->m_initialStart < endLoc)
|
||||
{
|
||||
addedAtEnd = endLoc - m_data->m_initialStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
addedAtEnd = 0;
|
||||
}
|
||||
if (addedAtEnd > m_maxTotalAddEnd)
|
||||
{
|
||||
m_maxTotalAddEnd = addedAtEnd;
|
||||
}
|
||||
TRACE ("end add="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
|
||||
", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
|
||||
", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
|
||||
}
|
||||
|
||||
void
|
||||
Buffer::RemoveAtStart (uint32_t start)
|
||||
{
|
||||
if (m_zeroAreaSize == 0)
|
||||
{
|
||||
if (m_size <= start)
|
||||
{
|
||||
m_start += m_size;
|
||||
m_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_start += start;
|
||||
m_size -= start;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT (m_data->m_initialStart >= m_start);
|
||||
uint32_t zeroStart = m_data->m_initialStart - m_start;
|
||||
uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
|
||||
uint32_t dataEnd = m_size + m_zeroAreaSize;
|
||||
if (start <= zeroStart)
|
||||
{
|
||||
/* only remove start of buffer */
|
||||
m_start += start;
|
||||
m_size -= start;
|
||||
}
|
||||
else if (start <= zeroEnd)
|
||||
{
|
||||
/* remove start of buffer _and_ start of zero area */
|
||||
m_start += zeroStart;
|
||||
uint32_t zeroDelta = start - zeroStart;
|
||||
m_zeroAreaSize -= zeroDelta;
|
||||
NS_ASSERT (zeroDelta <= start);
|
||||
m_size -= zeroStart;
|
||||
}
|
||||
else if (start <= dataEnd)
|
||||
{
|
||||
/* remove start of buffer, complete zero area, and part
|
||||
* of end of buffer */
|
||||
m_start += start - m_zeroAreaSize;
|
||||
m_size -= start - m_zeroAreaSize;
|
||||
m_zeroAreaSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remove all buffer */
|
||||
m_start += m_size;
|
||||
m_size = 0;
|
||||
m_zeroAreaSize = 0;
|
||||
}
|
||||
}
|
||||
TRACE ("start remove="<<start<<", start="<<m_start<<", size="<<m_size<<
|
||||
", zero="<<m_zeroAreaSize<<
|
||||
", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
|
||||
", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
|
||||
}
|
||||
void
|
||||
Buffer::RemoveAtEnd (uint32_t end)
|
||||
{
|
||||
if (m_zeroAreaSize == 0)
|
||||
{
|
||||
if (m_size <= end)
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_size -= end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT (m_data->m_initialStart >= m_start);
|
||||
uint32_t zeroStart = m_data->m_initialStart - m_start;
|
||||
uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
|
||||
uint32_t dataEnd = m_size + m_zeroAreaSize;
|
||||
NS_ASSERT (zeroStart <= m_size);
|
||||
NS_ASSERT (zeroEnd <= m_size + m_zeroAreaSize);
|
||||
if (dataEnd <= end)
|
||||
{
|
||||
/* remove all buffer */
|
||||
m_zeroAreaSize = 0;
|
||||
m_start += m_size;
|
||||
m_size = 0;
|
||||
}
|
||||
else if (dataEnd - zeroStart <= end)
|
||||
{
|
||||
/* remove end of buffer, zero area, part of start of buffer */
|
||||
NS_ASSERT (end >= m_zeroAreaSize);
|
||||
m_size -= end - m_zeroAreaSize;
|
||||
m_zeroAreaSize = 0;
|
||||
}
|
||||
else if (dataEnd - zeroEnd <= end)
|
||||
{
|
||||
/* remove end of buffer, part of zero area */
|
||||
uint32_t zeroDelta = end - (dataEnd - zeroEnd);
|
||||
m_zeroAreaSize -= zeroDelta;
|
||||
m_size -= end - zeroDelta;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remove part of end of buffer */
|
||||
m_size -= end;
|
||||
}
|
||||
}
|
||||
TRACE ("end remove="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
|
||||
", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
|
||||
", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
|
||||
}
|
||||
|
||||
Buffer
|
||||
Buffer::CreateFragment (uint32_t start, uint32_t length) const
|
||||
{
|
||||
uint32_t zeroStart = m_data->m_initialStart - m_start;
|
||||
uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
|
||||
if (m_zeroAreaSize != 0 &&
|
||||
start + length > zeroStart &&
|
||||
start <= zeroEnd)
|
||||
{
|
||||
TransformIntoRealBuffer ();
|
||||
}
|
||||
Buffer tmp = *this;
|
||||
tmp.RemoveAtStart (start);
|
||||
tmp.RemoveAtEnd (GetSize () - (start + length));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void
|
||||
Buffer::TransformIntoRealBuffer (void) const
|
||||
{
|
||||
if (m_zeroAreaSize != 0)
|
||||
{
|
||||
NS_ASSERT (m_data->m_initialStart >= m_start);
|
||||
NS_ASSERT (m_size >= (m_data->m_initialStart - m_start));
|
||||
Buffer tmp;
|
||||
tmp.AddAtStart (m_zeroAreaSize);
|
||||
tmp.Begin ().WriteU8 (0, m_zeroAreaSize);
|
||||
uint32_t dataStart = m_data->m_initialStart - m_start;
|
||||
tmp.AddAtStart (dataStart);
|
||||
tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
|
||||
uint32_t dataEnd = m_size - (m_data->m_initialStart - m_start);
|
||||
tmp.AddAtEnd (dataEnd);
|
||||
Buffer::Iterator i = tmp.End ();
|
||||
i.Prev (dataEnd);
|
||||
i.Write (m_data->m_data+m_data->m_initialStart,dataEnd);
|
||||
*const_cast<Buffer *> (this) = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t const*
|
||||
Buffer::PeekData (void) const
|
||||
{
|
||||
TransformIntoRealBuffer ();
|
||||
return m_data->m_data + m_start;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "ns3/test.h"
|
||||
#include <iomanip>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class BufferTest: public Test {
|
||||
private:
|
||||
bool EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[]);
|
||||
public:
|
||||
virtual bool RunTests (void);
|
||||
BufferTest ();
|
||||
};
|
||||
|
||||
|
||||
BufferTest::BufferTest ()
|
||||
: Test ("Buffer") {}
|
||||
|
||||
bool
|
||||
BufferTest::EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[])
|
||||
{
|
||||
bool success = true;
|
||||
uint8_t *expected = array;
|
||||
uint8_t const*got;
|
||||
got = b.PeekData ();
|
||||
for (uint32_t j = 0; j < n; j++)
|
||||
{
|
||||
if (got[j] != expected[j])
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
Failure () << "Buffer -- ";
|
||||
Failure () << "expected: n=";
|
||||
Failure () << n << ", ";
|
||||
Failure ().setf (std::ios::hex, std::ios::basefield);
|
||||
for (uint32_t j = 0; j < n; j++)
|
||||
{
|
||||
Failure () << (uint16_t)expected[j] << " ";
|
||||
}
|
||||
Failure ().setf (std::ios::dec, std::ios::basefield);
|
||||
Failure () << "got: ";
|
||||
Failure ().setf (std::ios::hex, std::ios::basefield);
|
||||
for (uint32_t j = 0; j < n; j++)
|
||||
{
|
||||
Failure () << (uint16_t)got[j] << " ";
|
||||
}
|
||||
Failure () << std::endl;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Note: works only when variadic macros are
|
||||
* available which is the case for gcc.
|
||||
* XXX
|
||||
*/
|
||||
#define ENSURE_WRITTEN_BYTES(buffer, n, ...) \
|
||||
{ \
|
||||
uint8_t bytes[] = {__VA_ARGS__}; \
|
||||
if (!EnsureWrittenBytes (buffer, n , bytes)) \
|
||||
{ \
|
||||
ok = false; \
|
||||
} \
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
Buffer buffer;
|
||||
Buffer::Iterator i;
|
||||
buffer.AddAtStart (6);
|
||||
i = buffer.Begin ();
|
||||
i.WriteU8 (0x66);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 1, 0x66);
|
||||
i = buffer.Begin ();
|
||||
i.WriteU8 (0x67);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 1, 0x67);
|
||||
i.WriteHtonU16 (0x6568);
|
||||
i = buffer.Begin ();
|
||||
ENSURE_WRITTEN_BYTES (buffer, 3, 0x67, 0x65, 0x68);
|
||||
i.WriteHtonU16 (0x6369);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 3, 0x63, 0x69, 0x68);
|
||||
i.WriteHtonU32 (0xdeadbeaf);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 6, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
|
||||
buffer.AddAtStart (2);
|
||||
i = buffer.Begin ();
|
||||
i.WriteU16 (0);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
|
||||
buffer.AddAtEnd (2);
|
||||
i = buffer.Begin ();
|
||||
i.Next (8);
|
||||
i.WriteU16 (0);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 10, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
|
||||
buffer.RemoveAtStart (3);
|
||||
i = buffer.Begin ();
|
||||
ENSURE_WRITTEN_BYTES (buffer, 7, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
|
||||
buffer.RemoveAtEnd (4);
|
||||
i = buffer.Begin ();
|
||||
ENSURE_WRITTEN_BYTES (buffer, 3, 0x69, 0xde, 0xad);
|
||||
buffer.AddAtStart (1);
|
||||
i = buffer.Begin ();
|
||||
i.WriteU8 (0xff);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 4, 0xff, 0x69, 0xde, 0xad);
|
||||
buffer.AddAtEnd (1);
|
||||
i = buffer.Begin ();
|
||||
i.Next (4);
|
||||
i.WriteU8 (0xff);
|
||||
i.Prev (2);
|
||||
uint16_t saved = i.ReadU16 ();
|
||||
i.Prev (2);
|
||||
i.WriteHtonU16 (0xff00);
|
||||
i.Prev (2);
|
||||
if (i.ReadNtohU16 () != 0xff00)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
i.Prev (2);
|
||||
i.WriteU16 (saved);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
|
||||
Buffer o = buffer;
|
||||
ENSURE_WRITTEN_BYTES (o, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
|
||||
o.AddAtStart (1);
|
||||
i = o.Begin ();
|
||||
i.WriteU8 (0xfe);
|
||||
ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
|
||||
buffer.AddAtStart (2);
|
||||
i = buffer.Begin ();
|
||||
i.WriteU8 (0xfd);
|
||||
i.WriteU8 (0xfd);
|
||||
ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 7, 0xfd, 0xfd, 0xff, 0x69, 0xde, 0xad, 0xff);
|
||||
|
||||
// test self-assignment
|
||||
{
|
||||
Buffer a = o;
|
||||
a = a;
|
||||
}
|
||||
|
||||
// test Remove start.
|
||||
buffer = Buffer (5);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
|
||||
buffer.RemoveAtStart (1);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
|
||||
buffer.AddAtStart (1);
|
||||
buffer.Begin ().WriteU8 (0xff);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0, 0, 0, 0);
|
||||
buffer.RemoveAtStart(3);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
|
||||
buffer.AddAtStart (4);
|
||||
buffer.Begin ().WriteHtonU32 (0xdeadbeaf);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 6, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
|
||||
buffer.RemoveAtStart (2);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 4, 0xbe, 0xaf, 0, 0);
|
||||
buffer.AddAtEnd (4);
|
||||
i = buffer.Begin ();
|
||||
i.Next (4);
|
||||
i.WriteHtonU32 (0xdeadbeaf);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 8, 0xbe, 0xaf, 0, 0, 0xde, 0xad, 0xbe, 0xaf);
|
||||
buffer.RemoveAtStart (5);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 3, 0xad, 0xbe, 0xaf);
|
||||
// test Remove end
|
||||
buffer = Buffer (5);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
|
||||
buffer.RemoveAtEnd (1);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
|
||||
buffer.AddAtEnd (2);
|
||||
i = buffer.Begin ();
|
||||
i.Next (4);
|
||||
i.WriteU8 (0xab);
|
||||
i.WriteU8 (0xac);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 6, 0, 0, 0, 0, 0xab, 0xac);
|
||||
buffer.RemoveAtEnd (1);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0xab);
|
||||
buffer.RemoveAtEnd (3);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
|
||||
buffer.AddAtEnd (6);
|
||||
i = buffer.Begin ();
|
||||
i.Next (2);
|
||||
i.WriteU8 (0xac);
|
||||
i.WriteU8 (0xad);
|
||||
i.WriteU8 (0xae);
|
||||
i.WriteU8 (0xaf);
|
||||
i.WriteU8 (0xba);
|
||||
i.WriteU8 (0xbb);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
|
||||
buffer.AddAtStart (3);
|
||||
i = buffer.Begin ();
|
||||
i.WriteU8 (0x30);
|
||||
i.WriteU8 (0x31);
|
||||
i.WriteU8 (0x32);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 11, 0x30, 0x31, 0x32, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
|
||||
buffer.RemoveAtEnd (9);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 2, 0x30, 0x31);
|
||||
buffer = Buffer (3);
|
||||
buffer.AddAtEnd (2);
|
||||
i = buffer.Begin ();
|
||||
i.Next (3);
|
||||
i.WriteHtonU16 (0xabcd);
|
||||
buffer.AddAtStart (1);
|
||||
buffer.Begin ().WriteU8 (0x21);
|
||||
ENSURE_WRITTEN_BYTES (buffer, 6, 0x21, 0, 0, 0, 0xab, 0xcd);
|
||||
buffer.RemoveAtEnd (8);
|
||||
if (buffer.GetSize () != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
buffer = Buffer (6);
|
||||
buffer.AddAtStart (9);
|
||||
buffer.AddAtEnd (3);
|
||||
i = buffer.End ();
|
||||
i.Prev (1);
|
||||
i.WriteU8 (1, 1);
|
||||
|
||||
buffer = Buffer (6);
|
||||
buffer.AddAtStart (3);
|
||||
buffer.RemoveAtEnd (8);
|
||||
buffer.AddAtEnd (4);
|
||||
i = buffer.End ();
|
||||
i.Prev (4);
|
||||
i.WriteU8 (1, 4);
|
||||
|
||||
buffer = Buffer (1);
|
||||
buffer.AddAtEnd (100);
|
||||
i = buffer.End ();
|
||||
i.Prev (100);
|
||||
i.WriteU8 (1, 100);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static BufferTest gBufferTest;
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
|
||||
|
||||
@@ -0,0 +1,708 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief automatically resized byte buffer
|
||||
*
|
||||
* This represents a buffer of bytes. Its size is
|
||||
* automatically adjusted to hold any data prepended
|
||||
* or appended by the user. Its implementation is optimized
|
||||
* to ensure that the number of buffer resizes is minimized,
|
||||
* by creating new Buffers of the maximum size ever used.
|
||||
* The correct maximum size is learned at runtime during use by
|
||||
* recording the maximum size of each packet.
|
||||
*/
|
||||
class Buffer {
|
||||
public:
|
||||
/**
|
||||
* \brief iterator in a Buffer instance
|
||||
*/
|
||||
class Iterator {
|
||||
public:
|
||||
inline Iterator ();
|
||||
/**
|
||||
* go forward by one byte
|
||||
*/
|
||||
inline void Next (void);
|
||||
/**
|
||||
* go backward by one byte
|
||||
*/
|
||||
inline void Prev (void);
|
||||
/**
|
||||
* \param delta number of bytes to go forward
|
||||
*/
|
||||
inline void Next (uint32_t delta);
|
||||
/**
|
||||
* \param delta number of bytes to go backward
|
||||
*/
|
||||
inline void Prev (uint32_t delta);
|
||||
/**
|
||||
* \param o the second iterator
|
||||
* \return number of bytes included between the two iterators
|
||||
*
|
||||
* This method works only if the two iterators point
|
||||
* to the same underlying buffer. Debug builds ensure
|
||||
* this with an assert.
|
||||
*/
|
||||
inline int32_t GetDistanceFrom (Iterator const &o) const;
|
||||
|
||||
/**
|
||||
* \return true if this iterator points to the end of the byte array.
|
||||
* false otherwise.
|
||||
*/
|
||||
inline bool IsEnd (void) const;
|
||||
/**
|
||||
* \return true if this iterator points to the start of the byte array.
|
||||
* false otherwise.
|
||||
*/
|
||||
inline bool IsStart (void) const;
|
||||
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by one byte.
|
||||
*/
|
||||
inline void WriteU8 (uint8_t data);
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
* \param len number of times data must be written in buffer
|
||||
*
|
||||
* Write the data in buffer len times and avance the iterator position
|
||||
* by len byte.
|
||||
*/
|
||||
inline void WriteU8 (uint8_t data, uint32_t len);
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by two bytes. The format of the data written in the byte
|
||||
* buffer is non-portable. We only ensure that readU16 will
|
||||
* return exactly what we wrote with writeU16 if the program
|
||||
* is run on the same machine.
|
||||
*/
|
||||
inline void WriteU16 (uint16_t data);
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by four bytes. The format of the data written in the byte
|
||||
* buffer is non-portable. We only ensure that readU32 will
|
||||
* return exactly what we wrote with writeU32 if the program
|
||||
* is run on the same machine.
|
||||
*/
|
||||
inline void WriteU32 (uint32_t data);
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by eight bytes. The format of the data written in the byte
|
||||
* buffer is non-portable. We only ensure that readU64 will
|
||||
* return exactly what we wrote with writeU64 if the program
|
||||
* is run on the same machine.
|
||||
*/
|
||||
inline void WriteU64 (uint64_t data);
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by two bytes. The data is written in network order and the
|
||||
* input data is expected to be in host order.
|
||||
*/
|
||||
inline void WriteHtonU16 (uint16_t data);
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by four bytes. The data is written in network order and the
|
||||
* input data is expected to be in host order.
|
||||
*/
|
||||
inline void WriteHtonU32 (uint32_t data);
|
||||
/**
|
||||
* \param data data to write in buffer
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by eight bytes. The data is written in network order and the
|
||||
* input data is expected to be in host order.
|
||||
*/
|
||||
inline void WriteHtonU64 (uint64_t data);
|
||||
/**
|
||||
* \param buffer a byte buffer to copy in the internal buffer.
|
||||
* \param size number of bytes to copy.
|
||||
*
|
||||
* Write the data in buffer and avance the iterator position
|
||||
* by size bytes.
|
||||
*/
|
||||
inline void Write (uint8_t const*buffer, uint16_t size);
|
||||
/**
|
||||
* \param start the start of the data to copy
|
||||
* \param end the end of the data to copy
|
||||
*
|
||||
* Write the data delimited by start and end in internal buffer
|
||||
* and avance the iterator position by the number of bytes
|
||||
* copied.
|
||||
* The input interators _must_ not point to the same Buffer as
|
||||
* we do to avoid overlapping copies. This is enforced
|
||||
* in debug builds by asserts.
|
||||
*/
|
||||
inline void Write (Iterator start, Iterator end);
|
||||
|
||||
/**
|
||||
* \return the byte read in the buffer.
|
||||
*
|
||||
* Read data and advance the Iterator by the number of bytes
|
||||
* read.
|
||||
*/
|
||||
inline uint8_t ReadU8 (void);
|
||||
/**
|
||||
* \return the two bytes read in the buffer.
|
||||
*
|
||||
* Read data and advance the Iterator by the number of bytes
|
||||
* read.
|
||||
* The data is read in the format written by writeU16.
|
||||
*/
|
||||
inline uint16_t ReadU16 (void);
|
||||
/**
|
||||
* \return the four bytes read in the buffer.
|
||||
*
|
||||
* Read data and advance the Iterator by the number of bytes
|
||||
* read.
|
||||
* The data is read in the format written by writeU32.
|
||||
*/
|
||||
inline uint32_t ReadU32 (void);
|
||||
/**
|
||||
* \return the eight bytes read in the buffer.
|
||||
*
|
||||
* Read data and advance the Iterator by the number of bytes
|
||||
* read.
|
||||
* The data is read in the format written by writeU64.
|
||||
*/
|
||||
inline uint64_t ReadU64 (void);
|
||||
/**
|
||||
* \return the two bytes read in the buffer.
|
||||
*
|
||||
* Read data and advance the Iterator by the number of bytes
|
||||
* read.
|
||||
* The data is read in network format and return in host format.
|
||||
*/
|
||||
inline uint16_t ReadNtohU16 (void);
|
||||
/**
|
||||
* \return the four bytes read in the buffer.
|
||||
*
|
||||
* Read data and advance the Iterator by the number of bytes
|
||||
* read.
|
||||
* The data is read in network format and return in host format.
|
||||
*/
|
||||
inline uint32_t ReadNtohU32 (void);
|
||||
/**
|
||||
* \return the eight bytes read in the buffer.
|
||||
*
|
||||
* Read data and advance the Iterator by the number of bytes
|
||||
* read.
|
||||
* The data is read in network format and return in host format.
|
||||
*/
|
||||
inline uint64_t ReadNtohU64 (void);
|
||||
/**
|
||||
* \param buffer buffer to copy data into
|
||||
* \param size number of bytes to copy
|
||||
*
|
||||
* Copy size bytes of data from the internal buffer to the
|
||||
* input buffer and avance the Iterator by the number of
|
||||
* bytes read.
|
||||
*/
|
||||
inline void Read (uint8_t *buffer, uint16_t size);
|
||||
private:
|
||||
friend class Buffer;
|
||||
inline Iterator (Buffer const*buffer, uint32_t m_current);
|
||||
inline uint32_t GetIndex (uint32_t n);
|
||||
uint32_t m_zeroStart;
|
||||
uint32_t m_zeroEnd;
|
||||
uint32_t m_dataEnd;
|
||||
uint32_t m_current;
|
||||
uint8_t *m_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* \return the number of bytes stored in this buffer.
|
||||
*/
|
||||
inline uint32_t GetSize (void) const;
|
||||
|
||||
/**
|
||||
* \return a pointer to the start of the internal
|
||||
* byte buffer.
|
||||
*
|
||||
* The returned pointer points to an area of
|
||||
* memory which is ns3::Buffer::GetSize () bytes big.
|
||||
* Please, try to never ever use this method. It is really
|
||||
* evil and is present only for a few specific uses.
|
||||
*/
|
||||
uint8_t const*PeekData (void) const;
|
||||
|
||||
/**
|
||||
* \param start size to reserve
|
||||
*
|
||||
* Add bytes at the start of the Buffer. The
|
||||
* content of these bytes is undefined but debugging
|
||||
* builds initialize them to 0x33.
|
||||
* Any call to this method invalidates any Iterator
|
||||
* pointing to this Buffer.
|
||||
*/
|
||||
void AddAtStart (uint32_t start);
|
||||
/**
|
||||
* \param end size to reserve
|
||||
*
|
||||
* Add bytes at the end of the Buffer. The
|
||||
* content of these bytes is undefined but debugging
|
||||
* builds initialize them to 0x33.
|
||||
* Any call to this method invalidates any Iterator
|
||||
* pointing to this Buffer.
|
||||
*/
|
||||
void AddAtEnd (uint32_t end);
|
||||
/**
|
||||
* \param start size to remove
|
||||
*
|
||||
* Remove bytes at the start of the Buffer.
|
||||
* Any call to this method invalidates any Iterator
|
||||
* pointing to this Buffer.
|
||||
*/
|
||||
void RemoveAtStart (uint32_t start);
|
||||
/**
|
||||
* \param end size to remove
|
||||
*
|
||||
* Remove bytes at the end of the Buffer.
|
||||
* Any call to this method invalidates any Iterator
|
||||
* pointing to this Buffer.
|
||||
*/
|
||||
void RemoveAtEnd (uint32_t end);
|
||||
|
||||
/**
|
||||
* \param start offset from start of packet
|
||||
* \param length
|
||||
*
|
||||
* \return a fragment of size length starting at offset
|
||||
* start.
|
||||
*/
|
||||
Buffer CreateFragment (uint32_t start, uint32_t length) const;
|
||||
|
||||
/**
|
||||
* \return an Iterator which points to the
|
||||
* start of this Buffer.
|
||||
*/
|
||||
inline Buffer::Iterator Begin (void) const;
|
||||
/**
|
||||
* \return an Iterator which points to the
|
||||
* end of this Buffer.
|
||||
*/
|
||||
inline Buffer::Iterator End (void) const;
|
||||
|
||||
void TransformIntoRealBuffer (void) const;
|
||||
|
||||
inline Buffer (Buffer const &o);
|
||||
inline Buffer &operator = (Buffer const &o);
|
||||
inline Buffer ();
|
||||
inline Buffer (uint32_t dataSize);
|
||||
inline ~Buffer ();
|
||||
private:
|
||||
struct BufferData {
|
||||
uint32_t m_count;
|
||||
uint32_t m_size;
|
||||
uint32_t m_initialStart;
|
||||
uint32_t m_dirtyStart;
|
||||
uint32_t m_dirtySize;
|
||||
uint8_t m_data[1];
|
||||
};
|
||||
typedef std::vector<struct Buffer::BufferData*> BufferDataList;
|
||||
|
||||
inline uint8_t *GetStart (void) const;
|
||||
static void Recycle (struct Buffer::BufferData *data);
|
||||
static struct Buffer::BufferData *Create (void);
|
||||
static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start);
|
||||
static void Deallocate (struct Buffer::BufferData *data);
|
||||
|
||||
static BufferDataList m_freeList;
|
||||
static uint32_t m_maxTotalAddStart;
|
||||
static uint32_t m_maxTotalAddEnd;
|
||||
|
||||
struct BufferData *m_data;
|
||||
uint32_t m_zeroAreaSize;
|
||||
uint32_t m_start;
|
||||
uint32_t m_size;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
/**************************************************
|
||||
Start of implementation of methods which
|
||||
need to be inline for performance reasons.
|
||||
*************************************************/
|
||||
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
Buffer::Buffer ()
|
||||
: m_data (Buffer::Create ()),
|
||||
m_zeroAreaSize (0),
|
||||
m_start (m_maxTotalAddStart),
|
||||
m_size (0)
|
||||
{
|
||||
if (m_start > m_data->m_size)
|
||||
{
|
||||
m_start = 0;
|
||||
}
|
||||
NS_ASSERT (m_start <= m_data->m_size);
|
||||
}
|
||||
|
||||
Buffer::Buffer (uint32_t dataSize)
|
||||
: m_data (Buffer::Create ()),
|
||||
m_zeroAreaSize (dataSize),
|
||||
m_start (m_maxTotalAddStart),
|
||||
m_size (0)
|
||||
{
|
||||
if (m_start > m_data->m_size)
|
||||
{
|
||||
m_start = 0;
|
||||
}
|
||||
NS_ASSERT (m_start <= m_data->m_size);
|
||||
}
|
||||
|
||||
|
||||
Buffer::Buffer (Buffer const&o)
|
||||
: m_data (o.m_data),
|
||||
m_zeroAreaSize (o.m_zeroAreaSize),
|
||||
m_start (o.m_start),
|
||||
m_size (o.m_size)
|
||||
{
|
||||
m_data->m_count++;
|
||||
NS_ASSERT (m_start <= m_data->m_size);
|
||||
}
|
||||
|
||||
Buffer &
|
||||
Buffer::operator = (Buffer const&o)
|
||||
{
|
||||
if (m_data != o.m_data)
|
||||
{
|
||||
// not assignment to self.
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
Recycle (m_data);
|
||||
}
|
||||
m_data = o.m_data;
|
||||
m_data->m_count++;
|
||||
}
|
||||
m_zeroAreaSize = o.m_zeroAreaSize;
|
||||
m_start = o.m_start;
|
||||
m_size = o.m_size;
|
||||
NS_ASSERT (m_start <= m_data->m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Buffer::~Buffer ()
|
||||
{
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
Recycle (m_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t *
|
||||
Buffer::GetStart (void) const
|
||||
{
|
||||
return m_data->m_data + m_start;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Buffer::GetSize (void) const
|
||||
{
|
||||
return m_size + m_zeroAreaSize;
|
||||
}
|
||||
|
||||
Buffer::Iterator
|
||||
Buffer::Begin (void) const
|
||||
{
|
||||
return Buffer::Iterator (this, 0);
|
||||
}
|
||||
Buffer::Iterator
|
||||
Buffer::End (void) const
|
||||
{
|
||||
return Buffer::Iterator (this, GetSize ());
|
||||
}
|
||||
|
||||
|
||||
Buffer::Iterator::Iterator ()
|
||||
: m_zeroStart (0),
|
||||
m_zeroEnd (0),
|
||||
m_dataEnd (0),
|
||||
m_current (0),
|
||||
m_data (0)
|
||||
{}
|
||||
Buffer::Iterator::Iterator (Buffer const*buffer, uint32_t current)
|
||||
: m_zeroStart (buffer->m_data->m_initialStart-buffer->m_start),
|
||||
m_zeroEnd (m_zeroStart+buffer->m_zeroAreaSize),
|
||||
m_dataEnd (buffer->GetSize ()),
|
||||
m_current (current),
|
||||
m_data (buffer->m_data->m_data+buffer->m_start)
|
||||
{}
|
||||
|
||||
void
|
||||
Buffer::Iterator::Next (void)
|
||||
{
|
||||
NS_ASSERT (m_current + 1 <= m_dataEnd);
|
||||
m_current++;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::Prev (void)
|
||||
{
|
||||
NS_ASSERT (m_current >= 1);
|
||||
m_current--;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::Next (uint32_t delta)
|
||||
{
|
||||
NS_ASSERT (m_current + delta <= m_dataEnd);
|
||||
m_current += delta;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::Prev (uint32_t delta)
|
||||
{
|
||||
NS_ASSERT (m_current >= delta);
|
||||
m_current -= delta;
|
||||
}
|
||||
int32_t
|
||||
Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
|
||||
{
|
||||
NS_ASSERT (m_data == o.m_data);
|
||||
int32_t start = m_current;
|
||||
int32_t end = o.m_current;
|
||||
return end - start;
|
||||
}
|
||||
|
||||
bool
|
||||
Buffer::Iterator::IsEnd (void) const
|
||||
{
|
||||
return m_current == m_dataEnd;
|
||||
}
|
||||
bool
|
||||
Buffer::Iterator::IsStart (void) const
|
||||
{
|
||||
return m_current == 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Buffer::Iterator::GetIndex (uint32_t n)
|
||||
{
|
||||
NS_ASSERT (
|
||||
(m_current + n <= m_dataEnd) &&
|
||||
((m_current + n <= m_zeroStart) ||
|
||||
(m_current >= m_zeroEnd) ||
|
||||
m_zeroStart == m_zeroEnd)
|
||||
);
|
||||
uint32_t index;
|
||||
if (m_current < m_zeroStart)
|
||||
{
|
||||
index = m_current;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = m_current - (m_zeroEnd-m_zeroStart);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Buffer::Iterator::Write (Iterator start, Iterator end)
|
||||
{
|
||||
NS_ASSERT (start.m_data == end.m_data);
|
||||
NS_ASSERT (start.m_current <= end.m_current);
|
||||
NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
|
||||
NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
|
||||
NS_ASSERT (m_data != start.m_data);
|
||||
uint32_t size = end.m_current - start.m_current;
|
||||
uint8_t *src = start.m_data + start.GetIndex (size);
|
||||
uint8_t *dest = m_data + GetIndex (size);
|
||||
memcpy (dest, src, size);
|
||||
m_current += size;
|
||||
}
|
||||
|
||||
void
|
||||
Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (len);
|
||||
memset (current, data, len);
|
||||
m_current += len;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::WriteU8 (uint8_t data)
|
||||
{
|
||||
m_data[GetIndex (1)] = data;
|
||||
m_current++;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::WriteU16 (uint16_t data)
|
||||
{
|
||||
uint16_t *buffer = (uint16_t *)(m_data + GetIndex (2));
|
||||
*buffer = data;
|
||||
m_current += 2;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::WriteU32 (uint32_t data)
|
||||
{
|
||||
uint32_t *buffer = (uint32_t *)(m_data + GetIndex (4));
|
||||
*buffer = data;
|
||||
m_current += 4;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::WriteU64 (uint64_t data)
|
||||
{
|
||||
uint64_t *buffer = (uint64_t *)(m_data + GetIndex (8));
|
||||
*buffer = data;
|
||||
m_current += 8;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::WriteHtonU16 (uint16_t data)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (2);
|
||||
*(current+0) = (data >> 8) & 0xff;
|
||||
*(current+1) = (data >> 0) & 0xff;
|
||||
m_current += 2;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::WriteHtonU32 (uint32_t data)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (4);
|
||||
*(current+0) = (data >> 24) & 0xff;
|
||||
*(current+1) = (data >> 16) & 0xff;
|
||||
*(current+2) = (data >> 8) & 0xff;
|
||||
*(current+3) = (data >> 0) & 0xff;
|
||||
m_current += 4;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::WriteHtonU64 (uint64_t data)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (8);
|
||||
*(current+0) = (data >> 56) & 0xff;
|
||||
*(current+1) = (data >> 48) & 0xff;
|
||||
*(current+2) = (data >> 40) & 0xff;
|
||||
*(current+3) = (data >> 32) & 0xff;
|
||||
*(current+4) = (data >> 24) & 0xff;
|
||||
*(current+5) = (data >> 16) & 0xff;
|
||||
*(current+6) = (data >> 8) & 0xff;
|
||||
*(current+7) = (data >> 0) & 0xff;
|
||||
m_current += 8;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::Write (uint8_t const*buffer, uint16_t size)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (size);
|
||||
memcpy (current, buffer, size);
|
||||
m_current += size;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
Buffer::Iterator::ReadU8 (void)
|
||||
{
|
||||
uint8_t data = m_data[GetIndex(1)];
|
||||
m_current++;
|
||||
return data;
|
||||
}
|
||||
uint16_t
|
||||
Buffer::Iterator::ReadU16 (void)
|
||||
{
|
||||
uint16_t *buffer = reinterpret_cast<uint16_t *>(m_data + GetIndex (2));
|
||||
m_current += 2;
|
||||
return *buffer;
|
||||
}
|
||||
uint32_t
|
||||
Buffer::Iterator::ReadU32 (void)
|
||||
{
|
||||
uint32_t *buffer = reinterpret_cast<uint32_t *>(m_data + GetIndex (4));
|
||||
m_current += 4;
|
||||
return *buffer;
|
||||
}
|
||||
uint64_t
|
||||
Buffer::Iterator::ReadU64 (void)
|
||||
{
|
||||
uint64_t *buffer = reinterpret_cast<uint64_t *>(m_data + GetIndex (8));
|
||||
m_current += 8;
|
||||
return *buffer;
|
||||
}
|
||||
uint16_t
|
||||
Buffer::Iterator::ReadNtohU16 (void)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (2);
|
||||
uint16_t retval = 0;
|
||||
retval |= static_cast<uint16_t> (current[0]) << 8;
|
||||
retval |= static_cast<uint16_t> (current[1]) << 0;
|
||||
m_current += 2;
|
||||
return retval;
|
||||
}
|
||||
uint32_t
|
||||
Buffer::Iterator::ReadNtohU32 (void)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (4);
|
||||
uint32_t retval = 0;
|
||||
retval |= static_cast<uint32_t> (current[0]) << 24;
|
||||
retval |= static_cast<uint32_t> (current[1]) << 16;
|
||||
retval |= static_cast<uint32_t> (current[2]) << 8;
|
||||
retval |= static_cast<uint32_t> (current[3]) << 0;
|
||||
m_current += 4;
|
||||
return retval;
|
||||
}
|
||||
uint64_t
|
||||
Buffer::Iterator::ReadNtohU64 (void)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (8);
|
||||
uint64_t retval = 0;
|
||||
retval |= static_cast<uint64_t> (current[0]) << 56;
|
||||
retval |= static_cast<uint64_t> (current[1]) << 48;
|
||||
retval |= static_cast<uint64_t> (current[2]) << 40;
|
||||
retval |= static_cast<uint64_t> (current[3]) << 32;
|
||||
retval |= static_cast<uint64_t> (current[4]) << 24;
|
||||
retval |= static_cast<uint64_t> (current[5]) << 16;
|
||||
retval |= static_cast<uint64_t> (current[6]) << 8;
|
||||
retval |= static_cast<uint64_t> (current[7]) << 0;
|
||||
m_current += 8;
|
||||
return retval;
|
||||
}
|
||||
void
|
||||
Buffer::Iterator::Read (uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
uint8_t *current = m_data + GetIndex (size);
|
||||
memcpy (buffer, current, size);
|
||||
m_current += size;
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#endif /* BUFFER_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "callback-trace-source.h"
|
||||
#include "ns3/test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class CallbackTraceSourceTest : public Test
|
||||
{
|
||||
public:
|
||||
CallbackTraceSourceTest ();
|
||||
virtual ~CallbackTraceSourceTest ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
void CbOne (TraceContext const &context, uint8_t a, double b);
|
||||
void CbTwo (TraceContext const &context, uint8_t a, double b);
|
||||
|
||||
bool m_one;
|
||||
bool m_two;
|
||||
};
|
||||
|
||||
CallbackTraceSourceTest::CallbackTraceSourceTest ()
|
||||
: Test ("CallbackTraceSource")
|
||||
{}
|
||||
CallbackTraceSourceTest::~CallbackTraceSourceTest ()
|
||||
{}
|
||||
void
|
||||
CallbackTraceSourceTest::CbOne (TraceContext const &context, uint8_t a, double b)
|
||||
{
|
||||
m_one = true;
|
||||
}
|
||||
void
|
||||
CallbackTraceSourceTest::CbTwo (TraceContext const &context, uint8_t a, double b)
|
||||
{
|
||||
m_two = true;
|
||||
}
|
||||
bool
|
||||
CallbackTraceSourceTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
TraceContext ctx;
|
||||
|
||||
CallbackTraceSource<uint8_t,double> trace;
|
||||
trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
|
||||
trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
|
||||
m_one = false;
|
||||
m_two = false;
|
||||
trace (1, 2);
|
||||
if (!m_one || !m_two)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this));
|
||||
m_one = false;
|
||||
m_two = false;
|
||||
trace (1, 2);
|
||||
if (m_one || !m_two)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this));
|
||||
m_one = false;
|
||||
m_two = false;
|
||||
trace (1, 2);
|
||||
if (m_one || m_two)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
CallbackTraceSourceTest g_callbackTraceTest;
|
||||
|
||||
|
||||
|
||||
}//namespace ns3
|
||||
@@ -0,0 +1,157 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006,2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef CALLBACK_TRACE_H
|
||||
#define CALLBACK_TRACE_H
|
||||
|
||||
#include <list>
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
#include "trace-context.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
/**
|
||||
* \brief log arbitrary number of parameters to a matching ns3::Callback
|
||||
* \ingroup lowleveltracing
|
||||
*
|
||||
* Whenever operator () is invoked on this class, the call and its arguments
|
||||
* are forwarded to the internal matching ns3::Callback.
|
||||
*/
|
||||
template<typename T1 = empty, typename T2 = empty,
|
||||
typename T3 = empty, typename T4 = empty>
|
||||
class CallbackTraceSource {
|
||||
public:
|
||||
CallbackTraceSource ();
|
||||
void AddCallback (CallbackBase const & callback, TraceContext const & context);
|
||||
void RemoveCallback (CallbackBase const & callback);
|
||||
void operator() (void);
|
||||
void operator() (T1 a1);
|
||||
void operator() (T1 a1, T2 a2);
|
||||
void operator() (T1 a1, T2 a2, T3 a3);
|
||||
void operator() (T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
|
||||
private:
|
||||
typedef std::list<Callback<void,TraceContext const &,T1,T2,T3,T4> > CallbackList;
|
||||
TraceContext m_context;
|
||||
CallbackList m_callbackList;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
// implementation below.
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
CallbackTraceSource<T1,T2,T3,T4>::CallbackTraceSource ()
|
||||
: m_callbackList ()
|
||||
{}
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
void
|
||||
CallbackTraceSource<T1,T2,T3,T4>::AddCallback (CallbackBase const & callback,
|
||||
TraceContext const &context)
|
||||
{
|
||||
Callback<void,TraceContext const &,T1,T2,T3,T4> cb;
|
||||
cb.Assign (callback);
|
||||
m_context.Add (context);
|
||||
m_callbackList.push_back (cb);
|
||||
}
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
void
|
||||
CallbackTraceSource<T1,T2,T3,T4>::RemoveCallback (CallbackBase const & callback)
|
||||
{
|
||||
for (typename CallbackList::iterator i = m_callbackList.begin ();
|
||||
i != m_callbackList.end (); /* empty */)
|
||||
{
|
||||
if ((*i).IsEqual (callback))
|
||||
{
|
||||
i = m_callbackList.erase (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
void
|
||||
CallbackTraceSource<T1,T2,T3,T4>::operator() (void)
|
||||
{
|
||||
for (typename CallbackList::iterator i = m_callbackList.begin ();
|
||||
i != m_callbackList.end (); i++)
|
||||
{
|
||||
(*i) (m_context);
|
||||
}
|
||||
}
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
void
|
||||
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1)
|
||||
{
|
||||
for (typename CallbackList::iterator i = m_callbackList.begin ();
|
||||
i != m_callbackList.end (); i++)
|
||||
{
|
||||
(*i) (m_context, a1);
|
||||
}
|
||||
}
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
void
|
||||
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2)
|
||||
{
|
||||
for (typename CallbackList::iterator i = m_callbackList.begin ();
|
||||
i != m_callbackList.end (); i++)
|
||||
{
|
||||
(*i) (m_context, a1, a2);
|
||||
}
|
||||
}
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
void
|
||||
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
for (typename CallbackList::iterator i = m_callbackList.begin ();
|
||||
i != m_callbackList.end (); i++)
|
||||
{
|
||||
(*i) (m_context, a1, a2, a3);
|
||||
}
|
||||
}
|
||||
template<typename T1, typename T2,
|
||||
typename T3, typename T4>
|
||||
void
|
||||
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
for (typename CallbackList::iterator i = m_callbackList.begin ();
|
||||
i != m_callbackList.end (); i++)
|
||||
{
|
||||
(*i) (m_context, a1, a2, a3, a4);
|
||||
}
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* CALLBACK_TRACE_H */
|
||||
@@ -0,0 +1,65 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "chunk.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
Chunk::Chunk ()
|
||||
{}
|
||||
|
||||
Chunk::~Chunk ()
|
||||
{}
|
||||
|
||||
std::string
|
||||
Chunk::GetName (void) const
|
||||
{
|
||||
return DoGetName ();
|
||||
}
|
||||
void
|
||||
Chunk::Print (std::ostream &os) const
|
||||
{
|
||||
PrintTo (os);
|
||||
}
|
||||
uint32_t
|
||||
Chunk::GetSize (void) const
|
||||
{
|
||||
return GetSerializedSize ();
|
||||
}
|
||||
void
|
||||
Chunk::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
SerializeTo (start);
|
||||
}
|
||||
uint32_t
|
||||
Chunk::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
uint32_t deserialized = DeserializeFrom (start);
|
||||
return deserialized;
|
||||
}
|
||||
std::ostream& operator<< (std::ostream& os, Chunk const& chunk)
|
||||
{
|
||||
chunk.Print (os);
|
||||
return os;
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef CHUNK_H
|
||||
#define CHUNK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ostream>
|
||||
#include "buffer.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk ();
|
||||
virtual ~Chunk ();
|
||||
|
||||
std::string GetName (void) const;
|
||||
void Print (std::ostream &os) const;
|
||||
uint32_t GetSize (void) const;
|
||||
void Serialize (Buffer::Iterator start) const;
|
||||
uint32_t Deserialize (Buffer::Iterator start);
|
||||
private:
|
||||
virtual std::string DoGetName (void) const = 0;
|
||||
virtual void PrintTo (std::ostream &os) const = 0;
|
||||
virtual uint32_t GetSerializedSize (void) const = 0;
|
||||
virtual void SerializeTo (Buffer::Iterator i) const = 0;
|
||||
virtual uint32_t DeserializeFrom (Buffer::Iterator i) = 0;
|
||||
};
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, Chunk const& chunk);
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* CHUNK_H */
|
||||
@@ -0,0 +1,331 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "composite-trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
CompositeTraceResolver::CompositeTraceResolver (TraceContext const &context)
|
||||
: TraceResolver (context)
|
||||
{}
|
||||
|
||||
CompositeTraceResolver::~CompositeTraceResolver ()
|
||||
{}
|
||||
|
||||
void
|
||||
CompositeTraceResolver::DoAdd (std::string name,
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver,
|
||||
TraceContext const &context)
|
||||
{
|
||||
struct CallbackTraceSourceItem item;
|
||||
item.name = name;
|
||||
item.createResolver = createResolver;
|
||||
item.context = context;
|
||||
m_items.push_back (item);
|
||||
}
|
||||
|
||||
TraceResolver::TraceResolverList
|
||||
CompositeTraceResolver::DoLookup (std::string id) const
|
||||
{
|
||||
if (id == "*")
|
||||
{
|
||||
TraceResolver::TraceResolverList list;
|
||||
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
|
||||
{
|
||||
list.push_back (i->createResolver (i->context));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
std::string::size_type start, end;
|
||||
start = id.find_first_of ("(", 0);
|
||||
end = id.find_first_of (")", 0);
|
||||
if (start != 0 || end != (id.size ()-1))
|
||||
{
|
||||
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
|
||||
{
|
||||
if (i->name == id)
|
||||
{
|
||||
TraceResolver::TraceResolverList list;
|
||||
list.push_back (i->createResolver (i->context));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::list<std::string> names;
|
||||
std::string alternatives = std::string (id, start+1, end-1);
|
||||
std::string::size_type next, cur;
|
||||
next = 0;
|
||||
cur = 0;
|
||||
while (true)
|
||||
{
|
||||
std::string element;
|
||||
next = alternatives.find ("|", cur);
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
element = std::string (alternatives, cur, alternatives.size ());
|
||||
names.push_back (element);
|
||||
break;
|
||||
}
|
||||
element = std::string (alternatives, cur, next);
|
||||
names.push_back (element);
|
||||
cur = next + 1;
|
||||
}
|
||||
TraceResolver::TraceResolverList list;
|
||||
for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
|
||||
{
|
||||
for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
|
||||
{
|
||||
if (j->name == *i)
|
||||
{
|
||||
list.push_back (j->createResolver (j->context));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "ns3/test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class CompositeTraceResolverTest : public Test
|
||||
{
|
||||
public:
|
||||
enum TraceSources {
|
||||
TEST_TRACE_DOUBLEA,
|
||||
TEST_TRACE_DOUBLEB,
|
||||
TEST_TRACE_SUBRESOLVER,
|
||||
};
|
||||
enum SubTraceSources {
|
||||
TEST_SUBTRACE_INT,
|
||||
};
|
||||
CompositeTraceResolverTest ();
|
||||
virtual ~CompositeTraceResolverTest ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
void TraceDouble (TraceContext const &context, double v);
|
||||
void TraceInt (TraceContext const &context, int v);
|
||||
TraceResolver *CreateSubResolver (TraceContext const &context);
|
||||
|
||||
|
||||
bool m_gotDoubleA;
|
||||
bool m_gotDoubleB;
|
||||
CallbackTraceSource<int> m_traceInt;
|
||||
bool m_gotInt;
|
||||
};
|
||||
|
||||
CompositeTraceResolverTest::CompositeTraceResolverTest ()
|
||||
: Test ("CompositeTraceResolver")
|
||||
{}
|
||||
CompositeTraceResolverTest::~CompositeTraceResolverTest ()
|
||||
{}
|
||||
void
|
||||
CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
|
||||
{
|
||||
enum CompositeTraceResolverTest::TraceSources source;
|
||||
context.Get (source);
|
||||
switch (source)
|
||||
{
|
||||
case TEST_TRACE_DOUBLEA:
|
||||
m_gotDoubleA = true;
|
||||
break;
|
||||
case TEST_TRACE_DOUBLEB:
|
||||
m_gotDoubleB = true;
|
||||
break;
|
||||
default:
|
||||
NS_FATAL_ERROR ("should not get any other trace source in this sink");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
|
||||
{
|
||||
m_gotInt = true;
|
||||
}
|
||||
|
||||
TraceResolver *
|
||||
CompositeTraceResolverTest::CreateSubResolver (TraceContext const &context)
|
||||
{
|
||||
CompositeTraceResolver *subresolver = new CompositeTraceResolver (context);
|
||||
subresolver->Add ("trace-int", m_traceInt, TEST_SUBTRACE_INT);
|
||||
return subresolver;
|
||||
}
|
||||
bool
|
||||
CompositeTraceResolverTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
CallbackTraceSource<double> traceDoubleA;
|
||||
CallbackTraceSource<double> traceDoubleB;
|
||||
TraceContext context;
|
||||
|
||||
CompositeTraceResolver resolver (context) ;
|
||||
|
||||
resolver.Add ("trace-double-a", traceDoubleA, TEST_TRACE_DOUBLEA);
|
||||
resolver.Add ("trace-double-b", traceDoubleB, TEST_TRACE_DOUBLEB);
|
||||
|
||||
resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
traceDoubleA (0);
|
||||
if (!m_gotDoubleA || m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
m_gotDoubleA = false;
|
||||
traceDoubleA (0);
|
||||
traceDoubleB (0);
|
||||
if (!m_gotDoubleA || !m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
|
||||
resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
traceDoubleA (0);
|
||||
traceDoubleB (0);
|
||||
if (m_gotDoubleA || m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
resolver.Connect ("/trace-double-a",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
traceDoubleA (0);
|
||||
traceDoubleB (0);
|
||||
if (!m_gotDoubleA || m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
resolver.Disconnect ("/trace-double-a",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
|
||||
resolver.Connect ("/(trace-double-a)",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
traceDoubleA (0);
|
||||
traceDoubleB (0);
|
||||
if (!m_gotDoubleA || m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
resolver.Disconnect ("/trace-double-a",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
|
||||
resolver.Connect ("/(trace-double-a|trace-double-b)",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
traceDoubleA (0);
|
||||
traceDoubleB (0);
|
||||
if (!m_gotDoubleA || !m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
resolver.Disconnect ("/trace-double-a",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
traceDoubleA (0);
|
||||
traceDoubleB (0);
|
||||
if (m_gotDoubleA || !m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
|
||||
resolver.Disconnect ("/(trace-double-a|trace-double-b)",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
||||
m_gotDoubleA = false;
|
||||
m_gotDoubleB = false;
|
||||
traceDoubleA (0);
|
||||
traceDoubleB (0);
|
||||
if (m_gotDoubleA || m_gotDoubleB)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
resolver.Add ("subresolver",
|
||||
MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this),
|
||||
TEST_TRACE_SUBRESOLVER);
|
||||
|
||||
resolver.Connect ("/subresolver/trace-int",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
|
||||
m_gotInt = false;
|
||||
m_traceInt (1);
|
||||
if (!m_gotInt)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
resolver.Disconnect ("/subresolver/trace-int",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
|
||||
m_gotInt = false;
|
||||
m_traceInt (1);
|
||||
if (m_gotInt)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
resolver.Connect ("/*/trace-int",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
|
||||
m_gotInt = false;
|
||||
m_traceInt (1);
|
||||
if (!m_gotInt)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
resolver.Disconnect ("/subresolver/trace-int",
|
||||
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
|
||||
m_gotInt = false;
|
||||
m_traceInt (1);
|
||||
if (m_gotInt)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static CompositeTraceResolverTest g_compositeTraceResolverTest;
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -0,0 +1,211 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef COMPOSITE_TRACE_RESOLVER_H
|
||||
#define COMPOSITE_TRACE_RESOLVER_H
|
||||
|
||||
#include "ns3/callback.h"
|
||||
#include "trace-resolver.h"
|
||||
#include "callback-trace-source.h"
|
||||
#include "uv-trace-source.h"
|
||||
#include "sv-trace-source.h"
|
||||
#include "fv-trace-source.h"
|
||||
#include "terminal-trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief a helper class to aggregate contained TraceResolver and other trace sources.
|
||||
* \ingroup lowleveltracing
|
||||
*/
|
||||
class CompositeTraceResolver : public TraceResolver
|
||||
{
|
||||
public:
|
||||
CompositeTraceResolver (TraceContext const &context);
|
||||
virtual ~CompositeTraceResolver ();
|
||||
/**
|
||||
* \param name name of trace source
|
||||
* \param trace a callback trace source
|
||||
* \param context the context associated to this trace source
|
||||
*
|
||||
* Add a callback trace source in this resolver. This trace
|
||||
* source will match the name specified during namespace
|
||||
* resolution. The TraceContext of this trace source will also
|
||||
* be automatically extended to contain the input context.
|
||||
*/
|
||||
template <typename T1, typename T2,
|
||||
typename T3, typename T4,
|
||||
typename T>
|
||||
void Add (std::string name,
|
||||
CallbackTraceSource<T1,T2,T3,T4> &trace, T const &context);
|
||||
/**
|
||||
* \param name name of trace source
|
||||
* \param trace a signed variable trace source
|
||||
* \param context the context associated to this trace source
|
||||
*
|
||||
* Add a signed variable trace source in this resolver.
|
||||
* This trace source will match the name specified during namespace
|
||||
* resolution. The TraceContext of this trace source will also
|
||||
* be automatically extended to contain the input context.
|
||||
*/
|
||||
template <typename T>
|
||||
void Add (std::string name,
|
||||
SVTraceSource<T> &trace, T const &context);
|
||||
/**
|
||||
* \param name name of trace source
|
||||
* \param trace an unsigned variable trace source
|
||||
* \param context the context associated to this trace source
|
||||
*
|
||||
* Add an unsigned variable trace source in this resolver.
|
||||
* This trace source will match the name specified during namespace
|
||||
* resolution. The TraceContext of this trace source will also
|
||||
* be automatically extended to contain the input context.
|
||||
*/
|
||||
template <typename T>
|
||||
void Add (std::string name,
|
||||
UVTraceSource<T> &trace, T const &context);
|
||||
/**
|
||||
* \param name name of trace source
|
||||
* \param trace a floating-point variable trace source
|
||||
* \param context the context associated to this trace source
|
||||
*
|
||||
* Add a floating-point variable trace source in this resolver.
|
||||
* This trace source will match the name specified during namespace
|
||||
* resolution. The TraceContext of this trace source will also
|
||||
* be automatically extended to contain the input context.
|
||||
*/
|
||||
template <typename T>
|
||||
void Add (std::string name,
|
||||
FVTraceSource<T> &trace, T const &context);
|
||||
|
||||
/**
|
||||
* \param name name of child trace resolver
|
||||
* \param createResolver a trace resolver constructor
|
||||
* \param context the context associated to this entry
|
||||
*
|
||||
* Add a child trace resolver to this resolver. This child
|
||||
* trace resolver will match the name specified during
|
||||
* namespace resolution. When this happens, the constructor
|
||||
* will be invoked to create the child trace resolver and
|
||||
* the associated TraceContext will be automatically extended
|
||||
* to contain the input context.
|
||||
*/
|
||||
template <typename T>
|
||||
void Add (std::string name,
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver,
|
||||
T const &context);
|
||||
private:
|
||||
template <typename SOURCE, typename CONTEXT>
|
||||
void DoAddTraceSource (std::string name,
|
||||
SOURCE &traceSource, CONTEXT const &context);
|
||||
template <typename SOURCE>
|
||||
static TraceResolver *CreateTerminalTraceResolver (SOURCE *trace,
|
||||
TraceContext const &context);
|
||||
void DoAdd (std::string name,
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver,
|
||||
TraceContext const &context);
|
||||
virtual TraceResolverList DoLookup (std::string id) const;
|
||||
|
||||
struct CallbackTraceSourceItem
|
||||
{
|
||||
std::string name;
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver;
|
||||
TraceContext context;
|
||||
};
|
||||
|
||||
typedef std::list<struct CallbackTraceSourceItem> TraceItems;
|
||||
TraceItems m_items;
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename SOURCE, typename CONTEXT>
|
||||
void
|
||||
CompositeTraceResolver::DoAddTraceSource (std::string name,
|
||||
SOURCE &traceSource, CONTEXT const &context)
|
||||
{
|
||||
TraceContext traceContext = GetContext ();
|
||||
traceContext.Add (context);
|
||||
TraceResolver *(*create) (SOURCE *trace, TraceContext const &context);
|
||||
create = &CompositeTraceResolver::CreateTerminalTraceResolver<SOURCE>;
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver =
|
||||
MakeBoundCallback (create, &traceSource);
|
||||
DoAdd (name, createResolver, traceContext);
|
||||
}
|
||||
|
||||
template <typename SOURCE>
|
||||
TraceResolver *
|
||||
CompositeTraceResolver::CreateTerminalTraceResolver (SOURCE *traceSource,
|
||||
TraceContext const &context)
|
||||
{
|
||||
return new TerminalTraceResolver<SOURCE> (*traceSource, context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename T1, typename T2,
|
||||
typename T3, typename T4,
|
||||
typename T>
|
||||
void
|
||||
CompositeTraceResolver::Add (std::string name,
|
||||
CallbackTraceSource<T1,T2,T3,T4> &trace,
|
||||
T const &context)
|
||||
{
|
||||
DoAddTraceSource (name, trace, context);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
CompositeTraceResolver::Add (std::string name,
|
||||
SVTraceSource<T> &trace, T const &context)
|
||||
{
|
||||
DoAddTraceSource (name, trace, context);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
CompositeTraceResolver::Add (std::string name,
|
||||
UVTraceSource<T> &trace, T const &context)
|
||||
{
|
||||
DoAddTraceSource (name, trace, context);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
CompositeTraceResolver::Add (std::string name,
|
||||
FVTraceSource<T> &trace, T const &context)
|
||||
{
|
||||
DoAddTraceSource (name, trace, context);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
CompositeTraceResolver::Add (std::string name,
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver,
|
||||
T const &context)
|
||||
{
|
||||
TraceContext traceContext = GetContext ();
|
||||
traceContext.Add (context);
|
||||
DoAdd (name, createResolver, traceContext);
|
||||
}
|
||||
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* COMPOSITE_TRACE_RESOLVER_H */
|
||||
@@ -0,0 +1,255 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
//
|
||||
// Copyright (c) 2006 Georgia Tech Research Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation;
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Author: Rajib Bhattacharjea<raj.b@gatech.edu>
|
||||
//
|
||||
|
||||
#include "data-rate.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
|
||||
|
||||
static bool
|
||||
DoParse (const std::string s, uint64_t *v)
|
||||
{
|
||||
std::string::size_type n = s.find_first_not_of("0123456789.");
|
||||
if (n != std::string::npos)
|
||||
{ // Found non-numeric
|
||||
double r = ::atof(s.substr(0, n).c_str());
|
||||
std::string trailer = s.substr(n, std::string::npos);
|
||||
if (trailer == "bps")
|
||||
{
|
||||
// Bit/s
|
||||
*v = (uint64_t)r;
|
||||
}
|
||||
else if (trailer == "b/s")
|
||||
{
|
||||
// Bit/s
|
||||
*v = (uint64_t)r;
|
||||
}
|
||||
else if (trailer == "Bps")
|
||||
{
|
||||
// Byte/s
|
||||
*v = (uint64_t)(r * 8);
|
||||
}
|
||||
else if (trailer == "B/s")
|
||||
{
|
||||
// Byte/s
|
||||
*v = (uint64_t)(r * 8);
|
||||
}
|
||||
else if (trailer == "kbps")
|
||||
{
|
||||
// KiloBit/s
|
||||
*v = (uint64_t)(r * 1000);
|
||||
}
|
||||
else if (trailer == "kb/s")
|
||||
{
|
||||
// KiloBit/s
|
||||
*v = (uint64_t)(r * 1000);
|
||||
}
|
||||
else if (trailer == "kBps")
|
||||
{
|
||||
// KiloBit/s
|
||||
*v = (uint64_t)(r * 1000);
|
||||
}
|
||||
else if (trailer == "kB/s")
|
||||
{
|
||||
// KiloBit/s
|
||||
*v = (uint64_t)(r * 1000);
|
||||
}
|
||||
else if (trailer == "Mbps")
|
||||
{
|
||||
// MegaBit/s
|
||||
*v = (uint64_t)(r * 1000000);
|
||||
}
|
||||
else if (trailer == "Mb/s")
|
||||
{
|
||||
// MegaBit/s
|
||||
*v = (uint64_t)(r * 1000000);
|
||||
}
|
||||
else if (trailer == "MBps")
|
||||
{
|
||||
// MegaByte/s
|
||||
*v = (uint64_t)(r * 8000000);
|
||||
}
|
||||
else if (trailer == "MB/s")
|
||||
{
|
||||
// MegaByte/s
|
||||
*v = (uint64_t)(r * 8000000);
|
||||
}
|
||||
else if (trailer == "Gbps")
|
||||
{
|
||||
// GigaBit/s
|
||||
*v = (uint64_t)(r * 1000000000);
|
||||
}
|
||||
else if (trailer == "Gb/s")
|
||||
{
|
||||
// GigaBit/s
|
||||
*v = (uint64_t)(r * 1000000000);
|
||||
}
|
||||
else if (trailer == "GBps")
|
||||
{
|
||||
// GigaByte/s
|
||||
*v = (uint64_t)(r * 8*1000000000);
|
||||
}
|
||||
else if (trailer == "GB/s")
|
||||
{
|
||||
// GigaByte/s
|
||||
*v = (uint64_t)(r * 8*1000000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*v = ::atoll(s.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
DataRate::DataRate(uint64_t bps)
|
||||
:m_bps(bps)
|
||||
{
|
||||
}
|
||||
|
||||
DataRate::DataRate (const std::string s)
|
||||
: m_bps(DataRate::Parse(s))
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t DataRate::Parse(const std::string s)
|
||||
{
|
||||
uint64_t v;
|
||||
if (!DoParse (s, &v))
|
||||
{
|
||||
NS_FATAL_ERROR("Can't Parse data rate "<<s);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
bool DataRate::operator < (const DataRate& rhs)
|
||||
{
|
||||
return m_bps<rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator <= (const DataRate& rhs)
|
||||
{
|
||||
return m_bps<=rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator > (const DataRate& rhs)
|
||||
{
|
||||
return m_bps>rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator >= (const DataRate& rhs)
|
||||
{
|
||||
return m_bps>=rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator == (const DataRate& rhs)
|
||||
{
|
||||
return m_bps==rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator != (const DataRate& rhs)
|
||||
{
|
||||
return m_bps!=rhs.m_bps;
|
||||
}
|
||||
|
||||
double DataRate::CalculateTxTime(uint32_t bytes) const
|
||||
{
|
||||
return static_cast<double>(bytes)*8/m_bps;
|
||||
}
|
||||
|
||||
uint64_t DataRate::GetBitRate() const
|
||||
{
|
||||
return m_bps;
|
||||
}
|
||||
|
||||
double operator*(const DataRate& lhs, const Time& rhs)
|
||||
{
|
||||
return rhs.GetSeconds()*lhs.GetBitRate();
|
||||
}
|
||||
|
||||
double operator*(const Time& lhs, const DataRate& rhs)
|
||||
{
|
||||
return lhs.GetSeconds()*rhs.GetBitRate();
|
||||
}
|
||||
|
||||
|
||||
DataRateDefaultValue::DataRateDefaultValue (std::string name,
|
||||
std::string help,
|
||||
DataRate defaultValue)
|
||||
: DefaultValueBase (name, help),
|
||||
m_defaultValue (defaultValue),
|
||||
m_value (defaultValue)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
}
|
||||
void
|
||||
DataRateDefaultValue::SetValue (DataRate rate)
|
||||
{
|
||||
m_value = rate;
|
||||
}
|
||||
DataRate
|
||||
DataRateDefaultValue::GetValue ()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
bool
|
||||
DataRateDefaultValue::DoParseValue (const std::string &value)
|
||||
{
|
||||
uint64_t v;
|
||||
if (DoParse (value, &v))
|
||||
{
|
||||
m_value = DataRate (v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string
|
||||
DataRateDefaultValue::DoGetType (void) const
|
||||
{
|
||||
return "(b/s|kb/s|Mb/s)";
|
||||
}
|
||||
std::string
|
||||
DataRateDefaultValue::DoGetDefaultValue (void) const
|
||||
{
|
||||
uint64_t defaultValue = m_defaultValue.GetBitRate ();
|
||||
std::ostringstream oss;
|
||||
if (defaultValue < 1000)
|
||||
{
|
||||
oss << defaultValue << "b/s";
|
||||
}
|
||||
else if (defaultValue < 1000000)
|
||||
{
|
||||
oss << (defaultValue/1000) << "kb/s";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << (defaultValue/1000) << "Mb/s";
|
||||
}
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
|
||||
};//namespace ns3
|
||||
@@ -0,0 +1,127 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
//
|
||||
// Copyright (c) 2006 Georgia Tech Research Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation;
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Author: Rajib Bhattacharjea<raj.b@gatech.edu>
|
||||
//
|
||||
|
||||
#ifndef DATA_RATE_H
|
||||
#define DATA_RATE_H
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/default-value.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Class for representing data rates
|
||||
*
|
||||
* Allows for natural and familiar use of data rates. Allows construction
|
||||
* from strings, natural multiplication e.g.:
|
||||
* \code
|
||||
* DataRate x("56kbps");
|
||||
* double nBits = x*ns3::Seconds(19.2);
|
||||
* uint32_t nBytes = 20;
|
||||
* double txtime = x.CalclulateTxTime(nBytes);
|
||||
* \endcode
|
||||
* This class also supports the regular comparison operators <, >, <=, >=, ==,
|
||||
* and !=
|
||||
*/
|
||||
class DataRate
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Integer constructor
|
||||
*
|
||||
* Construct a data rate from an integer. This class only supports positive
|
||||
* integer data rates in units of bits/s, meaning 1bit/s is the smallest
|
||||
* non-trivial bitrate availiable.
|
||||
*/
|
||||
DataRate (uint64_t bps);
|
||||
|
||||
/**
|
||||
* \brief String constructor
|
||||
*
|
||||
* Construct a DataRate from a string. The supported strings have a
|
||||
* numerical portion, followed by units in the following format:
|
||||
* - Prefix: nothing, "k", "M", "G"
|
||||
* - Data Unit: "b, "B"
|
||||
* - Time Suffix: "ps", "/s" \n
|
||||
* The prefixes are SI powers of 10 (10^0,10^3,10^6,10^9 respectively).\n
|
||||
* The units are the bit, and the (8-bit) byte respectively.\n
|
||||
* Both time suffixes denote "per second". Some supported examples include
|
||||
* "20B/s", "56kbps", "4.4MB/s", and "100Gb/s". Any malformed string causes
|
||||
* a fatal error.
|
||||
*/
|
||||
DataRate (const std::string s);
|
||||
|
||||
bool operator < (const DataRate& rhs);
|
||||
bool operator <= (const DataRate& rhs);
|
||||
bool operator > (const DataRate& rhs);
|
||||
bool operator >= (const DataRate& rhs);
|
||||
bool operator == (const DataRate& rhs);
|
||||
bool operator != (const DataRate& rhs);
|
||||
|
||||
/**
|
||||
* \brief Calculate transmission time
|
||||
*
|
||||
* Calculates the transmission time at this data rate
|
||||
* \param bytes The number of bytes (not bits) for which to calculate
|
||||
* \return The tranmission time in seconds for the number of bytes specified
|
||||
*/
|
||||
double CalculateTxTime(uint32_t bytes) const;
|
||||
|
||||
/**
|
||||
* Get the underlying bitrate
|
||||
* \return The underlying bitrate in bits per second
|
||||
*/
|
||||
uint64_t GetBitRate() const;
|
||||
|
||||
private:
|
||||
uint64_t m_bps;
|
||||
static uint64_t Parse(const std::string);
|
||||
};
|
||||
/**
|
||||
* \param lhs
|
||||
* \param rhs
|
||||
* \return Bits transmitted in rhs seconds at lhs b/s
|
||||
*/
|
||||
double operator*(const DataRate& lhs, const TimeUnit<1>& rhs);
|
||||
double operator*(const TimeUnit<1>& lhs, const DataRate& rhs);
|
||||
|
||||
class DataRateDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
DataRateDefaultValue (std::string name,
|
||||
std::string help,
|
||||
DataRate defaultValue);
|
||||
void SetValue (DataRate rate);
|
||||
DataRate GetValue ();
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
DataRate m_defaultValue;
|
||||
DataRate m_value;
|
||||
};
|
||||
|
||||
};//namespace ns3
|
||||
|
||||
#endif /* DATA_RATE_H */
|
||||
@@ -0,0 +1,121 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "data-writer.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "ns3/assert.h"
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
|
||||
#define noTRACE_DATA_WRITER 1
|
||||
|
||||
#ifdef TRACE_DATA_WRITER
|
||||
#include <iostream>
|
||||
# define TRACE(x) \
|
||||
std::cout << "DATA WRITER TRACE " << this << " " << x << std::endl;
|
||||
#else /* TRACE_DATA_WRITER */
|
||||
# define TRACE(format,...)
|
||||
#endif /* TRACE_DATA_WRITER */
|
||||
|
||||
#define BUFFER_SIZE (4096)
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class DataWriterPrivate {
|
||||
public:
|
||||
DataWriterPrivate ();
|
||||
~DataWriterPrivate ();
|
||||
|
||||
void open (char const *filename);
|
||||
void write (uint8_t *buffer, uint32_t size);
|
||||
private:
|
||||
uint8_t m_data[BUFFER_SIZE];
|
||||
uint32_t m_current;
|
||||
int m_fd;
|
||||
};
|
||||
|
||||
DataWriterPrivate::DataWriterPrivate ()
|
||||
: m_current (0)
|
||||
{}
|
||||
DataWriterPrivate::~DataWriterPrivate ()
|
||||
{
|
||||
::Write (m_fd, m_data, m_current);
|
||||
::Close (m_fd);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataWriterPrivate::Open (char const *filename)
|
||||
{
|
||||
m_fd = ::Open (filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
NS_ASSERT (m_fd != -1);
|
||||
}
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#endif /* min */
|
||||
|
||||
void
|
||||
DataWriterPrivate::Write (uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
while (size > 0)
|
||||
{
|
||||
uint32_t toCopy = min (BUFFER_SIZE - m_current, size);
|
||||
memcpy (m_data + m_current, buffer, toCopy);
|
||||
size -= toCopy;
|
||||
m_current += toCopy;
|
||||
buffer += toCopy;
|
||||
if (m_current == BUFFER_SIZE)
|
||||
{
|
||||
ssize_t written = 0;
|
||||
written = ::Write (m_fd, m_data, BUFFER_SIZE);
|
||||
NS_ASSERT (written == BUFFER_SIZE);
|
||||
m_current = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DataWriter::DataWriter ()
|
||||
: m_priv (new DataWriterPrivate ())
|
||||
{}
|
||||
DataWriter::~DataWriter ()
|
||||
{
|
||||
delete m_priv;
|
||||
m_priv = 0;
|
||||
}
|
||||
|
||||
void
|
||||
DataWriter::Open (char const *filename)
|
||||
{
|
||||
m_priv->Open (filename);
|
||||
}
|
||||
void
|
||||
DataWriter::Write (uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
m_priv->Write (buffer, size);
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
@@ -0,0 +1,44 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef DATA_WRITER_H
|
||||
#define DATA_WRITER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class DataWriterPrivate;
|
||||
|
||||
class DataWriter {
|
||||
public:
|
||||
DataWriter ();
|
||||
~DataWriter ();
|
||||
|
||||
void open (char const *filename);
|
||||
void write (uint8_t *buffer, uint32_t size);
|
||||
private:
|
||||
DataWriterPrivate *m_priv;
|
||||
};
|
||||
|
||||
}; //namespace ns3
|
||||
|
||||
#endif /* DATA_WRITER_H */
|
||||
@@ -0,0 +1,25 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "empty-trace-resolver.h"
|
||||
|
||||
ns3::EmptyTraceResolver::EmptyTraceResolver (TraceContext const &context)
|
||||
: TraceResolver (context)
|
||||
{}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef EMPTY_TRACE_RESOLVER_H
|
||||
#define EMPTY_TRACE_RESOLVER_H
|
||||
|
||||
#include "trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class TraceContext;
|
||||
|
||||
/**
|
||||
* \brief a TraceResolver instance which does not resolve anything.
|
||||
* \ingroup tracing
|
||||
*
|
||||
* Trying to resolve against this class will yield no matches and no
|
||||
* connections. Returning an instance of this class from a
|
||||
* CreateTraceResolver method is a hand way of not implementing
|
||||
* any Tracing code.
|
||||
*/
|
||||
class EmptyTraceResolver : public TraceResolver
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param o necessary context for this class.
|
||||
*
|
||||
* The only constructor exported by this class.
|
||||
*/
|
||||
EmptyTraceResolver (TraceContext const &o);
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* EMPTY_TRACE_RESOLVER_H */
|
||||
@@ -0,0 +1,67 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef F_VARIABLE_TRACER_H
|
||||
#define F_VARIABLE_TRACER_H
|
||||
|
||||
#include "callback-trace-source.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class FVTraceSourceBase {
|
||||
public:
|
||||
typedef CallbackTraceSource<double, double> ChangeNotifyCallback;
|
||||
|
||||
FVTraceSourceBase () {}
|
||||
FVTraceSourceBase (FVTraceSourceBase const &o) {}
|
||||
FVTraceSourceBase &operator = (FVTraceSourceBase const &o) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
~FVTraceSourceBase () {}
|
||||
|
||||
void AddCallback (CallbackBase const & callback, TraceContext const & context) {
|
||||
m_callback.AddCallback (callback, context);
|
||||
}
|
||||
void RemoveCallback (CallbackBase const & callback) {
|
||||
m_callback.RemoveCallback (callback);
|
||||
}
|
||||
protected:
|
||||
void notify (double oldVal, double newVal) {
|
||||
if (oldVal != newVal)
|
||||
{
|
||||
m_callback (oldVal, newVal);
|
||||
}
|
||||
}
|
||||
private:
|
||||
ChangeNotifyCallback m_callback;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class FVTraceSource : public FVTraceSourceBase
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* F_VARIABLE_TRACER_H */
|
||||
@@ -0,0 +1,29 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "header.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
Header::~Header ()
|
||||
{}
|
||||
|
||||
}; // namespace ns3
|
||||
@@ -0,0 +1,97 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef HEADER_H
|
||||
#define HEADER_H
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Protocol header serialization and deserialization.
|
||||
*
|
||||
* Every Protocol header which needs to be inserted or removed
|
||||
* from a Packet instance must derive from this abstract base class
|
||||
* and implement the private pure virtual methods listed below:
|
||||
* - ns3::Header::SerializeTo
|
||||
* - ns3::Header::DeserializeFrom
|
||||
* - ns3::Header::GetSerializedSize
|
||||
* - ns3::Header::PrintTo
|
||||
*/
|
||||
class Header : public Chunk {
|
||||
public:
|
||||
virtual ~Header ();
|
||||
private:
|
||||
/**
|
||||
* \returns a user-readable name to identify this type of header.
|
||||
*
|
||||
* The string returned is expected to be a single word with
|
||||
* all capital letters
|
||||
*/
|
||||
virtual std::string DoGetName (void) const = 0;
|
||||
/**
|
||||
* \param os the std output stream in which this
|
||||
* protocol header must print itself.
|
||||
*
|
||||
* Although the header is free to format its output as it
|
||||
* wishes, it is recommended to follow a few rules to integrate
|
||||
* with the packet pretty printer:
|
||||
* - start with flags, small field values located between a
|
||||
* pair of parens. Values should be separated by whitespace.
|
||||
* - follow the parens with the important fields, separated by
|
||||
* whitespace.
|
||||
* i.e.:
|
||||
* (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
|
||||
*/
|
||||
virtual void PrintTo (std::ostream &os) const = 0;
|
||||
|
||||
/**
|
||||
* \returns the size of the serialized Header.
|
||||
*
|
||||
* This method is used by Packet::AddHeader to reserve
|
||||
* enough room in the packet byte buffer prior to calling
|
||||
* Header::Serialize.
|
||||
*/
|
||||
virtual uint32_t GetSerializedSize (void) const = 0;
|
||||
|
||||
/**
|
||||
* \param start the buffer iterator in which the protocol header
|
||||
* must serialize itself. This iterator identifies
|
||||
* the start of the buffer.
|
||||
*/
|
||||
virtual void SerializeTo (Buffer::Iterator start) const = 0;
|
||||
/**
|
||||
* \param start the buffer iterator from which the protocol header must
|
||||
* deserialize itself. This iterator identifies
|
||||
* the start of the buffer.
|
||||
* \returns the number of bytes read from the buffer
|
||||
*
|
||||
* The value returned is used to trim the packet byte buffer of the
|
||||
* corresponding amount when this method is invoked from
|
||||
* Packet::RemoveHeader
|
||||
*/
|
||||
virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* HEADER_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,335 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006,2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef PACKET_METADATA_H
|
||||
#define PACKET_METADATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "packet-printer.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Chunk;
|
||||
class Buffer;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \brief handle packet metadata about packet headers and trailers
|
||||
*
|
||||
* This class is used by the Packet class to record every operation
|
||||
* performed on the packet's buffer. This class also provides
|
||||
* an implementation of the Packet::Print methods which uses
|
||||
* the metadata to analyse the content of the packet's buffer.
|
||||
*
|
||||
* To achieve this, this class maintains a linked list of so-called
|
||||
* "items", each of which represents a header or a trailer, or
|
||||
* payload, or a fragment of any of these. Each item contains a "next"
|
||||
* and a "prev" field which point to the next and previous entries
|
||||
* in the linked list. The PacketMetadata class maintains a pair
|
||||
* of pointers to the head and the tail of the linked list.
|
||||
*
|
||||
* Each entry in the list also maintains:
|
||||
* - its native size (the size it had when it was first added
|
||||
* to the packet)
|
||||
* - its type: identifies what kind of header, what kind of trailer,
|
||||
* if it is payload or not
|
||||
* - the uid of the packet to which it was first added
|
||||
* - the start and end of the area represented by a fragment
|
||||
* if it is one.
|
||||
*
|
||||
* This linked list is flattened in a byte buffer stored in
|
||||
* struct PacketMetadata::Data. Each entry of the linked list is
|
||||
* identified by an offset which identifies the first byte of the
|
||||
* entry from the start of the data buffer. The size of this data
|
||||
* buffer is 2^16-1 bytes maximum which somewhat limits the number
|
||||
* of entries which can be stored in this linked list but it is
|
||||
* quite unlikely to hit this limit in practice.
|
||||
*
|
||||
* Each item of the linked list is a variable-sized byte buffer
|
||||
* made of a number of fields. Some of these fields are stored
|
||||
* as fixed-size 32 bit integers, others as fixed-size 16 bit
|
||||
* integers, and some others as variable-size 32-bit integers.
|
||||
* The variable-size 32 bit integers are stored using the uleb128
|
||||
* encoding.
|
||||
*/
|
||||
class PacketMetadata {
|
||||
public:
|
||||
static void Enable (void);
|
||||
static void SetOptOne (bool optOne);
|
||||
|
||||
inline PacketMetadata (uint32_t uid, uint32_t size);
|
||||
inline PacketMetadata (PacketMetadata const &o);
|
||||
inline PacketMetadata &operator = (PacketMetadata const& o);
|
||||
inline ~PacketMetadata ();
|
||||
|
||||
template <typename T>
|
||||
void AddHeader (T const &header, uint32_t size);
|
||||
template <typename T>
|
||||
void RemoveHeader (T const &header, uint32_t size);
|
||||
|
||||
template <typename T>
|
||||
void AddTrailer (T const &trailer, uint32_t size);
|
||||
template <typename T>
|
||||
void RemoveTrailer (T const &trailer, uint32_t size);
|
||||
|
||||
PacketMetadata CreateFragment (uint32_t start, uint32_t end) const;
|
||||
void AddAtEnd (PacketMetadata const&o);
|
||||
void AddPaddingAtEnd (uint32_t end);
|
||||
void RemoveAtStart (uint32_t start);
|
||||
void RemoveAtEnd (uint32_t end);
|
||||
|
||||
uint32_t GetUid (void) const;
|
||||
|
||||
void PrintDefault (std::ostream &os, Buffer buffer) const;
|
||||
void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const;
|
||||
|
||||
static void PrintStats (void);
|
||||
|
||||
private:
|
||||
struct Data {
|
||||
/* number of references to this struct Data instance. */
|
||||
uint16_t m_count;
|
||||
/* size (in bytes) of m_data buffer below */
|
||||
uint16_t m_size;
|
||||
/* max of the m_used field over all objects which
|
||||
* reference this struct Data instance */
|
||||
uint16_t m_dirtyEnd;
|
||||
/* variable-sized buffer of bytes */
|
||||
uint8_t m_data[10];
|
||||
};
|
||||
/* Note that since the next and prev fields are 16 bit integers
|
||||
and since the value 0xffff is reserved to identify the
|
||||
fact that the end or the start of the list is reached,
|
||||
only a limited number of elements can be stored in
|
||||
a m_data byte buffer.
|
||||
*/
|
||||
struct SmallItem {
|
||||
/* offset (in bytes) from start of m_data buffer
|
||||
to next element in linked list. value is 0xffff
|
||||
if next element does not exist.
|
||||
stored as a fixed-size 16 bit integer.
|
||||
*/
|
||||
uint16_t next;
|
||||
/* offset (in bytes) from start of m_data buffer
|
||||
to previous element in linked list. value is 0xffff
|
||||
if previous element does not exist.
|
||||
stored as a fixed-size 16 bit integer.
|
||||
*/
|
||||
uint16_t prev;
|
||||
/* the high 31 bits of this field identify the
|
||||
type of the header or trailer represented by
|
||||
this item: the value zero represents payload.
|
||||
If the low bit of this uid is one, an ExtraItem
|
||||
structure follows this SmallItem structure.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t typeUid;
|
||||
/* the size (in bytes) of the header or trailer represented
|
||||
by this element.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t size;
|
||||
/* this field tries to uniquely identify each header or
|
||||
trailer _instance_ while the typeUid field uniquely
|
||||
identifies each header or trailer _type_. This field
|
||||
is used to test whether two items are equal in the sense
|
||||
that they represent the same header or trailer instance.
|
||||
That equality test is based on the typeUid and chunkUid
|
||||
fields so, the likelyhood that two header instances
|
||||
share the same chunkUid _and_ typeUid is very small
|
||||
unless they are really representations of the same header
|
||||
instance.
|
||||
stored as a fixed-size 16 bit integer.
|
||||
*/
|
||||
uint16_t chunkUid;
|
||||
};
|
||||
struct ExtraItem {
|
||||
/* offset (in bytes) from start of original header to
|
||||
the start of the fragment still present.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t fragmentStart;
|
||||
/* offset (in bytes) from start of original header to
|
||||
the end of the fragment still present.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t fragmentEnd;
|
||||
/* the packetUid of the packet in which this header or trailer
|
||||
was first added. It could be different from the m_packetUid
|
||||
field if the user has aggregated multiple packets into one.
|
||||
stored as a fixed-size 32 bit integer.
|
||||
*/
|
||||
uint32_t packetUid;
|
||||
};
|
||||
|
||||
typedef std::vector<struct Data *> DataFreeList;
|
||||
|
||||
PacketMetadata ();
|
||||
void DoAddHeader (uint32_t uid, uint32_t size);
|
||||
void DoRemoveHeader (uint32_t uid, uint32_t size);
|
||||
void DoAddTrailer (uint32_t uid, uint32_t size);
|
||||
void DoRemoveTrailer (uint32_t uid, uint32_t size);
|
||||
|
||||
inline uint16_t AddSmall (const PacketMetadata::SmallItem *item);
|
||||
uint16_t AddBig (uint32_t head, uint32_t tail,
|
||||
const PacketMetadata::SmallItem *item,
|
||||
const PacketMetadata::ExtraItem *extraItem);
|
||||
void ReplaceTail (PacketMetadata::SmallItem *item,
|
||||
PacketMetadata::ExtraItem *extraItem,
|
||||
uint32_t available);
|
||||
inline void UpdateHead (uint16_t written);
|
||||
inline void UpdateTail (uint16_t written);
|
||||
uint32_t GetUleb128Size (uint32_t value) const;
|
||||
uint32_t ReadUleb128 (const uint8_t **pBuffer) const;
|
||||
inline void Append16 (uint16_t value, uint8_t *buffer);
|
||||
inline bool TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
inline bool TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
inline bool TryToAppend32 (uint32_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
inline bool TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
void AppendValue (uint32_t value, uint8_t *buffer);
|
||||
void AppendValueExtra (uint32_t value, uint8_t *buffer);
|
||||
inline void Reserve (uint32_t n);
|
||||
void ReserveCopy (uint32_t n);
|
||||
uint32_t DoPrint (const struct PacketMetadata::SmallItem *item,
|
||||
const struct PacketMetadata::ExtraItem *extraItem,
|
||||
Buffer data, uint32_t offset, const PacketPrinter &printer,
|
||||
std::ostream &os) const;
|
||||
uint32_t GetTotalSize (void) const;
|
||||
uint32_t ReadItems (uint16_t current,
|
||||
struct PacketMetadata::SmallItem *item,
|
||||
struct PacketMetadata::ExtraItem *extraItem) const;
|
||||
|
||||
|
||||
static struct PacketMetadata::Data *Create (uint32_t size);
|
||||
static void Recycle (struct PacketMetadata::Data *data);
|
||||
static struct PacketMetadata::Data *Allocate (uint32_t n);
|
||||
static void Deallocate (struct PacketMetadata::Data *data);
|
||||
|
||||
static DataFreeList m_freeList;
|
||||
static bool m_enable;
|
||||
static uint32_t m_maxSize;
|
||||
static uint16_t m_chunkUid;
|
||||
|
||||
struct Data *m_data;
|
||||
/**
|
||||
head -(next)-> tail
|
||||
^ |
|
||||
\---(prev)---|
|
||||
*/
|
||||
uint16_t m_head;
|
||||
uint16_t m_tail;
|
||||
uint16_t m_used;
|
||||
uint32_t m_packetUid;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::AddHeader (T const &header, uint32_t size)
|
||||
{
|
||||
DoAddHeader (PacketPrinter::GetHeaderUid<T> (), size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::RemoveHeader (T const &header, uint32_t size)
|
||||
{
|
||||
DoRemoveHeader (PacketPrinter::GetHeaderUid<T> (), size);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::AddTrailer (T const &trailer, uint32_t size)
|
||||
{
|
||||
DoAddTrailer (PacketPrinter::GetTrailerUid<T> (), size);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size)
|
||||
{
|
||||
DoRemoveTrailer (PacketPrinter::GetTrailerUid<T> (), size);
|
||||
}
|
||||
|
||||
|
||||
PacketMetadata::PacketMetadata (uint32_t uid, uint32_t size)
|
||||
: m_data (m_data = PacketMetadata::Create (10)),
|
||||
m_head (0xffff),
|
||||
m_tail (0xffff),
|
||||
m_used (0),
|
||||
m_packetUid (uid)
|
||||
{
|
||||
memset (m_data->m_data, 0xff, 4);
|
||||
if (size > 0)
|
||||
{
|
||||
DoAddHeader (0, size);
|
||||
}
|
||||
}
|
||||
PacketMetadata::PacketMetadata (PacketMetadata const &o)
|
||||
: m_data (o.m_data),
|
||||
m_head (o.m_head),
|
||||
m_tail (o.m_tail),
|
||||
m_used (o.m_used),
|
||||
m_packetUid (o.m_packetUid)
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count++;
|
||||
}
|
||||
PacketMetadata &
|
||||
PacketMetadata::operator = (PacketMetadata const& o)
|
||||
{
|
||||
if (m_data == o.m_data)
|
||||
{
|
||||
// self assignment
|
||||
return *this;
|
||||
}
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketMetadata::Recycle (m_data);
|
||||
}
|
||||
m_data = o.m_data;
|
||||
m_head = o.m_head;
|
||||
m_tail = o.m_tail;
|
||||
m_used = o.m_used;
|
||||
m_packetUid = o.m_packetUid;
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count++;
|
||||
return *this;
|
||||
}
|
||||
PacketMetadata::~PacketMetadata ()
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketMetadata::Recycle (m_data);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#endif /* PACKET_METADATA_H */
|
||||
@@ -0,0 +1,235 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "packet-printer.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
PacketPrinter::PacketPrinter ()
|
||||
: m_forward (true),
|
||||
m_separator ("")
|
||||
{}
|
||||
|
||||
void
|
||||
PacketPrinter::PrintForward (void)
|
||||
{
|
||||
m_forward = true;
|
||||
}
|
||||
void
|
||||
PacketPrinter::PrintBackward (void)
|
||||
{
|
||||
m_forward = false;
|
||||
}
|
||||
void
|
||||
PacketPrinter::SetSeparator (std::string separator)
|
||||
{
|
||||
m_separator = separator;
|
||||
}
|
||||
void
|
||||
PacketPrinter::AddPayloadPrinter (PayloadPrinter printer)
|
||||
{
|
||||
m_payloadPrinter = printer;
|
||||
}
|
||||
void
|
||||
PacketPrinter::AddDefaultPrinter (DefaultPrinter printer)
|
||||
{
|
||||
m_defaultPrinter = printer;
|
||||
}
|
||||
|
||||
PacketPrinter::RegisteredChunks *
|
||||
PacketPrinter::GetRegisteredChunks (void)
|
||||
{
|
||||
static RegisteredChunks registeredChunks;
|
||||
return ®isteredChunks;
|
||||
}
|
||||
|
||||
PacketPrinter
|
||||
PacketPrinter::GetDefault (void)
|
||||
{
|
||||
return *(PacketPrinter::PeekDefault ());
|
||||
}
|
||||
PacketPrinter *
|
||||
PacketPrinter::PeekDefault (void)
|
||||
{
|
||||
static PacketPrinter *tmp = PacketPrinter::CreateStaticDefault ();
|
||||
return tmp;
|
||||
}
|
||||
PacketPrinter *
|
||||
PacketPrinter::CreateStaticDefault (void)
|
||||
{
|
||||
static PacketPrinter tmp;
|
||||
tmp.PrintForward ();
|
||||
tmp.AddPayloadPrinter (MakeCallback (&PacketPrinter::DoDefaultPrintPayload));
|
||||
tmp.SetSeparator (" ");
|
||||
return &tmp;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PacketPrinter::PrintChunk (uint32_t chunkUid,
|
||||
Buffer::Iterator start,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size) const
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
|
||||
for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
|
||||
{
|
||||
if (i->m_chunkUid == chunkUid)
|
||||
{
|
||||
DoPrintCallback cb = (*registeredChunks)[chunkUid/2-1].printCallback;
|
||||
cb (i->m_printer, start, os, packetUid, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
|
||||
std::string name = cb ();
|
||||
struct PacketPrinter::FragmentInformation info;
|
||||
info.start = 0;
|
||||
info.end = 0;
|
||||
if (!m_defaultPrinter.IsNull ())
|
||||
{
|
||||
m_defaultPrinter (os, packetUid, size, name, info);
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketPrinter::PrintChunkFragment (uint32_t chunkUid,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
uint32_t fragmentStart,
|
||||
uint32_t fragmentEnd) const
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
|
||||
DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
|
||||
std::string name = cb ();
|
||||
struct PacketPrinter::FragmentInformation info;
|
||||
info.start = fragmentStart;
|
||||
info.end = fragmentEnd;
|
||||
for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
|
||||
{
|
||||
if (i->m_chunkUid == chunkUid)
|
||||
{
|
||||
i->m_fragmentPrinter (os, packetUid, size, name, info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!m_defaultPrinter.IsNull ())
|
||||
{
|
||||
m_defaultPrinter (os, packetUid, size, name, info);
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
|
||||
uint32_t fragmentStart, uint32_t fragmentEnd) const
|
||||
{
|
||||
struct PacketPrinter::FragmentInformation info;
|
||||
info.start = fragmentStart;
|
||||
info.end = fragmentEnd;
|
||||
if (!m_payloadPrinter.IsNull ())
|
||||
{
|
||||
m_payloadPrinter (os, packetUid, size, info);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoDefaultPrintPayload (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << "DATA ("
|
||||
<< "length " << size - (info.end + info.start);
|
||||
if (info.start != 0 || info.end != 0)
|
||||
{
|
||||
os << " "
|
||||
<< "trim_start " << info.start << " "
|
||||
<< "trim_end " << info.end;
|
||||
}
|
||||
os << ")";
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoDefaultPrintDefault (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
NS_ASSERT_MSG (false, "This should never happen because we provide a printer for _all_ chunk types.");
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoDefaultPrintFragment (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
NS_ASSERT (info.start != 0 || info.end != 0);
|
||||
os << name << " "
|
||||
<< "("
|
||||
<< "length " << size - (info.end + info.start) << " "
|
||||
<< "trim_start " << info.start << " "
|
||||
<< "trim_end " << info.end
|
||||
<< ")"
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoAddPrinter (uint32_t uid,
|
||||
Ptr<CallbackImplBase> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter)
|
||||
{
|
||||
struct PacketPrinter::Printer p;
|
||||
p.m_chunkUid = uid;
|
||||
p.m_printer = printer;
|
||||
p.m_fragmentPrinter = fragmentPrinter;
|
||||
m_printerList.push_back (p);
|
||||
}
|
||||
|
||||
bool
|
||||
PacketPrinter::IsTrailer (uint32_t uid)
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
|
||||
bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
|
||||
return !isHeader;
|
||||
}
|
||||
bool
|
||||
PacketPrinter::IsHeader (uint32_t uid)
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
|
||||
bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
|
||||
return isHeader;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
@@ -0,0 +1,318 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef PACKET_PRINTER_H
|
||||
#define PACKET_PRINTER_H
|
||||
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "buffer.h"
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
class ItemList;
|
||||
}
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Chunk;
|
||||
|
||||
/**
|
||||
* \brief hold a list of print callbacks for packet headers and trailers
|
||||
*
|
||||
* Users can register in instances of this class print callbacks
|
||||
* which are used by Packet::Print to print the content of a packet.
|
||||
*/
|
||||
class PacketPrinter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief indicates how many bytes were trimmed from a header
|
||||
* or a trailer.
|
||||
*/
|
||||
struct FragmentInformation
|
||||
{
|
||||
/**
|
||||
* The number of bytes trimmed from the start of the header or the trailer.
|
||||
*/
|
||||
uint32_t start;
|
||||
/**
|
||||
* The number of bytes trimmed from the end of the header or the trailer.
|
||||
*/
|
||||
uint32_t end;
|
||||
};
|
||||
/**
|
||||
* \brief callback to print payload.
|
||||
*
|
||||
* Arguments: output stream, packet uid, size, fragment information
|
||||
*/
|
||||
typedef Callback<void,std::ostream &,uint32_t,uint32_t,struct PacketPrinter::FragmentInformation>
|
||||
PayloadPrinter;
|
||||
|
||||
/**
|
||||
* \brief callback to print fragmented chunks.
|
||||
*
|
||||
* Arguments: output stream, packet uid, size, header/trailer name, fragment information
|
||||
*/
|
||||
typedef Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
|
||||
ChunkFragmentPrinter;
|
||||
|
||||
/**
|
||||
* \brief callback to print chunks for which no specific callback was specified.
|
||||
*
|
||||
* Arguments: output stream, packet uid, size, header/trailer name, fragment information
|
||||
*/
|
||||
typedef Callback<void,std::ostream&,uint32_t,uint32_t,std::string&,struct PacketPrinter::FragmentInformation>
|
||||
DefaultPrinter;
|
||||
|
||||
PacketPrinter ();
|
||||
|
||||
/**
|
||||
* Print the content of the packet forward.
|
||||
*/
|
||||
void PrintForward (void);
|
||||
/**
|
||||
* Print the content of the packet backward.
|
||||
*/
|
||||
void PrintBackward (void);
|
||||
void SetSeparator (std::string separator);
|
||||
/**
|
||||
* \param printer printer for payload
|
||||
*/
|
||||
void AddPayloadPrinter (PayloadPrinter printer);
|
||||
/**
|
||||
* \param printer printer for the specified chunk
|
||||
* \param fragmentPrinter printer for a fragment of the specified chunk
|
||||
*
|
||||
* If the user has not specified a callback for a specific header present
|
||||
* in a packet, the "default" callback is invoked. If no such callback
|
||||
* was specified, nothing happens.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
|
||||
ChunkFragmentPrinter fragmentPrinter);
|
||||
/**
|
||||
* \param printer printer for the specified chunk
|
||||
* \param fragmentPrinter printer for a fragment of the specified chunk
|
||||
*
|
||||
* If the user has not specified a callback for a specific trailer present
|
||||
* in a packet, the "default" callback is invoked. If no such callback
|
||||
* was specified, nothing happens.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
|
||||
ChunkFragmentPrinter fragmentPrinter);
|
||||
/**
|
||||
* \param printer printer for a chunk for which no callback was specified explicitely
|
||||
*/
|
||||
void AddDefaultPrinter (DefaultPrinter printer);
|
||||
|
||||
private:
|
||||
friend class PacketMetadata;
|
||||
typedef void (*DoPrintCallback) (Ptr<CallbackImplBase>, Buffer::Iterator, std::ostream &,
|
||||
uint32_t, uint32_t);
|
||||
typedef std::string (*DoGetNameCallback) (void);
|
||||
struct Printer
|
||||
{
|
||||
uint32_t m_chunkUid;
|
||||
Ptr<CallbackImplBase> m_printer;
|
||||
Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
|
||||
m_fragmentPrinter;
|
||||
};
|
||||
struct RegisteredChunk
|
||||
{
|
||||
DoPrintCallback printCallback;
|
||||
DoGetNameCallback getNameCallback;
|
||||
bool isHeader;
|
||||
};
|
||||
typedef std::vector<struct PacketPrinter::Printer> PrinterList;
|
||||
typedef std::vector<struct RegisteredChunk> RegisteredChunks;
|
||||
|
||||
|
||||
static PacketPrinter GetDefault (void);
|
||||
static PacketPrinter *PeekDefault (void);
|
||||
static PacketPrinter *CreateStaticDefault (void);
|
||||
static void DoDefaultPrintPayload (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
struct PacketPrinter::FragmentInformation info);
|
||||
static void DoDefaultPrintDefault (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info);
|
||||
template <typename T>
|
||||
static void DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk);
|
||||
static void DoDefaultPrintFragment (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info);
|
||||
|
||||
template <typename T>
|
||||
static void DoPrint (Ptr<CallbackImplBase> callbackPrinter,
|
||||
Buffer::Iterator i,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size);
|
||||
template <typename T>
|
||||
static std::string DoGetName (void);
|
||||
template <typename T>
|
||||
static uint32_t GetTrailerUid (void);
|
||||
template <typename T>
|
||||
static uint32_t GetHeaderUid (void);
|
||||
template <typename T>
|
||||
static uint32_t AllocateUid (bool isHeader);
|
||||
static RegisteredChunks *GetRegisteredChunks (void);
|
||||
static bool IsTrailer (uint32_t uid);
|
||||
static bool IsHeader (uint32_t uid);
|
||||
|
||||
|
||||
void PrintChunk (uint32_t uid,
|
||||
Buffer::Iterator i,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size) const;
|
||||
void PrintChunkFragment (uint32_t uid,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
uint32_t fragmentStart,
|
||||
uint32_t fragmentEnd) const;
|
||||
void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
|
||||
uint32_t fragmentStart, uint32_t fragmentEnd) const;
|
||||
void DoAddPrinter (uint32_t uid,
|
||||
Ptr<CallbackImplBase> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter);
|
||||
|
||||
static PacketPrinter m_defaultPacketPrinter;
|
||||
PrinterList m_printerList;
|
||||
PayloadPrinter m_payloadPrinter;
|
||||
DefaultPrinter m_defaultPrinter;
|
||||
bool m_forward;
|
||||
std::string m_separator;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::AddHeaderPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::GetHeaderUid<T> ();
|
||||
DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::AddTrailerPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::GetTrailerUid<T> ();
|
||||
DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::DoPrint (Ptr<CallbackImplBase> printerCallback,
|
||||
Buffer::Iterator i,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size)
|
||||
{
|
||||
T chunk = T ();
|
||||
chunk.Deserialize (i);
|
||||
Callback<void,std::ostream&,uint32_t,uint32_t,const T*> callback;
|
||||
callback.Assign (printerCallback);
|
||||
callback (os, packetUid, size, &chunk);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string
|
||||
PacketPrinter::DoGetName (void)
|
||||
{
|
||||
T chunk = T ();
|
||||
return chunk.GetName ();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t
|
||||
PacketPrinter::GetHeaderUid (void)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::AllocateUid<T> (true);
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t
|
||||
PacketPrinter::GetTrailerUid (void)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::AllocateUid<T> (false);
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t
|
||||
PacketPrinter::AllocateUid (bool isHeader)
|
||||
{
|
||||
RegisteredChunks *chunks = PacketPrinter::GetRegisteredChunks ();
|
||||
RegisteredChunk chunk;
|
||||
chunk.printCallback = &PacketPrinter::DoPrint<T>;
|
||||
chunk.getNameCallback = &PacketPrinter::DoGetName<T>;
|
||||
chunk.isHeader = isHeader;
|
||||
chunks->push_back (chunk);
|
||||
uint32_t uid = chunks->size () * 2;
|
||||
PacketPrinter::PeekDefault ()->DoAddPrinter (uid,
|
||||
MakeCallback (&PacketPrinter::DoDefaultPrint<T>).GetImpl (),
|
||||
MakeCallback (&PacketPrinter::DoDefaultPrintFragment));
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk)
|
||||
{
|
||||
os << chunk->GetName () << " ";
|
||||
chunk->Print (os);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* PACKET_PRINTER_H */
|
||||
@@ -0,0 +1,201 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "packet.h"
|
||||
#include "packet-printer.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
uint32_t Packet::m_globalUid = 0;
|
||||
|
||||
Packet::Packet ()
|
||||
: m_buffer (),
|
||||
m_metadata (m_globalUid, 0)
|
||||
{
|
||||
m_globalUid++;
|
||||
}
|
||||
|
||||
Packet::Packet (uint32_t size)
|
||||
: m_buffer (size),
|
||||
m_metadata (m_globalUid, size)
|
||||
{
|
||||
m_globalUid++;
|
||||
}
|
||||
Packet::Packet (uint8_t const*buffer, uint32_t size)
|
||||
: m_buffer (),
|
||||
m_metadata (m_globalUid, size)
|
||||
{
|
||||
m_globalUid++;
|
||||
m_buffer.AddAtStart (size);
|
||||
Buffer::Iterator i = m_buffer.Begin ();
|
||||
i.Write (buffer, size);
|
||||
}
|
||||
|
||||
Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
|
||||
: m_buffer (buffer),
|
||||
m_tags (tags),
|
||||
m_metadata (metadata)
|
||||
{}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Packet::GetSize (void) const
|
||||
{
|
||||
return m_buffer.GetSize ();
|
||||
}
|
||||
|
||||
void
|
||||
Packet::AddAtEnd (Packet packet)
|
||||
{
|
||||
packet.m_buffer.TransformIntoRealBuffer ();
|
||||
m_buffer.TransformIntoRealBuffer ();
|
||||
|
||||
Buffer src = packet.m_buffer;
|
||||
m_buffer.AddAtEnd (src.GetSize ());
|
||||
Buffer::Iterator destStart = m_buffer.End ();
|
||||
destStart.Prev (src.GetSize ());
|
||||
destStart.Write (src.Begin (), src.End ());
|
||||
/**
|
||||
* XXX: we might need to merge the tag list of the
|
||||
* other packet into the current packet.
|
||||
*/
|
||||
m_metadata.AddAtEnd (packet.m_metadata);
|
||||
}
|
||||
void
|
||||
Packet::AddPaddingAtEnd (uint32_t size)
|
||||
{
|
||||
m_buffer.AddAtEnd (size);
|
||||
m_metadata.AddPaddingAtEnd (size);
|
||||
}
|
||||
void
|
||||
Packet::RemoveAtEnd (uint32_t size)
|
||||
{
|
||||
m_buffer.RemoveAtEnd (size);
|
||||
m_metadata.RemoveAtEnd (size);
|
||||
}
|
||||
void
|
||||
Packet::RemoveAtStart (uint32_t size)
|
||||
{
|
||||
m_buffer.RemoveAtStart (size);
|
||||
m_metadata.RemoveAtStart (size);
|
||||
}
|
||||
|
||||
void
|
||||
Packet::RemoveAllTags (void)
|
||||
{
|
||||
m_tags.RemoveAll ();
|
||||
}
|
||||
|
||||
uint8_t const *
|
||||
Packet::PeekData (void) const
|
||||
{
|
||||
return m_buffer.PeekData ();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Packet::GetUid (void) const
|
||||
{
|
||||
return m_metadata.GetUid ();
|
||||
}
|
||||
|
||||
void
|
||||
Packet::Print (std::ostream &os) const
|
||||
{
|
||||
m_metadata.PrintDefault (os, m_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
Packet::Print (std::ostream &os, const PacketPrinter &printer) const
|
||||
{
|
||||
m_metadata.Print (os, m_buffer, printer);
|
||||
}
|
||||
|
||||
void
|
||||
Packet::EnableMetadata (void)
|
||||
{
|
||||
PacketMetadata::Enable ();
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "ns3/test.h"
|
||||
#include <string>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class PacketTest: public Test {
|
||||
public:
|
||||
virtual bool RunTests (void);
|
||||
PacketTest ();
|
||||
};
|
||||
|
||||
|
||||
PacketTest::PacketTest ()
|
||||
: Test ("Packet") {}
|
||||
|
||||
|
||||
bool
|
||||
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);
|
||||
|
||||
if (packet.GetSize () != 11)
|
||||
{
|
||||
Failure () << "expected size 11, got " << packet.GetSize () << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
|
||||
std::string msg = std::string (reinterpret_cast<const char *>(packet.PeekData ()),
|
||||
packet.GetSize ());
|
||||
if (msg != "hello world")
|
||||
{
|
||||
Failure () << "expected size 'hello world', got " << msg << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
static PacketTest gPacketTest;
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -0,0 +1,379 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef PACKET_H
|
||||
#define PACKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "buffer.h"
|
||||
#include "header.h"
|
||||
#include "trailer.h"
|
||||
#include "tags.h"
|
||||
#include "packet-metadata.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class PacketPrinter;
|
||||
|
||||
/**
|
||||
* \brief network packets
|
||||
*
|
||||
* Each network packet contains a byte buffer and a list of tags.
|
||||
* - The byte buffer stores the serialized content of the headers and trailers
|
||||
* added to a packet. The serialized representation of these headers is expected
|
||||
* to match that of real network packets bit for bit (although nothing
|
||||
* forces you to do this) which means that the content of a packet buffer
|
||||
* is expected to be that of a real packet.
|
||||
* - The list of tags stores an arbitrarily large set of arbitrary
|
||||
* user-provided data structures in the packet: only one instance of
|
||||
* each type of data structure is allowed in a list of tags.
|
||||
* These tags typically contain per-packet cross-layer information or
|
||||
* flow identifiers. Each tag stored in the tag list can be at most
|
||||
* 16 bytes big. Trying to attach bigger data structures will trigger
|
||||
* crashes at runtime.
|
||||
*
|
||||
* Implementing a new type of Header for a new protocol is pretty easy
|
||||
* and is a matter of creating a subclass of the ns3::Header base class,
|
||||
* and implementing the 4 pure virtual methods defined in ns3::Header.
|
||||
* Sample code which shows how to create such a new Header, how to use
|
||||
* it, and how to manipulate tags is shown below:
|
||||
* \include samples/main-packet.cc
|
||||
*
|
||||
* The current implementation of the byte buffers and tag list is based
|
||||
* on COW (Copy On Write. An introduction to COW can be found in Scott
|
||||
* Meyer's "More Effective C++", items 17 and 29). What this means is that
|
||||
* copying packets without modifying them is very cheap (in terms of cpu
|
||||
* and memory usage) and modifying them can be also very cheap. What is
|
||||
* key for proper COW implementations is being
|
||||
* able to detect when a given modification of the state of a packet triggers
|
||||
* a full copy of the data prior to the modification: COW systems need
|
||||
* to detect when an operation is "dirty".
|
||||
*
|
||||
* Dirty operations:
|
||||
* - ns3::Packet::RemoveTag
|
||||
* - ns3::Packet::Add
|
||||
* - both versions of ns3::Packet::AddAtEnd
|
||||
*
|
||||
* Non-dirty operations:
|
||||
* - ns3::Packet::AddTag
|
||||
* - ns3::Packet::RemoveAllTags
|
||||
* - ns3::Packet::PeekTag
|
||||
* - ns3::Packet::Peek
|
||||
* - ns3::Packet::Remove
|
||||
* - ns3::Packet::CreateFragment
|
||||
* - ns3::Packet::RemoveAtStart
|
||||
* - ns3::Packet::RemoveAtEnd
|
||||
*
|
||||
* Dirty operations will always be slower than non-dirty operations,
|
||||
* sometimes by several orders of magnitude. However, even the
|
||||
* dirty operations have been optimized for common use-cases which
|
||||
* means that most of the time, these operations will not trigger
|
||||
* data copies and will thus be still very fast.
|
||||
*/
|
||||
class Packet {
|
||||
public:
|
||||
/**
|
||||
* Create an empty packet with a new uid (as returned
|
||||
* by getUid).
|
||||
*/
|
||||
Packet ();
|
||||
/**
|
||||
* Create a packet with a zero-filled payload.
|
||||
* The memory necessary for the payload is not allocated:
|
||||
* it will be allocated at any later point if you attempt
|
||||
* to fragment this packet or to access the zero-filled
|
||||
* bytes. The packet is allocated with a new uid (as
|
||||
* returned by getUid).
|
||||
*
|
||||
* \param size the size of the zero-filled payload
|
||||
*/
|
||||
Packet (uint32_t size);
|
||||
/**
|
||||
* Create a packet with payload filled with the content
|
||||
* of this buffer. The input data is copied: the input
|
||||
* buffer is untouched.
|
||||
*
|
||||
* \param buffer the data to store in the packet.
|
||||
* \param size the size of the input buffer.
|
||||
*/
|
||||
Packet (uint8_t const*buffer, uint32_t size);
|
||||
/**
|
||||
* Create a new packet which contains a fragment of the original
|
||||
* packet. The returned packet shares the same uid as this packet.
|
||||
*
|
||||
* \param start offset from start of packet to start of fragment to create
|
||||
* \param length length of fragment to create
|
||||
* \returns a fragment of the original packet
|
||||
*/
|
||||
Packet CreateFragment (uint32_t start, uint32_t length) const;
|
||||
/**
|
||||
* \returns the size in bytes of the packet (including the zero-filled
|
||||
* initial payload)
|
||||
*/
|
||||
uint32_t GetSize (void) const;
|
||||
/**
|
||||
* Add header to this packet. This method invokes the
|
||||
* ns3::Chunk::GetSerializedSize and ns3::Chunk::SerializeTo
|
||||
* methods to reserve space in the buffer and request the
|
||||
* header to serialize itself in the packet buffer.
|
||||
*
|
||||
* \param header a reference to the header to add to this packet.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddHeader (T const &header);
|
||||
/**
|
||||
* Deserialize and remove the header from the internal buffer.
|
||||
* This method invokes ns3::Chunk::DeserializeFrom.
|
||||
*
|
||||
* \param header a reference to the header to remove from the internal buffer.
|
||||
* \returns the number of bytes removed from the packet.
|
||||
*/
|
||||
template <typename T>
|
||||
uint32_t RemoveHeader (T &header);
|
||||
/**
|
||||
* Add trailer to this packet. This method invokes the
|
||||
* ns3::Chunk::GetSerializedSize and ns3::Trailer::serializeTo
|
||||
* methods to reserve space in the buffer and request the trailer
|
||||
* to serialize itself in the packet buffer.
|
||||
*
|
||||
* \param trailer a reference to the trailer to add to this packet.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddTrailer (T const &trailer);
|
||||
/**
|
||||
* Remove a deserialized trailer from the internal buffer.
|
||||
* This method invokes the ns3::Chunk::DeserializeFrom method.
|
||||
*
|
||||
* \param trailer a reference to the trailer to remove from the internal buffer.
|
||||
* \returns the number of bytes removed from the end of the packet.
|
||||
*/
|
||||
template <typename T>
|
||||
uint32_t RemoveTrailer (T &trailer);
|
||||
/**
|
||||
* Attach a tag to this packet. The tag is fully copied
|
||||
* in a packet-specific internal buffer. This operation
|
||||
* is expected to be really fast.
|
||||
*
|
||||
* \param tag a pointer to the tag to attach to this packet.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddTag (T const &tag);
|
||||
/**
|
||||
* Remove a tag from this packet. The data stored internally
|
||||
* for this tag is copied in the input tag if an instance
|
||||
* of this tag type is present in the internal buffer. If this
|
||||
* tag type is not present, the input tag is not modified.
|
||||
*
|
||||
* This operation can be potentially slow and might trigger
|
||||
* unexpectedly large memory allocations. It is thus
|
||||
* usually a better idea to create a copy of this packet,
|
||||
* and invoke removeAllTags on the copy to remove all
|
||||
* tags rather than remove the tags one by one from a packet.
|
||||
*
|
||||
* \param tag a pointer to the tag to remove from this packet
|
||||
* \returns true if an instance of this tag type is stored
|
||||
* in this packet, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
bool RemoveTag (T &tag);
|
||||
/**
|
||||
* Copy a tag stored internally to the input tag. If no instance
|
||||
* of this tag is present internally, the input tag is not modified.
|
||||
*
|
||||
* \param tag a pointer to the tag to read from this packet
|
||||
* \returns true if an instance of this tag type is stored
|
||||
* in this packet, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
bool PeekTag (T &tag) const;
|
||||
/**
|
||||
* Remove all the tags stored in this packet. This operation is
|
||||
* much much faster than invoking removeTag n times.
|
||||
*/
|
||||
void RemoveAllTags (void);
|
||||
/**
|
||||
* Concatenate the input packet at the end of the current
|
||||
* packet. This does not alter the uid of either packet.
|
||||
*
|
||||
* \param packet packet to concatenate
|
||||
*/
|
||||
void AddAtEnd (Packet packet);
|
||||
/**
|
||||
* \param size number of padding bytes to add.
|
||||
*/
|
||||
void AddPaddingAtEnd (uint32_t size);
|
||||
/**
|
||||
* Remove size bytes from the end of the current packet
|
||||
* It is safe to remove more bytes that what is present in
|
||||
* the packet.
|
||||
*
|
||||
* \param size number of bytes from remove
|
||||
*/
|
||||
void RemoveAtEnd (uint32_t size);
|
||||
/**
|
||||
* Remove size bytes from the start of the current packet.
|
||||
* It is safe to remove more bytes that what is present in
|
||||
* the packet.
|
||||
*
|
||||
* \param size number of bytes from remove
|
||||
*/
|
||||
void RemoveAtStart (uint32_t size);
|
||||
|
||||
/**
|
||||
* If you try to change the content of the buffer
|
||||
* returned by this method, you will die.
|
||||
*
|
||||
* \returns a pointer to the internal buffer of the packet.
|
||||
*/
|
||||
uint8_t const *PeekData (void) const;
|
||||
|
||||
/**
|
||||
* A packet is allocated a new uid when it is created
|
||||
* empty or with zero-filled payload.
|
||||
*
|
||||
* \returns an integer identifier which uniquely
|
||||
* identifies this packet.
|
||||
*/
|
||||
uint32_t GetUid (void) const;
|
||||
|
||||
/**
|
||||
* \param os output stream in which the data should be printed.
|
||||
*
|
||||
* Iterate over the headers and trailers present in this packet,
|
||||
* from the first header to the last trailer and invoke, for
|
||||
* each of them, the user-provided method Header::DoPrint or
|
||||
* Trailer::DoPrint methods.
|
||||
*/
|
||||
void Print (std::ostream &os) const;
|
||||
/**
|
||||
* \param os output stream in which the data should be printed.
|
||||
* \param printer the output formatter to use to print
|
||||
* the content of this packet.
|
||||
*
|
||||
* Iterate over the headers and trailers present in this packet,
|
||||
* either in the "forward" (first header to last trailer) or in
|
||||
* the "backward" (last trailer to first header) direction, as
|
||||
* specified by the PacketPrinter::PrintForward or the
|
||||
* PacketPrinter::PrintBackward methods. For each header, trailer,
|
||||
* or fragment of a header or a trailer, invoke the user-specified
|
||||
* print callback stored in the specified PacketPrinter.
|
||||
*/
|
||||
void Print (std::ostream &os, const PacketPrinter &printer) const;
|
||||
|
||||
/**
|
||||
* By default, packets do not keep around enough metadata to
|
||||
* perform the operations requested by the Print methods. If you
|
||||
* want to be able to invoke any of the two ::Print methods,
|
||||
* you need to invoke this method at least once during the
|
||||
* simulation setup and before any packet is created.
|
||||
*
|
||||
* The packet metadata is also used to perform extensive
|
||||
* sanity checks at runtime when performing operations on a
|
||||
* Packet. For example, this metadata is used to verify that
|
||||
* when you remove a header from a packet, this same header
|
||||
* was actually present at the front of the packet. These
|
||||
* errors will be detected and will abort the program.
|
||||
*/
|
||||
static void EnableMetadata (void);
|
||||
private:
|
||||
Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
|
||||
Buffer m_buffer;
|
||||
Tags m_tags;
|
||||
PacketMetadata m_metadata;
|
||||
static uint32_t m_globalUid;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
/**************************************************
|
||||
Start of implementation of templates defined
|
||||
above
|
||||
*************************************************/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
Packet::AddHeader (T const &header)
|
||||
{
|
||||
NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0,
|
||||
"Must pass Header subclass to Packet::AddHeader");
|
||||
uint32_t size = header.GetSize ();
|
||||
m_buffer.AddAtStart (size);
|
||||
header.Serialize (m_buffer.Begin ());
|
||||
m_metadata.AddHeader (header, size);
|
||||
}
|
||||
template <typename T>
|
||||
uint32_t
|
||||
Packet::RemoveHeader (T &header)
|
||||
{
|
||||
NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0,
|
||||
"Must pass Header subclass to Packet::RemoveHeader");
|
||||
uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
|
||||
m_buffer.RemoveAtStart (deserialized);
|
||||
m_metadata.RemoveHeader (header, deserialized);
|
||||
return deserialized;
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
Packet::AddTrailer (T const &trailer)
|
||||
{
|
||||
NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0,
|
||||
"Must pass Trailer subclass to Packet::AddTrailer");
|
||||
uint32_t size = trailer.GetSize ();
|
||||
m_buffer.AddAtEnd (size);
|
||||
Buffer::Iterator end = m_buffer.End ();
|
||||
trailer.Serialize (end);
|
||||
m_metadata.AddTrailer (trailer, size);
|
||||
}
|
||||
template <typename T>
|
||||
uint32_t
|
||||
Packet::RemoveTrailer (T &trailer)
|
||||
{
|
||||
NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0,
|
||||
"Must pass Trailer subclass to Packet::RemoveTrailer");
|
||||
uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
|
||||
m_buffer.RemoveAtEnd (deserialized);
|
||||
m_metadata.RemoveTrailer (trailer, deserialized);
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void Packet::AddTag (T const& tag)
|
||||
{
|
||||
m_tags.Add (tag);
|
||||
}
|
||||
template <typename T>
|
||||
bool Packet::RemoveTag (T & tag)
|
||||
{
|
||||
return m_tags.Remove (tag);
|
||||
}
|
||||
template <typename T>
|
||||
bool Packet::PeekTag (T & tag) const
|
||||
{
|
||||
return m_tags.Peek (tag);
|
||||
}
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* PACKET_H */
|
||||
@@ -0,0 +1,123 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Documentation kindly pointed out by Tom Henderson:
|
||||
* http://wiki.ethereal.com/Development/LibpcapFileFormat
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "pcap-writer.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
enum {
|
||||
PCAP_ETHERNET = 1,
|
||||
PCAP_RAW_IP = 101,
|
||||
PCAP_80211 = 105,
|
||||
};
|
||||
|
||||
PcapWriter::PcapWriter ()
|
||||
{
|
||||
m_writer = 0;
|
||||
}
|
||||
PcapWriter::~PcapWriter ()
|
||||
{
|
||||
delete m_writer;
|
||||
}
|
||||
|
||||
void
|
||||
PcapWriter::Open (std::string const &name)
|
||||
{
|
||||
m_writer = new std::ofstream ();
|
||||
m_writer->open (name.c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
PcapWriter::WriteEthernetHeader (void)
|
||||
{
|
||||
WriteHeader (PCAP_ETHERNET);
|
||||
}
|
||||
|
||||
void
|
||||
PcapWriter::WriteIpHeader (void)
|
||||
{
|
||||
WriteHeader (PCAP_RAW_IP);
|
||||
}
|
||||
|
||||
void
|
||||
PcapWriter::WriteWifiHeader (void)
|
||||
{
|
||||
WriteHeader (PCAP_80211);
|
||||
}
|
||||
|
||||
void
|
||||
PcapWriter::WriteHeader (uint32_t network)
|
||||
{
|
||||
Write32 (0xa1b2c3d4);
|
||||
Write16 (2);
|
||||
Write16 (4);
|
||||
Write32 (0);
|
||||
Write32 (0);
|
||||
Write32 (0xffff);
|
||||
Write32 (network);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
PcapWriter::WritePacket (Packet const packet)
|
||||
{
|
||||
if (m_writer != 0)
|
||||
{
|
||||
uint64_t current = Simulator::Now ().GetMicroSeconds ();
|
||||
uint64_t s = current / 1000000;
|
||||
uint64_t us = current % 1000000;
|
||||
Write32 (s & 0xffffffff);
|
||||
Write32 (us & 0xffffffff);
|
||||
Write32 (packet.GetSize ());
|
||||
Write32 (packet.GetSize ());
|
||||
WriteData (packet.PeekData (), packet.GetSize ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PcapWriter::WriteData (uint8_t const*buffer, uint32_t size)
|
||||
{
|
||||
m_writer->write ((char const *)buffer, size);
|
||||
}
|
||||
void
|
||||
PcapWriter::Write32 (uint32_t data)
|
||||
{
|
||||
WriteData ((uint8_t*)&data, 4);
|
||||
}
|
||||
void
|
||||
PcapWriter::Write16 (uint16_t data)
|
||||
{
|
||||
WriteData((uint8_t*)&data, 2);
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
@@ -0,0 +1,78 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef PCAP_WRITER_H
|
||||
#define PCAP_WRITER_H
|
||||
|
||||
#include "ns3/callback.h"
|
||||
#include <stdint.h>
|
||||
#include "packet.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Pcap output for Packet logger
|
||||
*
|
||||
* Log Packets to a file in pcap format which can be
|
||||
* read by pcap readers.
|
||||
*/
|
||||
class PcapWriter {
|
||||
public:
|
||||
PcapWriter ();
|
||||
~PcapWriter ();
|
||||
|
||||
/**
|
||||
* \param name the name of the file to store packet log into.
|
||||
* This method creates the file if it does not exist. If it
|
||||
* exists, the file is emptied.
|
||||
*/
|
||||
void Open (std::string const &name);
|
||||
|
||||
/**
|
||||
* Write a pcap header in the output file which specifies
|
||||
* that the content of the file will Packets with
|
||||
* Ethernet/LLC/SNAP encapsulation. This method should
|
||||
* be invoked before ns3::PcapWriter::writePacket and after
|
||||
* ns3::PcapWriter::open.
|
||||
*/
|
||||
void WriteEthernetHeader (void);
|
||||
|
||||
void WriteIpHeader (void);
|
||||
|
||||
void WriteWifiHeader (void);
|
||||
|
||||
/**
|
||||
* \param packet packet to write to output file
|
||||
*/
|
||||
void WritePacket (Packet const packet);
|
||||
|
||||
private:
|
||||
void WriteData (uint8_t const*buffer, uint32_t size);
|
||||
void Write32 (uint32_t data);
|
||||
void Write16 (uint16_t data);
|
||||
void WriteHeader (uint32_t network);
|
||||
std::ofstream *m_writer;
|
||||
Callback<void,uint8_t *,uint32_t> m_writeCallback;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* PCAP_WRITER_H */
|
||||
@@ -0,0 +1,68 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "stream-tracer.h"
|
||||
#include "ns3/test.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
namespace {
|
||||
|
||||
class TestStreamTracer : public ns3::Test {
|
||||
public:
|
||||
TestStreamTracer ();
|
||||
virtual bool RunTests (void);
|
||||
};
|
||||
|
||||
static TestStreamTracer gTestStream;
|
||||
|
||||
TestStreamTracer::TestStreamTracer ()
|
||||
: Test ("StreamTracer")
|
||||
{}
|
||||
|
||||
bool
|
||||
TestStreamTracer::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
ns3::StreamTracer trace;
|
||||
//trace.setStream (&std::cout);
|
||||
trace << 1;
|
||||
trace << " X ";
|
||||
trace << 1.0;
|
||||
trace << std::endl;
|
||||
trace << "test ";
|
||||
trace << 1 << " test";
|
||||
trace << "test "
|
||||
<< 1.0 << " "
|
||||
<< 0xdeadbead
|
||||
<< std::endl;
|
||||
trace << "0x" << std::hex
|
||||
<< 0xdeadbeaf
|
||||
<< std::dec << " "
|
||||
<< 0xdeadbeaf
|
||||
<< std::endl;
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -0,0 +1,76 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef STREAM_TRACER_H
|
||||
#define STREAM_TRACER_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief log arbitrary data to std::ostreams
|
||||
*
|
||||
* Whenever operator << is invoked on this class,
|
||||
* it is forwarded to the stored std::ostream output
|
||||
* stream (if there is one).
|
||||
*/
|
||||
class StreamTracer {
|
||||
public:
|
||||
StreamTracer ()
|
||||
: m_os (0) {}
|
||||
template <typename T>
|
||||
StreamTracer &operator << (T const&v) {
|
||||
if (m_os != 0)
|
||||
{
|
||||
(*m_os) << v;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T>
|
||||
StreamTracer &operator << (T &v) {
|
||||
if (m_os != 0)
|
||||
{
|
||||
(*m_os) << v;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
StreamTracer &operator << (std::ostream &(*v) (std::ostream &)) {
|
||||
if (m_os != 0)
|
||||
{
|
||||
(*m_os) << v;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param os the output stream to store
|
||||
*/
|
||||
void SetStream (std::ostream * os) {
|
||||
m_os = os;
|
||||
}
|
||||
private:
|
||||
std::ostream *m_os;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#endif /* TRACER_STREAM_H */
|
||||
@@ -0,0 +1,242 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SV_TRACE_SOURCE_H
|
||||
#define SV_TRACE_SOURCE_H
|
||||
|
||||
#include "callback-trace-source.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class SVTraceSourceBase {
|
||||
public:
|
||||
typedef CallbackTraceSource<int64_t, int64_t> ChangeNotifyCallback;
|
||||
|
||||
SVTraceSourceBase () {}
|
||||
SVTraceSourceBase (SVTraceSourceBase const &o) {}
|
||||
SVTraceSourceBase &operator = (SVTraceSourceBase const &o) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
~SVTraceSourceBase () {}
|
||||
|
||||
void AddCallback (CallbackBase const & callback, TraceContext const & context) {
|
||||
m_callback.AddCallback (callback, context);
|
||||
}
|
||||
void RemoveCallback (CallbackBase const & callback) {
|
||||
m_callback.RemoveCallback (callback);
|
||||
}
|
||||
protected:
|
||||
void Notify (int64_t oldVal, int64_t newVal) {
|
||||
if (oldVal != newVal)
|
||||
{
|
||||
m_callback (oldVal, newVal);
|
||||
}
|
||||
}
|
||||
private:
|
||||
ChangeNotifyCallback m_callback;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class UVTraceSource;
|
||||
|
||||
|
||||
/**
|
||||
* \brief trace variables of type "signed integer"
|
||||
* \ingroup lowleveltracing
|
||||
*
|
||||
* This template class implements a POD type: it
|
||||
* behaves like any other variable of type "signed integer"
|
||||
* except that it also reports any changes to its
|
||||
* value with its internal callback.
|
||||
*
|
||||
* To instantiate a 32-bit signed variable (to store
|
||||
* a TCP counter for example), you would create a variable of type
|
||||
* ns3::UVTraceSource<int32_t> :
|
||||
\code
|
||||
#include <stdint.h>
|
||||
#include "ns3/sv-trace-source.h"
|
||||
|
||||
ns3::SVTraceSource<uint16_t> var;
|
||||
\endcode
|
||||
* and you would use it like any other variable of type int32_t:
|
||||
\code
|
||||
var += 12;
|
||||
var = 10;
|
||||
var = -10;
|
||||
\endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class SVTraceSource : public SVTraceSourceBase {
|
||||
public:
|
||||
SVTraceSource ()
|
||||
: m_var (0)
|
||||
{}
|
||||
SVTraceSource (T const &var)
|
||||
: m_var (var)
|
||||
{}
|
||||
|
||||
SVTraceSource &operator = (SVTraceSource const &o) {
|
||||
Assign (o.Get ());
|
||||
return *this;
|
||||
}
|
||||
template <typename TT>
|
||||
SVTraceSource &operator = (SVTraceSource<TT> const &o) {
|
||||
Assign (o.Get ());
|
||||
return *this;
|
||||
}
|
||||
template <typename TT>
|
||||
SVTraceSource &operator = (UVTraceSource<TT> const &o) {
|
||||
Assign (o.Get ());
|
||||
return *this;
|
||||
}
|
||||
SVTraceSource &operator++ () {
|
||||
Assign (Get () + 1);
|
||||
return *this;
|
||||
}
|
||||
SVTraceSource &operator-- () {
|
||||
Assign (Get () - 1);
|
||||
return *this;
|
||||
}
|
||||
SVTraceSource operator++ (int) {
|
||||
SVTraceSource old (*this);
|
||||
++*this;
|
||||
return old;
|
||||
}
|
||||
SVTraceSource operator-- (int) {
|
||||
SVTraceSource old (*this);
|
||||
--*this;
|
||||
return old;
|
||||
}
|
||||
operator T () const {
|
||||
return Get ();
|
||||
}
|
||||
|
||||
|
||||
void Assign (T var) {
|
||||
Notify (m_var, var);
|
||||
m_var = var;
|
||||
}
|
||||
T Get (void) const {
|
||||
return m_var;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_var;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () + rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () - rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () * rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () / rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () << rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () >> rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () & rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () | rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () ^ rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () + rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () - rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () * rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () / rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () << rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () >> rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () & rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () | rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () ^ rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* SV_TRACE_SOURCE_H */
|
||||
@@ -0,0 +1,452 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "tags.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TagRegistry *
|
||||
TagRegistry::GetInstance (void)
|
||||
{
|
||||
static TagRegistry registry;
|
||||
return ®istry;
|
||||
}
|
||||
|
||||
TagRegistry::TagRegistry ()
|
||||
: m_sorted (false)
|
||||
{}
|
||||
|
||||
|
||||
void
|
||||
TagRegistry::Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor)
|
||||
{
|
||||
NS_ASSERT (!m_sorted);
|
||||
struct TagInfoItem item;
|
||||
item.uuid = uuid;
|
||||
item.printer = prettyPrinter;
|
||||
item.destructor = destructor;
|
||||
m_registry.push_back (item);
|
||||
}
|
||||
bool
|
||||
TagRegistry::CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b)
|
||||
{
|
||||
return a.uuid < b.uuid;
|
||||
}
|
||||
uint32_t
|
||||
TagRegistry::LookupUid (std::string uuid)
|
||||
{
|
||||
if (!m_sorted)
|
||||
{
|
||||
std::sort (m_registry.begin (), m_registry.end (), &TagRegistry::CompareItem);
|
||||
m_sorted = true;
|
||||
}
|
||||
NS_ASSERT (m_sorted);
|
||||
uint32_t uid = 1;
|
||||
for (TagsDataCI i = m_registry.begin (); i != m_registry.end (); i++)
|
||||
{
|
||||
if (i->uuid == uuid)
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
uid++;
|
||||
}
|
||||
// someone asked for a uid for an unregistered uuid.
|
||||
NS_ASSERT (!"You tried to use unregistered tag: make sure you create an instance of type TagRegistration<YouTagType>.");
|
||||
// quiet compiler
|
||||
return 0;
|
||||
}
|
||||
void
|
||||
TagRegistry::PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os)
|
||||
{
|
||||
NS_ASSERT (uid > 0);
|
||||
uint32_t index = uid - 1;
|
||||
NS_ASSERT (m_registry.size () > index);
|
||||
PrettyPrinter prettyPrinter = m_registry[index].printer;
|
||||
if (prettyPrinter != 0)
|
||||
{
|
||||
prettyPrinter (buf, os);
|
||||
}
|
||||
}
|
||||
void
|
||||
TagRegistry::Destruct (uint32_t uid, uint8_t buf[Tags::SIZE])
|
||||
{
|
||||
NS_ASSERT (uid > 0);
|
||||
uint32_t index = uid - 1;
|
||||
NS_ASSERT (m_registry.size () > index);
|
||||
Destructor destructor = m_registry[index].destructor;
|
||||
NS_ASSERT (destructor != 0);
|
||||
destructor (buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef USE_FREE_LIST
|
||||
|
||||
struct Tags::TagData *Tags::gFree = 0;
|
||||
uint32_t Tags::gN_free = 0;
|
||||
|
||||
struct Tags::TagData *
|
||||
Tags::AllocData (void)
|
||||
{
|
||||
struct Tags::TagData *retval;
|
||||
if (gFree != 0)
|
||||
{
|
||||
retval = gFree;
|
||||
gFree = gFree->m_next;
|
||||
gN_free--;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = new struct Tags::TagData ();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
Tags::FreeData (struct TagData *data)
|
||||
{
|
||||
if (gN_free > 1000)
|
||||
{
|
||||
delete data;
|
||||
return;
|
||||
}
|
||||
gN_free++;
|
||||
data->m_next = gFree;
|
||||
data->m_id = 0;
|
||||
gFree = data;
|
||||
}
|
||||
#else
|
||||
struct Tags::TagData *
|
||||
Tags::AllocData (void)
|
||||
{
|
||||
struct Tags::TagData *retval;
|
||||
retval = new struct Tags::TagData ();
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
Tags::FreeData (struct TagData *data)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
Tags::Remove (uint32_t id)
|
||||
{
|
||||
bool found = false;
|
||||
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
|
||||
{
|
||||
if (cur->m_id == id)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
struct TagData *start = 0;
|
||||
struct TagData **prevNext = &start;
|
||||
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
|
||||
{
|
||||
if (cur->m_id == id)
|
||||
{
|
||||
/**
|
||||
* XXX
|
||||
* Note: I believe that we could optimize this to
|
||||
* avoid copying each TagData located after the target id
|
||||
* and just link the already-copied list to the next tag.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
struct TagData *copy = AllocData ();
|
||||
copy->m_id = cur->m_id;
|
||||
copy->m_count = 1;
|
||||
copy->m_next = 0;
|
||||
memcpy (copy->m_data, cur->m_data, Tags::SIZE);
|
||||
*prevNext = copy;
|
||||
prevNext = ©->m_next;
|
||||
}
|
||||
*prevNext = 0;
|
||||
RemoveAll ();
|
||||
m_next = start;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Tags::PrettyPrint (std::ostream &os)
|
||||
{
|
||||
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
|
||||
{
|
||||
TagRegistry::GetInstance ()->PrettyPrint (cur->m_id, cur->m_data, os);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "ns3/test.h"
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
static bool g_a;
|
||||
static bool g_b;
|
||||
static bool g_c;
|
||||
static bool g_z;
|
||||
|
||||
class TagsTest : Test {
|
||||
public:
|
||||
TagsTest ();
|
||||
virtual ~TagsTest ();
|
||||
virtual bool RunTests (void);
|
||||
};
|
||||
|
||||
struct myTagA {
|
||||
uint8_t a;
|
||||
};
|
||||
struct myTagB {
|
||||
uint32_t b;
|
||||
};
|
||||
struct myTagC {
|
||||
uint8_t c [Tags::SIZE];
|
||||
};
|
||||
struct myInvalidTag {
|
||||
uint8_t invalid [Tags::SIZE+1];
|
||||
};
|
||||
struct myTagZ {
|
||||
uint8_t z;
|
||||
};
|
||||
|
||||
class MySmartTag
|
||||
{
|
||||
public:
|
||||
MySmartTag ()
|
||||
{
|
||||
//std::cout << "construct" << std::endl;
|
||||
}
|
||||
MySmartTag (const MySmartTag &o)
|
||||
{
|
||||
//std::cout << "copy" << std::endl;
|
||||
}
|
||||
~MySmartTag ()
|
||||
{
|
||||
//std::cout << "destruct" << std::endl;
|
||||
}
|
||||
MySmartTag &operator = (const MySmartTag &o)
|
||||
{
|
||||
//std::cout << "assign" << std::endl;
|
||||
return *this;
|
||||
}
|
||||
static void PrettyPrinterCb (const MySmartTag *a, std::ostream &os)
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
myTagAPrettyPrinterCb (struct myTagA const*a, std::ostream &os)
|
||||
{
|
||||
//os << "struct myTagA, a="<<(uint32_t)a->a<<std::endl;
|
||||
g_a = true;
|
||||
}
|
||||
static void
|
||||
myTagBPrettyPrinterCb (struct myTagB const*b, std::ostream &os)
|
||||
{
|
||||
//os << "struct myTagB, b="<<b->b<<std::endl;
|
||||
g_b = true;
|
||||
}
|
||||
static void
|
||||
myTagCPrettyPrinterCb (struct myTagC const*c, std::ostream &os)
|
||||
{
|
||||
//os << "struct myTagC, c="<<(uint32_t)c->c[0]<<std::endl;
|
||||
g_c = true;
|
||||
}
|
||||
static void
|
||||
myTagZPrettyPrinterCb (struct myTagZ const*z, std::ostream &os)
|
||||
{
|
||||
//os << "struct myTagZ" << std::endl;
|
||||
g_z = true;
|
||||
}
|
||||
|
||||
|
||||
static TagRegistration<struct myTagA> gMyTagARegistration ("A", &myTagAPrettyPrinterCb);
|
||||
static TagRegistration<struct myTagB> gMyTagBRegistration ("B", &myTagBPrettyPrinterCb);
|
||||
static TagRegistration<struct myTagC> gMyTagCRegistration ("C", &myTagCPrettyPrinterCb);
|
||||
static TagRegistration<struct myTagZ> g_myTagZRegistration ("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
|
||||
&myTagZPrettyPrinterCb);
|
||||
static TagRegistration<MySmartTag> g_myTagSmartRegistration ("SmartTag", &MySmartTag::PrettyPrinterCb);
|
||||
|
||||
|
||||
TagsTest::TagsTest ()
|
||||
: Test ("Tags")
|
||||
{}
|
||||
TagsTest::~TagsTest ()
|
||||
{}
|
||||
|
||||
bool
|
||||
TagsTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
// build initial tag.
|
||||
Tags tags;
|
||||
struct myTagA a;
|
||||
a.a = 10;
|
||||
tags.Add (a);
|
||||
a.a = 0;
|
||||
tags.Peek (a);
|
||||
if (a.a != 10)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
g_a = false;
|
||||
tags.PrettyPrint (std::cout);
|
||||
if (!g_a)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
struct myTagB b;
|
||||
b.b = 0xff;
|
||||
tags.Add (b);
|
||||
b.b = 0;
|
||||
tags.Peek (b);
|
||||
if (b.b != 0xff)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
g_b = false;
|
||||
g_a = false;
|
||||
tags.PrettyPrint (std::cout);
|
||||
if (!g_a || !g_b)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
// make sure copy contains copy.
|
||||
Tags other = tags;
|
||||
g_b = false;
|
||||
g_a = false;
|
||||
other.PrettyPrint (std::cout);
|
||||
if (!g_a || !g_b)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
g_b = false;
|
||||
g_a = false;
|
||||
tags.PrettyPrint (std::cout);
|
||||
if (!g_a || !g_b)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
struct myTagA oA;
|
||||
oA.a = 0;
|
||||
other.Peek (oA);
|
||||
if (oA.a != 10)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
struct myTagB oB;
|
||||
oB.b = 1;
|
||||
other.Peek (oB);
|
||||
if (oB.b != 0xff)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
// remove data.
|
||||
other.Remove (oA);
|
||||
if (other.Peek (oA))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
g_b = false;
|
||||
g_a = false;
|
||||
other.PrettyPrint (std::cout);
|
||||
if (g_a || !g_b)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (!tags.Peek (oA))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
other.Remove (oB);
|
||||
if (other.Peek (oB))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (!tags.Peek (oB))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
other = tags;
|
||||
Tags another = other;
|
||||
struct myTagC c;
|
||||
memset (c.c, 0x66, 16);
|
||||
another.Add (c);
|
||||
c.c[0] = 0;
|
||||
another.Peek (c);
|
||||
if (!another.Peek (c))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (tags.Peek (c))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
other = other;
|
||||
//other.prettyPrint (std::cout);
|
||||
|
||||
//struct myInvalidTag invalid;
|
||||
//tags.add (&invalid);
|
||||
|
||||
struct myTagZ tagZ;
|
||||
Tags testLastTag;
|
||||
tagZ.z = 0;
|
||||
testLastTag.Add (tagZ);
|
||||
g_z = false;
|
||||
testLastTag.PrettyPrint (std::cout);
|
||||
if (!g_z)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
MySmartTag smartTag;
|
||||
{
|
||||
Tags tmp;
|
||||
tmp.Add (smartTag);
|
||||
tmp.Peek (smartTag);
|
||||
tmp.Remove (smartTag);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static TagsTest gTagsTest;
|
||||
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef TAGS_H
|
||||
#define TAGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
class TagPrettyPrinter;
|
||||
|
||||
/**
|
||||
* \ingroup constants
|
||||
* \brief Tag maximum size
|
||||
* The maximum size (in bytes) of a Tag is stored
|
||||
* in this constant.
|
||||
*/
|
||||
#define TAGS_MAX_SIZE 16
|
||||
|
||||
class Tags {
|
||||
public:
|
||||
inline Tags ();
|
||||
inline Tags (Tags const &o);
|
||||
inline Tags &operator = (Tags const &o);
|
||||
inline ~Tags ();
|
||||
|
||||
template <typename T>
|
||||
void Add (T const&tag);
|
||||
|
||||
template <typename T>
|
||||
bool Remove (T &tag);
|
||||
|
||||
template <typename T>
|
||||
bool Peek (T &tag) const;
|
||||
|
||||
void PrettyPrint (std::ostream &os);
|
||||
|
||||
inline void RemoveAll (void);
|
||||
|
||||
enum {
|
||||
SIZE = TAGS_MAX_SIZE
|
||||
};
|
||||
private:
|
||||
struct TagData {
|
||||
uint8_t m_data[Tags::SIZE];
|
||||
struct TagData *m_next;
|
||||
uint32_t m_id;
|
||||
uint32_t m_count;
|
||||
};
|
||||
|
||||
bool Remove (uint32_t id);
|
||||
struct Tags::TagData *AllocData (void);
|
||||
void FreeData (struct TagData *data);
|
||||
|
||||
static struct Tags::TagData *gFree;
|
||||
static uint32_t gN_free;
|
||||
|
||||
struct TagData *m_next;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief pretty print packet tags
|
||||
*
|
||||
* This class is used to register a pretty-printer
|
||||
* callback function to print in a nice user-friendly
|
||||
* way the content of the target type. To register
|
||||
* such a type, all you need to do is instantiate
|
||||
* an instance of this type as a static variable.
|
||||
*/
|
||||
template <typename T>
|
||||
class TagRegistration {
|
||||
public:
|
||||
/**
|
||||
* \param uuid a uuid generated with uuidgen
|
||||
* \param fn a function which can pretty-print an instance
|
||||
* of type T in the output stream.
|
||||
*/
|
||||
TagRegistration<T> (std::string uuid, void(*fn) (T const*, std::ostream &));
|
||||
private:
|
||||
static void PrettyPrinterCb (uint8_t *buf, std::ostream &os);
|
||||
static void DestructorCb (uint8_t *buf);
|
||||
static void(*m_prettyPrinter) (T const*, std::ostream &);
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
|
||||
/**************************************************************
|
||||
An implementation of the templates defined above
|
||||
*************************************************************/
|
||||
#include "ns3/assert.h"
|
||||
#include <string>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class TagRegistry {
|
||||
public:
|
||||
typedef void (*PrettyPrinter) (uint8_t [Tags::SIZE], std::ostream &);
|
||||
typedef void (*Destructor) (uint8_t [Tags::SIZE]);
|
||||
void Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor);
|
||||
/**
|
||||
* returns a numeric integer which uniquely identifies the input string.
|
||||
* that integer cannot be zero which is a reserved value.
|
||||
*/
|
||||
uint32_t LookupUid (std::string uuid);
|
||||
void PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os);
|
||||
void Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]);
|
||||
|
||||
static TagRegistry *GetInstance (void);
|
||||
private:
|
||||
TagRegistry ();
|
||||
struct TagInfoItem
|
||||
{
|
||||
std::string uuid;
|
||||
PrettyPrinter printer;
|
||||
Destructor destructor;
|
||||
};
|
||||
typedef std::vector<struct TagInfoItem> TagsData;
|
||||
typedef std::vector<struct TagInfoItem>::const_iterator TagsDataCI;
|
||||
static bool CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b);
|
||||
bool m_sorted;
|
||||
TagsData m_registry;
|
||||
};
|
||||
/**
|
||||
* The TypeUid class is used to create a mapping Type --> uid
|
||||
* Note that we use a static getUuid function which contains a
|
||||
* static std::string variable rather than a simpler static
|
||||
* member std::string variable to ensure the proper order
|
||||
* of initialization when these methods are invoked
|
||||
* from the constructor of another static variable.
|
||||
*/
|
||||
template <typename T>
|
||||
class TypeUid {
|
||||
public:
|
||||
static void Record (std::string uuid);
|
||||
static const uint32_t GetUid (void);
|
||||
private:
|
||||
static std::string *GetUuid (void);
|
||||
T m_realType;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void TypeUid<T>::Record (std::string uuid)
|
||||
{
|
||||
*(GetUuid ()) = uuid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const uint32_t TypeUid<T>::GetUid (void)
|
||||
{
|
||||
static const uint32_t uid = TagRegistry::GetInstance ()->
|
||||
LookupUid (*(GetUuid ()));
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string *TypeUid<T>::GetUuid (void)
|
||||
{
|
||||
static std::string uuid;
|
||||
return &uuid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the TagRegistration registration class.
|
||||
* It records a callback with the TagRegistry
|
||||
* This callback performs type conversion before forwarding
|
||||
* the call to the user-provided function.
|
||||
*/
|
||||
template <typename T>
|
||||
TagRegistration<T>::TagRegistration (std::string uuid, void (*prettyPrinter) (T const*, std::ostream &))
|
||||
{
|
||||
NS_ASSERT (sizeof (T) <= Tags::SIZE);
|
||||
m_prettyPrinter = prettyPrinter;
|
||||
TagRegistry::GetInstance ()->
|
||||
Record (uuid, &TagRegistration<T>::PrettyPrinterCb, &TagRegistration<T>::DestructorCb);
|
||||
TypeUid<T>::Record (uuid);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
TagRegistration<T>::PrettyPrinterCb (uint8_t *buf, std::ostream &os)
|
||||
{
|
||||
NS_ASSERT (sizeof (T) <= Tags::SIZE);
|
||||
T *tag = reinterpret_cast<T *> (buf);
|
||||
(*m_prettyPrinter) (tag, os);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
TagRegistration<T>::DestructorCb (uint8_t *buf)
|
||||
{
|
||||
T *tag = reinterpret_cast<T *> (buf);
|
||||
tag->~T ();
|
||||
}
|
||||
template <typename T>
|
||||
void (*TagRegistration<T>::m_prettyPrinter) (T const*, std::ostream &) = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
Tags::Add (T const&tag)
|
||||
{
|
||||
NS_ASSERT (sizeof (T) <= Tags::SIZE);
|
||||
// ensure this id was not yet added
|
||||
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
|
||||
{
|
||||
NS_ASSERT (cur->m_id != TypeUid<T>::GetUid ());
|
||||
}
|
||||
struct TagData *newStart = AllocData ();
|
||||
newStart->m_count = 1;
|
||||
newStart->m_next = 0;
|
||||
newStart->m_id = TypeUid<T>::GetUid ();
|
||||
void *buf = &newStart->m_data;
|
||||
new (buf) T (tag);
|
||||
newStart->m_next = m_next;
|
||||
m_next = newStart;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
Tags::Remove (T &tag)
|
||||
{
|
||||
NS_ASSERT (sizeof (T) <= Tags::SIZE);
|
||||
return Remove (TypeUid<T>::GetUid ());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
Tags::Peek (T &tag) const
|
||||
{
|
||||
NS_ASSERT (sizeof (T) <= Tags::SIZE);
|
||||
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
|
||||
{
|
||||
if (cur->m_id == TypeUid<T>::GetUid ())
|
||||
{
|
||||
/* found tag */
|
||||
T *data = reinterpret_cast<T *> (&cur->m_data);
|
||||
tag = T (*data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* no tag found */
|
||||
return false;
|
||||
}
|
||||
|
||||
Tags::Tags ()
|
||||
: m_next ()
|
||||
{}
|
||||
|
||||
Tags::Tags (Tags const &o)
|
||||
: m_next (o.m_next)
|
||||
{
|
||||
if (m_next != 0)
|
||||
{
|
||||
m_next->m_count++;
|
||||
}
|
||||
}
|
||||
|
||||
Tags &
|
||||
Tags::operator = (Tags const &o)
|
||||
{
|
||||
// self assignment
|
||||
if (m_next == o.m_next)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
RemoveAll ();
|
||||
m_next = o.m_next;
|
||||
if (m_next != 0)
|
||||
{
|
||||
m_next->m_count++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tags::~Tags ()
|
||||
{
|
||||
RemoveAll ();
|
||||
}
|
||||
|
||||
void
|
||||
Tags::RemoveAll (void)
|
||||
{
|
||||
struct TagData *prev = 0;
|
||||
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
|
||||
{
|
||||
cur->m_count--;
|
||||
if (cur->m_count > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (prev != 0)
|
||||
{
|
||||
TagRegistry::GetInstance ()->
|
||||
Destruct (prev->m_id, prev->m_data);
|
||||
FreeData (prev);
|
||||
}
|
||||
prev = cur;
|
||||
}
|
||||
if (prev != 0)
|
||||
{
|
||||
TagRegistry::GetInstance ()->
|
||||
Destruct (prev->m_id, prev->m_data);
|
||||
FreeData (prev);
|
||||
}
|
||||
m_next = 0;
|
||||
}
|
||||
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* TAGS_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef TERMINAL_TRACE_RESOLVER_H
|
||||
#define TERMINAL_TRACE_RESOLVER_H
|
||||
|
||||
#include "trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class TraceContext;
|
||||
|
||||
template <typename T>
|
||||
class TerminalTraceResolver : public TraceResolver
|
||||
{
|
||||
public:
|
||||
TerminalTraceResolver (T &traceSource, TraceContext const &context);
|
||||
private:
|
||||
virtual void DoConnect (CallbackBase const &cb);
|
||||
virtual void DoDisconnect (CallbackBase const &cb);
|
||||
T &m_traceSource;
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
TerminalTraceResolver<T>::TerminalTraceResolver (T &traceSource,
|
||||
TraceContext const &context)
|
||||
: TraceResolver (context),
|
||||
m_traceSource (traceSource)
|
||||
{}
|
||||
template <typename T>
|
||||
void
|
||||
TerminalTraceResolver<T>::DoConnect (CallbackBase const &cb)
|
||||
{
|
||||
m_traceSource.AddCallback (cb, GetContext ());
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
TerminalTraceResolver<T>::DoDisconnect (CallbackBase const &cb)
|
||||
{
|
||||
m_traceSource.RemoveCallback (cb);
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* TERMINAL_TRACE_RESOLVER_H */
|
||||
@@ -0,0 +1,320 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "trace-context.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
std::vector<uint8_t> TraceContext::m_sizes;
|
||||
|
||||
TraceContext::TraceContext ()
|
||||
: m_data (0)
|
||||
{}
|
||||
TraceContext::TraceContext (TraceContext const &o)
|
||||
: m_data (o.m_data)
|
||||
{
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->count++;
|
||||
}
|
||||
}
|
||||
TraceContext const &
|
||||
TraceContext::operator = (TraceContext const &o)
|
||||
{
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->count--;
|
||||
if (m_data->count == 0)
|
||||
{
|
||||
uint8_t *buffer = (uint8_t *)m_data;
|
||||
delete [] buffer;
|
||||
}
|
||||
}
|
||||
m_data = o.m_data;
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->count++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
TraceContext::~TraceContext ()
|
||||
{
|
||||
if (m_data != 0)
|
||||
{
|
||||
m_data->count--;
|
||||
if (m_data->count == 0)
|
||||
{
|
||||
uint8_t *buffer = (uint8_t *)m_data;
|
||||
delete [] buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
TraceContext::GetSize (uint8_t uid)
|
||||
{
|
||||
return m_sizes[uid];
|
||||
}
|
||||
|
||||
void
|
||||
TraceContext::Add (TraceContext const &o)
|
||||
{
|
||||
if (o.m_data == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint8_t currentUid;
|
||||
uint16_t i = 0;
|
||||
while (i < o.m_data->size)
|
||||
{
|
||||
currentUid = o.m_data->data[i];
|
||||
uint8_t size = TraceContext::GetSize (currentUid);
|
||||
uint8_t *selfBuffer = CheckPresent (currentUid);
|
||||
uint8_t *otherBuffer = &(o.m_data->data[i+1]);
|
||||
if (selfBuffer != 0)
|
||||
{
|
||||
if (memcmp (selfBuffer, otherBuffer, size) != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("You cannot add TraceContexts which "<<
|
||||
"have different values stored in them.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DoAdd (currentUid, otherBuffer);
|
||||
}
|
||||
i += 1 + size;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
TraceContext::CheckPresent (uint8_t uid) const
|
||||
{
|
||||
if (m_data == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint8_t currentUid;
|
||||
uint16_t i = 0;
|
||||
do {
|
||||
currentUid = m_data->data[i];
|
||||
uint8_t size = TraceContext::GetSize (currentUid);
|
||||
if (currentUid == uid)
|
||||
{
|
||||
return &m_data->data[i+1];
|
||||
}
|
||||
i += 1 + size;
|
||||
} while (i < m_data->size && currentUid != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
|
||||
{
|
||||
NS_ASSERT (uid != 0);
|
||||
uint8_t size = TraceContext::GetSize (uid);
|
||||
uint8_t *present = CheckPresent (uid);
|
||||
if (present != 0) {
|
||||
if (memcmp (present, buffer, size) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_data == 0)
|
||||
{
|
||||
uint16_t newSize = 1 + size;
|
||||
uint16_t allocatedSize;
|
||||
if (newSize > 4)
|
||||
{
|
||||
allocatedSize = sizeof (struct Data) + newSize - 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocatedSize = sizeof (struct Data);
|
||||
}
|
||||
struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
|
||||
data->size = newSize;
|
||||
data->count = 1;
|
||||
data->data[0] = uid;
|
||||
memcpy (data->data + 1, buffer, size);
|
||||
m_data = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t newSize = m_data->size + 1 + size;
|
||||
uint16_t allocatedSize;
|
||||
if (newSize > 4)
|
||||
{
|
||||
allocatedSize = sizeof (struct Data) + newSize - 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocatedSize = sizeof (struct Data);
|
||||
}
|
||||
struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
|
||||
data->size = newSize;
|
||||
data->count = 1;
|
||||
memcpy (data->data, m_data->data, m_data->size);
|
||||
data->data[m_data->size] = uid;
|
||||
memcpy (data->data + m_data->size + 1, buffer, size);
|
||||
m_data->count--;
|
||||
if (m_data->count == 0)
|
||||
{
|
||||
uint8_t *buffer = (uint8_t *)m_data;
|
||||
delete [] buffer;
|
||||
}
|
||||
m_data = data;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool
|
||||
TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const
|
||||
{
|
||||
if (m_data == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint8_t currentUid;
|
||||
uint16_t i = 0;
|
||||
do {
|
||||
currentUid = m_data->data[i];
|
||||
uint8_t size = TraceContext::GetSize (currentUid);
|
||||
if (currentUid == uid)
|
||||
{
|
||||
memcpy (buffer, &m_data->data[i+1], size);
|
||||
return true;
|
||||
}
|
||||
i += 1 + size;
|
||||
} while (i < m_data->size && currentUid != 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
TraceContext::DoGetNextUid (void)
|
||||
{
|
||||
static uint8_t uid = 0;
|
||||
if (uid == 0)
|
||||
{
|
||||
m_sizes.push_back (0);
|
||||
}
|
||||
uid++;
|
||||
return uid;
|
||||
}
|
||||
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#include "ns3/test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <int N>
|
||||
class Ctx
|
||||
{
|
||||
public:
|
||||
Ctx () : m_v (0) {}
|
||||
Ctx (int v) : m_v (v) {}
|
||||
int Get (void) const { return N;}
|
||||
private:
|
||||
int m_v;
|
||||
};
|
||||
|
||||
class TraceContextTest : public Test
|
||||
{
|
||||
public:
|
||||
TraceContextTest ();
|
||||
virtual bool RunTests (void);
|
||||
};
|
||||
|
||||
TraceContextTest::TraceContextTest ()
|
||||
: Test ("TraceContext")
|
||||
{}
|
||||
bool
|
||||
TraceContextTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
TraceContext ctx;
|
||||
Ctx<0> v0;
|
||||
Ctx<0> v01 = Ctx<0> (1);
|
||||
Ctx<1> v1;
|
||||
Ctx<2> v2;
|
||||
Ctx<3> v3;
|
||||
|
||||
if (ctx.SafeGet (v0))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
ctx.Add (v0);
|
||||
ctx.Add (v0);
|
||||
if (ctx.SafeAdd (v01))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
ctx.Get (v0);
|
||||
ctx.Add (v1);
|
||||
ctx.Get (v1);
|
||||
ctx.Get (v0);
|
||||
ctx.Get (v1);
|
||||
|
||||
TraceContext copy = ctx;
|
||||
ctx.Get (v0);
|
||||
ctx.Get (v1);
|
||||
copy.Get (v0);
|
||||
copy.Get (v1);
|
||||
copy.Add (v2);
|
||||
copy.Get (v0);
|
||||
copy.Get (v1);
|
||||
copy.Get (v2);
|
||||
ctx.Add (v3);
|
||||
ctx.Get (v0);
|
||||
ctx.Get (v1);
|
||||
ctx.Get (v3);
|
||||
|
||||
if (ctx.SafeGet (v2))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (copy.SafeGet (v3))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
ctx.Add (copy);
|
||||
ctx.Get (v2);
|
||||
if (copy.SafeGet (v3))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
copy.Add (ctx);
|
||||
copy.Get (v3);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static TraceContextTest g_traceContextTest;
|
||||
|
||||
|
||||
}//namespace ns3
|
||||
@@ -0,0 +1,167 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef TRACE_CONTEXT_H
|
||||
#define TRACE_CONTEXT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include "ns3/fatal-error.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Provide context to trace sources
|
||||
* \ingroup lowleveltracing
|
||||
*
|
||||
* Instances of this class are used to hold context
|
||||
* for each trace source. Each instance holds a list of
|
||||
* 'contexts'. Trace sinks can lookup these contexts
|
||||
* from this list with the ns3::TraceContext::Get method.
|
||||
*
|
||||
* This class is implemented
|
||||
* using Copy On Write which means that copying unmodified
|
||||
* versions of this class is very cheap. However, modifying
|
||||
* the content of this class through a call
|
||||
* to ns3::TraceContext::Add will trigger a costly memory
|
||||
* reallocation if needed.
|
||||
*/
|
||||
class TraceContext
|
||||
{
|
||||
public:
|
||||
TraceContext ();
|
||||
TraceContext (TraceContext const &o);
|
||||
TraceContext const & operator = (TraceContext const &o);
|
||||
~TraceContext ();
|
||||
|
||||
/**
|
||||
* \param context add context to list of trace contexts.
|
||||
*/
|
||||
template <typename T>
|
||||
void Add (T const &context);
|
||||
|
||||
/**
|
||||
* \param o the other context
|
||||
*
|
||||
* Perform the Union operation (in the sense of set theory) on the
|
||||
* two input lists of elements. This method is used in the
|
||||
* ns3::CallbackTraceSourceSource class when multiple sinks are connected
|
||||
* to a single source to ensure that the source does not need
|
||||
* to store a single TraceContext instance per connected sink.
|
||||
* Instead, all sinks share the same TraceContext.
|
||||
*/
|
||||
void Add (TraceContext const &o);
|
||||
|
||||
/**
|
||||
* \param context context to get from this list of trace contexts.
|
||||
*
|
||||
* This method cannot fail. If the requested trace context is not
|
||||
* stored in this TraceContext, then, the program will halt.
|
||||
*/
|
||||
template <typename T>
|
||||
void Get (T &context) const;
|
||||
private:
|
||||
friend class TraceContextTest;
|
||||
// used exclusively for testing code.
|
||||
template <typename T>
|
||||
bool SafeGet (T &context) const;
|
||||
template <typename T>
|
||||
bool SafeAdd (T &context);
|
||||
|
||||
template <typename T>
|
||||
static uint8_t GetUid (void);
|
||||
template <typename T>
|
||||
static uint8_t GetNextUid (void);
|
||||
static uint8_t DoGetNextUid (void);
|
||||
static uint8_t GetSize (uint8_t uid);
|
||||
uint8_t *CheckPresent (uint8_t uid) const;
|
||||
bool DoAdd (uint8_t uid, uint8_t const *buffer);
|
||||
bool DoGet (uint8_t uid, uint8_t *buffer) const;
|
||||
|
||||
static std::vector<uint8_t> m_sizes;
|
||||
struct Data {
|
||||
uint16_t count;
|
||||
uint16_t size;
|
||||
uint8_t data[4];
|
||||
} * m_data;
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceContext::Add (T const &context)
|
||||
{
|
||||
uint8_t *data = (uint8_t *) &context;
|
||||
bool ok = DoAdd (TraceContext::GetUid<T> (), data);
|
||||
if (!ok)
|
||||
{
|
||||
NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid.");
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
TraceContext::Get (T &context) const
|
||||
{
|
||||
uint8_t *data = (uint8_t *) &context;
|
||||
bool found = DoGet (TraceContext::GetUid<T> (), data);
|
||||
if (!found)
|
||||
{
|
||||
NS_FATAL_ERROR ("Type not stored in TraceContext");
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
bool
|
||||
TraceContext::SafeGet (T &context) const
|
||||
{
|
||||
uint8_t *data = (uint8_t *) &context;
|
||||
bool found = DoGet (TraceContext::GetUid<T> (), data);
|
||||
return found;
|
||||
}
|
||||
template <typename T>
|
||||
bool
|
||||
TraceContext::SafeAdd (T &context)
|
||||
{
|
||||
uint8_t *data = (uint8_t *) &context;
|
||||
bool ok = DoAdd (TraceContext::GetUid<T> (), data);
|
||||
return ok;
|
||||
}
|
||||
template <typename T>
|
||||
uint8_t
|
||||
TraceContext::GetUid (void)
|
||||
{
|
||||
static uint8_t uid = GetNextUid<T> ();
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint8_t
|
||||
TraceContext::GetNextUid (void)
|
||||
{
|
||||
uint8_t uid = DoGetNextUid ();
|
||||
m_sizes.push_back (sizeof (T));
|
||||
return uid;
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* TRACE_CONTEXT_H */
|
||||
@@ -0,0 +1,104 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "trace-resolver.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TraceResolver::TraceResolver (TraceContext const &context)
|
||||
: m_context (context)
|
||||
{}
|
||||
|
||||
TraceResolver::~TraceResolver ()
|
||||
{}
|
||||
|
||||
TraceContext const &
|
||||
TraceResolver::GetContext (void) const
|
||||
{
|
||||
return m_context;
|
||||
}
|
||||
|
||||
void
|
||||
TraceResolver::Connect (std::string path, CallbackBase const &cb)
|
||||
{
|
||||
std::string::size_type cur = 1;
|
||||
// check that first char is "/"
|
||||
std::string::size_type next = path.find ("/", cur);
|
||||
std::string element = std::string (path, cur, next-1);
|
||||
TraceResolverList resolverList = DoLookup (element);
|
||||
for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
|
||||
{
|
||||
TraceResolver *resolver = *i;
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
// we really break the recursion here.
|
||||
resolver->DoConnect (cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string subpath = std::string (path, next, std::string::npos);
|
||||
resolver->Connect (subpath, cb);
|
||||
}
|
||||
delete resolver;
|
||||
}
|
||||
resolverList.erase (resolverList.begin (), resolverList.end ());
|
||||
}
|
||||
|
||||
void
|
||||
TraceResolver::Disconnect (std::string path, CallbackBase const &cb)
|
||||
{
|
||||
std::string::size_type cur = 1;
|
||||
// check that first char is "/"
|
||||
std::string::size_type next = path.find ("/", cur);
|
||||
std::string element = std::string (path, cur, next-1);
|
||||
TraceResolverList resolverList = DoLookup (element);
|
||||
for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
|
||||
{
|
||||
TraceResolver *resolver = *i;
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
// we really break the recursion here.
|
||||
resolver->DoDisconnect (cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string subpath = std::string (path, next, std::string::npos);
|
||||
resolver->Disconnect (subpath, cb);
|
||||
}
|
||||
delete resolver;
|
||||
}
|
||||
resolverList.erase (resolverList.begin (), resolverList.end ());
|
||||
}
|
||||
|
||||
TraceResolver::TraceResolverList
|
||||
TraceResolver::DoLookup (std::string id) const
|
||||
{
|
||||
return TraceResolverList ();
|
||||
}
|
||||
void
|
||||
TraceResolver::DoConnect (CallbackBase const &cb)
|
||||
{}
|
||||
|
||||
void
|
||||
TraceResolver::DoDisconnect (CallbackBase const &cb)
|
||||
{}
|
||||
|
||||
|
||||
}//namespace ns3
|
||||
@@ -0,0 +1,119 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef TRACE_RESOLVER_H
|
||||
#define TRACE_RESOLVER_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include "trace-context.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class CallbackBase;
|
||||
|
||||
/**
|
||||
* \brief the base class which is used to incremental perform trace
|
||||
* namespace resolution.
|
||||
* \ingroup lowleveltracing
|
||||
*
|
||||
* This class provides a public API to the ns3::TraceRoot object:
|
||||
* - ns3::TraceResolver::Connect
|
||||
* - ns3::TraceResolver::Disconnect
|
||||
*
|
||||
* It also provides an API for its subclasses. Each subclass should
|
||||
* implement one of:
|
||||
* - ns3::TraceResolver::DoLookup
|
||||
* - ns3::TraceResolver::DoConnect and ns3::TraceResolver::DoDisconnect
|
||||
* Each subclass must also provide an ns3::TraceContext to the TraceResolver
|
||||
* constructor. Finally, each subclass can access the ns3::TraceContext
|
||||
* associated to this ns3::TraceResolver through the
|
||||
* ns3::TraceResolver::GetContext method.
|
||||
*/
|
||||
class TraceResolver
|
||||
{
|
||||
public:
|
||||
virtual ~TraceResolver ();
|
||||
/**
|
||||
* \param path the namespace path to resolver
|
||||
* \param cb the callback to connect to the matching namespace
|
||||
*
|
||||
* This method is typically invoked by ns3::TraceRoot but advanced
|
||||
* users could also conceivably call it directly if they want to
|
||||
* skip the ns3::TraceRoot.
|
||||
*/
|
||||
void Connect (std::string path, CallbackBase const &cb);
|
||||
/**
|
||||
* \param path the namespace path to resolver
|
||||
* \param cb the callback to disconnect in the matching namespace
|
||||
*
|
||||
* This method is typically invoked by ns3::TraceRoot but advanced
|
||||
* users could also conceivably call it directly if they want to
|
||||
* skip the ns3::TraceRoot.
|
||||
*/
|
||||
void Disconnect (std::string path, CallbackBase const &cb);
|
||||
protected:
|
||||
/**
|
||||
* \param context the context used to initialize this TraceResolver.
|
||||
*
|
||||
* Every subclass must call this constructor
|
||||
*/
|
||||
TraceResolver (TraceContext const &context);
|
||||
/**
|
||||
* \returns the ns3::TraceContext stored in this ns3::TraceResolver.
|
||||
*
|
||||
* Subclasses usually invoke this method to get access to the
|
||||
* TraceContext stored here to pass it down to the TraceResolver
|
||||
* constructors invoked from within the DoLookup method.
|
||||
*/
|
||||
TraceContext const &GetContext (void) const;
|
||||
typedef std::list<TraceResolver *> TraceResolverList;
|
||||
private:
|
||||
TraceResolver ();
|
||||
/**
|
||||
* \param id the id to resolve. This is supposed to be
|
||||
* one element of the global tracing namespace.
|
||||
* \returns a list of reslvers which match the input namespace element
|
||||
*
|
||||
* A subclass which overrides this method should return a potentially
|
||||
* empty list of pointers to ns3::TraceResolver instances which match
|
||||
* the input namespace element. Each of these TraceResolver should be
|
||||
* instanciated with a TraceContext which holds enough context
|
||||
* information to identify the type of the TraceResolver.
|
||||
*/
|
||||
virtual TraceResolverList DoLookup (std::string id) const;
|
||||
/**
|
||||
* \param cb callback to connect
|
||||
*
|
||||
* This method is invoked on leaf trace resolvers.
|
||||
*/
|
||||
virtual void DoConnect (CallbackBase const &cb);
|
||||
/**
|
||||
* \param cb callback to disconnect
|
||||
*
|
||||
* This method is invoked on leaf trace resolvers.
|
||||
*/
|
||||
virtual void DoDisconnect (CallbackBase const &cb);
|
||||
TraceContext m_context;
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* TRACE_RESOLVER_H */
|
||||
@@ -0,0 +1,54 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "trace-root.h"
|
||||
#include "ns3/composite-trace-resolver.h"
|
||||
#include "ns3/trace-context.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
void
|
||||
TraceRoot::Connect (std::string path, CallbackBase const &cb)
|
||||
{
|
||||
TraceResolver *resolver = GetComposite ();
|
||||
resolver->Connect (path, cb);
|
||||
}
|
||||
void
|
||||
TraceRoot::Disconnect (std::string path, CallbackBase const &cb)
|
||||
{
|
||||
TraceResolver *resolver = GetComposite ();
|
||||
resolver->Disconnect (path, cb);
|
||||
}
|
||||
void
|
||||
TraceRoot::Register (std::string name,
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver)
|
||||
{
|
||||
CompositeTraceResolver *resolver = GetComposite ();
|
||||
resolver->Add (name, createResolver, TraceRoot::NOTHING);
|
||||
}
|
||||
|
||||
CompositeTraceResolver *
|
||||
TraceRoot::GetComposite (void)
|
||||
{
|
||||
static CompositeTraceResolver resolver = CompositeTraceResolver (TraceContext ());
|
||||
return &resolver;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -0,0 +1,338 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef TRACE_ROOT_H
|
||||
#define TRACE_ROOT_H
|
||||
|
||||
#include <string>
|
||||
#include "ns3/callback.h"
|
||||
|
||||
/**
|
||||
* \defgroup lowleveltracing Low-level tracing
|
||||
*
|
||||
* This low-level API is built around a few concepts:
|
||||
* - There can be any number of trace source objects. Each trace source
|
||||
* object can generate any number of trace events. The current
|
||||
* trace source objects are: ns3::CallbackTraceSourceSource, ns3::UVTraceSource,
|
||||
* ns3::SVTraceSource, and, ns3::FVTraceSource.
|
||||
* - Each trace source can be connected to any number of trace sinks.
|
||||
* A trace sink is a ns3::Callback with a very special signature. Its
|
||||
* first argument is always a ns3::TraceContext.
|
||||
* - Every trace source is uniquely identified by a ns3::TraceContext. Every
|
||||
* trace sink can query a ns3::TraceContext for information. This allows
|
||||
* a trace sink which is connected to multiple trace sources to identify
|
||||
* from which source each event is coming from.
|
||||
*
|
||||
* To define new trace sources, a model author needs to instante one trace source
|
||||
* object for each kind of tracing event he wants to export. The trace source objects
|
||||
* currently defined are:
|
||||
* - ns3::CallbackTraceSourceSource: this trace source can be used to convey any kind of
|
||||
* trace event to the user. It is a functor, that is, it is a variable
|
||||
* which behaves like a function which will forward every event to every
|
||||
* connected trace sink (i.e., ns3::Callback). This trace source takes
|
||||
* up to four arguments and forwards these 4 arguments together with the
|
||||
* ns3::TraceContext which identifies this trace source to the connected
|
||||
* trace sinks.
|
||||
* - ns3::UVTraceSource: this trace source is used to convey key state variable
|
||||
* changes to the user. It behaves like a normal integer unsigned variable:
|
||||
* you can apply every normal arithmetic operator to it. It will forward
|
||||
* every change in the value of the variable back to every connected trace
|
||||
* sink by providing a TraceContext, the old value and the new value.
|
||||
* - ns3::SVTraceSource: this is the signed integer equivalent of
|
||||
* ns3::UVTraceSource.
|
||||
* - ns3::FVTraceSource: this is the floating point equivalent of
|
||||
* ns3::UVTraceSource and ns3::SVTraceSource.
|
||||
*
|
||||
* For example, to define a trace source which notifies you of a new packet
|
||||
* being transmitted, you would have to:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void Tx (Packet const &p);
|
||||
* private:
|
||||
* CallbackTraceSource<Packet const &> m_txTrace;
|
||||
* };
|
||||
*
|
||||
* void
|
||||
* MyModel::Tx (Packet const &p)
|
||||
* {
|
||||
* // trace packet tx event.
|
||||
* m_txTrace (p);
|
||||
* // ... send the packet for real.
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Once the model author has instantiated these objects and has wired them
|
||||
* in his simulation code (that is, he calls them wherever he wants to trigger
|
||||
* a trace event), he needs to make these trace sources available to users
|
||||
* to allow them to connect any number of trace sources to any number
|
||||
* of user trace sinks. While it would be possible to make each model
|
||||
* export directly each of his trace source instances and request users to
|
||||
* invoke a source->Connect (callback) method to perform the connection
|
||||
* explicitely, it was felt that this was a bit cumbersome to do.
|
||||
*
|
||||
* As such, the ``connection'' between a set of sources and a sink is
|
||||
* performed through a third-party class, the TraceResolver, which
|
||||
* can be used to automate the connection of multiple matching trace sources
|
||||
* to a single sink. This TraceResolver works by defining a hierarchical
|
||||
* tracing namespace: the root of this namespace is accessed through the
|
||||
* ns3::TraceRoot class. The namespace is represented as a string made of
|
||||
* multiple elements, each of which is separated from the other elements
|
||||
* by the '/' character. A namespace string always starts with a '/'.
|
||||
*
|
||||
* By default, the current simulation models provide a '/nodes' tracing root.
|
||||
* This '/nodes' namespace is structured as follows:
|
||||
* \code
|
||||
* /nodes/n/arp
|
||||
* /nodes/n/udp
|
||||
* /nodes/n/ipv4
|
||||
* /tx
|
||||
* /rx
|
||||
* /drop
|
||||
* /interfaces/n/netdevice
|
||||
* /queue/
|
||||
* /enque
|
||||
* /deque
|
||||
* /drop
|
||||
* \endcode
|
||||
*
|
||||
* The 'n' element which follows the /nodes and /interfaces namespace elements
|
||||
* identify a specific node and interface through their index within the
|
||||
* ns3::NodeList and ns3::Ipv4 objects respectively.
|
||||
*
|
||||
* To connect a trace sink to a trace source identified by a namespace string,
|
||||
* a user can call the ns3::TraceRoot::Connect method (the ns3::TraceRoot::Disconnect
|
||||
* method does the symmetric operation). This connection method can accept
|
||||
* fully-detailed namespace strings but it can also perform pattern matching
|
||||
* on the user-provided namespace strings to connect multiple trace sources
|
||||
* to a single trace sink in a single connection operation.
|
||||
*
|
||||
* The syntax of the pattern matching rules are loosely based on regular
|
||||
* expressions:
|
||||
* - the '*' character matches every element
|
||||
* - the (a|b) construct matches element 'a' or 'b'
|
||||
* - the [ss-ee] construct matches all numerical values which belong
|
||||
* to the interval which includes ss and ee
|
||||
*
|
||||
* For example, the user could use the following to connect a single sink
|
||||
* to the ipv4 tx, rx, and drop trace events:
|
||||
*
|
||||
* \code
|
||||
* void MyTraceSink (TraceContext const &context, Packet &packet);
|
||||
* TraceRoot::Connect ("/nodes/ * /ipv4/ *", MakeCallback (&MyTraceSink));
|
||||
* \endcode
|
||||
*
|
||||
* Of course, this code would work only if the signature of the trace sink
|
||||
* is exactly equal to the signature of all the trace sources which match
|
||||
* the namespace string (if one of the matching trace source does not match
|
||||
* exactly, a fatal error will be triggered at runtime during the connection
|
||||
* process). The ns3::TraceContext extra argument contains
|
||||
* information on where the trace source is located in the namespace tree.
|
||||
* In that example, if there are multiple nodes in this scenario, each
|
||||
* call to the MyTraceSink function would receive a different TraceContext,
|
||||
* each of which would contain a different NodeList::Index object.
|
||||
*
|
||||
* It is important to understand exactly what an ns3::TraceContext
|
||||
* is. It is a container for a number of type instances. Each instance of
|
||||
* a ns3::TraceContext contains one and only one instance of a given type.
|
||||
* ns3::TraceContext::Add can be called to add a type instance into a
|
||||
* TraceContext instance and ns3::TraceContext::Get can be called to get
|
||||
* a copy of a type instance stored into the ns3::TraceContext. If ::Get
|
||||
* cannot retrieve the requested type, a fatal error is triggered at
|
||||
* runtime. The values stored into an ns3::TraceContext attached to a
|
||||
* trace source are automatically determined during the namespace
|
||||
* resolution process. To retrieve a value from a ns3::TraceContext, the
|
||||
* code can be as simple as this:
|
||||
* \code
|
||||
* void MyTraceSink (TraceContext const &context, Packet &packet)
|
||||
* {
|
||||
* NodeList::Index index;
|
||||
* context.Get (index);
|
||||
* std::cout << "node id=" << NodeList::GetNode (index)->GetId () << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* The hierarchical global namespace described here is not implemented
|
||||
* in a single central location: it was felt that doing this would make
|
||||
* it too hard to introduce user-specific models which could hook
|
||||
* automatically into the overal tracing system. If the tracing
|
||||
* namespace was implemented in a single central location, every model
|
||||
* author would have had to modify this central component to make
|
||||
* his own model available to trace users.
|
||||
*
|
||||
* Instead, the handling of the namespace is distributed across every relevant
|
||||
* model: every model implements only the part of the namespace it is
|
||||
* really responsible for. To do this, every model is expected
|
||||
* to provide an instance of a TraceResolver whose
|
||||
* responsability is to recursively provide access to the trace sources
|
||||
* defined in its model. Each TraceResolver instance should be a subclass
|
||||
* of the TraceResolver base class which implements either the DoLookup
|
||||
* or the DoConnect and DoDisconnect methods. Because implementing these
|
||||
* methods can be a bit tedious, our tracing framework provides a number
|
||||
* of helper template classes which should save the model author from
|
||||
* having to implement his own in most cases:
|
||||
* - ns3::CompositeTraceResolver: this subclass of ns3::TraceResolver can
|
||||
* be used to aggregate together multiple trace sources and multiple other
|
||||
* ns3::TraceResolver instances.
|
||||
* - ns3::ArrayTraceResolver: this subclass of ns3::TraceResolver can be
|
||||
* used to match any number of elements within an array where every element
|
||||
* is identified by its index.
|
||||
*
|
||||
* Once you can instantiate your own ns3::TraceResolver object instance, you
|
||||
* have to hook it up into the global namespace. There are two ways to do this:
|
||||
* - you can hook your ns3::TraceResolver creation method as a new trace
|
||||
* root by using the ns3::TraceRoot::Register method
|
||||
* - you can hook your new ns3::TraceResolver creation method into the
|
||||
* container of your model. This step will obvsiouly depend on which model
|
||||
* contains your own model but, if you wrote a new l3 protocol, all you
|
||||
* would have to do to hook into your container L3Demux class is to implement
|
||||
* the pure virtual method inherited from the L3Protocol class whose name is
|
||||
* ns3::L3protocol::CreateTraceResolver.
|
||||
*
|
||||
* So, in most cases, exporting a model's trace sources is a matter of
|
||||
* implementing a method CreateTraceResolver as shown below:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* enum TraceType {
|
||||
* TX,
|
||||
* RX,
|
||||
* ...
|
||||
* };
|
||||
* TraceResolver *CreateTraceResolver (TraceContext const &context);
|
||||
* void Tx (Packet const &p);
|
||||
* private:
|
||||
* CallbackTraceSource<Packet const &> m_txTrace;
|
||||
* };
|
||||
*
|
||||
* TraceResolver *
|
||||
* MyModel::CreateTraceResolver (TraceContext const &context)
|
||||
* {
|
||||
* CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
|
||||
* resolver->Add ("tx", m_txTrace, MyModel::TX);
|
||||
* return resolver;
|
||||
* }
|
||||
* void
|
||||
* MyModel::Tx (Packet const &p)
|
||||
* {
|
||||
* m_txTrace (p);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* If you really want to have fun and implement your own ns3::TraceResolver
|
||||
* subclass, you need to understand the basic Connection and Disconnection
|
||||
* algorithm. The code of that algorithm is wholy contained in the
|
||||
* ns3::TraceResolver::Connect and ns3::TraceResolver::Disconnect methods.
|
||||
* The idea is that we recursively parse the input namespace string by removing
|
||||
* the first namespace element. This element is 'resolved' is calling
|
||||
* the ns3::TraceResolver::DoLookup method which returns a list of
|
||||
* TraceResolver instances. Each of the returned TraceResolver instance is
|
||||
* then given what is left of the namespace by calling ns3::TraceResolver::Connect
|
||||
* until the last namespace element is processed. At this point, we invoke
|
||||
* the ns3::TraceResolver::DoConnect or ns3::TraceResolver::DoDisconnect
|
||||
* methods to break the recursion. A good way to understand this algorithm
|
||||
* is to trace its behavior. Let's say that you want to connect to
|
||||
* '/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *'. It would generate
|
||||
* the following call traces:
|
||||
*
|
||||
* \code
|
||||
* TraceRoot::Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
|
||||
* traceContext = TraceContext ();
|
||||
* rootResolver = CompositeTraceResolver (traceContext);
|
||||
* rootResolver->Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
|
||||
* resolver = CompositeTraceResolver::DoLookup ("nodes");
|
||||
* return NodeList::CreateTraceResolver (GetContext ());
|
||||
* return ArrayTraceResolver (context);
|
||||
* resolver->Connect ("/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
|
||||
* ArrayTraceResolver::DoLookup ("*");
|
||||
* for (i = 0; i < n_nodes; i++)
|
||||
* resolver = nodes[i]->CreateTraceResolver (GetContext ());
|
||||
* return CompositeTraceResolver (context);
|
||||
* resolvers.add (resolver);
|
||||
* return resolvers;
|
||||
* for resolver in (resolvers)
|
||||
* resolver->Connect ("/ipv4/interfaces/ * /netdevice/queue/ *", callback);
|
||||
* CompositeTraceResolver::DoLookup ("ipv4");
|
||||
* resolver = ipv4->CreateTraceResolver (GetContext ());
|
||||
* return CompositeTraceResolver (context);
|
||||
* return resolver;
|
||||
* resolver->Connect ("/interfaces/ * /netdevice/queue/ *", callback);
|
||||
* CompositeTraceResolver::DoLookup ("interfaces");
|
||||
* resolver = ArrayTraceResolver (GetContext ());
|
||||
* resolver->Connect ("/ * /netdevice/queue/ *", callback);
|
||||
* ArrayTraceResolver::DoLookup ("*");
|
||||
* for (i = 0; i < n_interfaces; i++)
|
||||
* resolver = interfaces[i]->CreateTraceResolver (GetContext ());
|
||||
* return CompositeTraceResolver ()
|
||||
* resolvers.add (resolver);
|
||||
* return resolvers;
|
||||
* resolver->Connect ("/netdevice/queue/ *", callback);
|
||||
* CompositeTraceResolver::DoLookup ("netdevice");
|
||||
* resolver = NetDevice::CreateTraceResolver (GetContext ());
|
||||
* return CompositeTraceResolver ();
|
||||
* return resolver;
|
||||
* resolver->Connect ("/queue/ *", callback);
|
||||
* CompositeTraceResolver::DoLookup ("queue");
|
||||
* resolver = Queue::CreateTraceResolver (GetContext ());
|
||||
* return CompositeTraceResolver ();
|
||||
* return resolver
|
||||
* resolver->Connect ("*", callback);
|
||||
* CompositeTraceResolver::DoLookup ("*");
|
||||
* for match in (matches)
|
||||
* resolver = TerminalTraceResolver ("match");
|
||||
* resolvers.add (resolver)
|
||||
* return resolvers;
|
||||
* for resolver in (resolvers)
|
||||
* TerminalTraceResolver->DoConnect (callback);
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class CompositeTraceResolver;
|
||||
class TraceResolver;
|
||||
class TraceContext;
|
||||
class CallbackBase;
|
||||
|
||||
/**
|
||||
* \brief The main class used to access tracing functionality for
|
||||
* a user.
|
||||
*
|
||||
* \ingroup lowleveltracing
|
||||
*/
|
||||
class TraceRoot
|
||||
{
|
||||
public:
|
||||
static void Connect (std::string path, CallbackBase const &cb);
|
||||
static void Disconnect (std::string path, CallbackBase const &cb);
|
||||
static void Register (std::string name,
|
||||
Callback<TraceResolver *,TraceContext const &> createResolver);
|
||||
private:
|
||||
static CompositeTraceResolver *GetComposite (void);
|
||||
enum TraceType {
|
||||
NOTHING,
|
||||
};
|
||||
};
|
||||
|
||||
}// namespace ns3
|
||||
|
||||
#endif /* TRACE_ROOT_H */
|
||||
@@ -0,0 +1,29 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "trailer.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
Trailer::~Trailer ()
|
||||
{}
|
||||
|
||||
}; // namespace ns3
|
||||
@@ -0,0 +1,127 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef TRAILER_H
|
||||
#define TRAILER_H
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Protocol trailer serialization and deserialization.
|
||||
*
|
||||
* Every Protocol trailer which needs to be inserted or removed
|
||||
* from a Packet instance must derive from this abstract base class
|
||||
* and implement the private pure virtual methods listed below:
|
||||
* - ns3::Trailer::SerializeTo
|
||||
* - ns3::Trailer::DeserializeFrom
|
||||
* - ns3::Trailer::GetSerializedSize
|
||||
* - ns3::Trailer::PrintTo
|
||||
*
|
||||
* Note that the SerializeTo and DeserializeFrom methods behave
|
||||
* in a way which might seem surprising to users: the input iterator
|
||||
* really points to the end of the buffer to which and from which
|
||||
* the user is expected to write and read respectively. This means that
|
||||
* if the trailer has a fixed size and if the user wishes to read or
|
||||
* write that trailer from front to back, the user must rewind the
|
||||
* iterator by hand to go to the start of the trailer. Typical code
|
||||
* looks like this:
|
||||
* \code
|
||||
* void CrcTrailer::SerializeTo (Buffer::Iterator end)
|
||||
* {
|
||||
* end.Prev (4);
|
||||
* end.WriteHtonU32 (m_crc);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Some users would have expected that the iterator would be rewinded
|
||||
* to the "start" of the trailer before calling SerializeTo and DeserializeFrom.
|
||||
* However, this behavior was not implemented because it cannot be made to
|
||||
* work reliably for trailers which have a variable size. i.e., if the trailer
|
||||
* contains options, the code which calls DeserializeFrom cannot rewind
|
||||
* to the start of the trailer because it does not know the real size of the
|
||||
* trailer. Hence, to make this legitimate use-case work (variable-sized
|
||||
* trailers), the input iterator to DeserializeFrom and SerializeTo points
|
||||
* to the end of the trailer, and not its start.
|
||||
*/
|
||||
class Trailer : public Chunk {
|
||||
public:
|
||||
virtual ~Trailer ();
|
||||
private:
|
||||
/**
|
||||
* \returns a user-readable name to identify this type of header.
|
||||
*
|
||||
* The string returned is expected to be a single word with
|
||||
* all capital letters
|
||||
*/
|
||||
virtual std::string DoGetName (void) const = 0;
|
||||
/**
|
||||
* \param os the std output stream in which this
|
||||
* protocol trailer must print itself.
|
||||
*
|
||||
* Although the header is free to format its output as it
|
||||
* wishes, it is recommended to follow a few rules to integrate
|
||||
* with the packet pretty printer:
|
||||
* - start with flags, small field values located between a
|
||||
* pair of parens. Values should be separated by whitespace.
|
||||
* - follow the parens with the important fields, separated by
|
||||
* whitespace.
|
||||
* i.e.:
|
||||
* (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
|
||||
*/
|
||||
virtual void PrintTo (std::ostream &os) const = 0;
|
||||
|
||||
/**
|
||||
* \returns the size of the serialized Trailer.
|
||||
*
|
||||
* This method is used by Packet::AddTrailer to reserve
|
||||
* enough room in the packet byte buffer prior to calling
|
||||
* Trailer::Serialize.
|
||||
*/
|
||||
virtual uint32_t GetSerializedSize (void) const = 0;
|
||||
|
||||
/**
|
||||
* \param end the buffer iterator in which the protocol trailer
|
||||
* must serialize itself. This iterator identifies
|
||||
* the end of the buffer.
|
||||
*
|
||||
* This iterator must be typically moved with the Buffer::Iterator::Prev
|
||||
* method before writing any byte in the buffer.
|
||||
*/
|
||||
virtual void SerializeTo (Buffer::Iterator end) const = 0;
|
||||
/**
|
||||
* \param end the buffer iterator from which the protocol trailer must
|
||||
* deserialize itself. This iterator identifies
|
||||
* the end of the buffer.
|
||||
* \returns the number of bytes read from the buffer
|
||||
*
|
||||
* This iterator must be typically moved with the Buffer::Iterator::Prev
|
||||
* method before reading any byte in the buffer. The value returned
|
||||
* is used to trim the packet byte buffer of the corresponding
|
||||
* amount when this method is invoked from Packet::RemoveTrailer
|
||||
*/
|
||||
virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* TRAILER_H */
|
||||
@@ -0,0 +1,245 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef UV_TRACE_SOURCE_H
|
||||
#define UV_TRACE_SOURCE_H
|
||||
|
||||
#include "callback-trace-source.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class UVTraceSourceBase {
|
||||
public:
|
||||
typedef CallbackTraceSource<uint64_t, uint64_t> ChangeNotifyCallback;
|
||||
|
||||
UVTraceSourceBase ()
|
||||
: m_callback () {}
|
||||
/* We don't want to copy the base callback. Only setCallback on
|
||||
* a specific instance will do something to it. */
|
||||
UVTraceSourceBase (UVTraceSourceBase const &o)
|
||||
: m_callback () {}
|
||||
UVTraceSourceBase &operator = (UVTraceSourceBase const &o) {
|
||||
return *this;
|
||||
}
|
||||
~UVTraceSourceBase () {}
|
||||
|
||||
void AddCallback (CallbackBase const & callback, TraceContext const & context) {
|
||||
m_callback.AddCallback (callback, context);
|
||||
}
|
||||
void RemoveCallback (CallbackBase const & callback) {
|
||||
m_callback.RemoveCallback (callback);
|
||||
}
|
||||
|
||||
protected:
|
||||
void Notify (uint64_t oldVal, uint64_t newVal) {
|
||||
if (oldVal != newVal)
|
||||
{
|
||||
m_callback (oldVal, newVal);
|
||||
}
|
||||
}
|
||||
private:
|
||||
ChangeNotifyCallback m_callback;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SVTraceSource;
|
||||
|
||||
|
||||
/**
|
||||
* \brief trace variables of type "unsigned integer"
|
||||
* \ingroup lowleveltracing
|
||||
*
|
||||
* This template class implements a POD type: it
|
||||
* behaves like any other variable of type "unsigned integer"
|
||||
* except that it also reports any changes to its
|
||||
* value with its internal callback.
|
||||
*
|
||||
* To instantiate a 32-bit unsigned variable (to store
|
||||
* a TCP counter for example), you would create a variable of type
|
||||
* ns3::UVTraceSource<uint32_t> :
|
||||
\code
|
||||
#include <stdint.h>
|
||||
#include "ns3/uv-trace-source.h"
|
||||
|
||||
ns3::UVTraceSource<uint32_t> var;
|
||||
\endcode
|
||||
* and you would use it like any other variable of type uint32_t:
|
||||
\code
|
||||
var += 12;
|
||||
var = 10;
|
||||
\endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class UVTraceSource : public UVTraceSourceBase {
|
||||
public:
|
||||
UVTraceSource ()
|
||||
: m_var ()
|
||||
{}
|
||||
UVTraceSource (T const &var)
|
||||
: m_var (var)
|
||||
{}
|
||||
|
||||
UVTraceSource &operator = (UVTraceSource const &o) {
|
||||
Assign (o.Get ());
|
||||
return *this;
|
||||
}
|
||||
template <typename TT>
|
||||
UVTraceSource &operator = (UVTraceSource<TT> const &o) {
|
||||
Assign (o.Get ());
|
||||
return *this;
|
||||
}
|
||||
template <typename TT>
|
||||
UVTraceSource &operator = (SVTraceSource<TT> const &o) {
|
||||
Assign (o.Get ());
|
||||
return *this;
|
||||
}
|
||||
UVTraceSource &operator++ () {
|
||||
Assign (Get () + 1);
|
||||
return *this;
|
||||
}
|
||||
UVTraceSource &operator-- () {
|
||||
Assign (Get () - 1);
|
||||
return *this;
|
||||
}
|
||||
UVTraceSource operator++ (int) {
|
||||
UVTraceSource old (*this);
|
||||
++*this;
|
||||
return old;
|
||||
}
|
||||
UVTraceSource operator-- (int) {
|
||||
UVTraceSource old (*this);
|
||||
--*this;
|
||||
return old;
|
||||
}
|
||||
operator T () const {
|
||||
return Get ();
|
||||
}
|
||||
|
||||
|
||||
void Assign (T var) {
|
||||
Notify (m_var, var);
|
||||
m_var = var;
|
||||
}
|
||||
T Get (void) const {
|
||||
return m_var;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_var;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () + rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () - rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () * rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () / rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () << rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () >> rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () & rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () | rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
template <typename T>
|
||||
UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
|
||||
lhs.Assign (lhs.Get () ^ rhs.Get ());
|
||||
return lhs;
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () + rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () - rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () * rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () / rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () << rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () >> rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () & rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () | rhs);
|
||||
return lhs;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, U const &rhs) {
|
||||
lhs.Assign (lhs.Get () ^ rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* UV_TRACE_SOURCE_H */
|
||||
@@ -0,0 +1,272 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "uv-trace-source.h"
|
||||
#include "sv-trace-source.h"
|
||||
#include "trace-context.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/callback.h"
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
void Notify (TraceContext const &contex, uint64_t oldVal, uint64_t newVal) {}
|
||||
};
|
||||
|
||||
class VariableTracerTest: public Test {
|
||||
public:
|
||||
VariableTracerTest ();
|
||||
void RunUnsignedTests (void);
|
||||
void RunSignedUnsignedTests (void);
|
||||
virtual bool RunTests (void);
|
||||
};
|
||||
void
|
||||
VariableTracerTest::RunUnsignedTests (void)
|
||||
{
|
||||
UVTraceSource<uint32_t> var, ovar, tmp;
|
||||
uint32_t utmp;
|
||||
Foo *foo = new Foo ();
|
||||
|
||||
var.AddCallback (MakeCallback (&Foo::Notify, foo), TraceContext ());
|
||||
|
||||
var = 10;
|
||||
ovar = var;
|
||||
|
||||
if (var == ovar)
|
||||
{
|
||||
}
|
||||
if (var != ovar)
|
||||
{
|
||||
}
|
||||
if (var > ovar)
|
||||
{
|
||||
}
|
||||
if (var >= ovar)
|
||||
{
|
||||
}
|
||||
if (var < ovar)
|
||||
{
|
||||
}
|
||||
|
||||
if (var <= ovar)
|
||||
|
||||
if (var == 1)
|
||||
{
|
||||
}
|
||||
if (var != 1)
|
||||
{
|
||||
}
|
||||
if (var > 1)
|
||||
{
|
||||
}
|
||||
if (var >= 1)
|
||||
{
|
||||
}
|
||||
if (var < 1)
|
||||
{
|
||||
}
|
||||
if (var <= 1)
|
||||
{
|
||||
}
|
||||
|
||||
if (1 == ovar)
|
||||
{
|
||||
}
|
||||
if (1 != ovar)
|
||||
{
|
||||
}
|
||||
if (1 > ovar)
|
||||
{
|
||||
}
|
||||
if (1 >= ovar)
|
||||
{
|
||||
}
|
||||
if (1 < ovar)
|
||||
{
|
||||
}
|
||||
if (1 <= ovar)
|
||||
{
|
||||
}
|
||||
|
||||
var++;
|
||||
++var;
|
||||
var--;
|
||||
--var;
|
||||
|
||||
tmp = var + ovar;
|
||||
tmp = var - ovar;
|
||||
tmp = var / ovar;
|
||||
tmp = var * ovar;
|
||||
tmp = var << ovar;
|
||||
tmp = var >> ovar;
|
||||
tmp = var & ovar;
|
||||
tmp = var | ovar;
|
||||
tmp = var ^ ovar;
|
||||
|
||||
tmp = var + 1;
|
||||
tmp = var - 1;
|
||||
tmp = var / 1;
|
||||
tmp = var * 1;
|
||||
tmp = var << 1;
|
||||
tmp = var >> 1;
|
||||
tmp = var & 1;
|
||||
tmp = var | 1;
|
||||
tmp = var ^ 1;
|
||||
|
||||
tmp = 1 + ovar;
|
||||
tmp = 1 - ovar;
|
||||
tmp = 1 / ovar;
|
||||
tmp = 1 * ovar;
|
||||
tmp = 1 << ovar;
|
||||
tmp = 1 >> ovar;
|
||||
tmp = 1 & ovar;
|
||||
tmp = 1 | ovar;
|
||||
tmp = 1 ^ ovar;
|
||||
|
||||
tmp += var;
|
||||
tmp -= var;
|
||||
tmp /= var;
|
||||
tmp *= var;
|
||||
tmp <<= var;
|
||||
tmp >>= var;
|
||||
tmp &= var;
|
||||
tmp |= var;
|
||||
tmp ^= var;
|
||||
|
||||
tmp += 1;
|
||||
tmp -= 1;
|
||||
tmp /= 1;
|
||||
tmp *= 1;
|
||||
tmp <<= 1;
|
||||
tmp >>= 1;
|
||||
tmp &= 1;
|
||||
tmp |= 1;
|
||||
tmp ^= 1;
|
||||
|
||||
|
||||
utmp = var + ovar;
|
||||
utmp = var - ovar;
|
||||
utmp = var / ovar;
|
||||
utmp = var * ovar;
|
||||
utmp = var << ovar;
|
||||
utmp = var >> ovar;
|
||||
utmp = var & ovar;
|
||||
utmp = var | ovar;
|
||||
utmp = var ^ ovar;
|
||||
|
||||
utmp = var + 1;
|
||||
utmp = var - 1;
|
||||
utmp = var / 1;
|
||||
utmp = var * 1;
|
||||
utmp = var << 1;
|
||||
utmp = var >> 1;
|
||||
utmp = var & 1;
|
||||
utmp = var | 1;
|
||||
utmp = var ^ 1;
|
||||
|
||||
utmp = 1 + ovar;
|
||||
utmp = 1 - ovar;
|
||||
utmp = 1 / ovar;
|
||||
utmp = 1 * ovar;
|
||||
utmp = 1 << ovar;
|
||||
utmp = 1 >> ovar;
|
||||
utmp = 1 & ovar;
|
||||
utmp = 1 | ovar;
|
||||
utmp = 1 ^ ovar;
|
||||
|
||||
utmp += var;
|
||||
utmp -= var;
|
||||
utmp /= var;
|
||||
utmp *= var;
|
||||
utmp <<= var;
|
||||
utmp >>= var;
|
||||
utmp &= var;
|
||||
utmp |= var;
|
||||
utmp ^= var;
|
||||
|
||||
utmp += 1;
|
||||
utmp -= 1;
|
||||
utmp /= 1;
|
||||
utmp *= 1;
|
||||
utmp <<= 1;
|
||||
utmp >>= 1;
|
||||
utmp &= 1;
|
||||
utmp |= 1;
|
||||
utmp ^= 1;
|
||||
|
||||
delete foo;
|
||||
}
|
||||
|
||||
void
|
||||
VariableTracerTest::RunSignedUnsignedTests (void)
|
||||
{
|
||||
unsigned short utmp = 10;
|
||||
unsigned int uitmp = 7;
|
||||
short stmp = 5;
|
||||
utmp = stmp;
|
||||
utmp += stmp;
|
||||
uitmp = utmp;
|
||||
utmp = uitmp;
|
||||
|
||||
UVTraceSource<unsigned short> uvar = 10;
|
||||
UVTraceSource<unsigned int> uivar = 5;
|
||||
SVTraceSource<short> svar = 5;
|
||||
SVTraceSource<int> sivar = 5;
|
||||
uvar = svar;
|
||||
svar = uvar;
|
||||
uvar += svar;
|
||||
svar += uvar;
|
||||
|
||||
uvar = sivar;
|
||||
sivar = uvar;
|
||||
uvar += sivar;
|
||||
sivar += uvar;
|
||||
|
||||
uivar = uvar;
|
||||
uvar = uivar;
|
||||
uivar += uvar;
|
||||
uvar += uivar;
|
||||
|
||||
sivar = svar;
|
||||
svar = sivar;
|
||||
sivar += svar;
|
||||
svar += sivar;
|
||||
}
|
||||
|
||||
bool
|
||||
VariableTracerTest::RunTests (void)
|
||||
{
|
||||
RunUnsignedTests ();
|
||||
RunSignedUnsignedTests ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
VariableTracerTest::VariableTracerTest ()
|
||||
: Test ("VariableTracer") {}
|
||||
|
||||
static VariableTracerTest gVariableTracerTest;
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
common = bld.create_obj('cpp', 'shlib')
|
||||
common.name = 'ns3-common'
|
||||
common.target = common.name
|
||||
common.uselib_local = ['ns3-core', 'ns3-simulator']
|
||||
common.source = [
|
||||
'buffer.cc',
|
||||
'chunk.cc',
|
||||
'header.cc',
|
||||
'trailer.cc',
|
||||
'packet-printer.cc',
|
||||
'packet-metadata.cc',
|
||||
'packet.cc',
|
||||
'tags.cc',
|
||||
'pcap-writer.cc',
|
||||
'variable-tracer-test.cc',
|
||||
'trace-context.cc',
|
||||
'trace-resolver.cc',
|
||||
'callback-trace-source.cc',
|
||||
'empty-trace-resolver.cc',
|
||||
'composite-trace-resolver.cc',
|
||||
'trace-root.cc',
|
||||
'data-rate.cc',
|
||||
]
|
||||
headers = bld.create_obj('ns3header')
|
||||
headers.source = [
|
||||
'buffer.h',
|
||||
'chunk.h',
|
||||
'header.h',
|
||||
'trailer.h',
|
||||
'tags.h',
|
||||
'packet.h',
|
||||
'packet-printer.h',
|
||||
'packet-metadata.h',
|
||||
'uv-trace-source.h',
|
||||
'sv-trace-source.h',
|
||||
'fv-trace-source.h',
|
||||
'pcap-writer.h',
|
||||
'callback-trace-source.h',
|
||||
'trace-context.h',
|
||||
'trace-resolver.h',
|
||||
'empty-trace-resolver.h',
|
||||
'composite-trace-resolver.h',
|
||||
'array-trace-resolver.h',
|
||||
'trace-root.h',
|
||||
'terminal-trace-resolver.h',
|
||||
'data-rate.h',
|
||||
]
|
||||
@@ -0,0 +1,41 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
void
|
||||
AssertBreakpoint (void)
|
||||
{
|
||||
int *a = 0;
|
||||
/**
|
||||
* we test here to allow a debugger to change the value of
|
||||
* the variable 'a' to allow the debugger to avoid the
|
||||
* subsequent segfault.
|
||||
*/
|
||||
if (a == 0)
|
||||
{
|
||||
*a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
@@ -0,0 +1,104 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef ASSERT_H
|
||||
#define ASSERT_H
|
||||
|
||||
/**
|
||||
* \defgroup assert Assert
|
||||
* \brief assert functions and macros
|
||||
*
|
||||
* The assert macros are used to verify
|
||||
* at runtime that a certain condition is true. If it is
|
||||
* not true, the program halts. These checks are built
|
||||
* into the program only in debugging builds. They are
|
||||
* removed in optimized builds.
|
||||
*/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup debugging
|
||||
*
|
||||
* When an NS_ASSERT cannot verify its condition,
|
||||
* this function is called. This is where you should
|
||||
* be able to put a breakpoint with a debugger if
|
||||
* you want to catch assertions before the program
|
||||
* halts.
|
||||
*/
|
||||
void AssertBreakpoint (void);
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#ifdef NS3_ASSERT_ENABLE
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* \ingroup assert
|
||||
* \param condition condition to verifiy.
|
||||
*
|
||||
* At runtime, in debugging builds, if this condition is not
|
||||
* true, the program prints the source file, line number and
|
||||
* unverified condition and halts in the ns3::AssertBreakpoint
|
||||
* function.
|
||||
*/
|
||||
#define NS_ASSERT(condition) \
|
||||
do \
|
||||
{ \
|
||||
if (!(condition)) \
|
||||
{ \
|
||||
std::cout << "assert failed. file=" << __FILE__ << \
|
||||
", line=" << __LINE__ << ", cond=\""#condition << \
|
||||
"\"" << std::endl; \
|
||||
ns3::AssertBreakpoint (); \
|
||||
} \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup assert
|
||||
* \param condition condition to verifiy.
|
||||
* \param message message to output
|
||||
*
|
||||
* At runtime, in debugging builds, if this condition is not
|
||||
* true, the program prints the message to output and
|
||||
* halts in the ns3::AssertBreakpoint function.
|
||||
*/
|
||||
#define NS_ASSERT_MSG(condition, message) \
|
||||
do \
|
||||
{ \
|
||||
if (!(condition)) \
|
||||
{ \
|
||||
std::cout << message << std::endl; \
|
||||
ns3::AssertBreakpoint (); \
|
||||
} \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
#else /* NS3_ASSERT_ENABLE */
|
||||
|
||||
#define NS_ASSERT(cond)
|
||||
#define NS_ASSERT_MSG(cond,msg)
|
||||
|
||||
#endif /* NS3_ASSERT_ENABLE */
|
||||
|
||||
#endif /* ASSERT_H */
|
||||
@@ -0,0 +1,226 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "callback.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
static bool gTest5 = false;
|
||||
static bool gTest6 = false;
|
||||
static bool gTest7 = false;
|
||||
|
||||
void Test5 (void)
|
||||
{
|
||||
gTest5 = true;
|
||||
}
|
||||
|
||||
void Test6 (int)
|
||||
{
|
||||
gTest6 = true;
|
||||
}
|
||||
|
||||
int Test7 (int a)
|
||||
{
|
||||
gTest7 = true;
|
||||
return a;
|
||||
}
|
||||
|
||||
void *Test9 (bool *a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
void *Test10 (bool *a, int const & b)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
class CallbackTest : public ns3::Test {
|
||||
private:
|
||||
bool m_test1;
|
||||
bool m_test2;
|
||||
bool m_test3;
|
||||
bool m_test4;
|
||||
public:
|
||||
CallbackTest ();
|
||||
virtual bool RunTests (void);
|
||||
void Reset (void);
|
||||
bool IsWrong (void);
|
||||
void Test1 (void);
|
||||
int Test2 (void);
|
||||
void Test3 (double a);
|
||||
int Test4 (double a, int b);
|
||||
void Test8 (Callback<void, int> callback);
|
||||
};
|
||||
|
||||
CallbackTest::CallbackTest ()
|
||||
: ns3::Test ("Callback"),
|
||||
m_test1 (false),
|
||||
m_test2 (false),
|
||||
m_test3 (false),
|
||||
m_test4 (false)
|
||||
{}
|
||||
|
||||
void
|
||||
CallbackTest::Test1 (void)
|
||||
{
|
||||
m_test1 = true;
|
||||
}
|
||||
int
|
||||
CallbackTest::Test2 (void)
|
||||
{
|
||||
m_test2 = true;
|
||||
return 2;
|
||||
}
|
||||
void
|
||||
CallbackTest::Test3 (double a)
|
||||
{
|
||||
m_test3 = true;
|
||||
}
|
||||
int
|
||||
CallbackTest::Test4 (double a, int b)
|
||||
{
|
||||
m_test4 = true;
|
||||
return 4;
|
||||
}
|
||||
void
|
||||
CallbackTest::Test8 (Callback<void,int> callback)
|
||||
{
|
||||
callback (3);
|
||||
}
|
||||
bool
|
||||
CallbackTest::IsWrong (void)
|
||||
{
|
||||
if (!m_test1 ||
|
||||
!m_test2 ||
|
||||
!m_test3 ||
|
||||
!m_test4 ||
|
||||
!gTest5 ||
|
||||
!gTest6 ||
|
||||
!gTest7)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CallbackTest::Reset (void)
|
||||
{
|
||||
m_test1 = false;
|
||||
m_test2 = false;
|
||||
m_test3 = false;
|
||||
m_test4 = false;
|
||||
gTest5 = false;
|
||||
gTest6 = false;
|
||||
gTest7 = false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CallbackTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
typedef ns3::Callback<void> A;
|
||||
typedef ns3::Callback<int> B;
|
||||
typedef ns3::Callback<void, double> C;
|
||||
typedef ns3::Callback<int, double, int> D;
|
||||
typedef ns3::Callback<void> E;
|
||||
typedef ns3::Callback<void,int> F;
|
||||
typedef ns3::Callback<int,int> G;
|
||||
|
||||
A a0 (this, &CallbackTest::Test1);
|
||||
B b0;
|
||||
b0 = B (this, &CallbackTest::Test2);
|
||||
C c0 = C (this, &CallbackTest::Test3);
|
||||
D d0 = D (this, &CallbackTest::Test4);
|
||||
E e0 = E (&Test5, true, true);
|
||||
F f0 = F (&Test6, true, true);
|
||||
G g0 = G (&Test7, true, true);
|
||||
|
||||
a0 ();
|
||||
b0 ();
|
||||
c0 (0.0);
|
||||
d0 (0.0, 1);
|
||||
e0 ();
|
||||
f0 (1);
|
||||
g0 (1);
|
||||
|
||||
if (IsWrong ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
Reset ();
|
||||
|
||||
A a1 = ns3::MakeCallback (&CallbackTest::Test1, this);
|
||||
B b1 = ns3::MakeCallback (&CallbackTest::Test2, this);
|
||||
C c1 = ns3::MakeCallback (&CallbackTest::Test3, this);
|
||||
D d1 = ns3::MakeCallback (&CallbackTest::Test4, this);
|
||||
E e1 = ns3::MakeCallback (&Test5);
|
||||
F f1 = ns3::MakeCallback (&Test6);
|
||||
G g1 = ns3::MakeCallback (&Test7);
|
||||
|
||||
a1 ();
|
||||
b1 ();
|
||||
c1 (0.0);
|
||||
d1 (0.0, 1);
|
||||
e1 ();
|
||||
f1 (1);
|
||||
g1 (2);
|
||||
|
||||
a1.Nullify ();
|
||||
b1.Nullify ();
|
||||
c1.Nullify ();
|
||||
d1.Nullify ();
|
||||
e1.Nullify ();
|
||||
g1.Nullify ();
|
||||
|
||||
Test8 (f1);
|
||||
|
||||
f1.Nullify ();
|
||||
|
||||
Callback<void, int64_t,int64_t> a2;
|
||||
|
||||
if (IsWrong ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
|
||||
MakeBoundCallback (&Test7, 0);
|
||||
bool v;
|
||||
MakeBoundCallback (&Test9, &v);
|
||||
MakeBoundCallback (&Test10, &v);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static CallbackTest gCallbackTest;
|
||||
|
||||
}; // namespace
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -0,0 +1,678 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef CALLBACK_H
|
||||
#define CALLBACK_H
|
||||
|
||||
#include "ptr.h"
|
||||
#include "fatal-error.h"
|
||||
#include "empty.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/***
|
||||
* \internal
|
||||
* This code was originally written based on the techniques
|
||||
* described in http://www.codeproject.com/cpp/TTLFunction.asp
|
||||
* It was subsequently rewritten to follow the architecture
|
||||
* outlined in "Modern C++ Design" by Andrei Alexandrescu in
|
||||
* chapter 5, "Generalized Functors".
|
||||
*
|
||||
* This code uses:
|
||||
* - default template parameters to saves users from having to
|
||||
* specify empty parameters when the number of parameters
|
||||
* is smaller than the maximum supported number
|
||||
* - the pimpl idiom: the Callback class is passed around by
|
||||
* value and delegates the crux of the work to its pimpl
|
||||
* pointer.
|
||||
* - 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.
|
||||
* - a reference list implementation to implement the Callback's
|
||||
* value semantics.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
template <typename T>
|
||||
struct CallbackTraits;
|
||||
|
||||
template <typename T>
|
||||
struct CallbackTraits<T *>
|
||||
{
|
||||
static T & GetReference (T * const p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
};
|
||||
|
||||
class CallbackImplBase {
|
||||
public:
|
||||
CallbackImplBase ()
|
||||
: m_count (1) {}
|
||||
virtual ~CallbackImplBase () {}
|
||||
void Ref (void) {
|
||||
m_count++;
|
||||
}
|
||||
void Unref (void) {
|
||||
m_count--;
|
||||
if (m_count == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const = 0;
|
||||
private:
|
||||
uint32_t m_count;
|
||||
};
|
||||
|
||||
// declare the CallbackImpl class
|
||||
template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
class CallbackImpl;
|
||||
// define CallbackImpl for 0 params
|
||||
template <typename R>
|
||||
class CallbackImpl<R,empty,empty,empty,empty,empty> : public CallbackImplBase {
|
||||
public:
|
||||
virtual ~CallbackImpl () {}
|
||||
virtual R operator() (void) = 0;
|
||||
};
|
||||
// define CallbackImpl for 1 params
|
||||
template <typename R, typename T1>
|
||||
class CallbackImpl<R,T1,empty,empty,empty,empty> : public CallbackImplBase {
|
||||
public:
|
||||
virtual ~CallbackImpl () {}
|
||||
virtual R operator() (T1) = 0;
|
||||
};
|
||||
// define CallbackImpl for 2 params
|
||||
template <typename R, typename T1, typename T2>
|
||||
class CallbackImpl<R,T1,T2,empty,empty,empty> : public CallbackImplBase {
|
||||
public:
|
||||
virtual ~CallbackImpl () {}
|
||||
virtual R operator() (T1, T2) = 0;
|
||||
};
|
||||
// define CallbackImpl for 3 params
|
||||
template <typename R, typename T1, typename T2, typename T3>
|
||||
class CallbackImpl<R,T1,T2,T3,empty,empty> : public CallbackImplBase {
|
||||
public:
|
||||
virtual ~CallbackImpl () {}
|
||||
virtual R operator() (T1, T2, T3) = 0;
|
||||
};
|
||||
// define CallbackImpl for 4 params
|
||||
template <typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
class CallbackImpl<R,T1,T2,T3,T4,empty> : public CallbackImplBase {
|
||||
public:
|
||||
virtual ~CallbackImpl () {}
|
||||
virtual R operator() (T1, T2, T3, T4) = 0;
|
||||
};
|
||||
// define CallbackImpl for 5 params
|
||||
template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
class CallbackImpl : public CallbackImplBase {
|
||||
public:
|
||||
virtual ~CallbackImpl () {}
|
||||
virtual R operator() (T1, T2, T3, T4, T5) = 0;
|
||||
};
|
||||
|
||||
|
||||
// an impl for Functors:
|
||||
template <typename T, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
|
||||
public:
|
||||
FunctorCallbackImpl (T const &functor)
|
||||
: m_functor (functor) {}
|
||||
virtual ~FunctorCallbackImpl () {}
|
||||
R operator() (void) {
|
||||
return m_functor ();
|
||||
}
|
||||
R operator() (T1 a1) {
|
||||
return m_functor (a1);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2) {
|
||||
return m_functor (a1,a2);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3) {
|
||||
return m_functor (a1,a2,a3);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4) {
|
||||
return m_functor (a1,a2,a3,a4);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
|
||||
return m_functor (a1,a2,a3,a4,a5);
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const {
|
||||
FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *otherDerived =
|
||||
dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *> (other);
|
||||
if (otherDerived == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (otherDerived->m_functor != m_functor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
T m_functor;
|
||||
};
|
||||
|
||||
// an impl for pointer to member functions
|
||||
template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
|
||||
public:
|
||||
MemPtrCallbackImpl (OBJ_PTR const&objPtr, MEM_PTR mem_ptr)
|
||||
: m_objPtr (objPtr), m_memPtr (mem_ptr) {}
|
||||
virtual ~MemPtrCallbackImpl () {}
|
||||
R operator() (void) {
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) ();
|
||||
}
|
||||
R operator() (T1 a1) {
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2) {
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3) {
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4) {
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5);
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const {
|
||||
MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *otherDerived =
|
||||
dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *> (other);
|
||||
if (otherDerived == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (otherDerived->m_objPtr != m_objPtr ||
|
||||
otherDerived->m_memPtr != m_memPtr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
OBJ_PTR const m_objPtr;
|
||||
MEM_PTR m_memPtr;
|
||||
};
|
||||
|
||||
class CallbackBase {
|
||||
public:
|
||||
virtual ~CallbackBase () {}
|
||||
virtual CallbackImplBase *PeekImpl (void) const = 0;
|
||||
virtual Ptr<CallbackImplBase> GetImpl (void) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Callback template class
|
||||
*
|
||||
* This class template implements the Functor Design Pattern.
|
||||
* It is used to declare the type of a Callback:
|
||||
* - the first non-optional template argument represents
|
||||
* the return type of the callback.
|
||||
* - the second optional template argument represents
|
||||
* the type of the first argument to the callback.
|
||||
* - the third optional template argument represents
|
||||
* the type of the second argument to the callback.
|
||||
* - the fourth optional template argument represents
|
||||
* the type of the third argument to the callback.
|
||||
* - the fifth optional template argument represents
|
||||
* the type of the fourth argument to the callback.
|
||||
* - the sixth optional template argument represents
|
||||
* the type of the fifth argument to the callback.
|
||||
*
|
||||
* Callback instances are built with the \ref MakeCallback
|
||||
* template functions. Callback instances have POD semantics:
|
||||
* the memory they allocate is managed automatically, without
|
||||
* user intervention which allows you to pass around Callback
|
||||
* instances by value.
|
||||
*
|
||||
* Sample code which shows how to use this class template
|
||||
* as well as the function templates \ref MakeCallback :
|
||||
* \include samples/main-callback.cc
|
||||
*/
|
||||
|
||||
template<typename R,
|
||||
typename T1 = empty, typename T2 = empty,
|
||||
typename T3 = empty, typename T4 = empty,
|
||||
typename T5 = empty>
|
||||
class Callback : public CallbackBase {
|
||||
public:
|
||||
// There are two dummy args below to ensure that this constructor is
|
||||
// always properly disambiguited by the c++ compiler
|
||||
template <typename FUNCTOR>
|
||||
Callback (FUNCTOR const &functor, bool, bool)
|
||||
: m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5> > (functor))
|
||||
{}
|
||||
|
||||
template <typename OBJ_PTR, typename MEM_PTR>
|
||||
Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr)
|
||||
: m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> > (objPtr, mem_ptr))
|
||||
{}
|
||||
|
||||
Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > const &impl)
|
||||
: m_impl (impl)
|
||||
{}
|
||||
|
||||
bool IsNull (void) const {
|
||||
return (PeekImpl () == 0)?true:false;
|
||||
}
|
||||
void Nullify (void) {
|
||||
m_impl = 0;
|
||||
}
|
||||
|
||||
Callback () : m_impl () {}
|
||||
R operator() (void) const {
|
||||
return (*(PeekImpl ())) ();
|
||||
}
|
||||
R operator() (T1 a1) const {
|
||||
return (*(PeekImpl ())) (a1);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2) const {
|
||||
return (*(PeekImpl ())) (a1,a2);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3) const {
|
||||
return (*(PeekImpl ())) (a1,a2,a3);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3, T4 a4) const {
|
||||
return (*(PeekImpl ())) (a1,a2,a3,a4);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const {
|
||||
return (*(PeekImpl ())) (a1,a2,a3,a4,a5);
|
||||
}
|
||||
|
||||
bool IsEqual (CallbackBase const &other) {
|
||||
return PeekImpl ()->IsEqual (other.PeekImpl ());
|
||||
}
|
||||
|
||||
bool CheckType (CallbackBase const& other) {
|
||||
CallbackImplBase *otherBase = other.PeekImpl ();
|
||||
if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (otherBase) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void Assign (CallbackBase const &other) {
|
||||
if (!CheckType (other))
|
||||
{
|
||||
NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
|
||||
" got=" << typeid (other).name () <<
|
||||
", expected=" << typeid (*this).name ());
|
||||
}
|
||||
const Callback<R, T1,T2,T3,T4,T5> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5> *> (&other);
|
||||
*this = *goodType;
|
||||
}
|
||||
void Assign (Ptr<CallbackImplBase> other) {
|
||||
CallbackImpl<R,T1,T2,T3,T4,T5> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (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> (impl);
|
||||
}
|
||||
virtual Ptr<CallbackImplBase>GetImpl (void) const {
|
||||
return m_impl;
|
||||
}
|
||||
private:
|
||||
virtual CallbackImpl<R,T1,T2,T3,T4,T5> *PeekImpl (void) const {
|
||||
return PeekPointer (m_impl);
|
||||
}
|
||||
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > m_impl;
|
||||
};
|
||||
|
||||
/**
|
||||
* \defgroup MakeCallback MakeCallback
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param mem_ptr class method member pointer
|
||||
* \param objPtr class instance
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for class method members which takes no arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename T, typename OBJ, typename R>
|
||||
Callback<R> MakeCallback (R (T::*memPtr) (void), OBJ objPtr) {
|
||||
return Callback<R> (objPtr, memPtr);
|
||||
}
|
||||
template <typename T, typename OBJ, typename R>
|
||||
Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ const objPtr) {
|
||||
return Callback<R> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param mem_ptr class method member pointer
|
||||
* \param objPtr class instance
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for class method members which takes one argument
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename T, typename OBJ, typename R, typename T1>
|
||||
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ *const objPtr) {
|
||||
return Callback<R,T1> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename T, typename OBJ, typename R, typename T1>
|
||||
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ const *const objPtr) {
|
||||
return Callback<R,T1> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param mem_ptr class method member pointer
|
||||
* \param objPtr class instance
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for class method members which takes two arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param mem_ptr class method member pointer
|
||||
* \param objPtr class instance
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for class method members which takes three arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
|
||||
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
|
||||
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param mem_ptr class method member pointer
|
||||
* \param objPtr class instance
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for class method members which takes four arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param mem_ptr class method member pointer
|
||||
* \param objPtr class instance
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for class method members which takes five arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param fnPtr function pointer
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for functions which takes no arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R>
|
||||
Callback<R> MakeCallback (R (*fnPtr) ()) {
|
||||
return Callback<R> (fnPtr, true, true);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param fnPtr function pointer
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for functions which takes one argument
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1>
|
||||
Callback<R,T1> MakeCallback (R (*fnPtr) (T1)) {
|
||||
return Callback<R,T1> (fnPtr, true, true);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param fnPtr function pointer
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for functions which takes two arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeCallback (R (*fnPtr) (T1,T2)) {
|
||||
return Callback<R,T1,T2> (fnPtr, true, true);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param fnPtr function pointer
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for functions which takes three arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2,typename T3>
|
||||
Callback<R,T1,T2,T3> MakeCallback (R (*fnPtr) (T1,T2,T3)) {
|
||||
return Callback<R,T1,T2,T3> (fnPtr, true, true);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param fnPtr function pointer
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for functions which takes four arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2,typename T3,typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeCallback (R (*fnPtr) (T1,T2,T3,T4)) {
|
||||
return Callback<R,T1,T2,T3,T4> (fnPtr, true, true);
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \param fnPtr function pointer
|
||||
* \return a wrapper Callback
|
||||
* Build Callbacks for functions which takes five arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5)) {
|
||||
return Callback<R,T1,T2,T3,T4,T5> (fnPtr, true, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \return a wrapper Callback
|
||||
* Build a null callback which takes no arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R>
|
||||
Callback<R> MakeNullCallback (void) {
|
||||
return Callback<R> ();
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \overload Callback<R> MakeNullCallback (void)
|
||||
* \return a wrapper Callback
|
||||
* Build a null callback which takes one argument
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1>
|
||||
Callback<R,T1> MakeNullCallback (void) {
|
||||
return Callback<R,T1> ();
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \overload Callback<R> MakeNullCallback (void)
|
||||
* \return a wrapper Callback
|
||||
* Build a null callback which takes two arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeNullCallback (void) {
|
||||
return Callback<R,T1,T2> ();
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \overload Callback<R> MakeNullCallback (void)
|
||||
* \return a wrapper Callback
|
||||
* Build a null callback which takes three arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2,typename T3>
|
||||
Callback<R,T1,T2,T3> MakeNullCallback (void) {
|
||||
return Callback<R,T1,T2,T3> ();
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \overload Callback<R> MakeNullCallback (void)
|
||||
* \return a wrapper Callback
|
||||
* Build a null callback which takes four arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2,typename T3,typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeNullCallback (void) {
|
||||
return Callback<R,T1,T2,T3,T4> ();
|
||||
}
|
||||
/**
|
||||
* \ingroup MakeCallback
|
||||
* \overload Callback<R> MakeNullCallback (void)
|
||||
* \return a wrapper Callback
|
||||
* Build a null callback which takes five arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeNullCallback (void) {
|
||||
return Callback<R,T1,T2,T3,T4,T5> ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The following is experimental code. It works but we have
|
||||
* not yet determined whether or not it is really useful and whether
|
||||
* or not we really want to use it.
|
||||
*/
|
||||
// an impl for Bound Functors:
|
||||
template <typename T, typename R, typename TX, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
class BoundFunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
|
||||
public:
|
||||
BoundFunctorCallbackImpl (T const &functor, TX a)
|
||||
: m_functor (functor), m_a (a) {}
|
||||
virtual ~BoundFunctorCallbackImpl () {}
|
||||
R operator() (void) {
|
||||
return m_functor (m_a);
|
||||
}
|
||||
R operator() (T1 a1) {
|
||||
return m_functor (m_a,a1);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2) {
|
||||
return m_functor (m_a,a1,a2);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3) {
|
||||
return m_functor (m_a,a1,a2,a3);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4) {
|
||||
return m_functor (m_a,a1,a2,a3,a4);
|
||||
}
|
||||
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 {
|
||||
BoundFunctorCallbackImpl<T,R,TX,T1,T2,T3,T4,T5> const *otherDerived =
|
||||
dynamic_cast<BoundFunctorCallbackImpl<T,R,TX,T1,T2,T3,T4,T5> const *> (other);
|
||||
if (otherDerived == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (otherDerived->m_functor != m_functor ||
|
||||
otherDerived->m_a != m_a)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
T m_functor;
|
||||
TX m_a;
|
||||
};
|
||||
|
||||
template <typename R, typename TX>
|
||||
Callback<R> MakeBoundCallback (R (*fnPtr) (TX), TX a) {
|
||||
Ptr<CallbackImpl<R,empty,empty,empty,empty,empty> > impl =
|
||||
Create<BoundFunctorCallbackImpl<R (*) (TX),R,TX,empty,empty,empty,empty,empty> >(fnPtr, a);
|
||||
return Callback<R> (impl);
|
||||
}
|
||||
|
||||
template <typename R, typename TX, typename T1>
|
||||
Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), TX a) {
|
||||
Ptr<CallbackImpl<R,T1,empty,empty,empty,empty> > impl =
|
||||
Create<BoundFunctorCallbackImpl<R (*) (TX,T1),R,TX,T1,empty,empty,empty,empty> > (fnPtr, a);
|
||||
return Callback<R,T1> (impl);
|
||||
}
|
||||
template <typename R, typename TX, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), TX a) {
|
||||
Ptr<CallbackImpl<R,T1,T2,empty,empty,empty> > impl =
|
||||
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2),R,TX,T1,T2,empty,empty,empty> > (fnPtr, a);
|
||||
return Callback<R,T1,T2> (impl);
|
||||
}
|
||||
template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), TX a) {
|
||||
Ptr<CallbackImpl<R,T1,T2,T3,T4,empty> > impl =
|
||||
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4),R,TX,T1,T2,T3,T4,empty> > (fnPtr, a);
|
||||
return Callback<R,T1,T2,T3,T4> (impl);
|
||||
}
|
||||
|
||||
template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), TX a) {
|
||||
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > impl =
|
||||
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4,T5),R,TX,T1,T2,T3,T4,T5> > (fnPtr, a);
|
||||
return Callback<R,T1,T2,T3,T4,T5> (impl);
|
||||
}
|
||||
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#endif /* CALLBACK_H */
|
||||
@@ -0,0 +1,150 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 Georgia Tech University, INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Raj Bhattacharjea <raj.b@gatech.edu>,
|
||||
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "command-line.h"
|
||||
#include <unistd.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
CommandDefaultValue CommandLine::g_help ("help",
|
||||
"Print Help text for all commands",
|
||||
MakeCallback (&CommandLine::PrintHelp));
|
||||
|
||||
void
|
||||
CommandLine::AddArgCommand (const std::string &name,
|
||||
const std::string &help,
|
||||
Callback<void> cb)
|
||||
{
|
||||
DefaultValueBase *base =
|
||||
new CommandDefaultValue (name, help, cb);
|
||||
GetUserList ()->push_back (base);
|
||||
}
|
||||
|
||||
CommandLine::List *
|
||||
CommandLine::GetUserList (void)
|
||||
{
|
||||
static List list;
|
||||
return &list;
|
||||
}
|
||||
|
||||
void
|
||||
CommandLine::PrintHelp (void)
|
||||
{
|
||||
for (List::iterator i = GetUserList ()->begin ();
|
||||
i != GetUserList ()->end (); i++)
|
||||
{
|
||||
DefaultValueBase *item = *i;
|
||||
if (item->GetType () == "" &&
|
||||
item->GetDefaultValue () == "")
|
||||
{
|
||||
std::cout << "--" << item->GetName () << "\t" << item->GetHelp () << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "--" << item->GetName () << "=[" << item->GetType () << ":"
|
||||
<< item->GetDefaultValue () << "]\t" << item->GetHelp () << std::endl;
|
||||
}
|
||||
}
|
||||
for (List::iterator i = DefaultValueList::Begin ();
|
||||
i != DefaultValueList::End (); i++)
|
||||
{
|
||||
DefaultValueBase *item = *i;
|
||||
if (item->GetType () == "" &&
|
||||
item->GetDefaultValue () == "")
|
||||
{
|
||||
std::cout << "--" << item->GetName () << "\t" << item->GetHelp () << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "--" << item->GetName () << "=[" << item->GetType () << ":"
|
||||
<< item->GetDefaultValue () << "]\t" << item->GetHelp () << std::endl;
|
||||
}
|
||||
}
|
||||
// XXX on win32, do the right thing here.
|
||||
exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
CommandLine::Parse (int argc, char *argv[])
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
while (argc > 0)
|
||||
{
|
||||
// remove "--" or "-" heading.
|
||||
std::string param = *argv;
|
||||
std::string::size_type cur = param.find ("--");
|
||||
if (cur == std::string::npos)
|
||||
{
|
||||
cur = param.find ("-");
|
||||
if (cur == std::string::npos)
|
||||
{
|
||||
// invalid argument. ignore it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (cur != 0)
|
||||
{
|
||||
// invalid argument. ignore it.
|
||||
continue;
|
||||
}
|
||||
param = std::string (param, 2, param.size ());
|
||||
cur = param.find ("=");
|
||||
std::string name, value;
|
||||
if (cur == std::string::npos)
|
||||
{
|
||||
name = param;
|
||||
value = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = std::string (param, 0, cur);
|
||||
value = std::string (param, cur + 1, std::string::npos);
|
||||
}
|
||||
// try to find this argument in the user args.
|
||||
for (List::iterator i = GetUserList ()->begin ();
|
||||
i != GetUserList ()->end (); i++)
|
||||
{
|
||||
DefaultValueBase *item = *i;
|
||||
if (item->GetName () == name)
|
||||
{
|
||||
item->ParseValue (value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// try to find this argument in the default args.
|
||||
for (List::iterator i = DefaultValueList::Begin ();
|
||||
i != DefaultValueList::End (); i++)
|
||||
{
|
||||
DefaultValueBase *item = *i;
|
||||
if (item->GetName () == name)
|
||||
{
|
||||
item->ParseValue (value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
@@ -0,0 +1,144 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 Georgia Tech University, INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Raj Bhattacharjea <raj.b@gatech.edu>,
|
||||
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef COMMAND_LINE_H
|
||||
#define COMMAND_LINE_H
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "default-value.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Command line argument processing class
|
||||
* \ingroup config
|
||||
*
|
||||
* Often times in simulations, the user will want the ability to change and
|
||||
* tweak simulation parameters without having to recompile the entire
|
||||
* simulation. This can be done by passing arguments in from the command
|
||||
* line invocation of a simulation.
|
||||
* This class is a collection of static functions to aid in this facility.
|
||||
* By using it, users get the automatic things like support for --help command
|
||||
* line arguments. See samples/main-default-value.cc for more info.
|
||||
*/
|
||||
class CommandLine
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Add a command line argument to the system
|
||||
* \param name Name of the string to expect on the command line
|
||||
* \param help A help string for this param, displayed --help is used.
|
||||
* \param value The desination to store the value read from the command line
|
||||
*/
|
||||
template <typename T>
|
||||
static void AddArgValue (const std::string &name,
|
||||
const std::string &help,
|
||||
T &value);
|
||||
/**
|
||||
* \brief Add a command line triggered function call to the system
|
||||
* \param name Name of the string to expect on the command line
|
||||
* \param help A help string for this param, displayed --help is used.
|
||||
* \param cb An ns3::Callback that gets called if name is present as a
|
||||
* commandline argument.
|
||||
*/
|
||||
static void AddArgCommand (const std::string &name,
|
||||
const std::string &help,
|
||||
Callback<void> cb);
|
||||
/**
|
||||
* \brief Parse the command line for arguments thus far added
|
||||
* \param argc Number of strings on the command line; pass this directly from
|
||||
* the first argument of your main(int,char**) function
|
||||
* \param argv Array of strings passed in as arguments; pass this directly from
|
||||
* the second argument of your main(int,char**) function
|
||||
*/
|
||||
static void Parse (int argc, char *argv[]);
|
||||
private:
|
||||
template <typename T>
|
||||
class UserDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
UserDefaultValue (const std::string &name,
|
||||
const std::string &help,
|
||||
T &value);
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
T *m_valuePtr;
|
||||
};
|
||||
static void PrintHelp (void);
|
||||
typedef std::list<DefaultValueBase *> List;
|
||||
static List *GetUserList (void);
|
||||
static CommandDefaultValue g_help;
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
CommandLine::AddArgValue (const std::string &name,
|
||||
const std::string &help,
|
||||
T &value)
|
||||
{
|
||||
DefaultValueBase *base =
|
||||
new UserDefaultValue<T> (name, help, value);
|
||||
GetUserList ()->push_back (base);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
CommandLine::UserDefaultValue<T>::UserDefaultValue (const std::string &name,
|
||||
const std::string &help,
|
||||
T &value)
|
||||
: DefaultValueBase (name, help),
|
||||
m_valuePtr (&value)
|
||||
{
|
||||
// we do not register in the DefaultValueList class on purpose.
|
||||
}
|
||||
template <typename T>
|
||||
bool
|
||||
CommandLine::UserDefaultValue<T>::DoParseValue (const std::string &value)
|
||||
{
|
||||
std::istringstream iss;
|
||||
iss.str (value);
|
||||
T v;
|
||||
iss >> v;
|
||||
*m_valuePtr = v;
|
||||
return !iss.bad () && !iss.fail ();
|
||||
}
|
||||
template <typename T>
|
||||
std::string
|
||||
CommandLine::UserDefaultValue<T>::DoGetType (void) const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
template <typename T>
|
||||
std::string
|
||||
CommandLine::UserDefaultValue<T>::DoGetDefaultValue (void) const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* COMMAND_LINE_H */
|
||||
@@ -0,0 +1,402 @@
|
||||
/* -*- 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 */
|
||||
@@ -0,0 +1,686 @@
|
||||
/* -*- 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);
|
||||
|
||||
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 */
|
||||
@@ -0,0 +1,186 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
#include "debug.h"
|
||||
#include "assert.h"
|
||||
#include "ns3/core-config.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
typedef std::list<std::pair <std::string, DebugComponent *> > ComponentList;
|
||||
typedef std::list<std::pair <std::string, DebugComponent *> >::iterator ComponentListI;
|
||||
|
||||
static
|
||||
ComponentList *GetComponentList (void)
|
||||
{
|
||||
static ComponentList components;
|
||||
return &components;
|
||||
}
|
||||
|
||||
|
||||
static bool g_firstDebug = true;
|
||||
|
||||
void
|
||||
DebugComponentEnableEnvVar (void)
|
||||
{
|
||||
#ifdef HAVE_GETENV
|
||||
char *envVar = getenv("NS_DEBUG");
|
||||
if (envVar == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::string env = envVar;
|
||||
std::string::size_type cur = 0;
|
||||
std::string::size_type next = 0;
|
||||
while (true)
|
||||
{
|
||||
next = env.find_first_of (";", cur);
|
||||
std::string tmp = std::string (env, cur, next);
|
||||
{
|
||||
/* The following code is a workaround for a bug in the g++
|
||||
* c++ string library. Its goal is to remove any trailing ';'
|
||||
* from the string even though there should not be any in
|
||||
* it. This code should be safe even if the bug is not there.
|
||||
*/
|
||||
std::string::size_type trailing = tmp.find_first_of (";");
|
||||
tmp = tmp.substr (0, trailing);
|
||||
}
|
||||
if (tmp.size () == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bool found = false;
|
||||
ComponentList *components = GetComponentList ();
|
||||
for (ComponentListI i = components->begin ();
|
||||
i != components->end ();
|
||||
i++)
|
||||
{
|
||||
if (i->first.compare (tmp) == 0)
|
||||
{
|
||||
found = true;
|
||||
i->second->Enable ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
std::cout << "No debug component named=\"" << tmp << "\"" << std::endl;
|
||||
}
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
cur = next + 1;
|
||||
if (cur >= env.size ())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
DebugComponent::DebugComponent (char const * name)
|
||||
: m_isEnabled (false)
|
||||
{
|
||||
ComponentList *components = GetComponentList ();
|
||||
for (ComponentListI i = components->begin ();
|
||||
i != components->end ();
|
||||
i++)
|
||||
{
|
||||
NS_ASSERT (i->first != name);
|
||||
}
|
||||
components->push_back (std::make_pair (name, this));
|
||||
}
|
||||
bool
|
||||
DebugComponent::IsEnabled (void)
|
||||
{
|
||||
if (g_firstDebug)
|
||||
{
|
||||
DebugComponentEnableEnvVar ();
|
||||
g_firstDebug = false;
|
||||
}
|
||||
return m_isEnabled;
|
||||
}
|
||||
void
|
||||
DebugComponent::Enable (void)
|
||||
{
|
||||
m_isEnabled = true;
|
||||
}
|
||||
void
|
||||
DebugComponent::Disable (void)
|
||||
{
|
||||
m_isEnabled = false;
|
||||
}
|
||||
|
||||
void
|
||||
DebugComponentEnable (char const *name)
|
||||
{
|
||||
ComponentList *components = GetComponentList ();
|
||||
for (ComponentListI i = components->begin ();
|
||||
i != components->end ();
|
||||
i++)
|
||||
{
|
||||
if (i->first.compare (name) == 0)
|
||||
{
|
||||
i->second->Enable ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
DebugComponentDisable (char const *name)
|
||||
{
|
||||
ComponentList *components = GetComponentList ();
|
||||
for (ComponentListI i = components->begin ();
|
||||
i != components->end ();
|
||||
i++)
|
||||
{
|
||||
if (i->first.compare (name) == 0)
|
||||
{
|
||||
i->second->Disable ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DebugComponentPrintList (void)
|
||||
{
|
||||
ComponentList *components = GetComponentList ();
|
||||
for (ComponentListI i = components->begin ();
|
||||
i != components->end ();
|
||||
i++)
|
||||
{
|
||||
std::cout << i->first << "=" << (i->second->IsEnabled ()?"enabled":"disabled") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
/**
|
||||
* \defgroup debugging Debugging
|
||||
* \brief Debugging functions and macros
|
||||
*
|
||||
* - DEBUG functionality: macros which allow developers to
|
||||
* send information out on screen only in debugging builds.
|
||||
* All debug messages are disabled by default. To enable
|
||||
* selected debug messages, use the ns3::DebugComponentEnable
|
||||
* function. Alternatively, you can use the NS_DEBUG
|
||||
* environment variable to define a ';'-separated list of
|
||||
* messages to enable. For example, NS_DEBUG=a;b;c;DAFD;GH
|
||||
* would enable the components 'a', 'b', 'c', 'DAFD', and, 'GH'.
|
||||
*/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \param name a debug component name
|
||||
* \ingroup debugging
|
||||
*
|
||||
* Enable the debugging output associated with that debug component.
|
||||
* The debugging output can be later disabled with a call
|
||||
* to ns3::DebugComponentDisable.
|
||||
*/
|
||||
void DebugComponentEnable (char const *name);
|
||||
/**
|
||||
* \param name a debug component name
|
||||
* \ingroup debugging
|
||||
*
|
||||
* Disable the debugging output associated with that debug component.
|
||||
* The debugging output can be later re-enabled with a call
|
||||
* to ns3::DebugComponentEnable.
|
||||
*/
|
||||
void DebugComponentDisable (char const *name);
|
||||
/**
|
||||
* \ingroup debugging
|
||||
* Print the list of debugging messages available.
|
||||
*/
|
||||
void DebugComponentPrintList (void);
|
||||
|
||||
class DebugComponent {
|
||||
public:
|
||||
DebugComponent (char const *name);
|
||||
bool IsEnabled (void);
|
||||
void Enable (void);
|
||||
void Disable (void);
|
||||
private:
|
||||
bool m_isEnabled;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#ifdef NS3_DEBUG_ENABLE
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup debugging
|
||||
* \param name a string
|
||||
*
|
||||
* Define a Debug component with a specific name. This macro
|
||||
* should be used at the top of every file in which you want
|
||||
* to use the NS_DEBUG macro. This macro defines a new
|
||||
* "debug component" which can be later selectively enabled
|
||||
* or disabled with the ns3::DebugComponentEnable and
|
||||
* ns3::DebugComponentDisable functions or with the NS_DEBUG
|
||||
* environment variable.
|
||||
*/
|
||||
#define NS_DEBUG_COMPONENT_DEFINE(name) \
|
||||
static ns3::DebugComponent g_debug = ns3::DebugComponent (name)
|
||||
|
||||
/**
|
||||
* \ingroup debugging
|
||||
* \param msg message to output
|
||||
*
|
||||
* Generate debugging output in the "debug component" of the
|
||||
* current file. i.e., every call to NS_DEBUG from within
|
||||
* a file implicitely generates out within the component
|
||||
* defined with the NS_DEBUG_COMPONENT_DEFINE macro in the
|
||||
* same file.
|
||||
*/
|
||||
#define NS_DEBUG(msg) \
|
||||
do \
|
||||
{ \
|
||||
if (g_debug.IsEnabled ()) \
|
||||
{ \
|
||||
std::cout << msg << std::endl; \
|
||||
} \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
/**
|
||||
* \ingroup debugging
|
||||
* \param msg message to output
|
||||
*
|
||||
* Generate debugging output unconditionally in all
|
||||
* debug builds.
|
||||
*/
|
||||
#define NS_DEBUG_UNCOND(msg) \
|
||||
do \
|
||||
{ \
|
||||
std::cout << msg << std::endl; \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
#else /* NS3_DEBUG_ENABLE */
|
||||
|
||||
#define NS_DEBUG_COMPONENT_DEFINE(name)
|
||||
#define NS_DEBUG(x)
|
||||
#define NS_DEBUG_UNCOND(msg)
|
||||
|
||||
#endif /* NS3_DEBUG_ENABLE */
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
@@ -0,0 +1,465 @@
|
||||
/* -*- 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 "default-value.h"
|
||||
#include "fatal-error.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
DefaultValueBase::DefaultValueBase (const std::string &name,
|
||||
const std::string &help)
|
||||
: m_name (name),
|
||||
m_help (help)
|
||||
{}
|
||||
DefaultValueBase::~DefaultValueBase ()
|
||||
{}
|
||||
std::string
|
||||
DefaultValueBase::GetName (void) const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
std::string
|
||||
DefaultValueBase::GetHelp (void) const
|
||||
{
|
||||
return m_help;
|
||||
}
|
||||
bool
|
||||
DefaultValueBase::ParseValue (const std::string &value)
|
||||
{
|
||||
return DoParseValue (value);
|
||||
}
|
||||
std::string
|
||||
DefaultValueBase::GetType (void) const
|
||||
{
|
||||
return DoGetType ();
|
||||
}
|
||||
std::string
|
||||
DefaultValueBase::GetDefaultValue (void) const
|
||||
{
|
||||
return DoGetDefaultValue ();
|
||||
}
|
||||
|
||||
|
||||
DefaultValueList::Iterator
|
||||
DefaultValueList::Begin (void)
|
||||
{
|
||||
return GetList ()->begin ();
|
||||
}
|
||||
DefaultValueList::Iterator
|
||||
DefaultValueList::End (void)
|
||||
{
|
||||
return GetList ()->end ();
|
||||
}
|
||||
void
|
||||
DefaultValueList::Remove (const std::string &name)
|
||||
{
|
||||
DefaultValueList::List *list = GetList ();
|
||||
for (List::iterator i = list->begin (); i != list->end (); /* nothing */)
|
||||
{
|
||||
if ((*i)->GetName () == name)
|
||||
{
|
||||
i = list->erase (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
DefaultValueList::Add (DefaultValueBase *defaultValue)
|
||||
{
|
||||
GetList ()->push_back (defaultValue);
|
||||
}
|
||||
|
||||
DefaultValueList::List *
|
||||
DefaultValueList::GetList (void)
|
||||
{
|
||||
static List list;
|
||||
return &list;
|
||||
}
|
||||
|
||||
enum BindStatus {
|
||||
OK,
|
||||
INVALID_VALUE,
|
||||
NOT_FOUND
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
enum BindStatus
|
||||
BindSafe (std::string name, std::string value)
|
||||
{
|
||||
for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
|
||||
i != DefaultValueList::End (); i++)
|
||||
{
|
||||
DefaultValueBase *cur = *i;
|
||||
if (cur->GetName () == name)
|
||||
{
|
||||
if (!cur->ParseValue (value))
|
||||
{
|
||||
return INVALID_VALUE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
void
|
||||
Bind (std::string name, std::string value)
|
||||
{
|
||||
switch (BindSafe (name, value)) {
|
||||
case INVALID_VALUE:
|
||||
NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
|
||||
break;
|
||||
case NOT_FOUND:
|
||||
NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
|
||||
break;
|
||||
case OK:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BooleanDefaultValue::BooleanDefaultValue (std::string name,
|
||||
std::string help,
|
||||
bool defaultValue)
|
||||
: DefaultValueBase (name, help),
|
||||
m_defaultValue (defaultValue),
|
||||
m_value (defaultValue)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
}
|
||||
bool
|
||||
BooleanDefaultValue::GetValue (void) const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
bool
|
||||
BooleanDefaultValue::DoParseValue (const std::string &value)
|
||||
{
|
||||
if (value.compare ("0") == 0 ||
|
||||
value.compare ("f") == 0 ||
|
||||
value.compare ("false") == 0 ||
|
||||
value.compare ("FALSE") == 0)
|
||||
{
|
||||
m_value = false;
|
||||
return true;
|
||||
}
|
||||
else if (value.compare ("1") == 0 ||
|
||||
value.compare ("t") == 0 ||
|
||||
value.compare ("true") == 0 ||
|
||||
value.compare ("TRUE") == 0)
|
||||
{
|
||||
m_value = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::string
|
||||
BooleanDefaultValue::DoGetType (void) const
|
||||
{
|
||||
return "bool";
|
||||
}
|
||||
std::string
|
||||
BooleanDefaultValue::DoGetDefaultValue (void) const
|
||||
{
|
||||
return m_defaultValue?"true":"false";
|
||||
}
|
||||
|
||||
|
||||
StringEnumDefaultValue::StringEnumDefaultValue (const std::string &name,
|
||||
const std::string &help)
|
||||
: DefaultValueBase (name, help),
|
||||
m_oneDefault (false)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
}
|
||||
void
|
||||
StringEnumDefaultValue::AddDefaultValue (const std::string &value)
|
||||
{
|
||||
if (m_oneDefault)
|
||||
{
|
||||
NS_FATAL_ERROR ("More than one default value registered: " << value);
|
||||
}
|
||||
m_oneDefault = true;
|
||||
for (std::list<std::string>::iterator i = m_possibleValues.begin ();
|
||||
i != m_possibleValues.end (); i++)
|
||||
{
|
||||
if (value == *i)
|
||||
{
|
||||
NS_FATAL_ERROR ("Value already exists: " << value);
|
||||
}
|
||||
}
|
||||
m_possibleValues.push_back (value);
|
||||
m_value = value;
|
||||
m_defaultValue = value;
|
||||
}
|
||||
void
|
||||
StringEnumDefaultValue::AddPossibleValue (const std::string &value)
|
||||
{
|
||||
for (std::list<std::string>::iterator i = m_possibleValues.begin ();
|
||||
i != m_possibleValues.end (); i++)
|
||||
{
|
||||
if (value == *i)
|
||||
{
|
||||
NS_FATAL_ERROR ("Value already exists: " << value);
|
||||
}
|
||||
}
|
||||
m_possibleValues.push_back (value);
|
||||
}
|
||||
std::string
|
||||
StringEnumDefaultValue::GetValue (void) const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
bool
|
||||
StringEnumDefaultValue::DoParseValue (const std::string &value)
|
||||
{
|
||||
for (std::list<std::string>::iterator i = m_possibleValues.begin ();
|
||||
i != m_possibleValues.end (); i++)
|
||||
{
|
||||
if (value == *i)
|
||||
{
|
||||
m_value = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string
|
||||
StringEnumDefaultValue::DoGetType (void) const
|
||||
{
|
||||
std::string retval;
|
||||
retval += "(";
|
||||
for (std::list<std::string>::const_iterator i = m_possibleValues.begin ();
|
||||
i != m_possibleValues.end (); i++)
|
||||
{
|
||||
if (i != m_possibleValues.begin ())
|
||||
{
|
||||
retval += "|";
|
||||
}
|
||||
retval += *i;
|
||||
}
|
||||
retval += ")";
|
||||
return retval;
|
||||
}
|
||||
std::string
|
||||
StringEnumDefaultValue::DoGetDefaultValue (void) const
|
||||
{
|
||||
return m_defaultValue;
|
||||
}
|
||||
|
||||
|
||||
CommandDefaultValue::CommandDefaultValue (const std::string &name,
|
||||
const std::string &help,
|
||||
Callback<void> cb)
|
||||
: DefaultValueBase (name, help),
|
||||
m_cb (cb)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
}
|
||||
bool
|
||||
CommandDefaultValue::DoParseValue (const std::string &value)
|
||||
{
|
||||
m_cb ();
|
||||
return true;
|
||||
}
|
||||
std::string
|
||||
CommandDefaultValue::DoGetType (void) const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::string
|
||||
CommandDefaultValue::DoGetDefaultValue (void) const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
#include "test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
enum MyEnum {
|
||||
MY_ENUM_A,
|
||||
MY_ENUM_B,
|
||||
MY_ENUM_C,
|
||||
MY_ENUM_D,
|
||||
};
|
||||
|
||||
|
||||
class DefaultValueTest : public Test
|
||||
{
|
||||
public:
|
||||
DefaultValueTest ();
|
||||
virtual bool RunTests (void);
|
||||
};
|
||||
|
||||
DefaultValueTest::DefaultValueTest ()
|
||||
: Test ("DefaultValue")
|
||||
{}
|
||||
bool
|
||||
DefaultValueTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
BooleanDefaultValue a ("bool-a", "help a", true);
|
||||
if (!a.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("bool-a", "false");
|
||||
if (a.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
BooleanDefaultValue b ("bool-b", "help b", false);
|
||||
Bind ("bool-b", "true");
|
||||
if (!b.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("bool-b", "0");
|
||||
if (b.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("bool-b", "1");
|
||||
if (!b.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("bool-b", "f");
|
||||
if (b.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("bool-b", "t");
|
||||
if (!b.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
Bind ("bool-b", "false");
|
||||
if (b.GetValue ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (BindSafe ("bool-b", "tr") != INVALID_VALUE)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
IntegerDefaultValue<int> i ("test-i", "help-i", -1);
|
||||
if (i.GetValue () != -1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("test-i", "-2");
|
||||
if (i.GetValue () != -2)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("test-i", "+2");
|
||||
if (i.GetValue () != 2)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (i.GetType () != "int32_t(-2147483648:2147483647)")
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
IntegerDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
|
||||
if (ui32.GetType () != "uint32_t(0:4294967295)")
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
IntegerDefaultValue<char> c ("test-c", "help-c", 10);
|
||||
if (c.GetValue () != 10)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("test-c", "257");
|
||||
|
||||
EnumDefaultValue<enum MyEnum> e ("test-e", "help-e",
|
||||
MY_ENUM_C, "C",
|
||||
MY_ENUM_A, "A",
|
||||
MY_ENUM_B, "B",
|
||||
0, (void*)0);
|
||||
if (e.GetValue () != MY_ENUM_C)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("test-e", "B");
|
||||
if (e.GetValue () != MY_ENUM_B)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (BindSafe ("test-e", "D") != INVALID_VALUE)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
class MyEnumSubclass : public EnumDefaultValue<enum MyEnum>
|
||||
{
|
||||
public:
|
||||
MyEnumSubclass ()
|
||||
: EnumDefaultValue<enum MyEnum> ("test-e1", "help-e1",
|
||||
MY_ENUM_B, "B",
|
||||
MY_ENUM_A, "A",
|
||||
0, (void*)0)
|
||||
{
|
||||
AddPossibleValue (MY_ENUM_C, "C");
|
||||
AddPossibleValue (MY_ENUM_D, "D");
|
||||
}
|
||||
} e1 ;
|
||||
if (e1.GetValue () != MY_ENUM_B)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
Bind ("test-e1", "D");
|
||||
if (e1.GetValue () != MY_ENUM_D)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
DefaultValueList::Remove ("test-e1");
|
||||
DefaultValueList::Remove ("test-e");
|
||||
DefaultValueList::Remove ("bool-b");
|
||||
DefaultValueList::Remove ("bool-a");
|
||||
DefaultValueList::Remove ("test-i");
|
||||
DefaultValueList::Remove ("test-c");
|
||||
DefaultValueList::Remove ("test-ui32");
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static DefaultValueTest g_default_value_tests;
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -0,0 +1,531 @@
|
||||
/* -*- 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 DEFAULT_VALUE_H
|
||||
#define DEFAULT_VALUE_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include "callback.h"
|
||||
|
||||
/**
|
||||
* \defgroup config Simulation configuration
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class DefaultValueBase
|
||||
{
|
||||
public:
|
||||
virtual ~DefaultValueBase ();
|
||||
std::string GetName (void) const;
|
||||
std::string GetHelp (void) const;
|
||||
// parse a matching parameter
|
||||
// return true in case of success, false otherwise.
|
||||
bool ParseValue (const std::string &value);
|
||||
std::string GetType (void) const;
|
||||
std::string GetDefaultValue (void) const;
|
||||
protected:
|
||||
DefaultValueBase (const std::string &name,
|
||||
const std::string &help);
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value) = 0;
|
||||
virtual std::string DoGetType (void) const = 0;
|
||||
virtual std::string DoGetDefaultValue (void) const = 0;
|
||||
std::string m_name;
|
||||
std::string m_help;
|
||||
};
|
||||
|
||||
class DefaultValueList
|
||||
{
|
||||
public:
|
||||
typedef std::list<DefaultValueBase *>::iterator Iterator;
|
||||
|
||||
static Iterator Begin (void);
|
||||
static Iterator End (void);
|
||||
static void Remove (const std::string &name);
|
||||
static void Add (DefaultValueBase *defaultValue);
|
||||
private:
|
||||
typedef std::list<DefaultValueBase *> List;
|
||||
static List *GetList (void);
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup config
|
||||
* \param name name of variable to bind
|
||||
* \param value value to bind to the specified variable
|
||||
*
|
||||
* If the variable name does not match any existing
|
||||
* variable or if the value is not compatible with
|
||||
* the variable type, this function will abort
|
||||
* at runtime and print an error message detailing
|
||||
* which variable or value triggered the problem.
|
||||
*/
|
||||
void Bind (std::string name, std::string value);
|
||||
|
||||
/**
|
||||
* \brief A Boolean variable for ns3::Bind
|
||||
* \ingroup config
|
||||
*
|
||||
* Every instance of this type is automatically
|
||||
* registered in the variable pool which is used
|
||||
* by ns3::Bind.
|
||||
*/
|
||||
class BooleanDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name name of variable
|
||||
* \param help help text which explains the purpose
|
||||
* and the semantics of this variable
|
||||
* \param defaultValue the default value to assign
|
||||
* to this variable.
|
||||
*
|
||||
* Unless the user invokes ns3::Bind with the right arguments,
|
||||
* the GetValue method will return the default value. Otherwise,
|
||||
* it will return the user-specified value.
|
||||
*/
|
||||
BooleanDefaultValue (std::string name,
|
||||
std::string help,
|
||||
bool defaultValue);
|
||||
/**
|
||||
* \returns the default value for this variable or a
|
||||
* user-provided overriden variable.
|
||||
*/
|
||||
bool GetValue (void) const;
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
bool m_defaultValue;
|
||||
bool m_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An Integer variable for ns3::Bind
|
||||
* \ingroup config
|
||||
*
|
||||
* Every instance of this type is automatically
|
||||
* registered in the variable pool which is used
|
||||
* by ns3::Bind.
|
||||
*/
|
||||
template <typename T>
|
||||
class IntegerDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name the name of the variable
|
||||
* \param help help text which explains the purpose
|
||||
* and the semantics of this variable
|
||||
* \param defaultValue the default value assigned
|
||||
* to this variable
|
||||
*
|
||||
* By default, the set of allowed values is the entire range
|
||||
* of values which can be stored and retrieved from the underlying
|
||||
* type.
|
||||
*/
|
||||
IntegerDefaultValue (std::string name,
|
||||
std::string help,
|
||||
T defaultValue);
|
||||
/**
|
||||
* \param name the name of the variable
|
||||
* \param help help text which explains the purpose
|
||||
* and the semantics of this variable
|
||||
* \param defaultValue the default value assigned to this
|
||||
* variable
|
||||
* \param minValue the minimum value which can be set
|
||||
* in this variable
|
||||
*/
|
||||
IntegerDefaultValue (std::string name,
|
||||
std::string help,
|
||||
T defaultValue,
|
||||
T minValue);
|
||||
|
||||
/**
|
||||
* \param name the name of the variable
|
||||
* \param help help text which explains the purpose
|
||||
* and the semantics of this variable
|
||||
* \param defaultValue the default value assigned to this
|
||||
* variable
|
||||
* \param minValue the minimum value which can be set
|
||||
* in this variable
|
||||
* \param maxValue the maximum value which can be set in this
|
||||
* variable.
|
||||
*/
|
||||
IntegerDefaultValue (std::string name,
|
||||
std::string help,
|
||||
T defaultValue,
|
||||
T minValue,
|
||||
T maxValue);
|
||||
|
||||
void SetValue (T v);
|
||||
|
||||
T GetValue (void) const;
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
T m_defaultValue;
|
||||
T m_minValue;
|
||||
T m_maxValue;
|
||||
T m_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Named enumeration defaults
|
||||
* \ingroup config
|
||||
*
|
||||
* Every instance of this type is automatically
|
||||
* registered in the variable pool which is used
|
||||
* by ns3::Bind.
|
||||
*/
|
||||
class StringEnumDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name The name of the variable
|
||||
* \param help The help string
|
||||
*/
|
||||
StringEnumDefaultValue (const std::string &name,
|
||||
const std::string &help);
|
||||
/**
|
||||
* \brief Add a default value to this enumeration of strings
|
||||
* \param value The string to make the default for this
|
||||
*/
|
||||
void AddDefaultValue (const std::string &value);
|
||||
/**
|
||||
* \brief Add a possible value to accept for this default value
|
||||
*/
|
||||
void AddPossibleValue (const std::string &value);
|
||||
/**
|
||||
* \brief Get the value of this default value.
|
||||
* \return The string that has been assigned to this default value, either by
|
||||
* Bind() or by a command line setting
|
||||
*/
|
||||
std::string GetValue (void) const;
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
|
||||
bool m_oneDefault;
|
||||
std::list<std::string> m_possibleValues;
|
||||
std::string m_defaultValue;
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An enum variable for ns3::Bind
|
||||
* \ingroup config
|
||||
*
|
||||
* Every instance of this type is automatically
|
||||
* registered in the variable pool which is used
|
||||
* by ns3::Bind.
|
||||
*/
|
||||
template <typename T>
|
||||
class EnumDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name the name of this variable
|
||||
* \param help help text which explains the purpose
|
||||
* and the semantics of this variable
|
||||
* \param defaultValue the default value assigned to this
|
||||
* variable unless it is overriden with ns3::Bind
|
||||
* \param defaultValueString the string which represents
|
||||
* the default value which should be used by ns3::Bind
|
||||
*
|
||||
* This method takes a variable number of arguments. The list of
|
||||
* arguments is terminated by the pair of values 0 and (void *)0.
|
||||
* Each pair of extra argument is assumed to be of the form
|
||||
* (enum value, string representing enum value). If ns3::Bind
|
||||
* is invoked on this variable, it will check that the user-provided
|
||||
* values are within the set of values specified in this constructor.
|
||||
*
|
||||
* Typical useage of this method will look like this:
|
||||
* \code
|
||||
* enum MyEnum {
|
||||
* MY_ENUM_A,
|
||||
* MY_ENUM_B,
|
||||
* MY_ENUM_C,
|
||||
* };
|
||||
* // set default value to be "B".
|
||||
* static EnumDefaultValue<enum MyEnum>
|
||||
* g_myDefaultValue ("my", "my help",
|
||||
* MY_ENUM_B, "B",
|
||||
* MY_ENUM_A, "A",
|
||||
* MY_ENUM_C, "C",);
|
||||
* 0, (void*)0);
|
||||
* \endcode
|
||||
* Note that to ensure portability to 64 bit systems, make sure that
|
||||
* the last element in the variable list of arguments is (void *)0.
|
||||
*/
|
||||
EnumDefaultValue (const std::string &name, const std::string &help,
|
||||
T defaultValue, const char *defaultValueString,
|
||||
...);
|
||||
void AddPossibleValue (T value, const std::string &valueString);
|
||||
/**
|
||||
* \returns the default value or any other value specified by the
|
||||
* user with ns3::Bind
|
||||
*/
|
||||
T GetValue (void);
|
||||
/**
|
||||
* \param value the new default value.
|
||||
*/
|
||||
void SetValue (T value);
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
|
||||
typedef std::list<std::pair<T,std::string> > PossibleValues;
|
||||
|
||||
T m_defaultValue;
|
||||
PossibleValues m_possibleValues;
|
||||
T m_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class used to call a certain function during the configuration of the
|
||||
* simulation
|
||||
* \ingroup config
|
||||
*/
|
||||
class CommandDefaultValue : public DefaultValueBase
|
||||
{
|
||||
public:
|
||||
CommandDefaultValue (const std::string &name,
|
||||
const std::string &help,
|
||||
Callback<void> cb);
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
virtual std::string DoGetDefaultValue (void) const;
|
||||
Callback<void> m_cb;
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#include "type-name.h"
|
||||
#include "assert.h"
|
||||
#include <sstream>
|
||||
#include <stdarg.h>
|
||||
#include <limits>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**************************************************************
|
||||
**************************************************************/
|
||||
|
||||
|
||||
template <typename T>
|
||||
IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
|
||||
std::string help,
|
||||
T defaultValue)
|
||||
: DefaultValueBase (name, help),
|
||||
m_defaultValue (defaultValue),
|
||||
m_minValue (std::numeric_limits<T>::min ()),
|
||||
m_maxValue (std::numeric_limits<T>::max ()),
|
||||
m_value (defaultValue)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
NS_ASSERT (m_minValue < m_maxValue);
|
||||
}
|
||||
template <typename T>
|
||||
IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
|
||||
std::string help,
|
||||
T defaultValue,
|
||||
T minValue)
|
||||
: DefaultValueBase (name, help),
|
||||
m_defaultValue (defaultValue),
|
||||
m_minValue (minValue),
|
||||
m_maxValue (std::numeric_limits<T>::max ()),
|
||||
m_value (defaultValue)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
NS_ASSERT (m_minValue < m_maxValue);
|
||||
NS_ASSERT (m_defaultValue <= m_maxValue &&
|
||||
m_defaultValue >= m_minValue);
|
||||
}
|
||||
template <typename T>
|
||||
IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
|
||||
std::string help,
|
||||
T defaultValue,
|
||||
T minValue,
|
||||
T maxValue)
|
||||
: DefaultValueBase (name, help),
|
||||
m_defaultValue (defaultValue),
|
||||
m_minValue (minValue),
|
||||
m_maxValue (maxValue),
|
||||
m_value (defaultValue)
|
||||
{
|
||||
DefaultValueList::Add (this);
|
||||
NS_ASSERT (m_minValue < m_maxValue);
|
||||
NS_ASSERT (m_defaultValue <= m_maxValue &&
|
||||
m_defaultValue >= m_minValue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
IntegerDefaultValue<T>::SetValue (T v)
|
||||
{
|
||||
NS_ASSERT (v <= m_maxValue &&
|
||||
v >= m_minValue);
|
||||
m_value = v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
IntegerDefaultValue<T>::GetValue (void) const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IntegerDefaultValue<T>::DoParseValue (const std::string &value)
|
||||
{
|
||||
std::istringstream iss;
|
||||
iss.str (value);
|
||||
iss >> m_value;
|
||||
if (m_value > m_maxValue ||
|
||||
m_value < m_minValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !iss.bad () && !iss.fail ();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string
|
||||
IntegerDefaultValue<T>::DoGetType (void) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << TypeNameGet<T> () << "("
|
||||
<< m_minValue << ":"
|
||||
<< m_maxValue << ")";
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string
|
||||
IntegerDefaultValue<T>::DoGetDefaultValue (void) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << m_defaultValue;
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
**************************************************************/
|
||||
|
||||
template <typename T>
|
||||
EnumDefaultValue<T>::EnumDefaultValue (const std::string &name, const std::string &help,
|
||||
T defaultValue, const char *defaultValueString,
|
||||
...)
|
||||
: DefaultValueBase (name, help),
|
||||
m_defaultValue (defaultValue),
|
||||
m_value (defaultValue)
|
||||
{
|
||||
AddPossibleValue (defaultValue, defaultValueString);
|
||||
va_list list;
|
||||
va_start (list, defaultValueString);
|
||||
while (true)
|
||||
{
|
||||
T v = (T) va_arg (list, int);
|
||||
const char *str = va_arg (list, const char *);
|
||||
if (v == 0 && str == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
AddPossibleValue (v, str);
|
||||
}
|
||||
DefaultValueList::Add (this);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
EnumDefaultValue<T>::AddPossibleValue (T value, const std::string &valueString)
|
||||
{
|
||||
m_possibleValues.push_back (std::make_pair (value, valueString));
|
||||
}
|
||||
template <typename T>
|
||||
T
|
||||
EnumDefaultValue<T>::GetValue (void)
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
EnumDefaultValue<T>::SetValue (T value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
template <typename T>
|
||||
bool
|
||||
EnumDefaultValue<T>::DoParseValue (const std::string &value)
|
||||
{
|
||||
for (typename PossibleValues::iterator i = m_possibleValues.begin ();
|
||||
i != m_possibleValues.end (); i++)
|
||||
{
|
||||
if (value == i->second)
|
||||
{
|
||||
m_value = i->first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <typename T>
|
||||
std::string
|
||||
EnumDefaultValue<T>::DoGetType (void) const
|
||||
{
|
||||
std::string retval;
|
||||
retval += "(";
|
||||
for (typename PossibleValues::const_iterator i = m_possibleValues.begin ();
|
||||
i != m_possibleValues.end (); i++)
|
||||
{
|
||||
if (i != m_possibleValues.begin ())
|
||||
{
|
||||
retval += "|";
|
||||
}
|
||||
retval += i->second;
|
||||
}
|
||||
retval += ")";
|
||||
return retval;
|
||||
}
|
||||
template <typename T>
|
||||
std::string
|
||||
EnumDefaultValue<T>::DoGetDefaultValue (void) const
|
||||
{
|
||||
for (typename PossibleValues::const_iterator i = m_possibleValues.begin ();
|
||||
i != m_possibleValues.end (); i++)
|
||||
{
|
||||
if (i->first == m_defaultValue)
|
||||
{
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
// cannot happen theoretically.
|
||||
NS_ASSERT (false);
|
||||
return ""; // quiet compiler
|
||||
}
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* DEFAULT_VALUE_H */
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef EMPTY_H
|
||||
#define EMPTY_H
|
||||
|
||||
namespace ns3 {
|
||||
class empty {};
|
||||
}
|
||||
|
||||
#endif /* EMPTY_H */
|
||||
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef FATAL_ERROR_H
|
||||
#define FATAL_ERROR_H
|
||||
|
||||
#include "assert.h"
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* \defgroup error Error
|
||||
* \brief fatal error handling
|
||||
*
|
||||
* \param msg message to output when this macro is hit.
|
||||
*
|
||||
* When this macro is hit at runtime, the user-specified
|
||||
* error message is output and the program is halted by calling
|
||||
* the ns3::AssertBreakpoint function. This macro is enabled
|
||||
* unconditionally in all builds, including debug and optimized
|
||||
* builds.
|
||||
*/
|
||||
#define NS_FATAL_ERROR(msg) \
|
||||
do \
|
||||
{ \
|
||||
std::cout << msg << std::endl; \
|
||||
ns3::AssertBreakpoint (); \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
|
||||
#endif /* FATAL_ERROR_H */
|
||||
@@ -0,0 +1,419 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA, Gustavo Carneiro
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
|
||||
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "object.h"
|
||||
#include "assert.h"
|
||||
#include "singleton.h"
|
||||
#include "uid-manager.h"
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
class IidManager : public ns3::UidManager
|
||||
{};
|
||||
|
||||
class IidTree
|
||||
{
|
||||
public:
|
||||
void SetParent (uint16_t child, const uint16_t *parent);
|
||||
uint16_t LookupParent (uint16_t child);
|
||||
private:
|
||||
std::vector<const uint16_t *> m_parents;
|
||||
};
|
||||
|
||||
void
|
||||
IidTree::SetParent (uint16_t child, const uint16_t *parent)
|
||||
{
|
||||
m_parents.resize (child+1);
|
||||
m_parents[child] = parent;
|
||||
}
|
||||
uint16_t
|
||||
IidTree::LookupParent (uint16_t child)
|
||||
{
|
||||
NS_ASSERT (child < m_parents.size ());
|
||||
return *(m_parents[child]);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
InterfaceId::InterfaceId (uint16_t iid)
|
||||
: m_iid (iid)
|
||||
{}
|
||||
InterfaceId::~InterfaceId ()
|
||||
{}
|
||||
InterfaceId
|
||||
InterfaceId::LookupByName (std::string name)
|
||||
{
|
||||
uint32_t uid = Singleton<IidManager>::Get ()->LookupByName (name);
|
||||
NS_ASSERT (uid != 0 && uid <= 0xffff);
|
||||
return InterfaceId (uid);
|
||||
}
|
||||
InterfaceId
|
||||
InterfaceId::LookupParent (InterfaceId iid)
|
||||
{
|
||||
return Singleton<IidTree>::Get ()->LookupParent (iid.m_iid);
|
||||
}
|
||||
|
||||
bool operator == (const InterfaceId &a, const InterfaceId &b)
|
||||
{
|
||||
return a.m_iid == b.m_iid;
|
||||
}
|
||||
|
||||
bool operator != (const InterfaceId &a, const InterfaceId &b)
|
||||
{
|
||||
return a.m_iid != b.m_iid;
|
||||
}
|
||||
|
||||
InterfaceId
|
||||
MakeInterfaceId (std::string name, const InterfaceId &parent)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
InterfaceId
|
||||
MakeObjectInterfaceId (void)
|
||||
{
|
||||
InterfaceId iid = Singleton<IidManager>::Get ()->Allocate ("Object");
|
||||
Singleton<IidTree>::Get ()->SetParent (iid.m_iid, &iid.m_iid);
|
||||
return iid;
|
||||
}
|
||||
|
||||
|
||||
const InterfaceId Object::iid = MakeObjectInterfaceId ();
|
||||
|
||||
|
||||
Object::Object ()
|
||||
: m_count (1),
|
||||
m_iid (Object::iid),
|
||||
m_disposed (false),
|
||||
m_next (this)
|
||||
{}
|
||||
Object::~Object ()
|
||||
{
|
||||
m_next = 0;
|
||||
}
|
||||
Ptr<Object>
|
||||
Object::DoQueryInterface (InterfaceId iid) const
|
||||
{
|
||||
NS_ASSERT (Check ());
|
||||
const Object *currentObject = this;
|
||||
do {
|
||||
NS_ASSERT (currentObject != 0);
|
||||
InterfaceId cur = currentObject->m_iid;
|
||||
while (cur != iid && cur != Object::iid)
|
||||
{
|
||||
cur = InterfaceId::LookupParent (cur);
|
||||
}
|
||||
if (cur == iid)
|
||||
{
|
||||
return const_cast<Object *> (currentObject);
|
||||
}
|
||||
currentObject = currentObject->m_next;
|
||||
} while (currentObject != this);
|
||||
return 0;
|
||||
}
|
||||
void
|
||||
Object::Dispose (void)
|
||||
{
|
||||
Object *current = this;
|
||||
do {
|
||||
NS_ASSERT (current != 0);
|
||||
NS_ASSERT (!current->m_disposed);
|
||||
current->DoDispose ();
|
||||
current->m_disposed = true;
|
||||
current = current->m_next;
|
||||
} while (current != this);
|
||||
}
|
||||
|
||||
void
|
||||
Object::AddInterface (Ptr<Object> o)
|
||||
{
|
||||
NS_ASSERT (!m_disposed);
|
||||
NS_ASSERT (!o->m_disposed);
|
||||
NS_ASSERT (Check ());
|
||||
NS_ASSERT (o->Check ());
|
||||
Object *other = PeekPointer (o);
|
||||
Object *next = m_next;
|
||||
m_next = other->m_next;
|
||||
other->m_next = next;
|
||||
NS_ASSERT (Check ());
|
||||
NS_ASSERT (o->Check ());
|
||||
}
|
||||
|
||||
void
|
||||
Object::SetInterfaceId (InterfaceId iid)
|
||||
{
|
||||
NS_ASSERT (Check ());
|
||||
m_iid = iid;
|
||||
}
|
||||
|
||||
void
|
||||
Object::DoDispose (void)
|
||||
{
|
||||
NS_ASSERT (!m_disposed);
|
||||
}
|
||||
|
||||
bool
|
||||
Object::Check (void) const
|
||||
{
|
||||
return (m_count > 0);
|
||||
}
|
||||
|
||||
void
|
||||
Object::MaybeDelete (void) const
|
||||
{
|
||||
// First, check if any of the attached
|
||||
// Object has a non-zero count.
|
||||
const Object *current = this;
|
||||
do {
|
||||
NS_ASSERT (current != 0);
|
||||
if (current->m_count != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
current = current->m_next;
|
||||
} while (current != this);
|
||||
|
||||
// all attached objects have a zero count so,
|
||||
// we can delete all attached objects.
|
||||
current = this;
|
||||
const Object *end = this;
|
||||
do {
|
||||
NS_ASSERT (current != 0);
|
||||
Object *next = current->m_next;
|
||||
delete current;
|
||||
current = next;
|
||||
} while (current != end);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "test.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class BaseA : public ns3::Object
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
BaseA ()
|
||||
{
|
||||
SetInterfaceId (BaseA::iid);
|
||||
}
|
||||
virtual void Dispose (void) {}
|
||||
};
|
||||
|
||||
class DerivedA : public BaseA
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
DerivedA (int v)
|
||||
{
|
||||
SetInterfaceId (DerivedA::iid);
|
||||
}
|
||||
virtual void Dispose (void) {
|
||||
BaseA::Dispose ();
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
virtual void Dispose (void) {}
|
||||
};
|
||||
|
||||
class DerivedB : public BaseB
|
||||
{
|
||||
public:
|
||||
static const ns3::InterfaceId iid;
|
||||
DerivedB (int v)
|
||||
{
|
||||
SetInterfaceId (DerivedB::iid);
|
||||
}
|
||||
virtual void Dispose (void) {
|
||||
BaseB::Dispose ();
|
||||
}
|
||||
};
|
||||
|
||||
const ns3::InterfaceId BaseB::iid =
|
||||
ns3::MakeInterfaceId ("BaseB", Object::iid);
|
||||
const ns3::InterfaceId DerivedB::iid =
|
||||
ns3::MakeInterfaceId ("DerivedB", BaseB::iid);;
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class ObjectTest : public Test
|
||||
{
|
||||
public:
|
||||
ObjectTest ();
|
||||
virtual bool RunTests (void);
|
||||
};
|
||||
|
||||
ObjectTest::ObjectTest ()
|
||||
: Test ("Object")
|
||||
{}
|
||||
bool
|
||||
ObjectTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
Ptr<BaseA> baseA = Create<BaseA> ();
|
||||
if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<BaseA> (DerivedA::iid) != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
baseA = Create<DerivedA> (10);
|
||||
if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<BaseA> (DerivedA::iid) != baseA)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<DerivedA> (DerivedA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
baseA = Create<BaseA> ();
|
||||
Ptr<BaseB> baseB = Create<BaseB> ();
|
||||
Ptr<BaseB> baseBCopy = baseB;
|
||||
baseA->AddInterface (baseB);
|
||||
if (baseA->QueryInterface<BaseA> (BaseA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<DerivedB> (DerivedB::iid) != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<DerivedB> (DerivedB::iid) != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<DerivedA> (DerivedA::iid) != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
baseA = Create<DerivedA> (1);
|
||||
baseB = Create<DerivedB> (1);
|
||||
baseBCopy = baseB;
|
||||
baseA->AddInterface (baseB);
|
||||
if (baseA->QueryInterface<DerivedB> (DerivedB::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<DerivedA> (DerivedA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<DerivedB> (DerivedB::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
baseA = Create<BaseA> ();
|
||||
baseB = Create<BaseB> ();
|
||||
baseA->AddInterface (baseB);
|
||||
baseA = 0;
|
||||
baseA = baseB->QueryInterface<BaseA> (BaseA::iid);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static ObjectTest g_interfaceObjectTests;
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA, Gustavo Carneiro
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
|
||||
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "ptr.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \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
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param name the name of the requested interface
|
||||
* \returns the unique id associated with the requested
|
||||
* name.
|
||||
*
|
||||
* This method cannot fail: it will crash if the input
|
||||
* name is not a valid interface name.
|
||||
*/
|
||||
static InterfaceId LookupByName (std::string name);
|
||||
/**
|
||||
* \param iid a unique id
|
||||
* \returns the parent of the requested id, as registered
|
||||
* by ns3::MakeInterfaceId.
|
||||
*
|
||||
* This method cannot fail: it will crash if the input
|
||||
* id is not a valid interface id.
|
||||
*/
|
||||
static InterfaceId LookupParent (InterfaceId iid);
|
||||
~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);
|
||||
|
||||
/**
|
||||
* \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.
|
||||
*/
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
|
||||
Object ();
|
||||
virtual ~Object ();
|
||||
/**
|
||||
* Increment the reference count. This method should not be called
|
||||
* by user code. Object instances are expected to be used in conjunction
|
||||
* of the Ptr template which would make calling Ref unecessary and
|
||||
* dangerous.
|
||||
*/
|
||||
inline void Ref (void) const;
|
||||
/**
|
||||
* Decrement the reference count. This method should not be called
|
||||
* by user code. Object instances are expected to be used in conjunction
|
||||
* of the Ptr template which would make calling Ref unecessary and
|
||||
* dangerous.
|
||||
*/
|
||||
inline void Unref (void) const;
|
||||
/**
|
||||
* \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;
|
||||
/**
|
||||
* Run the DoDispose methods of this object and all the
|
||||
* objects aggregated to it.
|
||||
* After calling this method, the object is expected to be
|
||||
* totally unusable except for the Ref and Unref methods.
|
||||
* It is an error to call Dispose twice on the same object
|
||||
* instance
|
||||
*/
|
||||
void Dispose (void);
|
||||
/**
|
||||
* \param other another object pointer
|
||||
*
|
||||
* This method aggregates the two objects together: after this
|
||||
* method returns, it becomes possible to call QueryInterface
|
||||
* on one to get the other, and vice-versa.
|
||||
*/
|
||||
void AddInterface (Ptr<Object> other);
|
||||
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
|
||||
* up to their parent's implementation once they are done.
|
||||
*/
|
||||
virtual void DoDispose (void);
|
||||
private:
|
||||
Ptr<Object> DoQueryInterface (InterfaceId iid) const;
|
||||
bool Check (void) const;
|
||||
void MaybeDelete (void) const;
|
||||
mutable uint32_t m_count;
|
||||
InterfaceId m_iid;
|
||||
bool m_disposed;
|
||||
Object *m_next;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
void
|
||||
Object::Ref (void) const
|
||||
{
|
||||
m_count++;
|
||||
}
|
||||
void
|
||||
Object::Unref (void) const
|
||||
{
|
||||
NS_ASSERT (Check ());
|
||||
m_count--;
|
||||
if (m_count == 0)
|
||||
{
|
||||
MaybeDelete ();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Ptr<T>
|
||||
Object::QueryInterface (InterfaceId iid) const
|
||||
{
|
||||
Ptr<Object> found = DoQueryInterface (iid);
|
||||
if (found != 0)
|
||||
{
|
||||
return Ptr<T> (dynamic_cast<T *> (PeekPointer (found)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* OBJECT_H */
|
||||
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "ptr.h"
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "test.h"
|
||||
#include "callback.h"
|
||||
#include "object.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class NoCount : public Object
|
||||
{
|
||||
public:
|
||||
NoCount (Callback<void> cb);
|
||||
~NoCount ();
|
||||
void Nothing (void) const;
|
||||
private:
|
||||
Callback<void> m_cb;
|
||||
};
|
||||
NoCount::NoCount (Callback<void> cb)
|
||||
: m_cb (cb)
|
||||
{}
|
||||
NoCount::~NoCount ()
|
||||
{
|
||||
m_cb ();
|
||||
}
|
||||
void
|
||||
NoCount::Nothing () const
|
||||
{}
|
||||
|
||||
class PtrTest : Test
|
||||
{
|
||||
public:
|
||||
PtrTest ();
|
||||
virtual ~PtrTest ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
void DestroyNotify (void);
|
||||
Ptr<NoCount> CallTest (Ptr<NoCount> p);
|
||||
Ptr<NoCount> const CallTestConst (Ptr<NoCount> const p);
|
||||
uint32_t m_nDestroyed;
|
||||
};
|
||||
|
||||
PtrTest::PtrTest ()
|
||||
: Test ("Ptr")
|
||||
{}
|
||||
|
||||
PtrTest::~PtrTest ()
|
||||
{}
|
||||
|
||||
void
|
||||
PtrTest::DestroyNotify (void)
|
||||
{
|
||||
m_nDestroyed++;
|
||||
}
|
||||
Ptr<NoCount>
|
||||
PtrTest::CallTest (Ptr<NoCount> p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
Ptr<NoCount> const
|
||||
PtrTest::CallTestConst (Ptr<NoCount> const p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
bool
|
||||
PtrTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
Callback<void> cb = MakeCallback (&PtrTest::DestroyNotify, this);
|
||||
m_nDestroyed = false;
|
||||
{
|
||||
Ptr<NoCount> p = Create<NoCount> (cb);
|
||||
}
|
||||
if (m_nDestroyed != 1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p;
|
||||
p = Create<NoCount> (cb);
|
||||
p = p;
|
||||
}
|
||||
if (m_nDestroyed != 1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
p1 = Create<NoCount> (cb);
|
||||
Ptr<NoCount> p2 = p1;
|
||||
}
|
||||
if (m_nDestroyed != 1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
p1 = Create<NoCount> (cb);
|
||||
Ptr<NoCount> p2;
|
||||
p2 = p1;
|
||||
}
|
||||
if (m_nDestroyed != 1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
p1 = Create<NoCount> (cb);
|
||||
Ptr<NoCount> p2 = Create<NoCount> (cb);
|
||||
p2 = p1;
|
||||
}
|
||||
if (m_nDestroyed != 2)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
p1 = Create<NoCount> (cb);
|
||||
Ptr<NoCount> p2;
|
||||
p2 = Create<NoCount> (cb);
|
||||
p2 = p1;
|
||||
}
|
||||
if (m_nDestroyed != 2)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
p1 = Create<NoCount> (cb);
|
||||
p1 = Create<NoCount> (cb);
|
||||
}
|
||||
if (m_nDestroyed != 2)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
{
|
||||
Ptr<NoCount> p2;
|
||||
p1 = Create<NoCount> (cb);
|
||||
p2 = Create<NoCount> (cb);
|
||||
p2 = p1;
|
||||
}
|
||||
if (m_nDestroyed != 1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (m_nDestroyed != 2)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
{
|
||||
Ptr<NoCount> p2;
|
||||
p1 = Create<NoCount> (cb);
|
||||
p2 = Create<NoCount> (cb);
|
||||
p2 = CallTest (p1);
|
||||
}
|
||||
if (m_nDestroyed != 1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (m_nDestroyed != 2)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
{
|
||||
Ptr<NoCount> p1;
|
||||
Ptr<NoCount> const p2 = CallTest (p1);
|
||||
Ptr<NoCount> const p3 = CallTestConst (p1);
|
||||
Ptr<NoCount> p4 = CallTestConst (p1);
|
||||
Ptr<NoCount const> p5 = p4;
|
||||
//p4 = p5; You cannot make a const pointer be a non-const pointer.
|
||||
// but if you use const_pointer_cast, you can.
|
||||
p4 = const_pointer_cast<NoCount> (p5);
|
||||
p5 = p1;
|
||||
Ptr<NoCount> p;
|
||||
if (p == 0)
|
||||
{}
|
||||
if (p != 0)
|
||||
{}
|
||||
if (0 == p)
|
||||
{}
|
||||
if (0 != p)
|
||||
{}
|
||||
if (p)
|
||||
{}
|
||||
if (!p)
|
||||
{}
|
||||
}
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
NoCount *raw;
|
||||
{
|
||||
Ptr<NoCount> p = Create<NoCount> (cb);
|
||||
{
|
||||
Ptr<NoCount const> p1 = p;
|
||||
}
|
||||
raw = GetPointer (p);
|
||||
p = 0;
|
||||
}
|
||||
if (m_nDestroyed != 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
delete raw;
|
||||
}
|
||||
|
||||
|
||||
m_nDestroyed = 0;
|
||||
{
|
||||
Ptr<NoCount> p = Create<NoCount> (cb);
|
||||
const NoCount *v1 = PeekPointer (p);
|
||||
NoCount *v2 = PeekPointer (p);
|
||||
v1->Nothing ();
|
||||
v2->Nothing ();
|
||||
}
|
||||
if (m_nDestroyed != 1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
{
|
||||
Ptr<Object> p0 = Create<NoCount> (cb);
|
||||
Ptr<NoCount> p1 = Create<NoCount> (cb);
|
||||
if (p0 == p1)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
if (p0 != p1)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Ptr<NoCount> p = Create<NoCount> (cb);
|
||||
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
|
||||
callback ();
|
||||
}
|
||||
{
|
||||
Ptr<const NoCount> p = Create<NoCount> (cb);
|
||||
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
|
||||
callback ();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// as expected, fails compilation.
|
||||
{
|
||||
Ptr<const Object> p = Create<NoCount> (cb);
|
||||
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
PtrTest g_ptr_test;
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user