Compare commits
704
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4eb0fb1b6 | ||
|
|
1a792daaa3 | ||
|
|
34e13e9802 | ||
|
|
3813f1c9ee | ||
|
|
3dc9fd0b82 | ||
|
|
c0c089314b | ||
|
|
9f6a7d97bc | ||
|
|
0bba81df36 | ||
|
|
2377ada11a | ||
|
|
b7e72c3a0a | ||
|
|
c1d4837b6f | ||
|
|
bc0e617e48 | ||
|
|
5bafd2c7c4 | ||
|
|
13d582abec | ||
|
|
d82134b850 | ||
|
|
ebc20f6000 | ||
|
|
fdc0645d77 | ||
|
|
e1cf4ba46a | ||
|
|
6bead9b6de | ||
|
|
f3bc3ae906 | ||
|
|
a158370ecb | ||
|
|
34b2b57831 | ||
|
|
1f237abbf1 | ||
|
|
3a2339a1b4 | ||
|
|
1752159ae0 | ||
|
|
4995bf960d | ||
|
|
c68b2e8a46 | ||
|
|
c29eb7f50e | ||
|
|
9d283adac4 | ||
|
|
b93fb6c831 | ||
|
|
8f290fc884 | ||
|
|
cb27d91658 | ||
|
|
9cec699867 | ||
|
|
d656aff913 | ||
|
|
22974904d3 | ||
|
|
69857c37c2 | ||
|
|
feeb918ea8 | ||
|
|
13ff259ec8 | ||
|
|
cb6551e96f | ||
|
|
56c68a364a | ||
|
|
51cf75c8f0 | ||
|
|
854866f424 | ||
|
|
32f7eac7cd | ||
|
|
5ab4cf83d9 | ||
|
|
f3ee808927 | ||
|
|
97f26a2618 | ||
|
|
e89118e8be | ||
|
|
fb034219ef | ||
|
|
cf9e1c7789 | ||
|
|
5a897699cf | ||
|
|
18c2b29e41 | ||
|
|
f7d2050f70 | ||
|
|
8e53127d0a | ||
|
|
2feb4596a9 | ||
|
|
6598fb0881 | ||
|
|
a499aa230f | ||
|
|
4bd4f71f60 | ||
|
|
a4abfb010f | ||
|
|
380668b6e2 | ||
|
|
606d5ddc9e | ||
|
|
24be073413 | ||
|
|
759db61b84 | ||
|
|
6c8c2a0b9c | ||
|
|
c88d2d4a61 | ||
|
|
cf1d0c0286 | ||
|
|
f689c7944b | ||
|
|
a6f637a166 | ||
|
|
df1dc6590c | ||
|
|
55d83d449d | ||
|
|
d8315bf75b | ||
|
|
7890a9f26d | ||
|
|
eb7b7abbee | ||
|
|
1402fa153d | ||
|
|
6be9387a4f | ||
|
|
9aafc2a086 | ||
|
|
57113d1369 | ||
|
|
07f2e2f516 | ||
|
|
f190cfa470 | ||
|
|
5153338a18 | ||
|
|
cb425e83e4 | ||
|
|
d214881326 | ||
|
|
5e4a02fe9e | ||
|
|
859a69e349 | ||
|
|
115ea63ecf | ||
|
|
17a7001ae9 | ||
|
|
9d491024ac | ||
|
|
13839ac94a | ||
|
|
602c3aaa56 | ||
|
|
47c343b9f2 | ||
|
|
73b4980eb6 | ||
|
|
25d9728d2f | ||
|
|
9d727857dc | ||
|
|
5f59607a8a | ||
|
|
b3a23ca711 | ||
|
|
075bb7dac4 | ||
|
|
14b391842b | ||
|
|
65c494acf0 | ||
|
|
a6bd7da559 | ||
|
|
b31206e87e | ||
|
|
2cae8cacf0 | ||
|
|
2840dbc868 | ||
|
|
0dc3cb1788 | ||
|
|
9222f3665b | ||
|
|
08b91c8d4e | ||
|
|
a6dec22caa | ||
|
|
03f45d2bb6 | ||
|
|
a809858c53 | ||
|
|
284bd626fd | ||
|
|
16916ae20a | ||
|
|
a681a24c22 | ||
|
|
14e71f0fe8 | ||
|
|
c6a65ad55e | ||
|
|
17c172ba6b | ||
|
|
cf7db2fd83 | ||
|
|
b7703adb88 | ||
|
|
1d12d2fe4e | ||
|
|
3626b59818 | ||
|
|
fa2aa50d8d | ||
|
|
0a71dd3a00 | ||
|
|
3dade00499 | ||
|
|
2d83a86255 | ||
|
|
c707948105 | ||
|
|
78ddcabcd0 | ||
|
|
8a05c7fd2a | ||
|
|
1b077f6028 | ||
|
|
50a6af341d | ||
|
|
77d0bfdaf0 | ||
|
|
2bdf60c4e8 | ||
|
|
6ecc3f8141 | ||
|
|
d3ae85dbad | ||
|
|
97e33024f2 | ||
|
|
19779d861e | ||
|
|
99a7ce1363 | ||
|
|
b8bd5ee965 | ||
|
|
77cddbc978 | ||
|
|
c38219e208 | ||
|
|
48b4587eee | ||
|
|
3ad49db6ea | ||
|
|
feddc3c054 | ||
|
|
9120cee21d | ||
|
|
97ab201be7 | ||
|
|
39465c218d | ||
|
|
00e32fede9 | ||
|
|
f392b8ff44 | ||
|
|
90290c5664 | ||
|
|
2849fd45f0 | ||
|
|
e271260c49 | ||
|
|
edb69c4375 | ||
|
|
dfbeda2f10 | ||
|
|
fbdd5cec13 | ||
|
|
8b663a9528 | ||
|
|
d29a5dab89 | ||
|
|
16cbadb47a | ||
|
|
774071c8d5 | ||
|
|
d27841b7d5 | ||
|
|
bc59dd0075 | ||
|
|
096f86a311 | ||
|
|
9be9980011 | ||
|
|
eef49a922e | ||
|
|
28181320e8 | ||
|
|
a4e6ec3155 | ||
|
|
5e1124ccac | ||
|
|
7570e778e4 | ||
|
|
6eb1ac9b49 | ||
|
|
f48d0809f0 | ||
|
|
e1bdc08302 | ||
|
|
407d569821 | ||
|
|
3c0c035609 | ||
|
|
5ba7dfc10f | ||
|
|
a46d41df0e | ||
|
|
922330b1e0 | ||
|
|
bce3cb528b | ||
|
|
7015694293 | ||
|
|
69692abf50 | ||
|
|
32e7609edf | ||
|
|
d47cd63b1b | ||
|
|
f59e58f202 | ||
|
|
5200904303 | ||
|
|
dda258af14 | ||
|
|
3e7fc83c12 | ||
|
|
f84bac5a7a | ||
|
|
f4cfed1a61 | ||
|
|
9f8b10e350 | ||
|
|
04d5ce685d | ||
|
|
952d6fd3d7 | ||
|
|
b53fe6444b | ||
|
|
a4d7fe0f22 | ||
|
|
457f135980 | ||
|
|
d657d53eea | ||
|
|
359135cfb2 | ||
|
|
4f8dd96fbf | ||
|
|
812d615717 | ||
|
|
e4b2238b33 | ||
|
|
1705744468 | ||
|
|
c0822fa4a5 | ||
|
|
7b8e797c32 | ||
|
|
9c33b90fd3 | ||
|
|
5f35f64d9a | ||
|
|
a3148081ce | ||
|
|
782a1d1621 | ||
|
|
67f797f9a3 | ||
|
|
21e0193e5c | ||
|
|
e34a2825f1 | ||
|
|
45898d2215 | ||
|
|
bd72431945 | ||
|
|
87fc0f8d6f | ||
|
|
981db808cb | ||
|
|
1cb619e63b | ||
|
|
ded17426c6 | ||
|
|
e4d745d41f | ||
|
|
43bb2315ea | ||
|
|
3bdc1decf6 | ||
|
|
30c37ab9bf | ||
|
|
c14a8acf39 | ||
|
|
971d9621ce | ||
|
|
3406dc9742 | ||
|
|
85a36632a7 | ||
|
|
7a36ac7d9d | ||
|
|
057d149fda | ||
|
|
7003e0bc66 | ||
|
|
3cf75dc10b | ||
|
|
068a71d6f0 | ||
|
|
0064c1dd91 | ||
|
|
cdf7845986 | ||
|
|
8dc473a724 | ||
|
|
6f09ab6cde | ||
|
|
cfb1a315ed | ||
|
|
63086448bf | ||
|
|
47456e7d98 | ||
|
|
b922c8891c | ||
|
|
9e5b8af1f5 | ||
|
|
6a88b5f435 | ||
|
|
d9c520bed9 | ||
|
|
d214744ab8 | ||
|
|
2a58815ee3 | ||
|
|
3f94ec31f3 | ||
|
|
e0bae0f64b | ||
|
|
fdcbb4d0ef | ||
|
|
acd00876f9 | ||
|
|
d7b44c817d | ||
|
|
4d82692800 | ||
|
|
56a741f29a | ||
|
|
17d1849dec | ||
|
|
003357899d | ||
|
|
de33245d9f | ||
|
|
26667e16df | ||
|
|
d5e89e8c7d | ||
|
|
c9b5e018ed | ||
|
|
02a0e0fbe3 | ||
|
|
92e4ea53ba | ||
|
|
494a955b56 | ||
|
|
332783b3e5 | ||
|
|
d96744d968 | ||
|
|
85244373f9 | ||
|
|
75306351ff | ||
|
|
3d2049fbc1 | ||
|
|
0c3e57b399 | ||
|
|
15b5505e01 | ||
|
|
97a010178c | ||
|
|
5cc706c8cb | ||
|
|
0e13e1e2e2 | ||
|
|
0c84164fd0 | ||
|
|
a6f2d245d7 | ||
|
|
8ce09032ff | ||
|
|
b49313db62 | ||
|
|
167040a677 | ||
|
|
3160a3f820 | ||
|
|
3257af2823 | ||
|
|
f2bfb44a4a | ||
|
|
8215a3ada6 | ||
|
|
4738f15594 | ||
|
|
00d39fda3c | ||
|
|
78ef901f24 | ||
|
|
3f9234b2cf | ||
|
|
0c63c63ed7 | ||
|
|
69b63dcdd4 | ||
|
|
41aba10d3d | ||
|
|
4253885f23 | ||
|
|
59769b1864 | ||
|
|
52ae3296bd | ||
|
|
bb734df9f6 | ||
|
|
bc79bd63c7 | ||
|
|
6daf2a39f5 | ||
|
|
22fba35327 | ||
|
|
84dd4ca348 | ||
|
|
b8d1fc7562 | ||
|
|
6d1c1c320b | ||
|
|
4b89a6e943 | ||
|
|
afb2059377 | ||
|
|
4e837f8d12 | ||
|
|
b5eee2066b | ||
|
|
0804f5dd1f | ||
|
|
847de408cb | ||
|
|
b5220706c6 | ||
|
|
38fb251c44 | ||
|
|
60b7d51063 | ||
|
|
085b9e3a6f | ||
|
|
cfe81d5098 | ||
|
|
042a331582 | ||
|
|
ac238f29be | ||
|
|
f940ae70f2 | ||
|
|
f54d0301c6 | ||
|
|
88043fcbe8 | ||
|
|
06a1eab063 | ||
|
|
a907980840 | ||
|
|
c25737cd9a | ||
|
|
84d3adcd6c | ||
|
|
a997d29622 | ||
|
|
c8f17e51ed | ||
|
|
c0a5a39a4f | ||
|
|
01bbd09ed8 | ||
|
|
15902efdef | ||
|
|
00a3c9dc86 | ||
|
|
8ca138de13 | ||
|
|
a5765d647b | ||
|
|
2642cd250b | ||
|
|
b15276f90e | ||
|
|
6126547e53 | ||
|
|
b8eebcb4aa | ||
|
|
79a92089e7 | ||
|
|
27b3854eb7 | ||
|
|
bbace1de47 | ||
|
|
4e1b6eee32 | ||
|
|
849e12a068 | ||
|
|
90015991bc | ||
|
|
bb6146ef74 | ||
|
|
6028619f71 | ||
|
|
fc2e13d58d | ||
|
|
944f38bb49 | ||
|
|
b347b7f189 | ||
|
|
6837d4f732 | ||
|
|
0ba6d64e5a | ||
|
|
2d49175d6e | ||
|
|
84d62cbbc6 | ||
|
|
7b0071e6a9 | ||
|
|
a5a3a87ae0 | ||
|
|
cb76686ecc | ||
|
|
0d82d0459c | ||
|
|
2760adcb80 | ||
|
|
f748a4e9e2 | ||
|
|
84c65c0546 | ||
|
|
9ac95d3c1c | ||
|
|
68ab43d8b7 | ||
|
|
0b0a71d801 | ||
|
|
1816d4b190 | ||
|
|
3b0815486e | ||
|
|
dbb6b3e119 | ||
|
|
8a1f170ea6 | ||
|
|
83be1dae4b | ||
|
|
08e96316be | ||
|
|
8eb5f8f3ed | ||
|
|
46afec48ec | ||
|
|
43ff2a9254 | ||
|
|
7744a4a298 | ||
|
|
f32ca897c5 | ||
|
|
221f53bb6f | ||
|
|
9f3973e7b7 | ||
|
|
7d8695d9e7 | ||
|
|
3f21e58a58 | ||
|
|
6eb0271fae | ||
|
|
33a24e8e8f | ||
|
|
16a3adfafc | ||
|
|
f4056d0242 | ||
|
|
9ae8857bce | ||
|
|
a94f3676c3 | ||
|
|
fe0580cb55 | ||
|
|
6f6ef012cb | ||
|
|
5c1bb36ae9 | ||
|
|
8d61c037a7 | ||
|
|
1cce2a3014 | ||
|
|
73bcad33b9 | ||
|
|
22db53973d | ||
|
|
38c7d9e6d7 | ||
|
|
8eda682a18 | ||
|
|
a3c9ddb21c | ||
|
|
acca18ae12 | ||
|
|
77911ccc73 | ||
|
|
c19408ddf2 | ||
|
|
e5eebad6d2 | ||
|
|
8fd15e628a | ||
|
|
b283f52c78 | ||
|
|
f03d4796d7 | ||
|
|
6fc57a69fa | ||
|
|
5d3e481956 | ||
|
|
f995f382ec | ||
|
|
cad76b6242 | ||
|
|
0d97692b40 | ||
|
|
78e32b0ee2 | ||
|
|
6bd6d0b50a | ||
|
|
bfea575095 | ||
|
|
fe4fce3a3f | ||
|
|
185ab29325 | ||
|
|
21f22e692f | ||
|
|
da89fa5a9f | ||
|
|
d2ea2350ad | ||
|
|
4f5cdcf421 | ||
|
|
d396b61ba1 | ||
|
|
1586aff97b | ||
|
|
9fcf123b19 | ||
|
|
635bf20ef5 | ||
|
|
f6af4f8913 | ||
|
|
1d62e62bc0 | ||
|
|
89c0ea0621 | ||
|
|
2fb3e8e3fe | ||
|
|
63b67e2b23 | ||
|
|
1a25a6edd0 | ||
|
|
2fe3af0577 | ||
|
|
ecdbe5f2a6 | ||
|
|
f7bf4093be | ||
|
|
084b79553f | ||
|
|
e38e261ae6 | ||
|
|
918e5d451e | ||
|
|
7a294d49ab | ||
|
|
d695801754 | ||
|
|
26cbdbd904 | ||
|
|
6fd1e7e5ef | ||
|
|
36e5429622 | ||
|
|
58ba3f9429 | ||
|
|
970f648843 | ||
|
|
8f803f292e | ||
|
|
05dd4441b0 | ||
|
|
1fbdb54f85 | ||
|
|
f9858fdd1a | ||
|
|
fab9e0de46 | ||
|
|
1d7fef5810 | ||
|
|
f0dfb33292 | ||
|
|
04262d9c84 | ||
|
|
056815ea8b | ||
|
|
215fd0b6d9 | ||
|
|
9954007722 | ||
|
|
ea47bde02e | ||
|
|
c344304026 | ||
|
|
1f481fa1a3 | ||
|
|
88a062de78 | ||
|
|
19e2e6d858 | ||
|
|
c31080d470 | ||
|
|
b47247dad9 | ||
|
|
8a84773fdb | ||
|
|
55e21b9e17 | ||
|
|
7d30d8556a | ||
|
|
64d99f21eb | ||
|
|
1b65ca1900 | ||
|
|
3409cd399d | ||
|
|
3206565bac | ||
|
|
32dab97321 | ||
|
|
7003c609b8 | ||
|
|
16320cd28b | ||
|
|
406deb5971 | ||
|
|
38b24c7b94 | ||
|
|
530cf00d68 | ||
|
|
465056e9c6 | ||
|
|
91f6ee0c72 | ||
|
|
b859031855 | ||
|
|
81a9a86305 | ||
|
|
7f566dd0e5 | ||
|
|
65800d22e7 | ||
|
|
4cb74319f9 | ||
|
|
3aba7548f4 | ||
|
|
593887c8d0 | ||
|
|
0e4a1f112d | ||
|
|
18739c4ac1 | ||
|
|
947192570d | ||
|
|
2a00194316 | ||
|
|
9137e9e2ae | ||
|
|
890afe9d85 | ||
|
|
d0e276f66a | ||
|
|
5e8755c774 | ||
|
|
037f4ab4b6 | ||
|
|
f15058ab06 | ||
|
|
c34d167b91 | ||
|
|
b4a5acd890 | ||
|
|
a88911105c | ||
|
|
7ee00fb680 | ||
|
|
c29c0b01a7 | ||
|
|
9db735958c | ||
|
|
57cda13f7b | ||
|
|
2a73f35ce6 | ||
|
|
aaa58a6c10 | ||
|
|
52fa45c6ee | ||
|
|
934f5055ab | ||
|
|
26c82ca131 | ||
|
|
52555b06d4 | ||
|
|
e21b3f3dc4 | ||
|
|
ee400b5235 | ||
|
|
e273333fba | ||
|
|
6d932e83d2 | ||
|
|
ae889380da | ||
|
|
a7f9a29e74 | ||
|
|
a6350d9395 | ||
|
|
6c13562d23 | ||
|
|
00dc91423e | ||
|
|
ac767aad0f | ||
|
|
89567d3b31 | ||
|
|
dcdf6212cc | ||
|
|
c5f651f014 | ||
|
|
a274292b93 | ||
|
|
d3ac777f7b | ||
|
|
ecc45cbc7e | ||
|
|
1b4ba050cc | ||
|
|
5f47aa6140 | ||
|
|
89c4cca866 | ||
|
|
27bdd1a325 | ||
|
|
6db5ce1912 | ||
|
|
91e1d7ce48 | ||
|
|
97210d5b15 | ||
|
|
436f3bd9fe | ||
|
|
7de0444d06 | ||
|
|
7c7951391c | ||
|
|
6e21cdb13f | ||
|
|
67019110d7 | ||
|
|
9a00fabed7 | ||
|
|
c05918c860 | ||
|
|
f40551a061 | ||
|
|
d8205106cc | ||
|
|
cffb4e5bce | ||
|
|
3495b8009c | ||
|
|
c143afea10 | ||
|
|
c69f9210d9 | ||
|
|
043c50147c | ||
|
|
e94804bd48 | ||
|
|
e342e8de70 | ||
|
|
c06746182b | ||
|
|
fc6515d2f7 | ||
|
|
3d1eb091c0 | ||
|
|
bf6acd5cc9 | ||
|
|
737c43cdad | ||
|
|
0fc97486ff | ||
|
|
e0edc4c06d | ||
|
|
0a5e5e2fa5 | ||
|
|
8527f86de4 | ||
|
|
6459e64f36 | ||
|
|
25c6ce41d5 | ||
|
|
cbc8e947bf | ||
|
|
0dba01018c | ||
|
|
b5aa7f58e8 | ||
|
|
64567bb12a | ||
|
|
58320f7156 | ||
|
|
5ad19febad | ||
|
|
88f5f7392b | ||
|
|
4260241659 | ||
|
|
231ddd7508 | ||
|
|
cf0f3ce319 | ||
|
|
aaa5dd3a00 | ||
|
|
a269f47bc7 | ||
|
|
9685cc5682 | ||
|
|
2f741327e6 | ||
|
|
8c39bf0b9f | ||
|
|
e0fa33b2a0 | ||
|
|
fc02186460 | ||
|
|
2af9ca368b | ||
|
|
0cc125c365 | ||
|
|
36b22256c1 | ||
|
|
fbe8efea55 | ||
|
|
2e526d70d2 | ||
|
|
06d6ba666d | ||
|
|
37175489ca | ||
|
|
9ddf1b5c26 | ||
|
|
217384025e | ||
|
|
29b4128397 | ||
|
|
331ade75da | ||
|
|
d243d71bf5 | ||
|
|
5b3feb6008 | ||
|
|
d7631279f7 | ||
|
|
f5409d434a | ||
|
|
1c2c6c45e2 | ||
|
|
b30863e0e2 | ||
|
|
13ad4b7a42 | ||
|
|
9f6ca60f74 | ||
|
|
dbef6dc8e2 | ||
|
|
3248205bb7 | ||
|
|
09cf13cd9f | ||
|
|
8ff0a86e18 | ||
|
|
b9420cf0c1 | ||
|
|
340d5533ea | ||
|
|
e7258ffa88 | ||
|
|
dd8f66140b | ||
|
|
15e98b00f5 | ||
|
|
759993b922 | ||
|
|
7f35843d58 | ||
|
|
f2420fc7a3 | ||
|
|
811c010098 | ||
|
|
67f30273dd | ||
|
|
352fc82185 | ||
|
|
9ede5bd312 | ||
|
|
e3cf285ee7 | ||
|
|
f9f7cf35ae | ||
|
|
b660b4c9c0 | ||
|
|
029401f6cc | ||
|
|
9f5b01dfd8 | ||
|
|
38f4ce9f25 | ||
|
|
9cff779038 | ||
|
|
02b73f5705 | ||
|
|
2570f3ec4f | ||
|
|
dcffdaafb5 | ||
|
|
80f9fcdaa1 | ||
|
|
71d12148c8 | ||
|
|
d23de8b9ef | ||
|
|
4a4ccfe7d6 | ||
|
|
5149320e5b | ||
|
|
cb27ea8185 | ||
|
|
ae04d34c17 | ||
|
|
b84e6743be | ||
|
|
5b43f9a74d | ||
|
|
581cf00ee8 | ||
|
|
a49a1abf12 | ||
|
|
3978c92af1 | ||
|
|
221b6fec69 | ||
|
|
ff10da6575 | ||
|
|
af9aa366fd | ||
|
|
a6de4290c8 | ||
|
|
8d843148d2 | ||
|
|
05cc50ae37 | ||
|
|
b260017fec | ||
|
|
8a4c29e8db | ||
|
|
fde3f54d67 | ||
|
|
cf0db02ced | ||
|
|
25a84074ab | ||
|
|
891f47bcfa | ||
|
|
d41d6077ce | ||
|
|
3d1874af59 | ||
|
|
6ca6cf7474 | ||
|
|
67079664ae | ||
|
|
f5aee94f15 | ||
|
|
2879779804 | ||
|
|
b184e5324d | ||
|
|
ff920303df | ||
|
|
e0d71b0bc0 | ||
|
|
ab49745afe | ||
|
|
ace83ac938 | ||
|
|
75142a10be | ||
|
|
b84bd3a8c4 | ||
|
|
cafae24473 | ||
|
|
cc7bee7d80 | ||
|
|
6602b3b179 | ||
|
|
4f1afaca16 | ||
|
|
d72f092052 | ||
|
|
8744c97a4d | ||
|
|
df846e5904 | ||
|
|
eee53aa5d5 | ||
|
|
f3410d8c59 | ||
|
|
4846f37117 | ||
|
|
39a79be5ae | ||
|
|
fef73e4b86 | ||
|
|
2c5a01a67d | ||
|
|
58d479cd4a | ||
|
|
305529410b | ||
|
|
150b80deee | ||
|
|
280d7dde50 | ||
|
|
8509398137 | ||
|
|
42388d6c08 | ||
|
|
ffe8bbb8aa | ||
|
|
330136a89e | ||
|
|
bb9102f7d4 | ||
|
|
4310d505a7 | ||
|
|
d5fe0cf158 | ||
|
|
9360623853 | ||
|
|
e6f0e91590 | ||
|
|
dd7e5da016 | ||
|
|
459cf197b7 | ||
|
|
073da60b19 | ||
|
|
4370fde844 | ||
|
|
965f23dd61 | ||
|
|
72cee94646 | ||
|
|
bc9ed49a55 | ||
|
|
6db75f0bd2 | ||
|
|
4100646192 | ||
|
|
3152abac67 | ||
|
|
9aac873415 | ||
|
|
da3ba96430 | ||
|
|
809462490f | ||
|
|
498373dd01 | ||
|
|
c64d30aeff | ||
|
|
5c47597be9 | ||
|
|
6d8ee7acc9 | ||
|
|
cde37ad608 | ||
|
|
c5401494fe | ||
|
|
65caf20092 | ||
|
|
ca25d72064 | ||
|
|
f22ebaf7f1 | ||
|
|
f35a5a9b08 | ||
|
|
f68f378a23 | ||
|
|
8717e87046 | ||
|
|
0de23a29c5 | ||
|
|
6c4a67af0d | ||
|
|
35120ea2f1 | ||
|
|
eee7b97d7b | ||
|
|
762912d711 | ||
|
|
bd916ad7fc | ||
|
|
4c3e6b89a1 | ||
|
|
8c0500fd97 | ||
|
|
da93f1fd0c | ||
|
|
57df288f5b | ||
|
|
52e8540a86 | ||
|
|
077df8fbb6 | ||
|
|
8728a25f1d | ||
|
|
d5134a7cd4 | ||
|
|
47ab029798 | ||
|
|
ed89ccc521 | ||
|
|
16aabbcc3b | ||
|
|
9c7c79f2eb | ||
|
|
a044be7ed9 | ||
|
|
2d6d5637c0 | ||
|
|
5b8a2b2128 | ||
|
|
abb307c9c5 |
No files matched your search
+29
-8
@@ -1,8 +1,29 @@
|
||||
.DS*
|
||||
.waf-1*
|
||||
.waf3-*
|
||||
.lock*
|
||||
**/*.pyc
|
||||
build/
|
||||
VERSION
|
||||
unit-tests.conf
|
||||
# Emacs
|
||||
*~
|
||||
\#*\#
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
*.elc
|
||||
.\#*
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
._*
|
||||
|
||||
# Waf build system
|
||||
/build/
|
||||
.waf-*-*/
|
||||
.waf3-*-*/
|
||||
.lock-waf*
|
||||
|
||||
# Compiled python code
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# Other
|
||||
/VERSION.info
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "websocketpp"]
|
||||
path = websocketpp
|
||||
url = https://github.com/zaphoyd/websocketpp.git
|
||||
url = https://github.com/cawka/websocketpp.git
|
||||
@@ -1,10 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
source .jenkins.d/util.sh
|
||||
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
export CACHE_DIR=${CACHE_DIR:-/tmp}
|
||||
export WAF_JOBS=${WAF_JOBS:-1}
|
||||
[[ $JOB_NAME == *"code-coverage" ]] && export DISABLE_ASAN=yes
|
||||
|
||||
for file in "$DIR"/.jenkins.d/*; do
|
||||
nanos() {
|
||||
# Cannot use date(1) because macOS does not support %N format specifier
|
||||
python3 -c 'import time; print(int(time.time() * 1e9))'
|
||||
}
|
||||
|
||||
for file in .jenkins.d/*; do
|
||||
[[ -f $file && -x $file ]] || continue
|
||||
echo "Run: $file"
|
||||
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/')
|
||||
echo -ne "travis_fold:start:${label}\r"
|
||||
echo -ne "travis_time:start:${label}\r"
|
||||
start=$(nanos)
|
||||
fi
|
||||
|
||||
echo "\$ $file"
|
||||
"$file"
|
||||
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
finish=$(nanos)
|
||||
echo -ne "travis_time:end:${label}:start=${start},finish=${finish},duration=$((finish-start)),event=${label}\r"
|
||||
echo -ne "travis_fold:end:${label}\r"
|
||||
fi
|
||||
done
|
||||
+33
-21
@@ -1,29 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
set -ex
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
if has OSX-10.8 $NODE_LABELS; then
|
||||
EXTRA_FLAGS=--c++11
|
||||
FORMULAE=(boost openssl pkg-config)
|
||||
if has OSX-10.13 $NODE_LABELS || has OSX-10.14 $NODE_LABELS; then
|
||||
FORMULAE+=(python)
|
||||
fi
|
||||
|
||||
set -x
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install boost pkg-config cryptopp $EXTRA_FLAGS
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
if has Ubuntu $NODE_LABELS; then
|
||||
BOOST_PKG=libboost-all-dev
|
||||
if has Ubuntu-12.04 $NODE_LABELS; then
|
||||
BOOST_PKG=libboost1.48-all-dev
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
# Travis images come with a large number of pre-installed
|
||||
# brew packages, don't waste time upgrading all of them
|
||||
brew list --versions "${FORMULAE[@]}" || brew update
|
||||
for FORMULA in "${FORMULAE[@]}"; do
|
||||
brew list --versions "$FORMULA" || brew install "$FORMULA"
|
||||
done
|
||||
# Ensure /usr/local/opt/openssl exists
|
||||
brew reinstall openssl
|
||||
else
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install "${FORMULAE[@]}"
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
set -x
|
||||
sudo apt-get update -qq -y
|
||||
sudo apt-get -qq -y install build-essential pkg-config $BOOST_PKG \
|
||||
libcrypto++-dev libsqlite3-dev libpcap-dev
|
||||
elif has Ubuntu $NODE_LABELS; then
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qy install build-essential pkg-config python3-minimal \
|
||||
libboost-all-dev libssl-dev libsqlite3-dev \
|
||||
libpcap-dev libsystemd-dev
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
sudo apt-get -qy install gcovr lcov
|
||||
fi
|
||||
|
||||
elif has CentOS-8 $NODE_LABELS; then
|
||||
sudo dnf config-manager --enable PowerTools
|
||||
sudo dnf -y install gcc-c++ libasan pkgconf-pkg-config python3 \
|
||||
boost-devel openssl-devel sqlite-devel \
|
||||
libpcap-devel systemd-devel
|
||||
fi
|
||||
+40
-27
@@ -1,42 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
pushd "$CACHE_DIR" >/dev/null
|
||||
|
||||
pushd /tmp >/dev/null
|
||||
|
||||
INSTALLED_VERSION=$((cd ndn-cxx && git rev-parse HEAD) 2>/dev/null || echo NONE)
|
||||
|
||||
sudo rm -Rf ndn-cxx-latest
|
||||
|
||||
git clone --depth 1 git://github.com/named-data/ndn-cxx ndn-cxx-latest
|
||||
|
||||
LATEST_VERSION=$((cd ndn-cxx-latest && git rev-parse HEAD) 2>/dev/null || echo UNKNOWN)
|
||||
|
||||
if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then
|
||||
sudo rm -Rf ndn-cxx
|
||||
mv ndn-cxx-latest ndn-cxx
|
||||
else
|
||||
sudo rm -Rf ndn-cxx-latest
|
||||
INSTALLED_VERSION=
|
||||
if has OSX $NODE_LABELS; then
|
||||
BOOST=$(brew ls --versions boost)
|
||||
OLD_BOOST=$(cat boost.txt || :)
|
||||
if [[ $OLD_BOOST != $BOOST ]]; then
|
||||
echo "$BOOST" > boost.txt
|
||||
INSTALLED_VERSION=NONE
|
||||
fi
|
||||
fi
|
||||
|
||||
sudo rm -Rf /usr/local/include/ndn-cxx
|
||||
sudo rm -f /usr/local/lib/libndn-cxx*
|
||||
sudo rm -f /usr/local/lib/pkgconfig/libndn-cxx*
|
||||
if [[ -z $INSTALLED_VERSION ]]; then
|
||||
INSTALLED_VERSION=$(git -C ndn-cxx rev-parse HEAD 2>/dev/null || echo NONE)
|
||||
fi
|
||||
|
||||
sudo rm -rf ndn-cxx-latest
|
||||
git clone --depth 1 https://github.com/named-data/ndn-cxx.git ndn-cxx-latest
|
||||
LATEST_VERSION=$(git -C ndn-cxx-latest rev-parse HEAD 2>/dev/null || echo UNKNOWN)
|
||||
|
||||
if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then
|
||||
sudo rm -rf ndn-cxx
|
||||
mv ndn-cxx-latest ndn-cxx
|
||||
else
|
||||
sudo rm -rf ndn-cxx-latest
|
||||
fi
|
||||
|
||||
sudo rm -f /usr/local/bin/ndnsec*
|
||||
sudo rm -fr /usr/local/include/ndn-cxx
|
||||
sudo rm -f /usr/local/lib{,64}/libndn-cxx*
|
||||
sudo rm -f /usr/local/lib{,64}/pkgconfig/libndn-cxx.pc
|
||||
|
||||
pushd ndn-cxx >/dev/null
|
||||
|
||||
./waf configure -j1 --color=yes --enable-shared --disable-static --without-osx-keychain
|
||||
./waf -j1 --color=yes
|
||||
sudo ./waf install -j1 --color=yes
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
|
||||
PCH="--without-pch"
|
||||
fi
|
||||
|
||||
./waf --color=yes configure --disable-static --enable-shared --without-osx-keychain $PCH
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
sudo_preserve_env PATH -- ./waf --color=yes install
|
||||
|
||||
popd >/dev/null
|
||||
popd >/dev/null
|
||||
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
|
||||
fi
|
||||
if has Linux $NODE_LABELS; then
|
||||
sudo ldconfig
|
||||
elif has FreeBSD $NODE_LABELS; then
|
||||
sudo ldconfig -a
|
||||
fi
|
||||
+29
-23
@@ -1,35 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
git submodule init
|
||||
git submodule sync
|
||||
git submodule update
|
||||
git submodule update --init
|
||||
|
||||
COVERAGE=$( python -c "print '--with-coverage' if 'code-coverage' in '$JOB_NAME' else ''" )
|
||||
if [[ -z $DISABLE_ASAN ]]; then
|
||||
ASAN="--with-sanitizer=address"
|
||||
fi
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
fi
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
|
||||
PCH="--without-pch"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
|
||||
# Build in release mode with tests and without precompiled headers
|
||||
./waf --color=yes configure --with-tests --without-pch
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# Configure/build in debug mode
|
||||
./waf -j1 --color=yes configure --with-tests --debug
|
||||
./waf -j1 --color=yes build
|
||||
# Cleanup
|
||||
./waf --color=yes distclean
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
# Build in release mode without tests, but with "other tests"
|
||||
./waf --color=yes configure --with-other-tests $PCH
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# Configure/build in optimized mode without tests with precompiled headers
|
||||
./waf -j1 --color=yes configure
|
||||
./waf -j1 --color=yes build
|
||||
# Cleanup
|
||||
./waf --color=yes distclean
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
# Build in debug mode with tests
|
||||
./waf --color=yes configure --debug --with-tests $ASAN $COVERAGE $PCH
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# Configure/build in optimized mode
|
||||
./waf -j1 --color=yes configure --with-tests --without-pch $COVERAGE
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# (tests will be run against optimized version)
|
||||
# (tests will be run against the debug version)
|
||||
|
||||
# Install
|
||||
sudo ./waf -j1 --color=yes install
|
||||
sudo_preserve_env PATH -- ./waf --color=yes install
|
||||
+35
-24
@@ -1,34 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
# Prepare environment
|
||||
rm -Rf ~/.ndnx ~/.ndn
|
||||
rm -rf ~/.ndn
|
||||
|
||||
echo $NODE_LABELS
|
||||
IS_OSX=$( python -c "print 'yes' if 'OSX' in '$NODE_LABELS'.strip().split(' ') else 'no'" )
|
||||
IS_LINUX=$( python -c "print 'yes' if 'Linux' in '$NODE_LABELS'.strip().split(' ') else 'no'" )
|
||||
|
||||
if [[ $IS_OSX == "yes" ]]; then
|
||||
security unlock-keychain -p "named-data"
|
||||
sudo chgrp admin /dev/bpf*
|
||||
sudo chmod g+rw /dev/bpf*
|
||||
fi
|
||||
if [[ $IS_LINUX = "yes" ]]; then
|
||||
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-core || true
|
||||
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-daemon || true
|
||||
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-rib || true
|
||||
if has OSX $NODE_LABELS; then
|
||||
security unlock-keychain -p named-data
|
||||
fi
|
||||
|
||||
ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
|
||||
|
||||
# Run unit tests
|
||||
# Core
|
||||
./build/unit-tests-core -l test_suite
|
||||
sudo ./build/unit-tests-core -t TestPrivilegeHelper -l test_suite
|
||||
# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
|
||||
ASAN_OPTIONS="color=always"
|
||||
ASAN_OPTIONS+=":check_initialization_order=1"
|
||||
ASAN_OPTIONS+=":detect_stack_use_after_return=1"
|
||||
ASAN_OPTIONS+=":strict_init_order=1"
|
||||
ASAN_OPTIONS+=":strict_string_checks=1"
|
||||
ASAN_OPTIONS+=":detect_invalid_pointer_pairs=2"
|
||||
ASAN_OPTIONS+=":detect_container_overflow=0"
|
||||
ASAN_OPTIONS+=":detect_leaks=0"
|
||||
ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
|
||||
export ASAN_OPTIONS
|
||||
|
||||
# Daemon
|
||||
./build/unit-tests-daemon -l test_suite
|
||||
export BOOST_TEST_BUILD_INFO=1
|
||||
export BOOST_TEST_COLOR_OUTPUT=1
|
||||
export BOOST_TEST_DETECT_MEMORY_LEAK=0
|
||||
|
||||
# RIB
|
||||
./build/unit-tests-rib -l test_suite
|
||||
ut_log_args() {
|
||||
echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-log${1:+-$1}.xml
|
||||
}
|
||||
|
||||
# First run all tests as unprivileged user
|
||||
./build/unit-tests-core $(ut_log_args core)
|
||||
./build/unit-tests-daemon $(ut_log_args daemon)
|
||||
./build/unit-tests-rib $(ut_log_args rib)
|
||||
./build/unit-tests-tools $(ut_log_args tools)
|
||||
|
||||
# Then use sudo to run those tests that need superuser powers
|
||||
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
|
||||
./build/unit-tests-daemon -t TestPrivilegeHelper $(ut_log_args daemon-privilege-helper)
|
||||
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
|
||||
./build/unit-tests-daemon -t Face/*Ethernet* $(ut_log_args daemon-ethernet)
|
||||
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
|
||||
./build/unit-tests-daemon -t Face/TestUdpFactory $(ut_log_args daemon-udp)
|
||||
@@ -1,10 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
IS_COVR=$( python -c "print 'yes' if 'code-coverage' in '$JOB_NAME' else 'no'" )
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
gcovr --object-directory=build \
|
||||
--output=build/coverage.xml \
|
||||
--exclude="$PWD/(tests|websocketpp)" \
|
||||
--root=. \
|
||||
--xml
|
||||
|
||||
if [[ $IS_COVR == "yes" ]]; then
|
||||
BASE="`pwd | sed -e 's|/|\\\/|g'`\\"
|
||||
(cd build && gcovr -x -f $BASE/core -f $BASE/daemon -f $BASE/rib -r ../ -o coverage.xml ./)
|
||||
# Generate also a detailed HTML output, but using lcov (better results)
|
||||
lcov --quiet \
|
||||
--capture \
|
||||
--directory . \
|
||||
--no-external \
|
||||
--rc lcov_branch_coverage=1 \
|
||||
--output-file build/coverage-with-tests-and-websocketpp.info
|
||||
|
||||
lcov --quiet \
|
||||
--remove build/coverage-with-tests-and-websocketpp.info "$PWD/websocketpp/*" \
|
||||
--rc lcov_branch_coverage=1 \
|
||||
--output-file build/coverage-with-tests.info
|
||||
|
||||
lcov --quiet \
|
||||
--remove build/coverage-with-tests.info "$PWD/tests/*" \
|
||||
--rc lcov_branch_coverage=1 \
|
||||
--output-file build/coverage.info
|
||||
|
||||
genhtml --branch-coverage \
|
||||
--demangle-cpp \
|
||||
--legend \
|
||||
--output-directory build/coverage \
|
||||
--title "NFD unit tests" \
|
||||
build/coverage.info
|
||||
fi
|
||||
+18
-20
@@ -1,30 +1,28 @@
|
||||
CONTINUOUS INTEGRATION SCRIPTS
|
||||
==============================
|
||||
# CONTINUOUS INTEGRATION SCRIPTS
|
||||
|
||||
Environment Variables Used in Build Scripts
|
||||
-------------------------------------------
|
||||
## Environment Variables Used in Build Scripts
|
||||
|
||||
- `NODE_LABELS`: the variable defines a list of OS properties. The set values are used by the
|
||||
build scripts to select proper behavior for different OS.
|
||||
- `NODE_LABELS`: space-separated list of platform properties. The included values are used by
|
||||
the build scripts to select the proper behavior for different operating systems and versions.
|
||||
|
||||
The list should include at least `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
The list should normally contain `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
|
||||
Possible values for Linux OS:
|
||||
Example values:
|
||||
|
||||
* `[OS_TYPE]`: `Linux`
|
||||
* `[DISTRO_TYPE]`: `Ubuntu`
|
||||
* `[DISTRO_VERSION]`: `Ubuntu-12.04`, `Ubuntu-14.04`, `Ubuntu-15.04`
|
||||
- `[OS_TYPE]`: `Linux`, `OSX`
|
||||
- `[DISTRO_TYPE]`: `Ubuntu`, `CentOS`
|
||||
- `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`, `CentOS-8`, `OSX-10.14`, `OSX-10.15`
|
||||
|
||||
Possible values of OSX OS:
|
||||
|
||||
* `[OS_TYPE]`: `OSX`
|
||||
* `[DISTRO_TYPE]`: `OSX` (can be absent)
|
||||
* `[DISTRO_VERSION]`: `OSX-10.10`, `OSX-10.9`, `OSX-10.8`, `OSX-10.7`
|
||||
|
||||
- `JOB_NAME`: optional variable to define type of the job. Depending on the defined job type,
|
||||
- `JOB_NAME`: optional variable that defines the type of build job. Depending on the job type,
|
||||
the build scripts can perform different tasks.
|
||||
|
||||
Possible values:
|
||||
|
||||
* empty: default build process
|
||||
* `code-coverage` (Linux OS is assumed): build process with code coverage analysis
|
||||
- empty: default build task
|
||||
- `code-coverage`: debug build with tests and code coverage analysis (Ubuntu Linux is assumed)
|
||||
- `limited-build`: only a single debug build with tests
|
||||
|
||||
- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled version
|
||||
of ndn-cxx. If not set, `/tmp` is used.
|
||||
|
||||
- `WAF_JOBS`: number of parallel build threads used by waf, defaults to 1.
|
||||
+34
-4
@@ -1,9 +1,39 @@
|
||||
has() {
|
||||
local saved_xtrace
|
||||
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
|
||||
set +x
|
||||
|
||||
local p=$1
|
||||
shift
|
||||
local x
|
||||
for x in "$@"; do
|
||||
[[ "${x}" == "${p}" ]] && return 0
|
||||
local i ret=1
|
||||
for i in "$@"; do
|
||||
if [[ "${i}" == "${p}" ]]; then
|
||||
ret=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
|
||||
set ${saved_xtrace}
|
||||
return ${ret}
|
||||
}
|
||||
export -f has
|
||||
|
||||
sudo_preserve_env() {
|
||||
local saved_xtrace
|
||||
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
|
||||
set +x
|
||||
|
||||
local vars=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
local arg=$1
|
||||
shift
|
||||
case ${arg} in
|
||||
--) break ;;
|
||||
*) vars+=("${arg}=${!arg}") ;;
|
||||
esac
|
||||
done
|
||||
|
||||
set ${saved_xtrace}
|
||||
sudo env "${vars[@]}" "$@"
|
||||
}
|
||||
export -f sudo_preserve_env
|
||||
@@ -0,0 +1,14 @@
|
||||
<aa@cs.fiu.edu> <alexander.afanasyev@ucla.edu>
|
||||
<davidepesa@gmail.com> <davide.pesavento@lip6.fr>
|
||||
<enewberry@email.arizona.edu> <enewberry@cs.arizona.edu>
|
||||
Vince Lehman <vslehman@memphis.edu> <vlehman1@gmail.com>
|
||||
<lybmath2009@gmail.com> <lybmath@ucla.edu>
|
||||
Hila Ben Abraham <hilata@gmail.com>
|
||||
<tuyukai1994@gmail.com> <tyk@bupt.edu.cn>
|
||||
Haowei Yuan <hyuan@wustl.edu>
|
||||
Minsheng Zhang <jimmyzms5@gmail.com>
|
||||
Spyridon Mastorakis <spiros.mastorakis@gmail.com>
|
||||
Md Ashiqur Rahman <marahman@email.arizona.edu>
|
||||
Yumin Xia <me@yumin-xia.com>
|
||||
<chghasemi@cs.arizona.edu> <chavoosh.ghasemi@gmail.com>
|
||||
Tai-Lin Chu <tailinchu@gmail.com>
|
||||
+112
-12
@@ -1,15 +1,115 @@
|
||||
sudo: true
|
||||
version: ~> 1.0
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
compiler:
|
||||
- gcc
|
||||
notifications:
|
||||
email:
|
||||
on_success: always
|
||||
on_failure: always
|
||||
os: linux
|
||||
dist: bionic
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
#- arm64 # Too slow, exceeds time limit
|
||||
#- ppc64le # Fails transport tests
|
||||
#- s390x # Fails transport tests
|
||||
|
||||
env:
|
||||
- COMPILER=g++-7
|
||||
- COMPILER=g++-9
|
||||
- COMPILER=clang++-6.0
|
||||
- COMPILER=clang++-9
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# Linux
|
||||
- env: COMPILER=g++-5
|
||||
- env: COMPILER=g++-6
|
||||
- env: COMPILER=g++-8
|
||||
- env: COMPILER=clang++-4.0
|
||||
- env: COMPILER=clang++-5.0
|
||||
- env: COMPILER=clang++-7
|
||||
- env: COMPILER=clang++-8
|
||||
- env: COMPILER=clang++-10
|
||||
- env: COMPILER=clang++-11
|
||||
- env: COMPILER=clang++-12
|
||||
|
||||
# macOS
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode10.3
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode11.3
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode11.6
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode12
|
||||
env: # default compiler
|
||||
|
||||
allow_failures:
|
||||
- env: COMPILER=g++-5
|
||||
- env: COMPILER=g++-6
|
||||
- env: COMPILER=clang++-4.0
|
||||
- env: COMPILER=clang++-12
|
||||
|
||||
fast_finish: true
|
||||
|
||||
before_install:
|
||||
- |
|
||||
: Adding apt repositories
|
||||
case ${COMPILER} in
|
||||
g++-9)
|
||||
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages
|
||||
travis_retry sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
travis_retry sudo apt-get -qq update
|
||||
;;
|
||||
clang++-1?)
|
||||
# https://apt.llvm.org/
|
||||
LLVM_REPO=${COMPILER/clang++/llvm-toolchain-${TRAVIS_DIST}}
|
||||
travis_retry wget -nv -O - "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add -
|
||||
travis_retry sudo add-apt-repository -y "deb http://apt.llvm.org/${TRAVIS_DIST}/ ${LLVM_REPO%-12} main"
|
||||
travis_retry sudo apt-get -qq update
|
||||
;;
|
||||
esac
|
||||
|
||||
install:
|
||||
- |
|
||||
: Installing C++ compiler
|
||||
if [[ -n ${COMPILER} ]]; then
|
||||
travis_retry sudo apt-get -qy install ${COMPILER/clang++/clang}
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- |
|
||||
: Setting environment variables
|
||||
if [[ -n ${COMPILER} ]]; then
|
||||
export CXX=${COMPILER}
|
||||
fi
|
||||
case ${TRAVIS_OS_NAME} in
|
||||
linux) export NODE_LABELS="Linux Ubuntu Ubuntu-18.04" ;;
|
||||
osx) export NODE_LABELS="OSX OSX-$(sw_vers -productVersion | cut -d . -f -2)" ;;
|
||||
esac
|
||||
export JOB_NAME=limited-build
|
||||
export WAF_JOBS=2
|
||||
- |
|
||||
: Enabling workarounds
|
||||
case "${TRAVIS_CPU_ARCH},${COMPILER}" in
|
||||
ppc64le,g++-7)
|
||||
# AddressSanitizer does not seem to be working
|
||||
export DISABLE_ASAN=yes
|
||||
;;
|
||||
*,clang++-8)
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=40808
|
||||
export DISABLE_ASAN=yes
|
||||
;;
|
||||
esac
|
||||
if [[ ${TRAVIS_OS_NAME} == linux ]]; then
|
||||
sudo sysctl -e -w net.ipv6.conf.all.disable_ipv6=0
|
||||
fi
|
||||
- ${CXX:-c++} --version
|
||||
|
||||
script:
|
||||
- if [[ $TRAVIS_OS_NAME == linux ]]; then export NODE_LABELS="Linux Ubuntu Ubuntu-12.04"; fi
|
||||
- if [[ $TRAVIS_OS_NAME == osx ]]; then export NODE_LABELS="OSX OSX-10.10"; fi
|
||||
- echo $NODE_LABELS
|
||||
- ./.jenkins
|
||||
@@ -1,23 +0,0 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
#
|
||||
# Copyright (c) 2014, Regents of the University of California
|
||||
#
|
||||
# GPL 3.0 license, see the COPYING.md file for more information
|
||||
|
||||
from waflib import Configure
|
||||
|
||||
BOOST_ASIO_HAS_KQUEUE_CHECK = '''
|
||||
#include <boost/asio.hpp>
|
||||
#if defined(BOOST_ASIO_HAS_KQUEUE) and BOOST_VERSION == 105600
|
||||
#error "Ethernet face support cannot be enabled on this platform with boost 1.56"
|
||||
#endif
|
||||
'''
|
||||
|
||||
@Configure.conf
|
||||
def check_asio_pcap_support(conf):
|
||||
# https://svn.boost.org/trac/boost/ticket/10367
|
||||
if conf.check_cxx(msg='Checking if Ethernet face support can be enabled',
|
||||
fragment=BOOST_ASIO_HAS_KQUEUE_CHECK,
|
||||
features='cxx', use='BOOST', mandatory=False):
|
||||
conf.define('HAVE_ASIO_PCAP_SUPPORT', 1)
|
||||
conf.env['HAVE_ASIO_PCAP_SUPPORT'] = True
|
||||
+252
-97
@@ -30,15 +30,15 @@ When using this tool, the wscript will look like:
|
||||
|
||||
Options are generated, in order to specify the location of boost includes/libraries.
|
||||
The `check_boost` configuration function allows to specify the used boost libraries.
|
||||
It can also provide default arguments to the --boost-static and --boost-mt command-line arguments.
|
||||
It can also provide default arguments to the --boost-mt command-line arguments.
|
||||
Everything will be packaged together in a BOOST component that you can use.
|
||||
|
||||
When using MSVC, a lot of compilation flags need to match your BOOST build configuration:
|
||||
- you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined.
|
||||
Errors: C4530
|
||||
- boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC
|
||||
So before calling `conf.check_boost` you might want to disabling by adding:
|
||||
conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
|
||||
So before calling `conf.check_boost` you might want to disabling by adding
|
||||
conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
|
||||
Errors:
|
||||
- boost might also be compiled with /MT, which links the runtime statically.
|
||||
If you have problems with redefined symbols,
|
||||
@@ -52,24 +52,60 @@ import sys
|
||||
import re
|
||||
from waflib import Utils, Logs, Errors
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import feature, after_method
|
||||
|
||||
BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib']
|
||||
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']
|
||||
|
||||
BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib', '/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', '/usr/local/ndn/lib']
|
||||
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include', '/usr/local/ndn/include']
|
||||
BOOST_VERSION_FILE = 'boost/version.hpp'
|
||||
BOOST_VERSION_CODE = '''
|
||||
#include <iostream>
|
||||
#include <boost/version.hpp>
|
||||
int main() { std::cout << BOOST_LIB_VERSION << ":" << BOOST_VERSION << std::endl; }
|
||||
'''
|
||||
BOOST_SYSTEM_CODE = '''
|
||||
|
||||
BOOST_ERROR_CODE = '''
|
||||
#include <boost/system/error_code.hpp>
|
||||
int main() { boost::system::error_code c; }
|
||||
'''
|
||||
|
||||
PTHREAD_CODE = '''
|
||||
#include <pthread.h>
|
||||
static void* f(void*) { return 0; }
|
||||
int main() {
|
||||
pthread_t th;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&th, &attr, &f, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_cleanup_push(0, 0);
|
||||
pthread_cleanup_pop(0);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
'''
|
||||
|
||||
BOOST_THREAD_CODE = '''
|
||||
#include <boost/thread.hpp>
|
||||
int main() { boost::thread t; }
|
||||
'''
|
||||
|
||||
BOOST_LOG_CODE = '''
|
||||
#include <boost/log/trivial.hpp>
|
||||
int main() { BOOST_LOG_TRIVIAL(info) << "boost_log is working"; }
|
||||
'''
|
||||
|
||||
BOOST_LOG_SETUP_CODE = '''
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
int main() {
|
||||
using namespace boost::log;
|
||||
add_common_attributes();
|
||||
add_console_log(std::clog, keywords::format = "%Message%");
|
||||
BOOST_LOG_TRIVIAL(info) << "boost_log_setup is working";
|
||||
}
|
||||
'''
|
||||
|
||||
# toolsets from {boost_dir}/tools/build/v2/tools/common.jam
|
||||
PLATFORM = Utils.unversioned_sys_platform()
|
||||
detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il'
|
||||
@@ -101,34 +137,37 @@ BOOST_TOOLSETS = {
|
||||
|
||||
def options(opt):
|
||||
opt = opt.add_option_group('Boost Options')
|
||||
|
||||
opt.add_option('--boost-includes', type='string',
|
||||
default='', dest='boost_includes',
|
||||
help='''path to the directory where the boost includes are, e.g., /path/to/boost_1_55_0/stage/include''')
|
||||
help='''path to the directory where the boost includes are,
|
||||
e.g., /path/to/boost_1_55_0/stage/include''')
|
||||
opt.add_option('--boost-libs', type='string',
|
||||
default='', dest='boost_libs',
|
||||
help='''path to the directory where the boost libs are, e.g., /path/to/boost_1_55_0/stage/lib''')
|
||||
opt.add_option('--boost-static', action='store_true',
|
||||
default=False, dest='boost_static',
|
||||
help='link with static boost libraries (.lib/.a)')
|
||||
help='''path to the directory where the boost libs are,
|
||||
e.g., path/to/boost_1_55_0/stage/lib''')
|
||||
opt.add_option('--boost-mt', action='store_true',
|
||||
default=False, dest='boost_mt',
|
||||
help='select multi-threaded libraries')
|
||||
opt.add_option('--boost-abi', type='string', default='', dest='boost_abi',
|
||||
help='''select libraries with tags (dgsyp, d for debug), see doc Boost, Getting Started, chapter 6.1''')
|
||||
opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect',
|
||||
help='''select libraries with tags (gd for debug, static is automatically added),
|
||||
see doc Boost, Getting Started, chapter 6.1''')
|
||||
opt.add_option('--boost-linkage_autodetect', action='store_true', dest='boost_linkage_autodetect',
|
||||
help="auto-detect boost linkage options (don't get used to it / might break other stuff)")
|
||||
opt.add_option('--boost-toolset', type='string',
|
||||
default='', dest='boost_toolset',
|
||||
help='force a toolset e.g. msvc, vc90, gcc, mingw, mgw45 (default: auto)')
|
||||
help='force a toolset e.g. msvc, vc90, \
|
||||
gcc, mingw, mgw45 (default: auto)')
|
||||
py_version = '%d%d' % (sys.version_info[0], sys.version_info[1])
|
||||
opt.add_option('--boost-python', type='string',
|
||||
default=py_version, dest='boost_python',
|
||||
help='select the lib python with this version (default: %s)' % py_version)
|
||||
help='select the lib python with this version \
|
||||
(default: %s)' % py_version)
|
||||
|
||||
|
||||
@conf
|
||||
def __boost_get_version_file(self, d):
|
||||
if not d:
|
||||
return None
|
||||
dnode = self.root.find_dir(d)
|
||||
if dnode:
|
||||
return dnode.find_node(BOOST_VERSION_FILE)
|
||||
@@ -141,33 +180,30 @@ def boost_get_version(self, d):
|
||||
if node:
|
||||
try:
|
||||
txt = node.read()
|
||||
except (OSError, IOError):
|
||||
Logs.error("Could not read the file %r" % node.abspath())
|
||||
except EnvironmentError:
|
||||
Logs.error('Could not read the file %r' % node.abspath())
|
||||
else:
|
||||
re_but1 = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.+)"', re.M)
|
||||
m1 = re_but1.search(txt)
|
||||
|
||||
re_but2 = re.compile('^#define\\s+BOOST_VERSION\\s+(\\d+)', re.M)
|
||||
m2 = re_but2.search(txt)
|
||||
|
||||
if m1 and m2:
|
||||
return (m1.group(1), m2.group(1))
|
||||
|
||||
return self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[d], execute=True, define_ret=True).split(":")
|
||||
return self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[d], execute=True, define_ret=True).split(':')
|
||||
|
||||
@conf
|
||||
def boost_get_includes(self, *k, **kw):
|
||||
includes = k and k[0] or kw.get('includes', None)
|
||||
if includes and self.__boost_get_version_file(includes):
|
||||
return includes
|
||||
for d in Utils.to_list(self.environ.get('INCLUDE', '')) + BOOST_INCLUDES:
|
||||
for d in self.environ.get('INCLUDE', '').split(';') + BOOST_INCLUDES:
|
||||
if self.__boost_get_version_file(d):
|
||||
return d
|
||||
if includes:
|
||||
self.end_msg('headers not found in %s' % includes)
|
||||
self.end_msg('headers not found in %s' % includes, 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
self.end_msg('headers not found, please provide a --boost-includes argument (see help)')
|
||||
self.end_msg('headers not found, please provide a --boost-includes argument (see help)', 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
|
||||
|
||||
@@ -195,7 +231,9 @@ def __boost_get_libs_path(self, *k, **kw):
|
||||
path = self.root.find_dir(libs)
|
||||
files = path.ant_glob('*boost_*')
|
||||
if not libs or not files:
|
||||
for d in Utils.to_list(self.environ.get('LIB', [])) + BOOST_LIBS:
|
||||
for d in self.environ.get('LIB', '').split(';') + BOOST_LIBS:
|
||||
if not d:
|
||||
continue
|
||||
path = self.root.find_dir(d)
|
||||
if path:
|
||||
files = path.ant_glob('*boost_*')
|
||||
@@ -208,10 +246,10 @@ def __boost_get_libs_path(self, *k, **kw):
|
||||
break
|
||||
if not path:
|
||||
if libs:
|
||||
self.end_msg('libs not found in %s' % libs)
|
||||
self.end_msg('libs not found in %s' % libs, 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
self.end_msg('libs not found, please provide a --boost-libs argument (see help)')
|
||||
self.end_msg('libs not found, please provide a --boost-libs argument (see help)', 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
|
||||
self.to_log('Found the boost path in %r with the libraries:' % path)
|
||||
@@ -226,15 +264,10 @@ def boost_get_libs(self, *k, **kw):
|
||||
according to the parameters
|
||||
'''
|
||||
path, files = self.__boost_get_libs_path(**kw)
|
||||
t = []
|
||||
if kw.get('mt', False):
|
||||
t.append('mt')
|
||||
if kw.get('abi', None):
|
||||
t.append(kw['abi'])
|
||||
tags = t and '(-%s)+' % '-'.join(t) or ''
|
||||
files = sorted(files, key=lambda f: (len(f.name), f.name), reverse=True)
|
||||
toolset = self.boost_get_toolset(kw.get('toolset', ''))
|
||||
toolset_pat = '(-%s[0-9]{0,3})+' % toolset
|
||||
version = '(-%s)+' % self.env.BOOST_VERSION
|
||||
toolset_pat = '(-%s[0-9]{0,3})' % toolset
|
||||
version = '-%s' % self.env.BOOST_VERSION
|
||||
|
||||
def find_lib(re_lib, files):
|
||||
for file in files:
|
||||
@@ -248,28 +281,109 @@ def boost_get_libs(self, *k, **kw):
|
||||
name = name[3:]
|
||||
return name[:name.rfind('.')]
|
||||
|
||||
libs = []
|
||||
for lib in Utils.to_list(k and k[0] or kw.get('lib', None)):
|
||||
py = (lib == 'python') and '(-py%s)+' % kw['python'] or ''
|
||||
# Trying libraries, from most strict match to least one
|
||||
for pattern in ['boost_%s%s%s%s%s' % (lib, toolset_pat, tags, py, version),
|
||||
'boost_%s%s%s%s' % (lib, tags, py, version),
|
||||
'boost_%s%s%s' % (lib, tags, version),
|
||||
# Give up trying to find the right version
|
||||
'boost_%s%s%s%s' % (lib, toolset_pat, tags, py),
|
||||
'boost_%s%s%s' % (lib, tags, py),
|
||||
'boost_%s%s' % (lib, tags)]:
|
||||
self.to_log('Trying pattern %s' % pattern)
|
||||
file = find_lib(re.compile(pattern), files)
|
||||
if file:
|
||||
libs.append(format_lib_name(file.name))
|
||||
break
|
||||
else:
|
||||
self.end_msg('lib %s not found in %s' % (lib, path.abspath()))
|
||||
self.fatal('The configuration failed')
|
||||
def match_libs(lib_names, is_static):
|
||||
libs = []
|
||||
lib_names = Utils.to_list(lib_names)
|
||||
if not lib_names:
|
||||
return libs
|
||||
t = []
|
||||
if kw.get('mt', False):
|
||||
t.append('-mt')
|
||||
if kw.get('abi', None):
|
||||
t.append('%s%s' % (is_static and '-s' or '-', kw['abi']))
|
||||
elif is_static:
|
||||
t.append('-s')
|
||||
tags_pat = t and ''.join(t) or ''
|
||||
ext = is_static and self.env.cxxstlib_PATTERN or self.env.cxxshlib_PATTERN
|
||||
ext = ext.partition('%s')[2] # remove '%s' or 'lib%s' from PATTERN
|
||||
|
||||
return path.abspath(), libs
|
||||
for lib in lib_names:
|
||||
if lib == 'python':
|
||||
# for instance, with python='27',
|
||||
# accepts '-py27', '-py2', '27' and '2'
|
||||
# but will reject '-py3', '-py26', '26' and '3'
|
||||
tags = '({0})?((-py{2})|(-py{1}(?=[^0-9]))|({2})|({1}(?=[^0-9]))|(?=[^0-9])(?!-py))'.format(tags_pat, kw['python'][0], kw['python'])
|
||||
else:
|
||||
tags = tags_pat
|
||||
# Trying libraries, from most strict match to least one
|
||||
for pattern in ['boost_%s%s%s%s%s$' % (lib, toolset_pat, tags, version, ext),
|
||||
'boost_%s%s%s%s$' % (lib, tags, version, ext),
|
||||
# Give up trying to find the right version
|
||||
'boost_%s%s%s%s$' % (lib, toolset_pat, tags, ext),
|
||||
'boost_%s%s%s$' % (lib, tags, ext),
|
||||
'boost_%s%s$' % (lib, ext),
|
||||
'boost_%s' % lib]:
|
||||
self.to_log('Trying pattern %s' % pattern)
|
||||
file = find_lib(re.compile(pattern), files)
|
||||
if file:
|
||||
libs.append(format_lib_name(file.name))
|
||||
break
|
||||
else:
|
||||
self.end_msg('lib %s not found in %s' % (lib, path.abspath()), 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
return libs
|
||||
|
||||
return path.abspath(), match_libs(kw.get('lib', None), False), match_libs(kw.get('stlib', None), True)
|
||||
|
||||
@conf
|
||||
def _check_pthread_flag(self, *k, **kw):
|
||||
'''
|
||||
Computes which flags should be added to CXXFLAGS and LINKFLAGS to compile in multi-threading mode
|
||||
|
||||
Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3,
|
||||
boost/thread.hpp will trigger a #error if -pthread isn't used:
|
||||
boost/config/requires_threads.hpp:47:5: #error "Compiler threading support
|
||||
is not turned on. Please set the correct command line options for
|
||||
threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)"
|
||||
|
||||
Based on _BOOST_PTHREAD_FLAG(): https://github.com/tsuna/boost.m4/blob/master/build-aux/boost.m4
|
||||
'''
|
||||
|
||||
var = kw.get('uselib_store', 'BOOST')
|
||||
|
||||
self.start_msg('Checking the flags needed to use pthreads')
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
# (none): in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -lpthreads: AIX (must check this before -lpthread)
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads)
|
||||
# -pthreads: Solaris/GCC
|
||||
# -mthreads: MinGW32/GCC, Lynx/GCC
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# -lpthread: GNU Linux, etc.
|
||||
# --thread-safe: KAI C++
|
||||
if Utils.unversioned_sys_platform() == 'sunos':
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
boost_pthread_flags = ['-pthreads', '-lpthread', '-mt', '-pthread']
|
||||
else:
|
||||
boost_pthread_flags = ['', '-lpthreads', '-Kthread', '-kthread', '-llthread', '-pthread',
|
||||
'-pthreads', '-mthreads', '-lpthread', '--thread-safe', '-mt']
|
||||
|
||||
for boost_pthread_flag in boost_pthread_flags:
|
||||
try:
|
||||
self.env.stash()
|
||||
self.env['CXXFLAGS_%s' % var] += [boost_pthread_flag]
|
||||
self.env['LINKFLAGS_%s' % var] += [boost_pthread_flag]
|
||||
self.check_cxx(code=PTHREAD_CODE, msg=None, use=var, execute=False, quiet=True)
|
||||
self.end_msg(boost_pthread_flag)
|
||||
return
|
||||
except self.errors.ConfigurationError:
|
||||
self.env.revert()
|
||||
self.end_msg('none')
|
||||
|
||||
@conf
|
||||
def check_boost(self, *k, **kw):
|
||||
@@ -282,7 +396,10 @@ def check_boost(self, *k, **kw):
|
||||
if not self.env['CXX']:
|
||||
self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
|
||||
|
||||
params = {'lib': k and k[0] or kw.get('lib', None)}
|
||||
params = {
|
||||
'lib': k and k[0] or kw.get('lib', None),
|
||||
'stlib': kw.get('stlib', None)
|
||||
}
|
||||
for key, value in self.options.__dict__.items():
|
||||
if not key.startswith('boost_'):
|
||||
continue
|
||||
@@ -291,48 +408,70 @@ def check_boost(self, *k, **kw):
|
||||
|
||||
var = kw.get('uselib_store', 'BOOST')
|
||||
|
||||
self.start_msg('Checking boost includes')
|
||||
self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params)
|
||||
versions = self.boost_get_version(inc)
|
||||
self.env.BOOST_VERSION = versions[0]
|
||||
self.env.BOOST_VERSION_NUMBER = int(versions[1])
|
||||
self.end_msg("%d.%d.%d" % (int(versions[1]) / 100000,
|
||||
int(versions[1]) / 100 % 1000,
|
||||
int(versions[1]) % 100))
|
||||
if Logs.verbose:
|
||||
Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var])
|
||||
if not self.env.DONE_FIND_BOOST_COMMON:
|
||||
self.find_program('dpkg-architecture', var='DPKG_ARCHITECTURE', mandatory=False)
|
||||
if self.env.DPKG_ARCHITECTURE:
|
||||
deb_host_multiarch = self.cmd_and_log([self.env.DPKG_ARCHITECTURE[0], '-qDEB_HOST_MULTIARCH'])
|
||||
BOOST_LIBS.insert(0, '/usr/lib/%s' % deb_host_multiarch.strip())
|
||||
|
||||
if not params['lib']:
|
||||
self.start_msg('Checking boost includes')
|
||||
self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params)
|
||||
versions = self.boost_get_version(inc)
|
||||
self.env.BOOST_VERSION = versions[0]
|
||||
self.env.BOOST_VERSION_NUMBER = int(versions[1])
|
||||
self.end_msg('%d.%d.%d' % (int(versions[1]) / 100000,
|
||||
int(versions[1]) / 100 % 1000,
|
||||
int(versions[1]) % 100))
|
||||
if Logs.verbose:
|
||||
Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var])
|
||||
|
||||
self.env.DONE_FIND_BOOST_COMMON = True
|
||||
|
||||
if not params['lib'] and not params['stlib']:
|
||||
return
|
||||
if 'static' in kw or 'static' in params:
|
||||
Logs.warn('boost: static parameter is deprecated, use stlib instead.')
|
||||
self.start_msg('Checking boost libs')
|
||||
suffix = params.get('static', None) and 'ST' or ''
|
||||
path, libs = self.boost_get_libs(**params)
|
||||
self.env['%sLIBPATH_%s' % (suffix, var)] = [path]
|
||||
self.env['%sLIB_%s' % (suffix, var)] = libs
|
||||
self.end_msg('ok')
|
||||
path, libs, stlibs = self.boost_get_libs(**params)
|
||||
self.env['LIBPATH_%s' % var] = [path]
|
||||
self.env['STLIBPATH_%s' % var] = [path]
|
||||
self.env['LIB_%s' % var] = libs
|
||||
self.env['STLIB_%s' % var] = stlibs
|
||||
self.end_msg(' '.join(libs + stlibs))
|
||||
if Logs.verbose:
|
||||
Logs.pprint('CYAN', ' path : %s' % path)
|
||||
Logs.pprint('CYAN', ' libs : %s' % libs)
|
||||
Logs.pprint('CYAN', ' shared libs : %s' % libs)
|
||||
Logs.pprint('CYAN', ' static libs : %s' % stlibs)
|
||||
|
||||
def has_shlib(lib):
|
||||
return params['lib'] and lib in params['lib']
|
||||
def has_stlib(lib):
|
||||
return params['stlib'] and lib in params['stlib']
|
||||
def has_lib(lib):
|
||||
return has_shlib(lib) or has_stlib(lib)
|
||||
if has_lib('thread'):
|
||||
# not inside try_link to make check visible in the output
|
||||
self._check_pthread_flag(k, kw)
|
||||
|
||||
def try_link():
|
||||
if 'system' in params['lib']:
|
||||
self.check_cxx(
|
||||
fragment=BOOST_SYSTEM_CODE,
|
||||
use=var,
|
||||
execute=False,
|
||||
)
|
||||
if 'thread' in params['lib']:
|
||||
self.check_cxx(
|
||||
fragment=BOOST_THREAD_CODE,
|
||||
use=var,
|
||||
execute=False,
|
||||
)
|
||||
if has_lib('system'):
|
||||
self.check_cxx(fragment=BOOST_ERROR_CODE, use=var, execute=False)
|
||||
if has_lib('thread'):
|
||||
self.check_cxx(fragment=BOOST_THREAD_CODE, use=var, execute=False)
|
||||
if has_lib('log') or has_lib('log_setup'):
|
||||
if not has_lib('thread'):
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_LOG_NO_THREADS']
|
||||
if has_shlib('log') or has_shlib('log_setup'):
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_LOG_DYN_LINK']
|
||||
if has_lib('log_setup'):
|
||||
self.check_cxx(fragment=BOOST_LOG_SETUP_CODE, use=var, execute=False)
|
||||
else:
|
||||
self.check_cxx(fragment=BOOST_LOG_CODE, use=var, execute=False)
|
||||
|
||||
if params.get('linkage_autodetect', False):
|
||||
self.start_msg("Attempting to detect boost linkage flags")
|
||||
self.start_msg('Attempting to detect boost linkage flags')
|
||||
toolset = self.boost_get_toolset(kw.get('toolset', ''))
|
||||
if toolset in ['vc']:
|
||||
if toolset in ('vc',):
|
||||
# disable auto-linking feature, causing error LNK1181
|
||||
# because the code wants to be linked against
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
|
||||
@@ -352,27 +491,43 @@ def check_boost(self, *k, **kw):
|
||||
# we attempt to play with some known-to-work CXXFLAGS combinations
|
||||
for cxxflags in (['/MD', '/EHsc'], []):
|
||||
self.env.stash()
|
||||
self.env["CXXFLAGS_%s" % var] += cxxflags
|
||||
self.env['CXXFLAGS_%s' % var] += cxxflags
|
||||
try:
|
||||
try_link()
|
||||
self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var]))
|
||||
e = None
|
||||
self.end_msg('ok: winning cxxflags combination: %s' % (self.env['CXXFLAGS_%s' % var]))
|
||||
exc = None
|
||||
break
|
||||
except Errors.ConfigurationError as exc:
|
||||
except Errors.ConfigurationError as e:
|
||||
self.env.revert()
|
||||
e = exc
|
||||
exc = e
|
||||
|
||||
if e is not None:
|
||||
self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=e)
|
||||
if exc is not None:
|
||||
self.end_msg('Could not auto-detect boost linking flags combination, you may report it to boost.py author', ex=exc)
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
self.end_msg("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain")
|
||||
self.end_msg('Boost linkage flags auto-detection not implemented (needed ?) for this toolchain')
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
self.start_msg('Checking for boost linkage')
|
||||
try:
|
||||
try_link()
|
||||
except Errors.ConfigurationError as e:
|
||||
self.end_msg("Could not link against boost libraries using supplied options")
|
||||
self.end_msg('Could not link against boost libraries using supplied options', 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
self.end_msg('ok')
|
||||
|
||||
|
||||
@feature('cxx')
|
||||
@after_method('apply_link')
|
||||
def install_boost(self):
|
||||
if install_boost.done or not Utils.is_win32 or not self.bld.cmd.startswith('install'):
|
||||
return
|
||||
install_boost.done = True
|
||||
inst_to = getattr(self, 'install_path', '${BINDIR}')
|
||||
for lib in self.env.LIB_BOOST:
|
||||
try:
|
||||
file = self.bld.find_file(self.env.cxxshlib_PATTERN % lib, self.env.LIBPATH_BOOST)
|
||||
self.bld.install_files(inst_to, self.bld.root.find_node(file))
|
||||
except:
|
||||
continue
|
||||
install_boost.done = False
|
||||
@@ -1,63 +0,0 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
from waflib.Configure import conf
|
||||
|
||||
OVERRIDE = '''
|
||||
class Base
|
||||
{
|
||||
virtual void
|
||||
f(int a);
|
||||
};
|
||||
|
||||
class Derived : public Base
|
||||
{
|
||||
virtual void
|
||||
f(int a) override;
|
||||
};
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_override(self):
|
||||
self.check_cxx(msg='Checking for override specifier',
|
||||
fragment=OVERRIDE,
|
||||
define_name='HAVE_CXX_OVERRIDE',
|
||||
features='cxx', mandatory=False)
|
||||
|
||||
FINAL = '''
|
||||
class Base
|
||||
{
|
||||
virtual void
|
||||
f(int a);
|
||||
};
|
||||
|
||||
class Derived : public Base
|
||||
{
|
||||
virtual void
|
||||
f(int a) final;
|
||||
};
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_final(self):
|
||||
self.check_cxx(msg='Checking for final specifier on method',
|
||||
fragment=FINAL,
|
||||
define_name='HAVE_CXX_FINAL',
|
||||
features='cxx', mandatory=False)
|
||||
|
||||
CLASS_FINAL = '''
|
||||
class A final
|
||||
{
|
||||
};
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_class_final(self):
|
||||
self.check_cxx(msg='Checking for final specifier on class',
|
||||
fragment=CLASS_FINAL,
|
||||
define_name='HAVE_CXX_CLASS_FINAL',
|
||||
features='cxx', mandatory=False)
|
||||
|
||||
def configure(conf):
|
||||
conf.check_override()
|
||||
conf.check_final()
|
||||
conf.check_class_final()
|
||||
@@ -1,17 +1,15 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
#
|
||||
# Copyright (c) 2014, Regents of the University of California
|
||||
#
|
||||
# GPL 3.0 license, see the COPYING.md file for more information
|
||||
|
||||
from waflib import TaskGen
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage',
|
||||
help='''Set compiler flags for gcc to enable code coverage information''')
|
||||
opt.add_option('--with-coverage', action='store_true', default=False,
|
||||
help='Add compiler flags to enable code coverage information')
|
||||
|
||||
def configure(conf):
|
||||
if conf.options.with_coverage:
|
||||
if not conf.options.debug:
|
||||
conf.fatal('Code coverage flags require debug mode compilation (add --debug)')
|
||||
conf.check_cxx(cxxflags=['-fprofile-arcs', '-ftest-coverage', '-fPIC'],
|
||||
linkflags=['-fprofile-arcs'], uselib_store='GCOV', mandatory=True)
|
||||
|
||||
|
||||
@@ -1,46 +1,76 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
from waflib import Logs, Configure, Utils
|
||||
import platform
|
||||
from waflib import Configure, Logs, Utils
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--debug', '--with-debug', action='store_true', default=False, dest='debug',
|
||||
help='''Compile in debugging mode without optimizations (-O0 or -Og)''')
|
||||
opt.add_option('--debug', '--with-debug', action='store_true', default=False,
|
||||
help='Compile in debugging mode with minimal optimizations (-Og)')
|
||||
|
||||
def configure(conf):
|
||||
cxx = conf.env['CXX_NAME'] # CXX_NAME represents generic name of the compiler
|
||||
conf.start_msg('Checking C++ compiler version')
|
||||
|
||||
cxx = conf.env.CXX_NAME # generic name of the compiler
|
||||
ccver = tuple(int(i) for i in conf.env.CC_VERSION)
|
||||
ccverstr = '.'.join(conf.env.CC_VERSION)
|
||||
errmsg = ''
|
||||
warnmsg = ''
|
||||
if cxx == 'gcc':
|
||||
flags = GccFlags()
|
||||
if ccver < (5, 3, 0):
|
||||
errmsg = ('The version of gcc you are using is too old.\n'
|
||||
'The minimum supported gcc version is 7.4.0.')
|
||||
elif ccver < (7, 4, 0):
|
||||
warnmsg = ('Using a version of gcc older than 7.4.0 is not '
|
||||
'officially supported and may result in build failures.')
|
||||
conf.flags = GccFlags()
|
||||
elif cxx == 'clang':
|
||||
flags = ClangFlags()
|
||||
if Utils.unversioned_sys_platform() == 'darwin' and ccver < (9, 0, 0):
|
||||
errmsg = ('The version of Xcode you are using is too old.\n'
|
||||
'The minimum supported Xcode version is 9.0.')
|
||||
elif ccver < (4, 0, 0):
|
||||
errmsg = ('The version of clang you are using is too old.\n'
|
||||
'The minimum supported clang version is 4.0.')
|
||||
conf.flags = ClangFlags()
|
||||
else:
|
||||
flags = CompilerFlags()
|
||||
Logs.warn('The code has not yet been tested with %s compiler' % cxx)
|
||||
warnmsg = '%s compiler is unsupported' % cxx
|
||||
conf.flags = CompilerFlags()
|
||||
|
||||
areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
|
||||
if errmsg:
|
||||
conf.end_msg(ccverstr, color='RED')
|
||||
conf.fatal(errmsg)
|
||||
elif warnmsg:
|
||||
conf.end_msg(ccverstr, color='YELLOW')
|
||||
Logs.warn('WARNING: ' + warnmsg)
|
||||
else:
|
||||
conf.end_msg(ccverstr)
|
||||
|
||||
# General flags are always applied (e.g., selecting C++11 mode)
|
||||
generalFlags = flags.getGeneralFlags(conf)
|
||||
conf.areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
|
||||
|
||||
# General flags are always applied (e.g., selecting C++ language standard)
|
||||
generalFlags = conf.flags.getGeneralFlags(conf)
|
||||
conf.add_supported_cxxflags(generalFlags['CXXFLAGS'])
|
||||
conf.add_supported_linkflags(generalFlags['LINKFLAGS'])
|
||||
conf.env.DEFINES += generalFlags['DEFINES']
|
||||
|
||||
@Configure.conf
|
||||
def check_compiler_flags(conf):
|
||||
# Debug or optimized CXXFLAGS and LINKFLAGS are applied only if the
|
||||
# corresponding environment variables are not set.
|
||||
# DEFINES are always applied.
|
||||
if conf.options.debug:
|
||||
extraFlags = flags.getDebugFlags(conf)
|
||||
if areCustomCxxflagsPresent:
|
||||
extraFlags = conf.flags.getDebugFlags(conf)
|
||||
if conf.areCustomCxxflagsPresent:
|
||||
missingFlags = [x for x in extraFlags['CXXFLAGS'] if x not in conf.env.CXXFLAGS]
|
||||
if len(missingFlags) > 0:
|
||||
Logs.warn("Selected debug mode, but CXXFLAGS is set to a custom value '%s'"
|
||||
% " ".join(conf.env.CXXFLAGS))
|
||||
Logs.warn("Default flags '%s' are not activated" % " ".join(missingFlags))
|
||||
if missingFlags:
|
||||
Logs.warn('Selected debug mode, but CXXFLAGS is set to a custom value "%s"'
|
||||
% ' '.join(conf.env.CXXFLAGS))
|
||||
Logs.warn('Default flags "%s" will not be used' % ' '.join(missingFlags))
|
||||
else:
|
||||
extraFlags = flags.getOptimizedFlags(conf)
|
||||
extraFlags = conf.flags.getOptimizedFlags(conf)
|
||||
|
||||
if not areCustomCxxflagsPresent:
|
||||
if not conf.areCustomCxxflagsPresent:
|
||||
conf.add_supported_cxxflags(extraFlags['CXXFLAGS'])
|
||||
conf.add_supported_cxxflags(extraFlags['LINKFLAGS'])
|
||||
conf.add_supported_linkflags(extraFlags['LINKFLAGS'])
|
||||
|
||||
conf.env.DEFINES += extraFlags['DEFINES']
|
||||
|
||||
@@ -55,12 +85,13 @@ def add_supported_cxxflags(self, cxxflags):
|
||||
self.start_msg('Checking supported CXXFLAGS')
|
||||
|
||||
supportedFlags = []
|
||||
for flag in cxxflags:
|
||||
if self.check_cxx(cxxflags=['-Werror', flag], mandatory=False):
|
||||
supportedFlags += [flag]
|
||||
for flags in cxxflags:
|
||||
flags = Utils.to_list(flags)
|
||||
if self.check_cxx(cxxflags=['-Werror'] + flags, mandatory=False):
|
||||
supportedFlags += flags
|
||||
|
||||
self.end_msg(' '.join(supportedFlags))
|
||||
self.env.CXXFLAGS = supportedFlags + self.env.CXXFLAGS
|
||||
self.env.prepend_value('CXXFLAGS', supportedFlags)
|
||||
|
||||
@Configure.conf
|
||||
def add_supported_linkflags(self, linkflags):
|
||||
@@ -73,101 +104,124 @@ def add_supported_linkflags(self, linkflags):
|
||||
self.start_msg('Checking supported LINKFLAGS')
|
||||
|
||||
supportedFlags = []
|
||||
for flag in linkflags:
|
||||
if self.check_cxx(linkflags=['-Werror', flag], mandatory=False):
|
||||
supportedFlags += [flag]
|
||||
for flags in linkflags:
|
||||
flags = Utils.to_list(flags)
|
||||
if self.check_cxx(linkflags=['-Werror'] + flags, mandatory=False):
|
||||
supportedFlags += flags
|
||||
|
||||
self.end_msg(' '.join(supportedFlags))
|
||||
self.env.LINKFLAGS = supportedFlags + self.env.LINKFLAGS
|
||||
self.env.prepend_value('LINKFLAGS', supportedFlags)
|
||||
|
||||
|
||||
class CompilerFlags(object):
|
||||
def getCompilerVersion(self, conf):
|
||||
return tuple(int(i) for i in conf.env.CC_VERSION)
|
||||
|
||||
def getGeneralFlags(self, conf):
|
||||
"""Get dict {'CXXFLAGS':[...], LINKFLAGS:[...], DEFINES:[...]} that are always needed"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': []}
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in debug mode"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in debug mode"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['_DEBUG']}
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in optimized mode"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in optimized mode"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['NDEBUG']}
|
||||
|
||||
class GccBasicFlags(CompilerFlags):
|
||||
"""
|
||||
This class defines basic flags that work for both gcc and clang compilers
|
||||
"""
|
||||
def getGeneralFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getGeneralFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-std=c++14']
|
||||
if Utils.unversioned_sys_platform() == 'linux':
|
||||
flags['LINKFLAGS'] += ['-fuse-ld=gold']
|
||||
elif Utils.unversioned_sys_platform() == 'freebsd':
|
||||
flags['LINKFLAGS'] += ['-fuse-ld=lld']
|
||||
return flags
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-pedantic',
|
||||
'-Wall',
|
||||
'-O0',
|
||||
flags['CXXFLAGS'] += ['-Og',
|
||||
'-g3',
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Werror',
|
||||
'-Wcatch-value=2',
|
||||
'-Wextra-semi',
|
||||
'-Wnon-virtual-dtor',
|
||||
'-Wno-error=deprecated-declarations', # Bug #3795
|
||||
'-Wno-error=maybe-uninitialized', # Bug #1615
|
||||
'-Wno-unused-parameter',
|
||||
]
|
||||
flags['LINKFLAGS'] += ['-Wl,-O1']
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-pedantic',
|
||||
'-Wall',
|
||||
'-O2',
|
||||
flags['CXXFLAGS'] += ['-O2',
|
||||
'-g',
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wcatch-value=2',
|
||||
'-Wextra-semi',
|
||||
'-Wnon-virtual-dtor',
|
||||
'-Wno-unused-parameter',
|
||||
]
|
||||
flags['LINKFLAGS'] += ['-Wl,-O1']
|
||||
return flags
|
||||
|
||||
class GccFlags(GccBasicFlags):
|
||||
def getGeneralFlags(self, conf):
|
||||
flags = super(GccFlags, self).getGeneralFlags(conf)
|
||||
version = tuple(int(i) for i in conf.env['CC_VERSION'])
|
||||
if version < (4, 6, 0):
|
||||
conf.fatal('The version of gcc you are using (%s) is too old.\n' %
|
||||
'.'.join(conf.env['CC_VERSION']) +
|
||||
'The minimum supported gcc version is 4.6.0.')
|
||||
elif version < (4, 7, 0):
|
||||
flags['CXXFLAGS'] += ['-std=c++0x']
|
||||
else:
|
||||
flags['CXXFLAGS'] += ['-std=c++11']
|
||||
if version < (4, 8, 0):
|
||||
flags['DEFINES'] += ['_GLIBCXX_USE_NANOSLEEP'] # Bug #2499
|
||||
return flags
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-Og', # gcc >= 4.8
|
||||
'-fdiagnostics-color', # gcc >= 4.9
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color',
|
||||
'-Wredundant-tags',
|
||||
]
|
||||
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(GccFlags, self).getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color'] # gcc >= 4.9
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color',
|
||||
'-Wredundant-tags',
|
||||
]
|
||||
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
|
||||
return flags
|
||||
|
||||
class ClangFlags(GccBasicFlags):
|
||||
def getGeneralFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getGeneralFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-std=c++11']
|
||||
if Utils.unversioned_sys_platform() == 'darwin':
|
||||
flags['CXXFLAGS'] += ['-stdlib=libc++']
|
||||
flags['LINKFLAGS'] += ['-stdlib=libc++']
|
||||
# Bug #4296
|
||||
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include'], # for Homebrew
|
||||
['-isystem', '/opt/local/include']] # for MacPorts
|
||||
elif Utils.unversioned_sys_platform() == 'freebsd':
|
||||
# Bug #4790
|
||||
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include']]
|
||||
return flags
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
|
||||
'-Wundefined-func-template',
|
||||
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
|
||||
'-Wno-error=unneeded-internal-declaration', # Bug #1588
|
||||
'-Wno-error=deprecated-register',
|
||||
'-Wno-error=keyword-macro', # Bug #3235
|
||||
]
|
||||
if self.getCompilerVersion(conf) < (6, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
|
||||
'-Wundefined-func-template',
|
||||
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
|
||||
]
|
||||
if self.getCompilerVersion(conf) < (6, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
|
||||
return flags
|
||||
@@ -4,10 +4,10 @@ from waflib import Options, Logs
|
||||
from waflib.Configure import conf
|
||||
|
||||
def addDependencyOptions(self, opt, name, extraHelp=''):
|
||||
opt.add_option('--with-%s' % name, type='string', default=None,
|
||||
dest='with_%s' % name,
|
||||
opt.add_option('--with-%s' % name, metavar='PATH',
|
||||
help='Path to %s, e.g., /usr/local %s' % (name, extraHelp))
|
||||
setattr(Options.OptionsContext, "addDependencyOptions", addDependencyOptions)
|
||||
|
||||
setattr(Options.OptionsContext, 'addDependencyOptions', addDependencyOptions)
|
||||
|
||||
@conf
|
||||
def checkDependency(self, name, **kw):
|
||||
@@ -18,8 +18,8 @@ def checkDependency(self, name, **kw):
|
||||
kw['mandatory'] = kw.get('mandatory', True)
|
||||
|
||||
if root:
|
||||
isOk = self.check_cxx(includes="%s/include" % root,
|
||||
libpath="%s/lib" % root,
|
||||
isOk = self.check_cxx(includes='%s/include' % root,
|
||||
libpath='%s/lib' % root,
|
||||
**kw)
|
||||
else:
|
||||
isOk = self.check_cxx(**kw)
|
||||
|
||||
@@ -85,7 +85,7 @@ class doxygen(Task.Task):
|
||||
|
||||
# Override with any parameters passed to the task generator
|
||||
if getattr(self.generator, 'pars', None):
|
||||
for k, v in self.generator.pars.iteritems():
|
||||
for k, v in self.generator.pars.items():
|
||||
self.pars[k] = v
|
||||
|
||||
self.doxy_inputs = getattr(self, 'doxy_inputs', [])
|
||||
|
||||
+5
-10
@@ -52,7 +52,7 @@ Note that precompiled header must have multiple inclusion guards. If the guards
|
||||
"""
|
||||
|
||||
import os
|
||||
from waflib import Task, TaskGen, Logs, Utils
|
||||
from waflib import Task, TaskGen, Utils
|
||||
from waflib.Tools import c_preproc, cxx
|
||||
|
||||
|
||||
@@ -67,11 +67,6 @@ def options(opt):
|
||||
|
||||
def configure(conf):
|
||||
if (conf.options.with_pch and conf.env['COMPILER_CXX'] in PCH_COMPILER_OPTIONS.keys()):
|
||||
if Utils.unversioned_sys_platform() == "darwin" and conf.env['CXX_NAME'] == 'clang':
|
||||
version = tuple(int(i) for i in conf.env['CC_VERSION'])
|
||||
if version < (6, 1, 0):
|
||||
# Issue #2804
|
||||
return
|
||||
conf.env.WITH_PCH = True
|
||||
flags = PCH_COMPILER_OPTIONS[conf.env['COMPILER_CXX']]
|
||||
conf.env.CXXPCH_F = flags[0]
|
||||
@@ -95,8 +90,8 @@ def apply_pch(self):
|
||||
|
||||
if getattr(self, 'name', None):
|
||||
try:
|
||||
task = self.bld.pch_tasks[self.name]
|
||||
self.bld.fatal("Duplicated 'pch' task with name %r" % self.name)
|
||||
task = self.bld.pch_tasks["%s.%s" % (self.name, self.idx)]
|
||||
self.bld.fatal("Duplicated 'pch' task with name %r" % "%s.%s" % (self.name, self.idx))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
@@ -109,7 +104,7 @@ def apply_pch(self):
|
||||
|
||||
self.pch_task = task
|
||||
if getattr(self, 'name', None):
|
||||
self.bld.pch_tasks[self.name] = task
|
||||
self.bld.pch_tasks["%s.%s" % (self.name, self.idx)] = task
|
||||
|
||||
@TaskGen.feature('cxx')
|
||||
@TaskGen.after_method('process_source', 'propagate_uselib_vars')
|
||||
@@ -134,7 +129,7 @@ def add_pch(self):
|
||||
x.env.append_value('CXXFLAGS', self.env['CXXPCH_F'] + [pch.target])
|
||||
|
||||
class gchx(Task.Task):
|
||||
run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${CXXPCH_FLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXXPCH_F:SRC} ${CXX_SRC_F}${SRC[0].abspath()} ${CXX_TGT_F}${TGT[0].abspath()}'
|
||||
run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CXXPCH_FLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXXPCH_F:SRC} ${CXX_SRC_F}${SRC[0].abspath()} ${CXX_TGT_F}${TGT[0].abspath()} ${CPPFLAGS}'
|
||||
scan = c_preproc.scan
|
||||
color = 'BLUE'
|
||||
ext_out=['.h']
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--with-sanitizer', action='store', default='', dest='sanitizers',
|
||||
help='Comma-separated list of compiler sanitizers to enable [default=none]')
|
||||
|
||||
def configure(conf):
|
||||
for san in conf.options.sanitizers.split(','):
|
||||
if not san:
|
||||
continue
|
||||
|
||||
sanflag = '-fsanitize=%s' % san
|
||||
conf.start_msg('Checking if compiler supports %s' % sanflag)
|
||||
|
||||
if conf.check_cxx(cxxflags=['-Werror', sanflag, '-fno-omit-frame-pointer'],
|
||||
linkflags=[sanflag], mandatory=False):
|
||||
conf.end_msg('yes')
|
||||
conf.env.append_unique('CXXFLAGS', [sanflag, '-fno-omit-frame-pointer'])
|
||||
conf.env.append_unique('LINKFLAGS', [sanflag])
|
||||
else:
|
||||
conf.end_msg('no', color='RED')
|
||||
conf.fatal('%s sanitizer is not supported by the current compiler' % san)
|
||||
@@ -44,28 +44,28 @@ def apply_sphinx(self):
|
||||
task.inputs.append(conf)
|
||||
|
||||
confdir = conf.parent.abspath()
|
||||
buildername = getattr(self, "builder", "html")
|
||||
srcdir = getattr(self, "srcdir", confdir)
|
||||
outdir = self.path.find_or_declare(getattr(self, "outdir", buildername)).get_bld()
|
||||
doctreedir = getattr(self, "doctreedir", os.path.join(outdir.abspath(), ".doctrees"))
|
||||
buildername = getattr(self, 'builder', 'html')
|
||||
srcdir = getattr(self, 'srcdir', confdir)
|
||||
outdir = self.path.find_or_declare(getattr(self, 'outdir', buildername)).get_bld()
|
||||
doctreedir = getattr(self, 'doctreedir', os.path.join(outdir.abspath(), '.doctrees'))
|
||||
|
||||
task.env['BUILDERNAME'] = buildername
|
||||
task.env['SRCDIR'] = srcdir
|
||||
task.env['DOCTREEDIR'] = doctreedir
|
||||
task.env['OUTDIR'] = outdir.abspath()
|
||||
task.env['VERSION'] = "version=%s" % self.VERSION
|
||||
task.env['RELEASE'] = "release=%s" % self.VERSION
|
||||
task.env['VERSION'] = 'version=%s' % self.version
|
||||
task.env['RELEASE'] = 'release=%s' % getattr(self, 'release', self.version)
|
||||
|
||||
import imp
|
||||
confData = imp.load_source('sphinx_conf', conf.abspath())
|
||||
|
||||
if buildername == "man":
|
||||
if buildername == 'man':
|
||||
for i in confData.man_pages:
|
||||
target = outdir.find_or_declare('%s.%d' % (i[1], i[4]))
|
||||
task.outputs.append(target)
|
||||
|
||||
if self.install_path:
|
||||
self.bld.install_files("%s/man%d/" % (self.install_path, i[4]), target)
|
||||
self.bld.install_files('%s/man%d/' % (self.install_path, i[4]), target)
|
||||
else:
|
||||
task.outputs.append(outdir)
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
#
|
||||
# Copyright (c) 2014, Regents of the University of California
|
||||
#
|
||||
# GPL 3.0 license, see the COPYING.md file for more information
|
||||
|
||||
from waflib import Configure
|
||||
|
||||
IS_DEFAULT_CONSTRUCTIBLE_CHECK = '''
|
||||
#include <type_traits>
|
||||
static_assert(std::is_default_constructible<int>::value, "");
|
||||
'''
|
||||
|
||||
IS_MOVE_CONSTRUCTIBLE_CHECK = '''
|
||||
#include <type_traits>
|
||||
static_assert(std::is_move_constructible<int>::value, "");
|
||||
'''
|
||||
|
||||
def configure(conf):
|
||||
if conf.check_cxx(msg='Checking for std::is_default_constructible',
|
||||
fragment=IS_DEFAULT_CONSTRUCTIBLE_CHECK,
|
||||
features='cxx', mandatory=False):
|
||||
conf.define('HAVE_IS_DEFAULT_CONSTRUCTIBLE', 1)
|
||||
conf.env['HAVE_IS_DEFAULT_CONSTRUCTIBLE'] = True
|
||||
|
||||
if conf.check_cxx(msg='Checking for std::is_move_constructible',
|
||||
fragment=IS_MOVE_CONSTRUCTIBLE_CHECK,
|
||||
features='cxx', mandatory=False):
|
||||
conf.define('HAVE_IS_MOVE_CONSTRUCTIBLE', 1)
|
||||
conf.env['HAVE_IS_MOVE_CONSTRUCTIBLE'] = True
|
||||
@@ -1,13 +1,13 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
#
|
||||
# Copyright (c) 2014, Regents of the University of California
|
||||
# Copyright (c) 2014-2019, Regents of the University of California
|
||||
#
|
||||
# GPL 3.0 license, see the COPYING.md file for more information
|
||||
|
||||
from waflib import Options
|
||||
|
||||
BOOST_ASIO_HAS_LOCAL_SOCKETS_CHECK = '''
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/local/basic_endpoint.hpp>
|
||||
#ifndef BOOST_ASIO_HAS_LOCAL_SOCKETS
|
||||
#error "Unix sockets are not available on this platform"
|
||||
#endif
|
||||
@@ -15,8 +15,9 @@ BOOST_ASIO_HAS_LOCAL_SOCKETS_CHECK = '''
|
||||
|
||||
def addUnixOptions(self, opt):
|
||||
opt.add_option('--force-unix-socket', action='store_true', default=False,
|
||||
dest='force_unix_socket', help='''Forcefully enable Unix sockets support''')
|
||||
setattr(Options.OptionsContext, "addUnixOptions", addUnixOptions)
|
||||
help='Forcefully enable Unix sockets support')
|
||||
|
||||
setattr(Options.OptionsContext, 'addUnixOptions', addUnixOptions)
|
||||
|
||||
def configure(conf):
|
||||
def boost_asio_has_local_sockets():
|
||||
@@ -24,6 +25,5 @@ def configure(conf):
|
||||
fragment=BOOST_ASIO_HAS_LOCAL_SOCKETS_CHECK,
|
||||
features='cxx', use='BOOST', mandatory=False)
|
||||
|
||||
if conf.options.force_unix_socket or boost_asio_has_local_sockets():
|
||||
conf.define('HAVE_UNIX_SOCKETS', 1)
|
||||
conf.env['HAVE_UNIX_SOCKETS'] = True
|
||||
conf.env.HAVE_UNIX_SOCKETS = conf.options.force_unix_socket or boost_asio_has_local_sockets()
|
||||
conf.define_cond('HAVE_UNIX_SOCKETS', conf.env.HAVE_UNIX_SOCKETS)
|
||||
+25
-31
@@ -1,24 +1,22 @@
|
||||
# encoding: utf-8
|
||||
|
||||
from waflib import Options, Logs, Errors
|
||||
from waflib.Configure import conf
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
from waflib import Options, Logs, Errors, Configure
|
||||
import re
|
||||
|
||||
def addWebsocketOptions(self, opt):
|
||||
opt.add_option('--without-websocket', action='store_false', default=True,
|
||||
dest='with_websocket',
|
||||
help='Disable WebSocket face support')
|
||||
setattr(Options.OptionsContext, "addWebsocketOptions", addWebsocketOptions)
|
||||
dest='with_websocket', help='Disable WebSocket face support')
|
||||
|
||||
@conf
|
||||
setattr(Options.OptionsContext, 'addWebsocketOptions', addWebsocketOptions)
|
||||
|
||||
@Configure.conf
|
||||
def checkWebsocket(self, **kw):
|
||||
if not self.options.with_websocket:
|
||||
return
|
||||
|
||||
isMandatory = kw.get('mandatory', True)
|
||||
|
||||
self.start_msg('Checking for WebSocket includes')
|
||||
self.start_msg('Checking for WebSocket++ includes')
|
||||
|
||||
try:
|
||||
websocketDir = self.path.find_dir('websocketpp/websocketpp')
|
||||
@@ -27,53 +25,49 @@ def checkWebsocket(self, **kw):
|
||||
|
||||
versionFile = websocketDir.find_node('version.hpp')
|
||||
if not websocketDir:
|
||||
raise Errors.WafError('Corrupted: WebSocket version file not found')
|
||||
raise Errors.WafError('WebSocket++ version file not found')
|
||||
|
||||
try:
|
||||
txt = versionFile.read()
|
||||
except (OSError, IOError):
|
||||
raise Errors.WafError('Corrupted: cannot read WebSocket version file')
|
||||
|
||||
# Looking for the following:
|
||||
# static int const major_version = 0;
|
||||
# static int const minor_version = 5;
|
||||
# static int const patch_version = 1;
|
||||
raise Errors.WafError('Cannot read WebSocket++ version file')
|
||||
|
||||
version = [None, None, None]
|
||||
|
||||
# Looking for the following:
|
||||
# static int const major_version = 0;
|
||||
# static int const minor_version = 7;
|
||||
# static int const patch_version = 0;
|
||||
majorVersion = re.compile('^static int const major_version = (\\d+);$', re.M)
|
||||
version[0] = majorVersion.search(txt)
|
||||
|
||||
minorVersion = re.compile('^static int const minor_version = (\\d+);$', re.M)
|
||||
version[1] = minorVersion.search(txt)
|
||||
|
||||
patchVersion = re.compile('^static int const patch_version = (\\d+);$', re.M)
|
||||
version[2] = patchVersion.search(txt)
|
||||
|
||||
if not version[0] or not version[1] or not version[2]:
|
||||
raise Errors.WafError('Corrupted: cannot detect websocket version')
|
||||
raise Errors.WafError('Cannot detect WebSocket++ version')
|
||||
|
||||
self.env['WEBSOCKET_VERSION'] = [i.group(1) for i in version]
|
||||
self.env.WEBSOCKET_VERSION = [i.group(1) for i in version]
|
||||
|
||||
# todo: version checking, if necessary
|
||||
|
||||
self.end_msg('.'.join(self.env['WEBSOCKET_VERSION']))
|
||||
self.end_msg('.'.join(self.env.WEBSOCKET_VERSION))
|
||||
|
||||
self.env['INCLUDES_WEBSOCKET'] = websocketDir.parent.abspath()
|
||||
self.env['HAVE_WEBSOCKET'] = True
|
||||
self.env.INCLUDES_WEBSOCKET = websocketDir.parent.abspath()
|
||||
self.env.HAVE_WEBSOCKET = True
|
||||
self.define('HAVE_WEBSOCKET', 1)
|
||||
self.define('_WEBSOCKETPP_CPP11_STL_', 1)
|
||||
|
||||
except Errors.WafError as error:
|
||||
if isMandatory:
|
||||
self.end_msg(str(error), color='RED')
|
||||
Logs.warn('If you are using git NFD repository, checkout websocketpp submodule: ')
|
||||
Logs.warn(' git submodule init && git submodule update')
|
||||
Logs.warn('Otherwise, manually download and extract websocketpp library:')
|
||||
Logs.warn(' mkdir websocketpp')
|
||||
Logs.warn(' curl -L https://github.com/zaphoyd/websocketpp/archive/0.5.1.tar.gz > websocket.tar.gz')
|
||||
Logs.warn(' tar zxf websocket.tar.gz -C websocketpp/ --strip 1')
|
||||
Logs.warn('If you are using NFD from the git repository, checkout the websocketpp submodule: ')
|
||||
Logs.warn(' git submodule update --init')
|
||||
Logs.warn('Otherwise, manually download and extract the websocketpp library:')
|
||||
Logs.warn(' mkdir -p websocketpp')
|
||||
Logs.warn(' curl -L https://github.com/cawka/websocketpp/archive/0.8.1-hotfix.tar.gz > websocketpp.tar.gz')
|
||||
Logs.warn(' tar xf websocketpp.tar.gz -C websocketpp/ --strip 1')
|
||||
Logs.warn('Alternatively, WebSocket support can be disabled with --without-websocket')
|
||||
self.fatal("The configuration failed")
|
||||
self.fatal('WebSocket++ not found')
|
||||
else:
|
||||
self.end_msg(str(error))
|
||||
+58
-75
@@ -1,79 +1,62 @@
|
||||
NFD Authors
|
||||
===========
|
||||
# NFD Authors
|
||||
|
||||
NFD is an open source project started in late 2013, includes contributions
|
||||
from many people around the world, and open for new contributions from new
|
||||
volunteers.
|
||||
The following lists maintainers, primary developers, and all much-appreciated contributors to NFD in alphabetic order.
|
||||
The specific contributions of individual authors can be obtained from the git history of the [official NFD repository](https://github.com/named-data/NFD).
|
||||
If you would like to become a contributor to the official repository, please follow the recommendations in https://github.com/named-data/.github/blob/master/CONTRIBUTING.md.
|
||||
|
||||
* Jerald Paul Abraham <https://cs.arizona.edu/~jeraldabraham>
|
||||
* ***(Maintainer)*** Alexander Afanasyev <https://users.cs.fiu.edu/~afanasyev>
|
||||
* Syed Obai Amin <http://obaidamin.weebly.com>
|
||||
* Hila Ben Abraham <https://sites.wustl.edu/hbabraham>
|
||||
* Muktadir R Chowdhury <https://github.com/alvyC>
|
||||
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
|
||||
* Stephanie DiBenedetto
|
||||
* Saurab Dulal <https://dulalsaurab.github.io>
|
||||
* Chengyu Fan <https://github.com/chengyu>
|
||||
* Ashlesh Gawande <https://www.linkedin.com/in/agawande>
|
||||
* Chavoosh Ghasemi <https://chavoosh.github.io>
|
||||
* Mathias Gibbens <https://calenhad.com>
|
||||
* Nick Gordon <https://github.com/gorgonical>
|
||||
* Giulio Grassi <https://www.lip6.fr/actualite/personnes-fiche.php?ident=D1461>
|
||||
* Yi Huang <https://www.linkedin.com/in/yihuang1991>
|
||||
* Jongseok Lee <https://github.com/imwhiz>
|
||||
* Spencer Lee <https://www.linkedin.com/in/spenlee>
|
||||
* Vince Lehman <http://vslehman.com>
|
||||
* Yanbiao Li <https://www.linkedin.com/pub/yanbiao-li/24/7a1/4ba>
|
||||
* Teng Liang <https://cs.arizona.edu/~philoliang>
|
||||
* Weiwei Liu <https://www.linkedin.com/in/weiweiliu10>
|
||||
* Spyridon Mastorakis <https://sites.google.com/site/spyridonmastorakis>
|
||||
* Ernest McCracken <https://github.com/emccrckn>
|
||||
* Ilya Moiseenko <https://www.linkedin.com/in/ilya-moiseenko-52884317>
|
||||
* Eric Newberry <https://ericnewberry.com>
|
||||
* Ju Pan <https://cs-jupan.com>
|
||||
* João Pereira <http://website.jpereira.co.uk>
|
||||
* Davide Pesavento <https://github.com/Pesa>
|
||||
* Felix Rabe <https://twitter.com/felixrabe>
|
||||
* Md Ashiqur Rahman <https://ashiqrahman.com>
|
||||
* Matteo Sammarco <https://www.linkedin.com/in/matteo-sammarco-9b544530>
|
||||
* Niv Sardi <http://core.evilgiggle.com>
|
||||
* Klaus Schneider <https://cs.arizona.edu/~klaus>
|
||||
* Wentao Shang <https://irl.cs.ucla.edu/~wentao>
|
||||
* Susmit Shannigrahi <https://susm.it>
|
||||
* ***(Former Maintainer)*** Junxiao Shi <https://cs.arizona.edu/~shijunxiao>
|
||||
* Yukai Tu <https://irl.cs.ucla.edu/~yukai>
|
||||
* Sebastian Wölke <https://inet.haw-hamburg.de/members/alumni-1/sebastian-woelke>
|
||||
* Yumin Xia <https://github.com/Stumble>
|
||||
* Yingdi Yu <https://irl.cs.ucla.edu/~yingdi>
|
||||
* Haowei Yuan <http://www.cse.wustl.edu/~yuanh>
|
||||
* Hang Zhang <http://netlab.bit.edu.cn/z_hang>
|
||||
* Minsheng Zhang <https://github.com/mzhang4>
|
||||
* Zhiyi Zhang <https://zhiyi-zhang.com>
|
||||
* Qi Zhao <https://web.cs.ucla.edu/~qi.zhao>
|
||||
* Wenkai Zheng <https://github.com/wenkaizheng>
|
||||
|
||||
## Project technical leads:
|
||||
## Technical Advisors
|
||||
|
||||
* Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
|
||||
* Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
|
||||
|
||||
|
||||
## Technical advisors:
|
||||
|
||||
* Beichuan Zhang <http://www.cs.arizona.edu/~bzhang/>
|
||||
* Lixia Zhang <http://www.cs.ucla.edu/~lixia/>
|
||||
|
||||
|
||||
## Main project authors and their affiliations:
|
||||
|
||||
* University of California, Los Angeles
|
||||
|
||||
* Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
|
||||
* Ilya Moiseenko <http://ilyamoiseenko.com/>
|
||||
* Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/web/index.html>
|
||||
* Wentao Shang <http://irl.cs.ucla.edu/~wentao/>
|
||||
* Lixia Zhang <http://www.cs.ucla.edu/~lixia/>
|
||||
|
||||
* The University of Arizona
|
||||
|
||||
* Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
|
||||
* Yi Huang <ethanhuang1991@gmail.com>
|
||||
* Jerald Paul Abraham <http://www.cs.arizona.edu/people/jeraldabraham/>
|
||||
* Beichuan Zhang <http://www.cs.arizona.edu/~bzhang/>
|
||||
|
||||
* Colorado State University
|
||||
|
||||
* Steve DiBenedetto <http://www.cs.colostate.edu/~dibenede/>
|
||||
* Chengyu Fan <chengyu@cs.colostate.edu>
|
||||
* Christos Papadopoulos <http://www.cs.colostate.edu/~christos/>
|
||||
|
||||
* University Pierre & Marie Curie, Sorbonne University
|
||||
|
||||
* Davide Pesavento <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1469>
|
||||
* Giulio Grassi <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1461>
|
||||
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
|
||||
|
||||
* Beijing Institute of Technology
|
||||
|
||||
* Hang Zhang <http://netlab.bit.edu.cn/z_hang>
|
||||
* Tian Song <http://cs.bit.edu.cn/songtian>
|
||||
|
||||
* Washington University in St. Louis
|
||||
|
||||
* Haowei Yuan <http://www.cse.wustl.edu/~yuanh/>
|
||||
* Hila Ben Abraham <http://research.engineering.wustl.edu/~abrahamh/>
|
||||
* Patrick Crowley <http://www.arl.wustl.edu/~pcrowley/>
|
||||
|
||||
* The University of Memphis
|
||||
|
||||
* Syed Obaid Amin <http://obaidamin.weebly.com/>
|
||||
* Vince Lehman <vslehman@memphis.edu>
|
||||
* Minsheng Zhang <mzhang4@memphis.edu>
|
||||
* Lan Wang <http://www.cs.memphis.edu/~lanwang/>
|
||||
|
||||
## Project contributors
|
||||
|
||||
The following is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS,
|
||||
people who have reported bugs, submitted patches, and implemented new features
|
||||
in the library:
|
||||
|
||||
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
|
||||
* Spyridon Mastorakis <http://cs.ucla.edu/~mastorakis/>
|
||||
* Eric Newberry <http://ericnewberry.com>
|
||||
* Yukai Tu <tuyukai1994@gmail.com>
|
||||
* João Pereira <http://website.jpereira.co.uk>
|
||||
* Mathias Gibbens <gibmat@cs.arizona.edu>
|
||||
* Patrick Crowley <https://www.arl.wustl.edu/~pcrowley>
|
||||
* Christos Papadopoulos <https://www.cs.colostate.edu/~christos>
|
||||
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
|
||||
* Tian Song <http://www.bit-netlab.org/songtian>
|
||||
* Lan Wang <http://www.cs.memphis.edu/~lanwang>
|
||||
* Beichuan Zhang <https://cs.arizona.edu/~bzhang>
|
||||
* Lixia Zhang <https://cs.ucla.edu/~lixia>
|
||||
@@ -0,0 +1,81 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our
|
||||
project and our community a harassment-free experience for everyone,
|
||||
regardless of age, body size, disability, ethnicity, gender identity
|
||||
and expression, level of experience, nationality, personal appearance,
|
||||
race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive
|
||||
environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual
|
||||
attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political
|
||||
attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or
|
||||
electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in
|
||||
a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of
|
||||
acceptable behavior and are expected to take appropriate and fair
|
||||
corrective action in response to any instances of unacceptable
|
||||
behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit,
|
||||
or reject comments, commits, code, wiki edits, issues, and other
|
||||
contributions that are not aligned to this Code of Conduct, or to ban
|
||||
temporarily or permanently any contributor for other behaviors that
|
||||
they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public
|
||||
spaces when an individual is representing the project or its
|
||||
community. Examples of representing a project or community include
|
||||
using an official project e-mail address, posting via an official
|
||||
social media account, or acting as an appointed representative at an
|
||||
online or offline event. Representation of a project may be further
|
||||
defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior
|
||||
may be reported by contacting the project leaders Lixia Zhang,
|
||||
Beichuan Zhang, or Alex Afanasyev
|
||||
at
|
||||
[lixia@cs.ucla.edu](mailto:lixia@cs.ucla.edu),
|
||||
[bzhang@cs.arizona.edu](mailto:bzhang@cs.arizona.edu),
|
||||
and [aa@cs.ucla.edu](mailto:aa@cs.ucla.edu). All complaints will be
|
||||
reviewed and investigated and will result in a response that is deemed
|
||||
necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of
|
||||
an incident. Further details of specific enforcement policies may be
|
||||
posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct
|
||||
in good faith may face temporary or permanent repercussions as
|
||||
determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from
|
||||
the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available
|
||||
at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4/)
|
||||
+489
@@ -0,0 +1,489 @@
|
||||
# Contributing to the NDN Codebase
|
||||
## Getting Started
|
||||
|
||||
The NDN team is very glad you are interested in contributing! The NDN
|
||||
(Named Data Networking) codebase is composed of many projects, with
|
||||
multiple universities across the world contributing. This
|
||||
documentation will help you understand how we work and what we expect
|
||||
from contributors.
|
||||
|
||||
### Code of Conduct
|
||||
|
||||
NDN codebase development adheres to the Contributor Covenant, located
|
||||
in `CODE_OF_CONDUCT.md`. By contributing, you are expected to also
|
||||
adhere to this code. If you feel someone has breached this code of
|
||||
conduct,
|
||||
please
|
||||
[email us](mailto:lixia@cs.ucla.edu,bzhang@cs.arizona.edu,aa@cs.ucla.edu).
|
||||
|
||||
### What can I do?
|
||||
|
||||
The NDN codebase continually needs help with, among other
|
||||
things:
|
||||
|
||||
1. Implementing new features
|
||||
2. Writing fixes for bugs
|
||||
3. Writing documentation for features that have recently changed or
|
||||
that change quickly. Sometimes people forget to update
|
||||
documentation!
|
||||
4. Code review
|
||||
|
||||
## Finding Documentation
|
||||
|
||||
The NDN team maintains a community
|
||||
([Redmine site](https://redmine.named-data.net/projects/nfd)) for
|
||||
issue tracking and documentation hosting. Redmine is the hub for
|
||||
design activity. In particular, all design discussion and decisions
|
||||
will either occur or be copied there.
|
||||
|
||||
**Why did they do it *this* way?** When writing code, if you ever have
|
||||
questions about why some design decision was made, the best approach
|
||||
is to use `git blame` on a file to inspect the last commit for some
|
||||
line of code. In this view there will be a commit hash in hex
|
||||
(e.g. `0ab12e3a`) in the first column. Using our example, `git show
|
||||
0ab12e3a` would show the commit made for that line. In the commit view
|
||||
there should be a reference number (e.g. `refs: #1234`). Using this
|
||||
number, you can find a pertaining issue on the Redmine
|
||||
(e.g., `https://redmine.named-data.net/issues/1234`).
|
||||
|
||||
Additionally, in some cases there are published papers you can read in
|
||||
order to gain a better understanding of the project. Searching for
|
||||
these papers is not difficult; in many cases you can find a pertaining
|
||||
paper or technical report listed on
|
||||
[the main NDN website](https://named-data.net/publications).
|
||||
Usually the title of a project will be a good keyword.
|
||||
|
||||
If you cannot find an answer to your question, the best place to go is
|
||||
the
|
||||
[mailing lists](https://named-data.net/codebase/platform/support/mailing-lists/).
|
||||
There are multiple different lists for different interests, so be sure you
|
||||
are mailing the right list for a quick response.
|
||||
|
||||
## Tracking work on Redmine ##
|
||||
|
||||
As mentioned above, Redmine is the organizational hub of the NDN
|
||||
projects. As such, extensive use of it is made, and learning how it
|
||||
works will help you. In particular, there is a workflow associated
|
||||
with Redmine. Generally it is:
|
||||
|
||||
1. An issue is reported by someone. At this point they should
|
||||
describe the issue, including relationships to other
|
||||
issues. Unless they know what they're doing, they should leave
|
||||
particulars blank. Such particulars are priority, target version,
|
||||
assignees, and categories.
|
||||
2. Design discussion about the issue occurs, and the issue is either
|
||||
accepted or rejected.
|
||||
3. Someone either is assigned to, or assigns themselves to work on the
|
||||
issue, setting the status to "In progress."
|
||||
**Note:** You must be a "Developer" of the project before you are
|
||||
able to toggle the Status field. A user should contact a project
|
||||
manager to be granted Developer privilege. Project managers can be
|
||||
found on "Overview" page of the project.
|
||||
4. After every useful chunk of progress, notes are made on the issue
|
||||
and the progress percentage is updated to reflect this. Remember
|
||||
that notes are actually Markdown, so it is advised to use the
|
||||
'preview' button to ensure your note looks right.
|
||||
5. The changes are uploaded to Gerrit for review. Once all changes
|
||||
pertaining to an issue are on Gerrit, an issues status should
|
||||
change to "Code review."
|
||||
6. Once all changes are cleared for merging, they either can be
|
||||
merged, or held for feedback, at which point the issue status
|
||||
should become "Feedback."
|
||||
7. After all changes have been merged, the issue should be set to
|
||||
"Closed."
|
||||
|
||||
Redmine provides other facilities for managing your work on NDN
|
||||
projects, too, such as time logging and time estimation.
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
### Repositories ###
|
||||
|
||||
All NDN projects are hosted on GitHub, at various organizations, using git
|
||||
for version control:
|
||||
|
||||
- [Main NDN codebase](https://github.com/named-data)
|
||||
- [NDN codebase for mobile platforms](https://github.com/named-data-mobile)
|
||||
- [NDN codebase for IoT](https://github.com/named-data-iot)
|
||||
- [ndnSIM codebase](https://github.com/named-data-ndnSIM)
|
||||
- [Other NDN codebase (REMAP)](https://github.com/remap)
|
||||
|
||||
If you are unfamiliar with git, some kind
|
||||
of [tutorial on git](https://git-scm.com/book/en/v1/Getting-Started)
|
||||
should be your first step.
|
||||
|
||||
There is also a [Git game](http://learngitbranching.js.org/index.html)
|
||||
you can play. Finally, there is a
|
||||
[wiki page](https://redmine.named-data.net/projects/nfd/wiki#Development-process)
|
||||
on NFD's Redmine that has more useful links.
|
||||
|
||||
There are a lot of different projects, so take some time to look
|
||||
through them for ones that pertain to your interests. NDN projects
|
||||
use [Gerrit](https://gerrit.named-data.net/) for code review purposes.
|
||||
|
||||
Occasionally there will be other repositories used privately to test
|
||||
changes, but this is uncommon. In general, you will not need to refer
|
||||
to these repositories.
|
||||
|
||||
### Style ###
|
||||
|
||||
Most NDN projects are written in C++, and there is a
|
||||
[style guide](https://named-data.net/doc/ndn-cxx/current/code-style.html).
|
||||
In general the NDN style is similar to the GNU style, but there are
|
||||
some significant changes. This style guide is not exhaustive, and in
|
||||
all cases not covered by the guide you should emulate the current
|
||||
style of the project.
|
||||
|
||||
There is a
|
||||
[partial styleguide](https://redmine.named-data.net/projects/nfd/wiki/CodeStyle)
|
||||
for Python. It applies many of the provisions from the C++ guide, in
|
||||
addition to some other Python-specific things.
|
||||
|
||||
Some NDN projects are written in JavaScript, and there is a [style guide](https://named-data.net/codebase/platform/documentation/ndn-platform-development-guidelines/cpp-code-guidelines/) for that language, too.
|
||||
|
||||
#### Commit Messages ####
|
||||
|
||||
Commit messages are very important, as they are usually the first
|
||||
thing (besides the changelog file) a developer looks at when trying to
|
||||
understand the timeline of a project. Commit messages should:
|
||||
|
||||
- Have a short, descriptive first line, starting with the module
|
||||
they change. A good rule of thumb is a maximum length of 65
|
||||
characters.
|
||||
- If including a body, leave a blank line between the first line and
|
||||
the rest, and ensure that each line is no longer than 72 characters.
|
||||
- Include Redmine issue numbers. The exact syntax is given below.
|
||||
- Be written in an imperative mood. E.g. `"Make foo a bar"` and not
|
||||
`"Foo is now a bar"`
|
||||
- Use the present tense. E.g. `"Make foo a bar"` and not `"Made foo a
|
||||
bar"`
|
||||
|
||||
To explain, the anatomy of a typical commit message is like this:
|
||||
|
||||
docs: write contributing guide and code of conduct
|
||||
|
||||
This commit adds a guide that may be useful for new-comers to NDN in
|
||||
becoming productive contributors. This commit also adds a code of
|
||||
conduct.
|
||||
|
||||
refs: #3898
|
||||
Change-Id: Ife89360305027dba9020f0b298793c1121ae1fd6c
|
||||
|
||||
Explaining this:
|
||||
|
||||
- `docs` is the module that the commit affects. We want this because
|
||||
it lets someone know at a glance what part of the project it
|
||||
changes. For some projects, there will be only one module or only
|
||||
very small other modules. This practice should be observed in
|
||||
those cases, too.
|
||||
- `#3898` is the Redmine issue number. Gerrit transforms these into
|
||||
clickable links, and it is useful to reviewers to gain background
|
||||
understanding of the issue. You can have multiple by separating
|
||||
them with commas.
|
||||
- `Change-Id` should be filled automatically. It is used by Gerrit
|
||||
to track changes.
|
||||
|
||||
### Unit Tests ###
|
||||
With a few exceptions, every patch needs to have unit tests that
|
||||
accompany them. For C++, we use
|
||||
the [Boost unit test framework](http://www.boost.org/libs/test) to
|
||||
help us out. Note that this link points to the newest version of the
|
||||
Boost Test library documentation, and you may need to refer to older
|
||||
documentation if you are using an older version of Boost. More
|
||||
information on this is available in
|
||||
the
|
||||
[NFD Dev Guide](https://named-data.net/publications/techreports/ndn-0021-7-nfd-developer-guide/)
|
||||
|
||||
When designing and writing tests, a few things need to be kept in mind:
|
||||
|
||||
1. Unit tests are **design** tools, *not* debug tools. Just because
|
||||
your code passes some unit tests does not mean it is
|
||||
bug-free. Unit tests are tools to convince you that your code does
|
||||
what you think it does.
|
||||
2. It can be difficult to know when you should test something. If
|
||||
you find that you are having a hard time designing a test for
|
||||
something, ask yourself whether it is because it doesn't make
|
||||
sense to test what you've just written, or if it's because the way
|
||||
you designed it makes it difficult to test. Consider a second look
|
||||
at your design if you think it's the second one.
|
||||
3. The method that gave the world unit tests says that unit tests
|
||||
should be written *before* the code they test. This is
|
||||
a contentious issue, so writing them either before or after is
|
||||
acceptable. If writing them later, keep the tests in mind when
|
||||
writing the code, and it will help design good interfaces.
|
||||
4. At the very least, write the test for a completed module/unit of
|
||||
code before moving on. Doing this will ensure that the test gets
|
||||
written, and will help you think about the interface that you need
|
||||
to examine. If you don't, you may forget exactly what each piece
|
||||
is responsible for when you're looking at the whole system
|
||||
afterward.
|
||||
5. Separate your I/O, as it is very hard to test, so I/O should be
|
||||
isolated if possible. Consider something like separating a
|
||||
function that invokes I/O into two functions: one that does the
|
||||
I/O and calls the other one, which takes that I/O result. This
|
||||
will make it easier to test that second function than if they were
|
||||
combined.
|
||||
|
||||
Writing unit tests using the Boost framework is quite simple, and you
|
||||
can refer to existing unit tests for examples.
|
||||
([This is a good example.](https://github.com/named-data/NFD/blob/master/tests/rib/rib.t.cpp))
|
||||
|
||||
#### Building and running unit tests ####
|
||||
This is mentioned in greater depth in
|
||||
the [developer's readme](README-dev.md), but the basic procedure is:
|
||||
|
||||
1. In the base directory of the project, run `./waf distclean`. This
|
||||
removes all prior build files.
|
||||
2. Run `./waf configure --with-tests`. This configures the next build
|
||||
to also build the tests.
|
||||
3. Run `./waf`. This will build the tests.
|
||||
4. Then, the unit tests will be in the `build` directory, and will be
|
||||
named `unit-tests-<module name`, e.g. `unit-tests-nlsr` or
|
||||
`unit-tests-rib`. To run just one test suite, run
|
||||
`./unit-tests-exampleModule -t ExampleTestSuite`. To run a
|
||||
specific test in a suite, use `./unit-tests-exampleModule -t
|
||||
ExampleTestSuite/ExampleTestCase`.
|
||||
|
||||
## Gerrit: Uploading Patches and Code Review ##
|
||||
|
||||
As mentioned above, NDN projects
|
||||
use [Gerrit](https://gerrit.named-data.net/) for code review. This is
|
||||
a web-hosted, open code review platform that allows for interactive
|
||||
code review, rebasing, and cross-linking with the Redmine, and a
|
||||
developer interacts with it using the familiar git. For issues that
|
||||
require a tracker reference, a particularly useful feature is that
|
||||
the `refs: #...` becomes a clickable link to the issue for design
|
||||
discussion.
|
||||
|
||||
### First-time Setup ###
|
||||
|
||||
The first-time Gerrit setup goes like this:
|
||||
|
||||
1. Log in to Gerrit. You can authenticate using many different
|
||||
methods, including GitHub OAuth. You need to ensure that you have a Gerrit username:
|
||||
1. Log in.
|
||||
2. Click on your name in the top right corner and click "Settings" in the pop-up box.
|
||||
3. In the `Username` box, check for a name. If there's already one there, great.
|
||||
4. If not, type one in, and this will be used in later steps.
|
||||
|
||||
2. Set up your Gerrit credentials. This will depend on how you
|
||||
configured your Gerrit remote in step 1. Among other things, you
|
||||
need to set up identities so that the email on your Gerrit profile
|
||||
matches whatever email you will be committing with on your git
|
||||
repo.
|
||||
**Note:** We only support using
|
||||
[SSH access to Gerrit](https://gerrit.named-data.net/Documentation/user-upload.html#ssh).
|
||||
|
||||
This shows what the identities panel looks like. If you do
|
||||
not see the email here that you have configured git to use, you
|
||||
cannot upload to Gerrit.
|
||||

|
||||
|
||||
In that case, add it under contact information panel.
|
||||
.
|
||||
|
||||
Gerrit itself has
|
||||
[extensive documentation](https://gerrit.named-data.net/Documentation/error-messages.html)
|
||||
regarding error messages, and this identity-based one is by far the most
|
||||
common. This is the
|
||||
[documentation for an identity error.](https://gerrit.named-data.net/Documentation/error-invalid-author.html)
|
||||
|
||||
3. Clone the source for a project from Gerrit.
|
||||
1. While logged in to Gerrit, there will be a link in the top-left
|
||||
area, `Projects`.
|
||||
2. From this project view, click on the `Clone with commit-msg
|
||||
hook` tab.
|
||||
3. Click on the `ssh` tab to select cloning over SSH. **Note:**
|
||||
This will require setting up SSH access to Gerrit first.
|
||||
4. Copy-and-paste the `git clone ...` command into your terminal
|
||||
to fetch the project source.
|
||||
|
||||
After this, your remotes will be set up correctly, and pushing to
|
||||
Gerrit will only require `git push origin HEAD:refs/for/master` after
|
||||
committing work. This section has some
|
||||
[git tips and tricks to type less][type-less].
|
||||
|
||||
### Uploading patches ###
|
||||
|
||||
Most patches should have a corresponding Redmine issue that they can
|
||||
reference. If you search the Redmine and notice there is no relevant
|
||||
issue for a patch you are writing, please create an issue first. You
|
||||
will need a Redmine account, which can be created there.
|
||||
|
||||
After writing some changes, commit them locally as normal. After
|
||||
saving and exiting your editor, the commit hook will insert a unique
|
||||
`Change-Id` to the message.
|
||||
|
||||
|
||||
Once you have a commit message you are happy with, simply run `git
|
||||
push HEAD:refs/for/master`.
|
||||
|
||||
**Note:** Gerrit separates commits into patch sets by the unique
|
||||
`Change-Id`s. As a result, you must either:
|
||||
|
||||
* Squash your various commits into one with `git rebase -i
|
||||
<initial commit>`, ensuring that the ultimate `Change-Id` in the
|
||||
commit is the one on the patch set on Gerrit. This workflow is
|
||||
generally preferred.
|
||||
* Amend your commit with any new changes using `git commit --amend`.
|
||||
|
||||
If you do not do this, what will happen is that each commit will be
|
||||
interpreted by Gerrit as a separate patch set. This is probably not
|
||||
what you want.
|
||||
|
||||
### Code Review ###
|
||||
#### Dealing with Code Review ####
|
||||
|
||||
It is important to remember that code review is about improving
|
||||
the quality of code contributed, and nothing else. Further, code
|
||||
review is highly important, as every line of code that's
|
||||
committed comes with a burden of maintenance. Code review helps
|
||||
minimize the burden of that maintenance. Consider that when you
|
||||
are receiving comments, those comments are influenced by two
|
||||
things:
|
||||
|
||||
- How the reviewer personally feels about the change ("Would I
|
||||
be happy to see this code in a year?" or "Would I be happy if
|
||||
I wrote this?") and
|
||||
- How the reviewer feels the change abides by style and usage
|
||||
requirements ("I may not personally mind, but we have to do it
|
||||
this way.")
|
||||
|
||||
Remembering these things when reading comments helps to separate
|
||||
what can feel like needless negativity.
|
||||
|
||||
#### Doing Code Review and Writing Comments ####
|
||||
|
||||
**Code review is *extremely* important!** We need every bit of code
|
||||
review you can give. In many cases this is the bottleneck for
|
||||
new contributors who do not fully understand how certain
|
||||
language constructs should be used, what best practices are,
|
||||
etc. In these cases it is important to give constructive
|
||||
feedback.
|
||||
|
||||
Writing comments is somewhat counter-intuitive on Gerrit. If you are
|
||||
signed in through a modern browser, you can leave a comment in a file
|
||||
either by clicking on the line number, by selecting some text you want
|
||||
to comment and pressing 'c', or by clicking on someone else's
|
||||
comment. After typing, click the `Save` button there. After navigating
|
||||
through the patch set with the arrows at the top-right of the Gerrit
|
||||
UI, you then must click the up-arrow to get back to the Change
|
||||
screen. **At this point your comments have *not* been made yet!** You
|
||||
must then click the `Reply...` button, and assign a score. If you
|
||||
correctly saved your comments, they will be shown at the bottom of
|
||||
that box. Once you click post, the comments will be made public to
|
||||
others.
|
||||
|
||||
Minimally, a review *must* include:
|
||||
|
||||
- A score (usually -1, 0, or +1)
|
||||
- An "itemized" commentary on each objection you have, or a
|
||||
justification for a whole-change objection.
|
||||
|
||||
Optimally, a review should include:
|
||||
|
||||
- A useful explanation of *why* you object to some item. This is
|
||||
more important than it first appears. Consider that although
|
||||
you may have been writing code since before you could count,
|
||||
not everyone has. Some things may not be obvious to others,
|
||||
and sharing your knowledge is key to making an open-source
|
||||
project work.
|
||||
- Comments about good design decisions. These help motivate
|
||||
developers when otherwise a review is entirely negative
|
||||
comments.
|
||||
|
||||
#### Expediting the Code Review Process ####
|
||||
|
||||
If you observe that code review takes a long time, there are a
|
||||
few things that you can do to to expedite the process:
|
||||
|
||||
1. **Think about language best practices.**
|
||||
2. **Ask yourself how you would feel about this code, if you saw it "in the wild."**
|
||||
3. **When making code decisions, ask yourself "why *shouldn't* I do it this way?"**
|
||||
|
||||
#### Responding to Code Review ####
|
||||
|
||||
There are a few things to remember when responding to code review, including:
|
||||
|
||||
- **Don't** click "Done" on a comment if you agree with a comment and
|
||||
are updating the code accordingly. These comments are essentially
|
||||
useless and only clutter the discussion. Gerrit has a convenient
|
||||
mechanism to check the differences between two patch sets, so
|
||||
reviewers are expected to check that their comments have been
|
||||
addressed.
|
||||
- **Don't** blindly follow what is suggested. Review is just that: a
|
||||
review. Sometimes what is suggested is functionally equivalent to
|
||||
what you have implemented. Other times, the reviewer has not
|
||||
considered something when writing their review, and their
|
||||
suggestion will not work. Lastly, if you disagree with a suggestion
|
||||
for some other reason, feel free to object, but you may be asked to
|
||||
provide an explanation.
|
||||
- **How** to reply. To reply to a comment, click on the comment in
|
||||
the Gerrit interface, type your reply, and then press save. After
|
||||
replying, you **must remember** to go to the main patch set change
|
||||
screen, and press `Reply...`. Your comments will be shown as
|
||||
drafts, and you must click `Post` to make them visible to others.
|
||||
|
||||
### Jenkins ###
|
||||
|
||||
As a supplement to the code review process, every patch set is automatically
|
||||
compiled and tested on multiple platforms
|
||||
using [our instance of Jenkins](http://jenkins.named-data.net/), the
|
||||
continuous integration system. Interacting with Jenkins is not usually
|
||||
necessary, as Jenkins automatically picks up new patch sets and posts
|
||||
the results. Typically the only interaction needed with Jenkins is
|
||||
when some kind of glitch occurs and a build needs to be retriggered.
|
||||
|
||||
It is expected that code is checked locally. Reviewers may wait until
|
||||
Jenkins checks the code before doing a more functional review of the
|
||||
code. Since Jenkins checks can take a while, you can save some time by
|
||||
checking yourself first.
|
||||
|
||||
### Gerrit Change-Id Commit Hook ###
|
||||
|
||||
If you encounter an error like this when trying to push work:
|
||||
|
||||
remote: ERROR: [4311462] missing Change-Id in commit message footer
|
||||
remote:
|
||||
remote: Hint: To automatically insert Change-Id, install the hook:
|
||||
remote: gitdir=$(git rev-parse --git-dir); scp -p -P 29418 someuser@gerrit.named-data.net:hooks/commit-msg ${gitdir}/hooks/
|
||||
remote: And then amend the commit:
|
||||
remote: git commit --amend
|
||||
|
||||
Then your commit hook has not been set up correctly, somehow. Follow
|
||||
the instructions in the terminal to resolve this.
|
||||
|
||||
### Code Style Robot ###
|
||||
|
||||
As part of CI, there is a script that checks every patch uploaded to
|
||||
Gerrit for code style consistency. Checking these kinds of things is
|
||||
notoriously difficult, and while the robot is very good in general, it
|
||||
will occasionally report false positives and miss things. So all
|
||||
issues it raises should be inspected manually to ensure they really
|
||||
are style problems. Further, since this automated check is not
|
||||
perfect, you should take steps (e.g., configure your editor or run a
|
||||
linter before you commit) to ensure you adhere to code style rules.
|
||||
|
||||
### <a name="type-less"></a> Typing Less to Upload Patches to Gerrit ###
|
||||
|
||||
If typing `HEAD:refs/for/master` feels
|
||||
repetitive, you have a few options:
|
||||
|
||||
* You can configure git to do the work for you, as described
|
||||
in [this blog post](https://yoursunny.com/t/2017/NFD-devbox/#Uploading-to-Gerrit)
|
||||
|
||||
* Git has an alias system that you can use to specify certain
|
||||
commands. For example, you can use `git config --global alias.pg
|
||||
"push origin HEAD:refs/for/master"` to make `git pg` push to
|
||||
Gerrit. [Learn about git aliases here.](https://githowto.com/aliases)
|
||||
|
||||
* If using Linux or macOS, it is relatively simple to create a shell
|
||||
alias: `alias gs="git status"` for example, or `alias gitpush="git
|
||||
push origin HEAD:refs/for/master`. The alias itself must be one
|
||||
word, but it can represent multiple words. To persist your
|
||||
aliases, they need to go in your environment file, which is
|
||||
generally at `~/.bashrc` or `~/.zshrc` or `~/.profile`. The exact
|
||||
syntax of aliases and the environment variables file will vary by
|
||||
shell. You should be careful not to overuse aliases, however.
|
||||
|
||||
[type-less]: #type-less
|
||||
+383
-356
File diff suppressed because it is too large.
Load diff
@@ -1,5 +0,0 @@
|
||||
NFD Installation Instructions
|
||||
=============================
|
||||
|
||||
See [`docs/INSTALL.rst`](https://github.com/named-data/NFD/blob/master/docs/INSTALL.rst)
|
||||
for detailed NFD installation instructions.
|
||||
+30
-27
@@ -1,18 +1,23 @@
|
||||
Notes for NFD developers
|
||||
========================
|
||||
# Notes for NFD developers
|
||||
|
||||
Requirements
|
||||
------------
|
||||
If you are new to the NDN software community, please read the
|
||||
[Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md).
|
||||
|
||||
Contributions to NFD must be licensed under GPL 3.0 or compatible license. If you are
|
||||
choosing GPL 3.0, please use the following license boilerplate in all `.hpp` and `.cpp`
|
||||
files:
|
||||
## Code style
|
||||
|
||||
NFD code is subject to [NFD code style](https://redmine.named-data.net/projects/nfd/wiki/CodeStyle).
|
||||
|
||||
## Licensing
|
||||
|
||||
Contributions to NFD must be licensed under the GPL 3.0 or compatible license. If you
|
||||
are choosing GPL 3.0, please use the following license boilerplate in all `.hpp` and
|
||||
`.cpp` files:
|
||||
|
||||
Include the following license boilerplate into all `.hpp` and `.cpp` files:
|
||||
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) [Year(s)], [Copyright Holder(s)].
|
||||
/*
|
||||
* Copyright (c) [Year(s)], [Copyright Holder(s)].
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -30,39 +35,38 @@ Include the following license boilerplate into all `.hpp` and `.cpp` files:
|
||||
*/
|
||||
|
||||
If you are affiliated to an NSF-supported NDN project institution, please use the [NDN Team License
|
||||
Boilerplate](http://redmine.named-data.net/projects/nfd/wiki/NDN_Team_License_Boilerplate_(NFD)).
|
||||
Boilerplate](https://redmine.named-data.net/projects/nfd/wiki/NDN_Team_License_Boilerplate_(NFD)).
|
||||
|
||||
Recommendations
|
||||
---------------
|
||||
## Logging
|
||||
|
||||
NFD code is subject to NFD [code style](http://redmine.named-data.net/projects/nfd/wiki/CodeStyle).
|
||||
Fine-grained per-module logging can be configured via the `NDN_LOG` environment variable.
|
||||
This is especially useful when running unit tests or tools such as `nfdc` that do not
|
||||
have a configuration file. See `ndn-log(7)` manual page for syntax and examples.
|
||||
|
||||
|
||||
Running unit-tests
|
||||
------------------
|
||||
## Unit tests
|
||||
|
||||
To run unit tests, NFD needs to be configured and build with unit test support:
|
||||
|
||||
./waf configure --with-tests
|
||||
./waf configure --with-tests # --debug is also strongly recommended while developing
|
||||
./waf
|
||||
|
||||
The simplest way to run tests, is just to run the compiled binary without any parameters:
|
||||
The simplest way to run the tests is to launch the compiled binary without any parameters:
|
||||
|
||||
# Run core tests
|
||||
./build/unit-tests-core
|
||||
|
||||
# Run NFD daemon tests
|
||||
# Run NFD daemon tests
|
||||
./build/unit-tests-daemon
|
||||
|
||||
# Run NFD RIB management tests
|
||||
./build/unit-tests-rib
|
||||
|
||||
However, [Boost.Test framework](http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/)
|
||||
The [Boost.Test framework](https://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/index.html)
|
||||
is very flexible and allows a number of run-time customization of what tests should be run.
|
||||
For example, it is possible to choose to run only a specific test suite, only a specific
|
||||
test case within a suite, or specific test cases within specific test suites:
|
||||
|
||||
# Run only TCP Face test suite of NFD daemon tests (see tests/daemon/face/tcp.cpp)
|
||||
# Run only the TCP Face test suite of NFD daemon tests
|
||||
./build/unit-tests-daemon -t FaceTcp
|
||||
|
||||
# Run only test case EndToEnd4 from the same test suite
|
||||
@@ -73,8 +77,8 @@ test case within a suite, or specific test cases within specific test suites:
|
||||
|
||||
By default, Boost.Test framework will produce verbose output only when a test case fails.
|
||||
If it is desired to see verbose output (result of each test assertion), add `-l all`
|
||||
option to `./build/unit-tests` command. To see test progress, you can use `-l test_suite`
|
||||
or `-p` to show progress bar:
|
||||
option to `./build/unit-tests` command. To see test progress, you can use `-l test_suite`,
|
||||
or `-p` to show a progress bar:
|
||||
|
||||
# Show report all log messages including the passed test notification
|
||||
./build/unit-tests-daemon -l all
|
||||
@@ -88,7 +92,6 @@ or `-p` to show progress bar:
|
||||
# Show progress bar
|
||||
./build/unit-tests-core -p
|
||||
|
||||
There are many more command line options available, information about
|
||||
which can be obtained either from the command line using `--help`
|
||||
switch, or online on [Boost.Test library](http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/)
|
||||
website.
|
||||
There are many more command line options available, information about which can be obtained
|
||||
either from the command line using the `--help` switch, or online on the
|
||||
[Boost.Test website](https://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/index.html).
|
||||
@@ -1,33 +1,15 @@
|
||||
NFD - Named Data Networking Forwarding Daemon
|
||||
=============================================
|
||||
# NFD - Named Data Networking Forwarding Daemon
|
||||
|
||||
For complete documentation, including step-by-step installation instructions and
|
||||
tutorials, please visit the [NFD homepage](http://named-data.net/doc/NFD/).
|
||||

|
||||
[](https://travis-ci.org/named-data/NFD)
|
||||

|
||||
|
||||
## Overview
|
||||
|
||||
NFD is a network forwarder that implements and evolves together with the Named Data
|
||||
Networking (NDN) [protocol](http://named-data.net/doc/ndn-tlv/). After the initial
|
||||
release, NFD will become a core component of the
|
||||
[NDN Platform](http://named-data.net/codebase/platform/) and will follow the same release
|
||||
cycle.
|
||||
|
||||
NFD is an open and free software package licensed under GPL 3.0 license and is the
|
||||
centerpiece of our committement to making NDN's core technology open and free to all
|
||||
Internet users and developers. For more information about the licensing details and
|
||||
limitation, refer to
|
||||
[`COPYING.md`](https://github.com/named-data/NFD/blob/master/COPYING.md).
|
||||
|
||||
NFD is developed by a community effort. Although the first release was mostly done by the
|
||||
members of [NSF-sponsored NDN project team](http://named-data.net/project/participants/),
|
||||
it already contains significant contributions from people outside the project team (for
|
||||
more details, refer to
|
||||
[`AUTHORS.md`](https://github.com/named-data/NFD/blob/master/AUTHORS.md)). We strongly
|
||||
encourage participation from all interested parties, since broader community support is
|
||||
key for NDN to succeed as a new Internet architecture. Bug reports and feedback are
|
||||
highly appreciated and can be made through
|
||||
[Redmine site](http://redmine.named-data.net/projects/nfd) and the
|
||||
[ndn-interest mailing list](http://www.lists.cs.ucla.edu/mailman/listinfo/ndn-interest).
|
||||
Networking (NDN) [protocol](https://named-data.net/doc/NDN-packet-spec/current/).
|
||||
Since the initial public release in 2014, NFD has been a core component of the
|
||||
[NDN Platform](https://named-data.net/codebase/platform/).
|
||||
|
||||
The main design goal of NFD is to support diverse experimentation of NDN technology. The
|
||||
design emphasizes *modularity* and *extensibility* to allow easy experiments with new
|
||||
@@ -40,3 +22,34 @@ NFD will keep evolving in three aspects: improvement of the modularity framework
|
||||
up with the NDN protocol spec, and addition of other new features. We hope to keep the
|
||||
modular framework stable and lean, allowing researchers to implement and experiment with
|
||||
various features, some of which may eventually work into the protocol spec.
|
||||
|
||||
## Documentation
|
||||
|
||||
See [`docs/INSTALL.rst`](docs/INSTALL.rst) for compilation and installation instructions.
|
||||
|
||||
Extensive documentation is available on NFD's [homepage](https://named-data.net/doc/NFD/).
|
||||
|
||||
## Reporting bugs
|
||||
|
||||
Bug reports and feedback are highly appreciated and can be submitted through the
|
||||
[NFD issue tracker](https://redmine.named-data.net/projects/nfd/issues) or the
|
||||
[ndn-interest mailing list](http://www.lists.cs.ucla.edu/mailman/listinfo/ndn-interest).
|
||||
|
||||
## Contributing
|
||||
|
||||
NFD is developed by a community effort. Although the first release was mostly done by the
|
||||
members of [NSF-sponsored NDN project team](https://named-data.net/project/participants/),
|
||||
it already contains significant contributions from people outside the project team (see
|
||||
[`AUTHORS.md`](AUTHORS.md)). We strongly encourage participation from all interested parties,
|
||||
since broader community support is key for NDN to succeed as a new Internet architecture.
|
||||
|
||||
If you are new to the NDN software community, please read [`README-dev.md`](README-dev.md)
|
||||
and the [Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md)
|
||||
to get started.
|
||||
|
||||
## License
|
||||
|
||||
NFD is a free and open-source software package licensed under the GPL version 3 and
|
||||
is the centerpiece of our committement to making NDN's core technology free and open
|
||||
to all Internet users and developers. For more information about licensing, refer to
|
||||
[`COPYING.md`](COPYING.md).
|
||||
+1
-1
@@ -1 +1 @@
|
||||
docs/release-notes/release-notes-0.4.0.rst
|
||||
docs/release-notes-latest.rst
|
||||
@@ -0,0 +1,3 @@
|
||||
# Enable ndn-autoconfig to run in parallel with NFD. Disabled by default
|
||||
# enabled=true
|
||||
enabled=false
|
||||
@@ -1,130 +0,0 @@
|
||||
Starting NFD on Linux with systemd
|
||||
==================================
|
||||
|
||||
Newer versions of Ubuntu (starting with 15.04) and some other Linux distributions, including Debian
|
||||
use systemd to start system daemons, monitor their health, and restart them when they die.
|
||||
|
||||
Initial setup
|
||||
-------------
|
||||
|
||||
* Edit `nfd.service`, correcting the paths to the `nfd` executable, configuration, and
|
||||
``HOME`` directories.
|
||||
|
||||
* Copy the systemd config file for NFD to the proper directory
|
||||
|
||||
sudo cp nfd.service /etc/systemd/system
|
||||
|
||||
* Reload the systemd manager configuration
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
### Assumptions in the default scripts
|
||||
|
||||
* `nfd` is installed into `/usr/local/bin`
|
||||
* Configuraton file is `/usr/local/etc/ndn/nfd.conf`
|
||||
* `nfd` will be run as root
|
||||
* Log files will be written to `/usr/local/var/log/ndn` folder, which is owned by user `ndn`
|
||||
|
||||
### Creating users
|
||||
|
||||
If the `ndn` user and group do not exist, they need to be manually created.
|
||||
|
||||
# Create group `ndn`
|
||||
sudo addgroup --system ndn
|
||||
|
||||
# Create user `ndn`
|
||||
sudo adduser --system \
|
||||
--disabled-login \
|
||||
--ingroup ndn \
|
||||
--home /nonexistent \
|
||||
--gecos "NDN User" \
|
||||
--shell /bin/false \
|
||||
ndn
|
||||
|
||||
|
||||
### Creating folders
|
||||
|
||||
Folder `/usr/local/var/log/ndn` should be created and assigned proper user and group:
|
||||
|
||||
sudo mkdir -p /usr/local/var/log/ndn
|
||||
sudo chown -R ndn:ndn /usr/local/var/log/ndn
|
||||
|
||||
`HOME` directory for `nfd` should be created prior to starting. This is necessary to manage
|
||||
unique security credentials for the daemon.
|
||||
|
||||
# Create HOME and generate self-signed NDN certificate for nfd
|
||||
sudo sh -c ' \
|
||||
mkdir -p /usr/local/var/lib/ndn/nfd/.ndn; \
|
||||
export HOME=/usr/local/var/lib/ndn/nfd; \
|
||||
ndnsec-keygen /localhost/daemons/nfd | ndnsec-install-cert -; \
|
||||
'
|
||||
|
||||
### Configuring NFD's security
|
||||
|
||||
NFD sample configuration allows anybody to create faces, add nexthops to FIB, and set
|
||||
strategy choice for namespaces. While such settings could be a good start, it is
|
||||
generally not a good idea to run NFD in this mode.
|
||||
|
||||
While thorough discussion about the security configuration of NFD is outside the scope of
|
||||
this document, at least the following change should be done in ``nfd.conf`` in the
|
||||
authorize section:
|
||||
|
||||
authorizations
|
||||
{
|
||||
authorize
|
||||
{
|
||||
certfile certs/localhost_daemons_nfd.ndncert
|
||||
privileges
|
||||
{
|
||||
faces
|
||||
fib
|
||||
strategy-choice
|
||||
}
|
||||
}
|
||||
|
||||
authorize
|
||||
{
|
||||
certfile any
|
||||
privileges
|
||||
{
|
||||
faces
|
||||
strategy-choice
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
While this configuration still allows the management of faces and updating strategy choice by
|
||||
anyone, only NFD's RIB Manager (i.e., NFD itself) is allowed to manage FIB.
|
||||
|
||||
As the final step to make this configuration work, nfd's self-signed certificate needs to
|
||||
be exported into the `localhost_daemons_nfd.ndncert` file:
|
||||
|
||||
sudo sh -c '\
|
||||
mkdir -p /usr/local/etc/ndn/certs || true; \
|
||||
export HOME=/usr/local/var/lib/ndn/nfd; \
|
||||
ndnsec-dump-certificate -i /localhost/daemons/nfd > \
|
||||
/usr/local/etc/ndn/certs/localhost_daemons_nfd.ndncert; \
|
||||
'
|
||||
|
||||
Enable auto-start
|
||||
-----------------
|
||||
|
||||
After copying the provided upstart script, auto-start of the `nfd` daemon can be enabled with:
|
||||
|
||||
sudo systemctl enable nfd
|
||||
|
||||
To manually start it, use the following command:
|
||||
|
||||
sudo systemctl start nfd
|
||||
|
||||
Disable auto-start
|
||||
------------------
|
||||
|
||||
To stop the `nfd` daemon, use the following command:
|
||||
|
||||
sudo systemctl stop nfd
|
||||
|
||||
To permanently stop the `nfd` daemon and disable it from being automatically started on reboot,
|
||||
disable the service:
|
||||
|
||||
sudo systemctl disable nfd
|
||||
@@ -1,42 +0,0 @@
|
||||
# Copyright (c) 2015, Regents of the University of California,
|
||||
# Arizona Board of Regents,
|
||||
# Colorado State University,
|
||||
# University Pierre & Marie Curie, Sorbonne University,
|
||||
# Washington University in St. Louis,
|
||||
# Beijing Institute of Technology,
|
||||
# The University of Memphis.
|
||||
#
|
||||
# This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
# See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
#
|
||||
# NFD 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 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Eric Newberry <enewberry@email.arizona.edu>
|
||||
|
||||
[Unit]
|
||||
Description=NDN Forwarding Daemon
|
||||
Documentation=man:nfd man:nfdc man:nfd-status
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Environment=HOME=/usr/local/var/lib/ndn/nfd
|
||||
ExecStart=/usr/local/bin/nfd --config /usr/local/etc/ndn/nfd.conf
|
||||
ExecStartPost=/bin/sh -ec 'sleep 2; if [ -f /usr/local/etc/ndn/nfd-init.sh ]; then . /usr/local/etc/ndn/nfd-init.sh; fi'
|
||||
Restart=on-failure
|
||||
ProtectSystem=full
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=yes
|
||||
ProtectHome=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,125 +0,0 @@
|
||||
Starting NFD on Linux with upstart
|
||||
==================================
|
||||
|
||||
Some Linux distributions, such as Ubuntu, use [upstart](http://upstart.ubuntu.com/) as a
|
||||
standard mechanism to start system daemons, monitor their health, and restart
|
||||
when they die.
|
||||
|
||||
Initial setup
|
||||
-------------
|
||||
|
||||
* Edit `nfd.conf` correcting paths for `nfd` binary, configuration and log files.
|
||||
|
||||
* Copy upstart config file for NFD
|
||||
|
||||
sudo cp nfd.conf /etc/init/
|
||||
|
||||
### Assumptions in the default scripts
|
||||
|
||||
* `nfd` is installed into `/usr/local/bin`
|
||||
* Configuration file is `/usr/local/etc/ndn/nfd.conf`
|
||||
* `nfd` will be run as root
|
||||
* Log files will be written to `/usr/local/var/log/ndn` folder, which is owned by user `ndn`
|
||||
|
||||
### Creating users
|
||||
|
||||
If `ndn` user and group does not exists, they need to be manually created.
|
||||
|
||||
# Create group `ndn`
|
||||
addgroup --system ndn
|
||||
|
||||
# Create user `ndn`
|
||||
sudo adduser --system \
|
||||
--disabled-login \
|
||||
--ingroup ndn \
|
||||
--home /nonexistent \
|
||||
--gecos "NDN User" \
|
||||
--shell /bin/false \
|
||||
ndn
|
||||
|
||||
|
||||
### Creating folders
|
||||
|
||||
Folder `/usr/local/var/log/ndn` should be created and assigned proper user and group:
|
||||
|
||||
sudo mkdir -p /usr/local/var/log/ndn
|
||||
sudo chown -R ndn:ndn /usr/local/var/log/ndn
|
||||
|
||||
`HOME` directory for `nfd` should be created prior to starting. This is necessary to manage
|
||||
unique security credentials for the deamon.
|
||||
|
||||
# Create HOME and generate self-signed NDN certificate for nfd
|
||||
sudo -s -- ' \
|
||||
mkdir -p /usr/local/var/lib/ndn/nfd/.ndn; \
|
||||
export HOME=/usr/local/var/lib/ndn/nfd; \
|
||||
ndnsec-keygen /localhost/daemons/nfd | ndnsec-install-cert -; \
|
||||
'
|
||||
|
||||
### Configuring NFD's security
|
||||
|
||||
NFD sample configuration allows anybody to create faces, add nexthops to FIB, and set
|
||||
strategy choice for namespaces. While such settings could be a good start, it is
|
||||
generally not a good idea to run NFD in this mode.
|
||||
|
||||
While thorough discussion about security configuration of NFD is outside the scope of this
|
||||
document, at least the following change should be done to ``nfd.conf`` in authorize
|
||||
section:
|
||||
|
||||
authorizations
|
||||
{
|
||||
authorize
|
||||
{
|
||||
certfile certs/localhost_daemons_nfd.ndncert
|
||||
privileges
|
||||
{
|
||||
faces
|
||||
fib
|
||||
strategy-choice
|
||||
}
|
||||
}
|
||||
|
||||
authorize
|
||||
{
|
||||
certfile any
|
||||
privileges
|
||||
{
|
||||
faces
|
||||
strategy-choice
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
While this configuration still allows management of faces and updating strategy choice by
|
||||
anybody, only NFD's RIB Manager (i.e., NFD itself) is allowed to manage FIB.
|
||||
|
||||
As the final step to make this configuration work, nfd's self-signed certificate needs to
|
||||
be exported into `localhost_daemons_nfd.ndncert` file:
|
||||
|
||||
sudo -s -- '\
|
||||
mkdir -p /usr/local/etc/ndn/certs || true; \
|
||||
export HOME=/usr/local/var/lib/ndn/nfd; \
|
||||
ndnsec-dump-certificate -i /localhost/daemons/nfd > \
|
||||
/usr/local/etc/ndn/certs/localhost_daemons_nfd.ndncert; \
|
||||
'
|
||||
|
||||
|
||||
Enable auto-start
|
||||
-----------------
|
||||
|
||||
After copying the provided upstart script, `nfd` daemon will automatically run after the reboot.
|
||||
To manually start them, use the following commands:
|
||||
|
||||
sudo start nfd
|
||||
|
||||
Disable auto-start
|
||||
------------------
|
||||
|
||||
To stop `nfd` daemon, use the following commands:
|
||||
|
||||
sudo stop nfd
|
||||
|
||||
Note that as long as upstart files are present in `/etc/init/`, the daemon will
|
||||
automatically start after the reboot. To permanently stop `nfd` daemon, delete
|
||||
the upstart files:
|
||||
|
||||
sudo rm /etc/init/nfd.conf
|
||||
@@ -1,26 +0,0 @@
|
||||
# nfd.conf
|
||||
#
|
||||
# NDN Forwarding Daemon
|
||||
|
||||
description "NDN forwarding daemon"
|
||||
|
||||
start on (local-filesystems and net-device-up IFACE!=lo)
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
respawn limit unlimited
|
||||
|
||||
env HOME=/usr/local/var/lib/ndn/nfd
|
||||
export HOME
|
||||
|
||||
exec /usr/local/bin/nfd --config /usr/local/etc/ndn/nfd.conf 2>> /usr/local/var/log/ndn/nfd.log
|
||||
|
||||
post-start script
|
||||
if [ -f /usr/local/etc/ndn/nfd-init.sh ]; then
|
||||
sleep 2 # post-start is executed just after nfd process starts, but there is no guarantee
|
||||
# that all initialization has been finished
|
||||
. /usr/local/etc/ndn/nfd-init.sh
|
||||
fi
|
||||
end script
|
||||
|
||||
post-stop exec sleep 2
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,83 +23,60 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_COMMON_HPP
|
||||
#define NFD_COMMON_HPP
|
||||
#ifndef NFD_CORE_COMMON_HPP
|
||||
#define NFD_CORE_COMMON_HPP
|
||||
|
||||
#include "config.hpp"
|
||||
#include "core/config.hpp"
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
#define VIRTUAL_WITH_TESTS virtual
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED public
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE public
|
||||
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE protected
|
||||
#define OVERRIDE_WITH_TESTS_ELSE_FINAL override
|
||||
#define FINAL_UNLESS_WITH_TESTS
|
||||
#else
|
||||
#define VIRTUAL_WITH_TESTS
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED protected
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE private
|
||||
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE private
|
||||
#endif
|
||||
|
||||
/** \def DECL_OVERRIDE
|
||||
* \brief expands to 'override' if compiler supports 'override' specifier,
|
||||
* otherwise expands to nothing
|
||||
*/
|
||||
#ifdef HAVE_CXX_OVERRIDE
|
||||
#define DECL_OVERRIDE override
|
||||
#else
|
||||
#define DECL_OVERRIDE
|
||||
#endif
|
||||
|
||||
/** \def DECL_FINAL
|
||||
* \brief expands to 'final' if compiler supports 'final' specifier on method,
|
||||
* otherwise expands to nothing
|
||||
*/
|
||||
#ifdef HAVE_CXX_FINAL
|
||||
#define DECL_FINAL final
|
||||
#else
|
||||
#define DECL_FINAL
|
||||
#endif
|
||||
|
||||
/** \def DECL_CLASS_FINAL
|
||||
* \brief expands to 'final' if compiler supports 'final' specifier on class,
|
||||
* otherwise expands to nothing
|
||||
*/
|
||||
#ifdef HAVE_CXX_CLASS_FINAL
|
||||
#define DECL_CLASS_FINAL final
|
||||
#else
|
||||
#define DECL_CLASS_FINAL
|
||||
#define OVERRIDE_WITH_TESTS_ELSE_FINAL final
|
||||
#define FINAL_UNLESS_WITH_TESTS final
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <ndn-cxx/interest.hpp>
|
||||
#include <ndn-cxx/data.hpp>
|
||||
#include <ndn-cxx/delegation.hpp>
|
||||
#include <ndn-cxx/delegation-list.hpp>
|
||||
#include <ndn-cxx/interest.hpp>
|
||||
#include <ndn-cxx/name.hpp>
|
||||
#include <ndn-cxx/encoding/block.hpp>
|
||||
#include <ndn-cxx/lp/nack.hpp>
|
||||
#include <ndn-cxx/net/face-uri.hpp>
|
||||
#include <ndn-cxx/util/backports.hpp>
|
||||
#include <ndn-cxx/util/face-uri.hpp>
|
||||
#include <ndn-cxx/util/exception.hpp>
|
||||
#include <ndn-cxx/util/scheduler.hpp>
|
||||
#include <ndn-cxx/util/signal.hpp>
|
||||
#include <ndn-cxx/util/time.hpp>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -111,39 +88,44 @@ using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
using std::weak_ptr;
|
||||
using std::make_shared;
|
||||
using ndn::make_unique;
|
||||
using std::enable_shared_from_this;
|
||||
using std::make_unique;
|
||||
|
||||
using std::static_pointer_cast;
|
||||
using std::dynamic_pointer_cast;
|
||||
using std::const_pointer_cast;
|
||||
|
||||
using std::function;
|
||||
using std::bind;
|
||||
using std::ref;
|
||||
using std::cref;
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
using ndn::optional;
|
||||
using ndn::nullopt;
|
||||
using ndn::to_string;
|
||||
|
||||
using ndn::Interest;
|
||||
using ndn::Block;
|
||||
using ndn::Data;
|
||||
using ndn::Delegation;
|
||||
using ndn::DelegationList;
|
||||
using ndn::FaceUri;
|
||||
using ndn::Interest;
|
||||
using ndn::Name;
|
||||
using ndn::PartialName;
|
||||
using ndn::Exclude;
|
||||
using ndn::Link;
|
||||
using ndn::Block;
|
||||
using ndn::util::FaceUri;
|
||||
using ndn::Scheduler;
|
||||
|
||||
// Not using a namespace alias (namespace tlv = ndn::tlv), because
|
||||
// it doesn't allow NFD to add other members to the namespace
|
||||
namespace tlv {
|
||||
// Don't write "namespace tlv = ndn::tlv", because NFD can add other members into this namespace.
|
||||
using namespace ndn::tlv;
|
||||
} // namespace tlv
|
||||
|
||||
namespace lp = ndn::lp;
|
||||
namespace name = ndn::name;
|
||||
namespace time = ndn::time;
|
||||
namespace scheduler = ndn::scheduler;
|
||||
namespace signal = ndn::util::signal;
|
||||
namespace time = ndn::time;
|
||||
using namespace ndn::time_literals;
|
||||
using ndn::operator""_block;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_COMMON_HPP
|
||||
#endif // NFD_CORE_COMMON_HPP
|
||||
@@ -1,48 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014 Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef NFD_CORE_GLOBAL_IO_HPP
|
||||
#define NFD_CORE_GLOBAL_IO_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \return the global io_service instance
|
||||
*/
|
||||
boost::asio::io_service&
|
||||
getGlobalIoService();
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
/** \brief delete the global io_service instance
|
||||
*
|
||||
* It will be recreated at the next invocation of getGlobalIoService.
|
||||
*/
|
||||
void
|
||||
resetGlobalIoService();
|
||||
#endif
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_GLOBAL_IO_HPP
|
||||
@@ -1,209 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "logger-factory.hpp"
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
#ifdef HAVE_CUSTOM_LOGGER
|
||||
#error "This file should not be compiled when custom logger is used"
|
||||
#endif
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INIT("LoggerFactory");
|
||||
|
||||
LoggerFactory&
|
||||
LoggerFactory::getInstance()
|
||||
{
|
||||
static LoggerFactory globalLoggerFactory;
|
||||
|
||||
return globalLoggerFactory;
|
||||
}
|
||||
|
||||
LoggerFactory::LoggerFactory()
|
||||
: m_defaultLevel(LOG_INFO)
|
||||
{
|
||||
m_levelNames["NONE"] = LOG_NONE;
|
||||
m_levelNames["ERROR"] = LOG_ERROR;
|
||||
m_levelNames["WARN"] = LOG_WARN;
|
||||
m_levelNames["INFO"] = LOG_INFO;
|
||||
m_levelNames["DEBUG"] = LOG_DEBUG;
|
||||
m_levelNames["TRACE"] = LOG_TRACE;
|
||||
m_levelNames["ALL"] = LOG_ALL;
|
||||
}
|
||||
|
||||
void
|
||||
LoggerFactory::setConfigFile(ConfigFile& config)
|
||||
{
|
||||
config.addSectionHandler("log", bind(&LoggerFactory::onConfig, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
LogLevel
|
||||
LoggerFactory::parseLevel(const std::string& level)
|
||||
{
|
||||
std::string upperLevel = level;
|
||||
boost::to_upper(upperLevel);
|
||||
|
||||
// std::cerr << "parsing level: " << upperLevel << std::endl;;
|
||||
// std::cerr << "# levels: " << m_levelNames.size() << std::endl;
|
||||
// std::cerr << m_levelNames.begin()->first << std::endl;
|
||||
|
||||
LevelMap::const_iterator levelIt = m_levelNames.find(upperLevel);
|
||||
if (levelIt != m_levelNames.end()) {
|
||||
return levelIt->second;
|
||||
}
|
||||
try {
|
||||
uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
|
||||
|
||||
if ((boost::lexical_cast<uint32_t>(LOG_NONE) <= levelNo &&
|
||||
levelNo <= boost::lexical_cast<uint32_t>(LOG_TRACE)) ||
|
||||
levelNo == LOG_ALL) {
|
||||
return static_cast<LogLevel>(levelNo);
|
||||
}
|
||||
}
|
||||
catch (const boost::bad_lexical_cast& error) {
|
||||
}
|
||||
|
||||
BOOST_THROW_EXCEPTION(LoggerFactory::Error("Unsupported logging level \"" + level + "\""));
|
||||
}
|
||||
|
||||
LogLevel
|
||||
LoggerFactory::extractLevel(const ConfigSection& item, const std::string& key)
|
||||
{
|
||||
std::string levelString;
|
||||
try {
|
||||
levelString = item.get_value<std::string>();
|
||||
}
|
||||
catch (const boost::property_tree::ptree_error& error) {
|
||||
}
|
||||
|
||||
if (levelString.empty()) {
|
||||
BOOST_THROW_EXCEPTION(LoggerFactory::Error("No logging level found for option \"" + key + "\""));
|
||||
}
|
||||
|
||||
return parseLevel(levelString);
|
||||
}
|
||||
|
||||
void
|
||||
LoggerFactory::onConfig(const ConfigSection& section,
|
||||
bool isDryRun,
|
||||
const std::string& filename)
|
||||
{
|
||||
// log
|
||||
// {
|
||||
// ; default_level specifies the logging level for modules
|
||||
// ; that are not explicitly named. All debugging levels
|
||||
// ; listed above the selected value are enabled.
|
||||
//
|
||||
// default_level INFO
|
||||
//
|
||||
// ; You may also override the default for specific modules:
|
||||
//
|
||||
// FibManager DEBUG
|
||||
// Forwarder WARN
|
||||
// }
|
||||
|
||||
if (!isDryRun) {
|
||||
ConfigSection::const_assoc_iterator item = section.find("default_level");
|
||||
if (item != section.not_found()) {
|
||||
LogLevel level = extractLevel(item->second, "default_level");
|
||||
setDefaultLevel(level);
|
||||
}
|
||||
else {
|
||||
setDefaultLevel(LOG_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& i : section) {
|
||||
LogLevel level = extractLevel(i.second, i.first);
|
||||
|
||||
if (i.first == "default_level") {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
std::unique_lock<std::mutex> lock(m_loggersGuard);
|
||||
LoggerMap::iterator loggerIt = m_loggers.find(i.first);
|
||||
if (loggerIt == m_loggers.end()) {
|
||||
lock.unlock();
|
||||
NFD_LOG_DEBUG("Failed to configure logging level for module \"" <<
|
||||
i.first << "\" (module not found)");
|
||||
}
|
||||
else if (!isDryRun) {
|
||||
loggerIt->second.setLogLevel(level);
|
||||
lock.unlock();
|
||||
NFD_LOG_DEBUG("Changing level for module " << i.first << " to " << level);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LoggerFactory::setDefaultLevel(LogLevel level)
|
||||
{
|
||||
// std::cerr << "changing to default_level " << level << std::endl;
|
||||
std::lock_guard<std::mutex> lock(m_loggersGuard);
|
||||
|
||||
m_defaultLevel = level;
|
||||
for (auto&& logger : m_loggers) {
|
||||
// std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
|
||||
logger.second.setLogLevel(m_defaultLevel);
|
||||
}
|
||||
}
|
||||
|
||||
Logger&
|
||||
LoggerFactory::create(const std::string& moduleName)
|
||||
{
|
||||
return LoggerFactory::getInstance().createLogger(moduleName);
|
||||
}
|
||||
|
||||
Logger&
|
||||
LoggerFactory::createLogger(const std::string& moduleName)
|
||||
{
|
||||
// std::cerr << "creating logger for " << moduleName
|
||||
// << " with level " << m_defaultLevel << std::endl;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_loggersGuard);
|
||||
|
||||
std::pair<LoggerMap::iterator, bool> loggerIt =
|
||||
m_loggers.insert(NameAndLogger(moduleName, Logger(moduleName, m_defaultLevel)));
|
||||
|
||||
return loggerIt.first->second;
|
||||
}
|
||||
|
||||
std::list<std::string>
|
||||
LoggerFactory::getModules() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_loggersGuard);
|
||||
|
||||
std::list<std::string> modules;
|
||||
for (const auto& loggerName : m_loggers | boost::adaptors::map_keys) {
|
||||
modules.push_back(loggerName);
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,119 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_LOGGER_FACTORY_HPP
|
||||
#define NFD_CORE_LOGGER_FACTORY_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#ifdef HAVE_CUSTOM_LOGGER
|
||||
#include "custom-logger-factory.hpp"
|
||||
#else
|
||||
|
||||
#include "config-file.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class LoggerFactory : noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& error)
|
||||
: std::runtime_error(error)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static LoggerFactory&
|
||||
getInstance();
|
||||
|
||||
void
|
||||
setConfigFile(ConfigFile& config);
|
||||
|
||||
void
|
||||
onConfig(const ConfigSection& section, bool isDryRun, const std::string& filename);
|
||||
|
||||
std::list<std::string>
|
||||
getModules() const;
|
||||
|
||||
static Logger&
|
||||
create(const std::string& moduleName);
|
||||
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
|
||||
// these methods are used during unit-testing
|
||||
|
||||
LogLevel
|
||||
getDefaultLevel() const;
|
||||
|
||||
void
|
||||
setDefaultLevel(LogLevel level);
|
||||
|
||||
private:
|
||||
|
||||
LoggerFactory();
|
||||
|
||||
Logger&
|
||||
createLogger(const std::string& moduleName);
|
||||
|
||||
LogLevel
|
||||
parseLevel(const std::string& level);
|
||||
|
||||
LogLevel
|
||||
extractLevel(const ConfigSection& item, const std::string& key);
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<std::string, LogLevel> LevelMap;
|
||||
typedef std::pair<std::string, LogLevel> NameAndLevel;
|
||||
|
||||
LevelMap m_levelNames;
|
||||
|
||||
typedef std::map<std::string, Logger> LoggerMap;
|
||||
typedef std::pair<std::string, Logger> NameAndLogger;
|
||||
|
||||
LoggerMap m_loggers;
|
||||
mutable std::mutex m_loggersGuard;
|
||||
|
||||
LogLevel m_defaultLevel;
|
||||
};
|
||||
|
||||
inline LogLevel
|
||||
LoggerFactory::getDefaultLevel() const
|
||||
{
|
||||
return m_defaultLevel;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // HAVE_CUSTOM_LOGGER
|
||||
|
||||
#endif // NFD_CORE_LOGGER_FACTORY_HPP
|
||||
@@ -1,74 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "logger.hpp"
|
||||
|
||||
#ifdef HAVE_CUSTOM_LOGGER
|
||||
#error "This file should not be compiled when custom logger is used"
|
||||
#endif
|
||||
|
||||
#include <ndn-cxx/util/time.hpp>
|
||||
#include <cinttypes>
|
||||
#include <stdio.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
std::mutex g_logMutex;
|
||||
|
||||
Logger::Logger(const std::string& name, LogLevel level)
|
||||
: m_moduleName(name)
|
||||
, m_enabledLogLevel(level)
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
Logger::now()
|
||||
{
|
||||
using namespace ndn::time;
|
||||
|
||||
static const microseconds::rep ONE_SECOND = 1000000;
|
||||
microseconds::rep microsecondsSinceEpoch = duration_cast<microseconds>(
|
||||
system_clock::now().time_since_epoch()).count();
|
||||
|
||||
// 10 (whole seconds) + '.' + 6 (fraction) + '\0'
|
||||
static char buffer[10 + 1 + 6 + 1];
|
||||
BOOST_ASSERT_MSG(microsecondsSinceEpoch / ONE_SECOND <= 9999999999L,
|
||||
"whole seconds cannot fit in 10 characters");
|
||||
|
||||
static_assert(std::is_same<microseconds::rep, int_least64_t>::value,
|
||||
"PRIdLEAST64 is incompatible with microseconds::rep");
|
||||
// - std::snprintf not found in some environments
|
||||
// http://redmine.named-data.net/issues/2299 for more information
|
||||
snprintf(buffer, sizeof(buffer), "%" PRIdLEAST64 ".%06" PRIdLEAST64,
|
||||
microsecondsSinceEpoch / ONE_SECOND,
|
||||
microsecondsSinceEpoch % ONE_SECOND);
|
||||
|
||||
// It's okay to return a statically allocated buffer, because Logger::now() is invoked
|
||||
// only once per log macro.
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_LOGGER_HPP
|
||||
#define NFD_CORE_LOGGER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#ifdef HAVE_CUSTOM_LOGGER
|
||||
#include "custom-logger.hpp"
|
||||
#else
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief indicates a log level
|
||||
* \note This type is internal. Logger should be accessed through NFD_LOG_* macros.
|
||||
*/
|
||||
enum LogLevel {
|
||||
LOG_FATAL = -1, // fatal (will be logged unconditionally)
|
||||
LOG_NONE = 0, // no messages
|
||||
LOG_ERROR = 1, // serious error messages
|
||||
LOG_WARN = 2, // warning messages
|
||||
LOG_INFO = 3, // informational messages
|
||||
LOG_DEBUG = 4, // debug messages
|
||||
LOG_TRACE = 5, // trace messages (most verbose)
|
||||
LOG_ALL = 255 // all messages
|
||||
};
|
||||
|
||||
/** \brief provides logging for a module
|
||||
* \note This type is internal. Logger should be accessed through NFD_LOG_* macros.
|
||||
* \note This type is copyable because logger can be declared as a field of
|
||||
* (usually template) classes, and shouldn't prevent those classes to be copyable.
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
Logger(const std::string& name, LogLevel level);
|
||||
|
||||
bool
|
||||
isEnabled(LogLevel level) const
|
||||
{
|
||||
return m_enabledLogLevel >= level;
|
||||
}
|
||||
|
||||
void
|
||||
setLogLevel(LogLevel level)
|
||||
{
|
||||
m_enabledLogLevel = level;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
getName() const
|
||||
{
|
||||
return m_moduleName;
|
||||
}
|
||||
|
||||
void
|
||||
setName(const std::string& name)
|
||||
{
|
||||
m_moduleName = name;
|
||||
}
|
||||
|
||||
/** \return string representation of time since epoch: seconds.microseconds
|
||||
* \warning Return value is in a statically allocated buffer,
|
||||
* which subsequent calls will overwrite.
|
||||
*/
|
||||
static const char*
|
||||
now();
|
||||
|
||||
private:
|
||||
std::string m_moduleName;
|
||||
LogLevel m_enabledLogLevel;
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& output, const Logger& logger)
|
||||
{
|
||||
output << logger.getName();
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#include "core/logger-factory.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
#define NFD_LOG_INIT(name) \
|
||||
static nfd::Logger& g_logger = nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_DECLARE() \
|
||||
static nfd::Logger& g_logger
|
||||
|
||||
#define NFD_LOG_INCLASS_DEFINE(cls, name) \
|
||||
nfd::Logger& cls::g_logger = nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_TEMPLATE_DEFINE(cls, name) \
|
||||
template<class T> \
|
||||
nfd::Logger& cls<T>::g_logger = nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(cls, specialization, name) \
|
||||
template<> \
|
||||
nfd::Logger& cls<specialization>::g_logger = nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(cls, s1, s2, name) \
|
||||
template<> \
|
||||
nfd::Logger& cls<s1, s2>::g_logger = nfd::LoggerFactory::create(name)
|
||||
|
||||
extern std::mutex g_logMutex;
|
||||
|
||||
#define NFD_LOG(level, msg, expression) \
|
||||
do { \
|
||||
if (g_logger.isEnabled(::nfd::LOG_##level)) { \
|
||||
std::lock_guard<std::mutex> lock(::nfd::g_logMutex); \
|
||||
std::clog << ::nfd::Logger::now() << " "#msg": " \
|
||||
<< "[" << g_logger << "] " << expression << "\n"; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define NFD_LOG_TRACE(expression) NFD_LOG(TRACE, TRACE, expression)
|
||||
#define NFD_LOG_DEBUG(expression) NFD_LOG(DEBUG, DEBUG, expression)
|
||||
#define NFD_LOG_INFO(expression) NFD_LOG(INFO, INFO, expression)
|
||||
#define NFD_LOG_WARN(expression) NFD_LOG(WARN, WARNING, expression)
|
||||
#define NFD_LOG_ERROR(expression) NFD_LOG(ERROR, ERROR, expression)
|
||||
#define NFD_LOG_FATAL(expression) NFD_LOG(FATAL, FATAL, expression)
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // HAVE_CUSTOM_LOGGER
|
||||
|
||||
#endif // NFD_CORE_LOGGER_HPP
|
||||
@@ -1,185 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "network-interface.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h> // for getifaddrs()
|
||||
|
||||
#include <arpa/inet.h> // for inet_ntop()
|
||||
#include <netinet/in.h> // for struct sockaddr_in{,6}
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <net/if_arp.h> // for ARPHRD_* constants
|
||||
#include <netpacket/packet.h> // for struct sockaddr_ll
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <net/if_dl.h> // for struct sockaddr_dl
|
||||
#include <net/if_types.h> // for IFT_* constants
|
||||
#endif
|
||||
|
||||
#endif // HAVE_IFADDRS_H
|
||||
|
||||
|
||||
NFD_LOG_INIT("NetworkInterfaceInfo");
|
||||
|
||||
namespace nfd {
|
||||
|
||||
static_assert(std::is_standard_layout<NetworkInterfaceInfo>::value,
|
||||
"NetworkInterfaceInfo must be a standard layout type");
|
||||
#ifdef HAVE_IS_DEFAULT_CONSTRUCTIBLE
|
||||
static_assert(std::is_default_constructible<NetworkInterfaceInfo>::value,
|
||||
"NetworkInterfaceInfo must provide a default constructor");
|
||||
#endif
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
static shared_ptr<std::vector<NetworkInterfaceInfo>> s_debugNetworkInterfaces = nullptr;
|
||||
|
||||
void
|
||||
setDebugNetworkInterfaces(shared_ptr<std::vector<NetworkInterfaceInfo>> interfaces)
|
||||
{
|
||||
s_debugNetworkInterfaces = interfaces;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<NetworkInterfaceInfo>
|
||||
listNetworkInterfaces()
|
||||
{
|
||||
#ifdef WITH_TESTS
|
||||
if (s_debugNetworkInterfaces != nullptr) {
|
||||
return *s_debugNetworkInterfaces;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
using namespace boost::asio::ip;
|
||||
using std::strerror;
|
||||
|
||||
std::unordered_map<std::string, NetworkInterfaceInfo> ifmap;
|
||||
ifaddrs* ifa_list = nullptr;
|
||||
|
||||
if (::getifaddrs(&ifa_list) < 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(std::string("getifaddrs() failed: ") +
|
||||
strerror(errno)));
|
||||
|
||||
for (ifaddrs* ifa = ifa_list; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
std::string ifname(ifa->ifa_name);
|
||||
NetworkInterfaceInfo& netif = ifmap[ifname];
|
||||
netif.name = ifa->ifa_name;
|
||||
netif.flags = ifa->ifa_flags;
|
||||
|
||||
if (ifa->ifa_addr == nullptr)
|
||||
continue;
|
||||
|
||||
switch (ifa->ifa_addr->sa_family) {
|
||||
|
||||
case AF_INET: {
|
||||
const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_addr);
|
||||
char address[INET_ADDRSTRLEN];
|
||||
if (::inet_ntop(AF_INET, &sin->sin_addr, address, sizeof(address))) {
|
||||
netif.ipv4Addresses.push_back(address_v4::from_string(address));
|
||||
NFD_LOG_TRACE(ifname << ": added IPv4 address " << address);
|
||||
}
|
||||
else
|
||||
NFD_LOG_WARN(ifname << ": inet_ntop(AF_INET) failed: " << strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
case AF_INET6: {
|
||||
const sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(ifa->ifa_addr);
|
||||
char address[INET6_ADDRSTRLEN];
|
||||
if (::inet_ntop(AF_INET6, &sin6->sin6_addr, address, sizeof(address))) {
|
||||
netif.ipv6Addresses.push_back(address_v6::from_string(address));
|
||||
NFD_LOG_TRACE(ifname << ": added IPv6 address " << address);
|
||||
}
|
||||
else
|
||||
NFD_LOG_WARN(ifname << ": inet_ntop(AF_INET6) failed: " << strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
case AF_PACKET: {
|
||||
const sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ifa->ifa_addr);
|
||||
netif.index = sll->sll_ifindex;
|
||||
if (sll->sll_hatype == ARPHRD_ETHER && sll->sll_halen == ethernet::ADDR_LEN) {
|
||||
netif.etherAddress = ethernet::Address(sll->sll_addr);
|
||||
NFD_LOG_TRACE(ifname << ": added Ethernet address " << netif.etherAddress);
|
||||
}
|
||||
else if (sll->sll_hatype != ARPHRD_LOOPBACK) {
|
||||
NFD_LOG_DEBUG(ifname << ": ignoring link-layer address for unhandled hardware type "
|
||||
<< sll->sll_hatype);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
case AF_LINK: {
|
||||
const sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(ifa->ifa_addr);
|
||||
netif.index = sdl->sdl_index;
|
||||
if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ethernet::ADDR_LEN) {
|
||||
netif.etherAddress = ethernet::Address(reinterpret_cast<uint8_t*>(LLADDR(sdl)));
|
||||
NFD_LOG_TRACE(ifname << ": added Ethernet address " << netif.etherAddress);
|
||||
}
|
||||
else if (sdl->sdl_type != IFT_LOOP) {
|
||||
NFD_LOG_DEBUG(ifname << ": ignoring link-layer address for unhandled interface type "
|
||||
<< sdl->sdl_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (netif.isBroadcastCapable() && ifa->ifa_broadaddr != nullptr) {
|
||||
const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_broadaddr);
|
||||
char address[INET_ADDRSTRLEN];
|
||||
if (::inet_ntop(AF_INET, &sin->sin_addr, address, sizeof(address))) {
|
||||
netif.broadcastAddress = address_v4::from_string(address);
|
||||
NFD_LOG_TRACE(ifname << ": added IPv4 broadcast address " << address);
|
||||
}
|
||||
else
|
||||
NFD_LOG_WARN(ifname << ": inet_ntop(AF_INET) for broadaddr failed: " << strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
::freeifaddrs(ifa_list);
|
||||
|
||||
std::vector<NetworkInterfaceInfo> v;
|
||||
v.reserve(ifmap.size());
|
||||
for (auto&& element : ifmap) {
|
||||
v.push_back(element.second);
|
||||
}
|
||||
|
||||
return v;
|
||||
#else
|
||||
return {};
|
||||
#endif // HAVE_IFADDRS_H
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,107 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_NETWORK_INTERFACE_HPP
|
||||
#define NFD_CORE_NETWORK_INTERFACE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <ndn-cxx/util/ethernet.hpp>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
namespace ethernet = ndn::util::ethernet;
|
||||
|
||||
/** \brief contains information about a network interface
|
||||
*/
|
||||
class NetworkInterfaceInfo
|
||||
{
|
||||
public:
|
||||
|
||||
int index;
|
||||
std::string name;
|
||||
ethernet::Address etherAddress;
|
||||
std::vector<boost::asio::ip::address_v4> ipv4Addresses;
|
||||
std::vector<boost::asio::ip::address_v6> ipv6Addresses;
|
||||
boost::asio::ip::address_v4 broadcastAddress;
|
||||
unsigned int flags;
|
||||
|
||||
bool
|
||||
isLoopback() const;
|
||||
|
||||
bool
|
||||
isMulticastCapable() const;
|
||||
|
||||
bool
|
||||
isBroadcastCapable() const;
|
||||
|
||||
bool
|
||||
isUp() const;
|
||||
|
||||
};
|
||||
|
||||
inline bool
|
||||
NetworkInterfaceInfo::isLoopback() const
|
||||
{
|
||||
return (flags & IFF_LOOPBACK) != 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
NetworkInterfaceInfo::isMulticastCapable() const
|
||||
{
|
||||
return (flags & IFF_MULTICAST) != 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
NetworkInterfaceInfo::isBroadcastCapable() const
|
||||
{
|
||||
return (flags & IFF_BROADCAST) != 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
NetworkInterfaceInfo::isUp() const
|
||||
{
|
||||
return (flags & IFF_UP) != 0;
|
||||
}
|
||||
|
||||
/** \brief List configured network interfaces on the system and their info
|
||||
* \warning invalid IP addresses (e.g., 0.0.0.0) may be returned in some environments
|
||||
*/
|
||||
std::vector<NetworkInterfaceInfo>
|
||||
listNetworkInterfaces();
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
/** \brief Set a list of network interfaces to be returned by subsequent listNetworkInterfaces call
|
||||
* \note To reset to normal behavior, use `setDebugNetworkInterfaces(nullptr);`
|
||||
*/
|
||||
void
|
||||
setDebugNetworkInterfaces(shared_ptr<std::vector<NetworkInterfaceInfo>> interfaces);
|
||||
#endif
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_NETWORK_INTERFACE_HPP
|
||||
+120
-72
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -21,23 +21,30 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
*/
|
||||
|
||||
#include "network.hpp"
|
||||
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
void
|
||||
Network::print(std::ostream& os) const
|
||||
Network::Network() = default;
|
||||
|
||||
Network::Network(const boost::asio::ip::address& minAddress,
|
||||
const boost::asio::ip::address& maxAddress)
|
||||
: m_minAddress(minAddress)
|
||||
, m_maxAddress(maxAddress)
|
||||
{
|
||||
os << m_minAddress << " <-> " << m_maxAddress;
|
||||
}
|
||||
|
||||
const Network&
|
||||
Network::getMaxRangeV4()
|
||||
{
|
||||
using boost::asio::ip::address_v4;
|
||||
static Network range = Network(address_v4(0), address_v4(0xFFFFFFFF));
|
||||
static Network range{address_v4{}, address_v4{0xffffffff}};
|
||||
return range;
|
||||
}
|
||||
|
||||
@@ -47,86 +54,127 @@ Network::getMaxRangeV6()
|
||||
using boost::asio::ip::address_v6;
|
||||
static address_v6::bytes_type maxV6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||
static Network range = Network(address_v6(), address_v6(maxV6));
|
||||
static Network range{address_v6{}, address_v6{maxV6}};
|
||||
return range;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
Network::isValidCidr(const std::string& cidr)
|
||||
{
|
||||
auto pos = cidr.find('/');
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
boost::lexical_cast<Network>(cidr);
|
||||
return true;
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Network& network)
|
||||
{
|
||||
network.print(os);
|
||||
return os;
|
||||
return os << network.m_minAddress << " <-> " << network.m_maxAddress;
|
||||
}
|
||||
|
||||
std::istream&
|
||||
operator>>(std::istream& is, Network& network)
|
||||
{
|
||||
using namespace boost::asio;
|
||||
namespace ip = boost::asio::ip;
|
||||
|
||||
std::string networkStr;
|
||||
is >> networkStr;
|
||||
|
||||
size_t position = networkStr.find('/');
|
||||
if (position == std::string::npos)
|
||||
{
|
||||
if (position == std::string::npos) {
|
||||
try {
|
||||
network.m_minAddress = ip::address::from_string(networkStr);
|
||||
network.m_maxAddress = ip::address::from_string(networkStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip::address address = ip::address::from_string(networkStr.substr(0, position));
|
||||
size_t mask = boost::lexical_cast<size_t>(networkStr.substr(position+1));
|
||||
|
||||
if (address.is_v4())
|
||||
{
|
||||
ip::address_v4::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++)
|
||||
{
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
ip::address_v4::bytes_type addressBytes = address.to_v4().to_bytes();
|
||||
ip::address_v4::bytes_type min;
|
||||
ip::address_v4::bytes_type max;
|
||||
|
||||
for (size_t i = 0; i < addressBytes.size(); i++)
|
||||
{
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
network.m_minAddress = ip::address_v4(min);
|
||||
network.m_maxAddress = ip::address_v4(max);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip::address_v6::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++)
|
||||
{
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
ip::address_v6::bytes_type addressBytes = address.to_v6().to_bytes();
|
||||
ip::address_v6::bytes_type min;
|
||||
ip::address_v6::bytes_type max;
|
||||
|
||||
for (size_t i = 0; i < addressBytes.size(); i++)
|
||||
{
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
network.m_minAddress = ip::address_v6(min);
|
||||
network.m_maxAddress = ip::address_v6(max);
|
||||
}
|
||||
catch (const boost::system::system_error&) {
|
||||
is.setstate(std::ios::failbit);
|
||||
return is;
|
||||
}
|
||||
}
|
||||
else {
|
||||
boost::system::error_code ec;
|
||||
auto address = ip::address::from_string(networkStr.substr(0, position), ec);
|
||||
if (ec) {
|
||||
is.setstate(std::ios::failbit);
|
||||
return is;
|
||||
}
|
||||
|
||||
auto prefixLenStr = networkStr.substr(position + 1);
|
||||
if (!std::all_of(prefixLenStr.begin(), prefixLenStr.end(),
|
||||
[] (unsigned char c) { return std::isdigit(c); })) {
|
||||
is.setstate(std::ios::failbit);
|
||||
return is;
|
||||
}
|
||||
size_t mask;
|
||||
try {
|
||||
mask = boost::lexical_cast<size_t>(prefixLenStr);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
is.setstate(std::ios::failbit);
|
||||
return is;
|
||||
}
|
||||
|
||||
if (address.is_v4()) {
|
||||
if (mask > 32) {
|
||||
is.setstate(std::ios::failbit);
|
||||
return is;
|
||||
}
|
||||
|
||||
ip::address_v4::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++) {
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
ip::address_v4::bytes_type addressBytes = address.to_v4().to_bytes();
|
||||
ip::address_v4::bytes_type min;
|
||||
ip::address_v4::bytes_type max;
|
||||
|
||||
for (size_t i = 0; i < addressBytes.size(); i++) {
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
network.m_minAddress = ip::address_v4(min);
|
||||
network.m_maxAddress = ip::address_v4(max);
|
||||
}
|
||||
else {
|
||||
if (mask > 128) {
|
||||
is.setstate(std::ios::failbit);
|
||||
return is;
|
||||
}
|
||||
|
||||
ip::address_v6::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++) {
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
ip::address_v6::bytes_type addressBytes = address.to_v6().to_bytes();
|
||||
ip::address_v6::bytes_type min;
|
||||
ip::address_v6::bytes_type max;
|
||||
|
||||
for (size_t i = 0; i < addressBytes.size(); i++) {
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
network.m_minAddress = ip::address_v6(min);
|
||||
network.m_maxAddress = ip::address_v6(max);
|
||||
}
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
+17
-25
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -26,33 +26,22 @@
|
||||
#ifndef NFD_CORE_NETWORK_HPP
|
||||
#define NFD_CORE_NETWORK_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class Network
|
||||
{
|
||||
public:
|
||||
Network()
|
||||
{
|
||||
}
|
||||
Network();
|
||||
|
||||
Network(const boost::asio::ip::address& minAddress,
|
||||
const boost::asio::ip::address& maxAddress)
|
||||
: m_minAddress(minAddress)
|
||||
, m_maxAddress(maxAddress)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
print(std::ostream& os) const;
|
||||
const boost::asio::ip::address& maxAddress);
|
||||
|
||||
bool
|
||||
doesContain(const boost::asio::ip::address& address) const
|
||||
{
|
||||
return (m_minAddress <= address && address <= m_maxAddress);
|
||||
return m_minAddress <= address && address <= m_maxAddress;
|
||||
}
|
||||
|
||||
static const Network&
|
||||
@@ -61,6 +50,9 @@ public:
|
||||
static const Network&
|
||||
getMaxRangeV6();
|
||||
|
||||
static bool
|
||||
isValidCidr(const std::string& cidr);
|
||||
|
||||
bool
|
||||
operator==(const Network& rhs) const
|
||||
{
|
||||
@@ -77,11 +69,11 @@ private:
|
||||
boost::asio::ip::address m_minAddress;
|
||||
boost::asio::ip::address m_maxAddress;
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& is, Network& network);
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, const Network& network);
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& is, Network& network);
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "privilege-helper.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INIT("PrivilegeHelper");
|
||||
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
uid_t PrivilegeHelper::s_normalUid = ::geteuid();
|
||||
gid_t PrivilegeHelper::s_normalGid = ::getegid();
|
||||
|
||||
uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
|
||||
gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
|
||||
void
|
||||
PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
|
||||
{
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16kB
|
||||
static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
|
||||
|
||||
static const size_t FALLBACK_GROUP_BUFFER_SIZE = 1024;
|
||||
static const size_t FALLBACK_PASSWD_BUFFER_SIZE = 1024;
|
||||
|
||||
NFD_LOG_TRACE("initializing privilege helper with user \"" << userName << "\""
|
||||
<< " group \"" << groupName << "\"");
|
||||
|
||||
// workflow from man getpwnam_r
|
||||
|
||||
if (!groupName.empty())
|
||||
{
|
||||
static int groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||
|
||||
if (groupSize == -1)
|
||||
{
|
||||
groupSize = FALLBACK_GROUP_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
std::vector<char> groupBuffer(groupSize);
|
||||
struct group group;
|
||||
struct group* groupResult = 0;
|
||||
|
||||
int errorCode = getgrnam_r(groupName.c_str(), &group,
|
||||
&groupBuffer[0], groupSize, &groupResult);
|
||||
|
||||
while (errorCode == ERANGE)
|
||||
{
|
||||
if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
|
||||
{
|
||||
throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct group");
|
||||
}
|
||||
|
||||
groupBuffer.resize(groupBuffer.size() * 2);
|
||||
|
||||
errorCode = getgrnam_r(groupName.c_str(), &group,
|
||||
&groupBuffer[0], groupBuffer.size(), &groupResult);
|
||||
}
|
||||
|
||||
if (errorCode != 0 || !groupResult)
|
||||
{
|
||||
throw PrivilegeHelper::Error("Failed to get gid for \"" + groupName + "\"");
|
||||
}
|
||||
|
||||
s_normalGid = group.gr_gid;
|
||||
}
|
||||
|
||||
if (!userName.empty())
|
||||
{
|
||||
static int passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
||||
if (passwdSize == -1)
|
||||
{
|
||||
passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
std::vector<char> passwdBuffer(passwdSize);
|
||||
struct passwd passwd;
|
||||
struct passwd* passwdResult = 0;
|
||||
|
||||
int errorCode =
|
||||
getpwnam_r(userName.c_str(), &passwd,
|
||||
&passwdBuffer[0], passwdBuffer.size(), &passwdResult);
|
||||
|
||||
while (errorCode == ERANGE)
|
||||
{
|
||||
if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
|
||||
{
|
||||
throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct passwd");
|
||||
}
|
||||
|
||||
passwdBuffer.resize(passwdBuffer.size() * 2);
|
||||
|
||||
errorCode = getpwnam_r(userName.c_str(), &passwd,
|
||||
&passwdBuffer[0], passwdBuffer.size(), &passwdResult);
|
||||
}
|
||||
|
||||
if (errorCode != 0 || !passwdResult)
|
||||
{
|
||||
throw PrivilegeHelper::Error("Failed to get uid for \"" + userName + "\"");
|
||||
}
|
||||
|
||||
s_normalUid = passwd.pw_uid;
|
||||
}
|
||||
#else
|
||||
if (!userName.empty() || !groupName.empty()) {
|
||||
throw Error("Dropping and raising privileges is not supported on this platform");
|
||||
}
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
void
|
||||
PrivilegeHelper::drop()
|
||||
{
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
|
||||
if (::setegid(s_normalGid) != 0)
|
||||
{
|
||||
std::stringstream error;
|
||||
error << "Failed to drop to effective gid=" << s_normalGid;
|
||||
|
||||
throw PrivilegeHelper::Error(error.str());
|
||||
}
|
||||
|
||||
NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
|
||||
if (::seteuid(s_normalUid) != 0)
|
||||
{
|
||||
std::stringstream error;
|
||||
error << "Failed to drop to effective uid=" << s_normalUid;
|
||||
|
||||
throw PrivilegeHelper::Error(error.str());
|
||||
}
|
||||
|
||||
NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
|
||||
#else
|
||||
NFD_LOG_WARN("Dropping privileges is not supported on this platform");
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
void
|
||||
PrivilegeHelper::raise()
|
||||
{
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
|
||||
if (::seteuid(s_privilegedUid) != 0)
|
||||
{
|
||||
std::stringstream error;
|
||||
error << "Failed to elevate to effective uid=" << s_privilegedUid;
|
||||
|
||||
throw PrivilegeHelper::Error(error.str());
|
||||
}
|
||||
|
||||
NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
|
||||
if (::setegid(s_privilegedGid) != 0)
|
||||
{
|
||||
std::stringstream error;
|
||||
error << "Failed to elevate to effective gid=" << s_privilegedGid;
|
||||
|
||||
throw PrivilegeHelper::Error(error.str());
|
||||
}
|
||||
NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
|
||||
#else
|
||||
NFD_LOG_WARN("Elevating privileges is not supported on this platform");
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
void
|
||||
PrivilegeHelper::runElevated(function<void()> f)
|
||||
{
|
||||
raise();
|
||||
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
drop();
|
||||
throw;
|
||||
}
|
||||
drop();
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,49 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file declares the global random number generator
|
||||
* All random numbers in NFD should use this global random number generator,
|
||||
* so that the generator can be properly seeded when necessary.
|
||||
*
|
||||
* This random number generator is not suitable for security purposes;
|
||||
* security-critical code should use CryptoPP random number generator instead.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_RANDOM_HPP
|
||||
#define NFD_CORE_RANDOM_HPP
|
||||
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \return the global random number generator instance
|
||||
*/
|
||||
boost::random::mt19937&
|
||||
getGlobalRng();
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_RANDOM_HPP
|
||||
@@ -1,99 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_SCHEDULER_HPP
|
||||
#define NFD_CORE_SCHEDULER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include <ndn-cxx/util/scheduler.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace scheduler {
|
||||
|
||||
using ndn::Scheduler;
|
||||
|
||||
/** \class EventId
|
||||
* \brief Opaque type (shared_ptr) representing ID of a scheduled event
|
||||
*/
|
||||
using ndn::EventId;
|
||||
|
||||
/** \brief schedule an event
|
||||
*/
|
||||
EventId
|
||||
schedule(const time::nanoseconds& after, const Scheduler::Event& event);
|
||||
|
||||
/** \brief cancel a scheduled event
|
||||
*/
|
||||
void
|
||||
cancel(const EventId& eventId);
|
||||
|
||||
/** \brief cancels an event automatically upon destruction
|
||||
*/
|
||||
class ScopedEventId : noncopyable
|
||||
{
|
||||
public:
|
||||
ScopedEventId();
|
||||
|
||||
/** \brief implicit constructor from EventId
|
||||
* \param event the event to be cancelled upon destruction
|
||||
*/
|
||||
ScopedEventId(const EventId& event);
|
||||
|
||||
/** \brief move constructor
|
||||
*/
|
||||
ScopedEventId(ScopedEventId&& other);
|
||||
|
||||
/** \brief assigns an event
|
||||
*
|
||||
* If a different event has been assigned to this instance previously,
|
||||
* that event will be cancelled immediately.
|
||||
*/
|
||||
ScopedEventId&
|
||||
operator=(const EventId& event);
|
||||
|
||||
/** \brief cancels the event
|
||||
*/
|
||||
~ScopedEventId();
|
||||
|
||||
/** \brief cancels the event manually
|
||||
*/
|
||||
void
|
||||
cancel();
|
||||
|
||||
/** \brief releases the event so that it won't be disconnected
|
||||
* when this ScopedEventId is destructed
|
||||
*/
|
||||
void
|
||||
release();
|
||||
|
||||
private:
|
||||
EventId m_event;
|
||||
};
|
||||
|
||||
} // namespace scheduler
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_SCHEDULER_HPP
|
||||
@@ -1,132 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_SEGMENT_PUBLISHER_HPP
|
||||
#define NFD_CORE_SEGMENT_PUBLISHER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <ndn-cxx/encoding/encoding-buffer.hpp>
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief provides a publisher of Status Dataset or other segmented octet stream
|
||||
* \sa http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
|
||||
*/
|
||||
template <class FaceBase>
|
||||
class SegmentPublisher : noncopyable
|
||||
{
|
||||
public:
|
||||
SegmentPublisher(FaceBase& face,
|
||||
const Name& prefix,
|
||||
ndn::KeyChain& keyChain,
|
||||
const time::milliseconds& freshnessPeriod = getDefaultFreshness())
|
||||
: m_face(face)
|
||||
, m_prefix(prefix)
|
||||
, m_keyChain(keyChain)
|
||||
, m_freshnessPeriod(freshnessPeriod)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~SegmentPublisher()
|
||||
{
|
||||
}
|
||||
|
||||
static size_t
|
||||
getMaxSegmentSize()
|
||||
{
|
||||
static const size_t MAX_SEGMENT_SIZE = ndn::MAX_NDN_PACKET_SIZE >> 1;
|
||||
return MAX_SEGMENT_SIZE;
|
||||
}
|
||||
|
||||
static constexpr time::milliseconds
|
||||
getDefaultFreshness()
|
||||
{
|
||||
return time::milliseconds(1000);
|
||||
}
|
||||
|
||||
void
|
||||
publish()
|
||||
{
|
||||
ndn::EncodingBuffer buffer;
|
||||
generate(buffer);
|
||||
|
||||
const uint8_t* rawBuffer = buffer.buf();
|
||||
const uint8_t* segmentBegin = rawBuffer;
|
||||
const uint8_t* end = rawBuffer + buffer.size();
|
||||
|
||||
Name segmentPrefix(m_prefix);
|
||||
segmentPrefix.appendVersion();
|
||||
|
||||
uint64_t segmentNo = 0;
|
||||
do {
|
||||
const uint8_t* segmentEnd = segmentBegin + getMaxSegmentSize();
|
||||
if (segmentEnd > end) {
|
||||
segmentEnd = end;
|
||||
}
|
||||
|
||||
Name segmentName(segmentPrefix);
|
||||
segmentName.appendSegment(segmentNo);
|
||||
|
||||
shared_ptr<Data> data = make_shared<Data>(segmentName);
|
||||
data->setContent(segmentBegin, segmentEnd - segmentBegin);
|
||||
data->setFreshnessPeriod(m_freshnessPeriod);
|
||||
|
||||
segmentBegin = segmentEnd;
|
||||
if (segmentBegin >= end) {
|
||||
data->setFinalBlockId(segmentName[-1]);
|
||||
}
|
||||
|
||||
publishSegment(data);
|
||||
++segmentNo;
|
||||
} while (segmentBegin < end);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief In a derived class, write the octets into outBuffer.
|
||||
*/
|
||||
virtual size_t
|
||||
generate(ndn::EncodingBuffer& outBuffer) = 0;
|
||||
|
||||
private:
|
||||
void
|
||||
publishSegment(shared_ptr<Data>& data)
|
||||
{
|
||||
m_keyChain.sign(*data);
|
||||
m_face.put(*data);
|
||||
}
|
||||
|
||||
private:
|
||||
FaceBase& m_face;
|
||||
const Name m_prefix;
|
||||
ndn::KeyChain& m_keyChain;
|
||||
const time::milliseconds m_freshnessPeriod;
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_SEGMENT_PUBLISHER_HPP
|
||||
@@ -0,0 +1,29 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "core/version.hpp"
|
||||
|
||||
const char NFD_VERSION_STRING[] = "@VERSION_STRING@";
|
||||
const char NFD_VERSION_BUILD_STRING[] = "@VERSION_BUILD@";
|
||||
@@ -0,0 +1,73 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_VERSION_HPP
|
||||
#define NFD_CORE_VERSION_HPP
|
||||
|
||||
// NFD version follows Semantic Versioning 2.0.0
|
||||
// https://semver.org/spec/v2.0.0.html
|
||||
//
|
||||
// To change version number, modify VERSION variable in top-level wscript.
|
||||
|
||||
/** \brief NFD version represented as an integer.
|
||||
*
|
||||
* Equivalent to: `#NFD_VERSION_MAJOR*1000000 + #NFD_VERSION_MINOR*1000 + #NFD_VERSION_PATCH`
|
||||
*/
|
||||
#define NFD_VERSION @VERSION@
|
||||
|
||||
/// The major version of NFD
|
||||
#define NFD_VERSION_MAJOR @VERSION_MAJOR@
|
||||
/// The minor version of NFD
|
||||
#define NFD_VERSION_MINOR @VERSION_MINOR@
|
||||
/// The patch version of NFD
|
||||
#define NFD_VERSION_PATCH @VERSION_PATCH@
|
||||
|
||||
/** \brief NFD version represented as a string.
|
||||
*
|
||||
* Format:
|
||||
* @code
|
||||
* MAJOR.MINOR.PATCH
|
||||
* @endcode
|
||||
*/
|
||||
extern const char NFD_VERSION_STRING[];
|
||||
|
||||
/** \brief NFD version string, including git commit information, if NFD is build from
|
||||
* specific git commit.
|
||||
*
|
||||
* #NFD_VERSION_BUILD_STRING is obtained using the following command (`NFD-` prefix is
|
||||
* afterwards removed): `git describe --match 'NFD-*'`
|
||||
*
|
||||
* When NFD is not built from git, #NFD_VERSION_BUILD_STRING equals #NFD_VERSION_STRING.
|
||||
*
|
||||
* Format:
|
||||
* @code
|
||||
* MAJOR.MINOR.PATCH(-release-candidate-tag)(-(number-of-commits-since-tag)-COMMIT-HASH)
|
||||
* @endcode
|
||||
*
|
||||
* Example: 0.1.0-rc1-1-g5c86570
|
||||
*/
|
||||
extern const char NFD_VERSION_BUILD_STRING[];
|
||||
|
||||
#endif // NFD_CORE_VERSION_HPP
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,11 +23,12 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config-file.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "common/config-file.hpp"
|
||||
|
||||
#include <boost/property_tree/info_parser.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -42,11 +43,8 @@ ConfigFile::throwErrorOnUnknownSection(const std::string& filename,
|
||||
const ConfigSection& section,
|
||||
bool isDryRun)
|
||||
{
|
||||
std::string msg = "Error processing configuration file ";
|
||||
msg += filename;
|
||||
msg += ": no module subscribed for section \"" + sectionName + "\"";
|
||||
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error(msg));
|
||||
NDN_THROW(Error("Error processing configuration file " + filename +
|
||||
": no module subscribed for section '" + sectionName + "'"));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -59,10 +57,10 @@ ConfigFile::ignoreUnknownSection(const std::string& filename,
|
||||
}
|
||||
|
||||
bool
|
||||
ConfigFile::parseYesNo(const ConfigSection::value_type& option,
|
||||
ConfigFile::parseYesNo(const ConfigSection& node, const std::string& key,
|
||||
const std::string& sectionName)
|
||||
{
|
||||
auto value = option.second.get_value<std::string>();
|
||||
auto value = node.get_value<std::string>();
|
||||
|
||||
if (value == "yes") {
|
||||
return true;
|
||||
@@ -71,8 +69,8 @@ ConfigFile::parseYesNo(const ConfigSection::value_type& option,
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + value + "\" for option \"" +
|
||||
option.first + "\" in \"" + sectionName + "\" section"));
|
||||
NDN_THROW(Error("Invalid value '" + value + "' for option '" +
|
||||
key + "' in section '" + sectionName + "'"));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -85,14 +83,10 @@ ConfigFile::addSectionHandler(const std::string& sectionName,
|
||||
void
|
||||
ConfigFile::parse(const std::string& filename, bool isDryRun)
|
||||
{
|
||||
std::ifstream inputFile;
|
||||
inputFile.open(filename.c_str());
|
||||
if (!inputFile.good() || !inputFile.is_open())
|
||||
{
|
||||
std::string msg = "Failed to read configuration file: ";
|
||||
msg += filename;
|
||||
BOOST_THROW_EXCEPTION(Error(msg));
|
||||
}
|
||||
std::ifstream inputFile(filename);
|
||||
if (!inputFile.good() || !inputFile.is_open()) {
|
||||
NDN_THROW(Error("Failed to read configuration file " + filename));
|
||||
}
|
||||
parse(inputFile, isDryRun, filename);
|
||||
inputFile.close();
|
||||
}
|
||||
@@ -107,18 +101,13 @@ ConfigFile::parse(const std::string& input, bool isDryRun, const std::string& fi
|
||||
void
|
||||
ConfigFile::parse(std::istream& input, bool isDryRun, const std::string& filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_info(input, m_global);
|
||||
}
|
||||
catch (const boost::property_tree::info_parser_error& error)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Failed to parse configuration file";
|
||||
msg << " " << filename;
|
||||
msg << " " << error.message() << " line " << error.line();
|
||||
BOOST_THROW_EXCEPTION(Error(msg.str()));
|
||||
}
|
||||
try {
|
||||
boost::property_tree::read_info(input, m_global);
|
||||
}
|
||||
catch (const boost::property_tree::info_parser_error& error) {
|
||||
NDN_THROW(Error("Failed to parse configuration file " + filename +
|
||||
": " + error.message() + " on line " + to_string(error.line())));
|
||||
}
|
||||
|
||||
process(isDryRun, filename);
|
||||
}
|
||||
@@ -135,16 +124,9 @@ ConfigFile::process(bool isDryRun, const std::string& filename) const
|
||||
{
|
||||
BOOST_ASSERT(!filename.empty());
|
||||
|
||||
if (m_global.begin() == m_global.end()) {
|
||||
std::string msg = "Error processing configuration file: ";
|
||||
msg += filename;
|
||||
msg += " no data";
|
||||
BOOST_THROW_EXCEPTION(Error(msg));
|
||||
}
|
||||
|
||||
for (const auto& i : m_global) {
|
||||
try {
|
||||
ConfigSectionHandler subscriber = m_subscriptions.at(i.first);
|
||||
const ConfigSectionHandler& subscriber = m_subscriptions.at(i.first);
|
||||
subscriber(i.second, isDryRun, filename);
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
@@ -153,4 +135,4 @@ ConfigFile::process(bool isDryRun, const std::string& filename) const
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,44 +23,50 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_CONFIG_FILE_HPP
|
||||
#define NFD_CORE_CONFIG_FILE_HPP
|
||||
#ifndef NFD_DAEMON_COMMON_CONFIG_FILE_HPP
|
||||
#define NFD_DAEMON_COMMON_CONFIG_FILE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/common.hpp"
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
typedef boost::property_tree::ptree ConfigSection;
|
||||
/** \brief a config file section
|
||||
*/
|
||||
using ConfigSection = boost::property_tree::ptree;
|
||||
|
||||
/// \brief callback for config file sections
|
||||
typedef function<void(const ConfigSection& /*section*/,
|
||||
bool /*isDryRun*/,
|
||||
const std::string& /*filename*/)> ConfigSectionHandler;
|
||||
/** \brief an optional config file section
|
||||
*/
|
||||
using OptionalConfigSection = boost::optional<const ConfigSection&>;
|
||||
|
||||
/// \brief callback for config file sections without a subscribed handler
|
||||
typedef function<void(const std::string& /*filename*/,
|
||||
const std::string& /*sectionName*/,
|
||||
const ConfigSection& /*section*/,
|
||||
bool /*isDryRun*/)> UnknownConfigSectionHandler;
|
||||
/** \brief callback to process a config file section
|
||||
*/
|
||||
using ConfigSectionHandler = std::function<void(const ConfigSection& section, bool isDryRun,
|
||||
const std::string& filename)>;
|
||||
|
||||
/** \brief callback to process a config file section without a \p ConfigSectionHandler
|
||||
*/
|
||||
using UnknownConfigSectionHandler = std::function<void(const std::string& filename,
|
||||
const std::string& sectionName,
|
||||
const ConfigSection& section,
|
||||
bool isDryRun)>;
|
||||
|
||||
/** \brief configuration file parsing utility
|
||||
*/
|
||||
class ConfigFile : noncopyable
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
explicit
|
||||
ConfigFile(UnknownConfigSectionHandler unknownSectionCallback = throwErrorOnUnknownSection);
|
||||
|
||||
public: // unknown section handlers
|
||||
static void
|
||||
throwErrorOnUnknownSection(const std::string& filename,
|
||||
const std::string& sectionName,
|
||||
@@ -73,27 +79,52 @@ public:
|
||||
const ConfigSection& section,
|
||||
bool isDryRun);
|
||||
|
||||
/**
|
||||
* \brief parse a config option that can be either "yes" or "no"
|
||||
*
|
||||
* \return true if "yes", false if "no"
|
||||
* \throw Error the value is neither "yes" nor "no"
|
||||
public: // parse helpers
|
||||
/** \brief parse a config option that can be either "yes" or "no"
|
||||
* \retval true "yes"
|
||||
* \retval false "no"
|
||||
* \throw Error the value is neither "yes" nor "no"
|
||||
*/
|
||||
static bool
|
||||
parseYesNo(const ConfigSection::value_type& option,
|
||||
const std::string& sectionName);
|
||||
parseYesNo(const ConfigSection& node, const std::string& key, const std::string& sectionName);
|
||||
|
||||
static bool
|
||||
parseYesNo(const ConfigSection::value_type& option, const std::string& sectionName)
|
||||
{
|
||||
return parseYesNo(option.second, option.first, sectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief parse a numeric (integral or floating point) config option
|
||||
* \tparam T an arithmetic type
|
||||
*
|
||||
* \return the numeric value of the parsed option
|
||||
* \throw Error the value cannot be converted to the specified type
|
||||
*/
|
||||
template <typename T>
|
||||
static typename std::enable_if<std::is_arithmetic<T>::value, T>::type
|
||||
parseNumber(const ConfigSection::value_type& option,
|
||||
const std::string& sectionName);
|
||||
template<typename T>
|
||||
static T
|
||||
parseNumber(const ConfigSection& node, const std::string& key, const std::string& sectionName)
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");
|
||||
|
||||
boost::optional<T> value = node.get_value_optional<T>();
|
||||
// Unsigned logic is workaround for https://redmine.named-data.net/issues/4489
|
||||
if (value &&
|
||||
(std::is_signed<T>() || node.get_value<std::string>().find("-") == std::string::npos)) {
|
||||
return *value;
|
||||
}
|
||||
NDN_THROW(Error("Invalid value '" + node.get_value<std::string>() +
|
||||
"' for option '" + key + "' in section '" + sectionName + "'"));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T
|
||||
parseNumber(const ConfigSection::value_type& option, const std::string& sectionName)
|
||||
{
|
||||
return parseNumber<T>(option.second, option.first, sectionName);
|
||||
}
|
||||
|
||||
public: // setup and parsing
|
||||
/// \brief setup notification of configuration file sections
|
||||
void
|
||||
addSectionHandler(const std::string& sectionName,
|
||||
@@ -146,22 +177,6 @@ private:
|
||||
ConfigSection m_global;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type
|
||||
ConfigFile::parseNumber(const ConfigSection::value_type& option,
|
||||
const std::string& sectionName)
|
||||
{
|
||||
auto value = option.second.get_value<std::string>();
|
||||
|
||||
try {
|
||||
return boost::lexical_cast<T>(value);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + value + "\" for option \"" +
|
||||
option.first + "\" in \"" + sectionName + "\" section"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_CONFIG_FILE_HPP
|
||||
#endif // NFD_DAEMON_COMMON_CONFIG_FILE_HPP
|
||||
@@ -0,0 +1,134 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_COMMON_COUNTER_HPP
|
||||
#define NFD_DAEMON_COMMON_COUNTER_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief represents a counter that encloses an integer value
|
||||
*
|
||||
* SimpleCounter is noncopyable, because increment should be called on the counter,
|
||||
* not a copy of it; it's implicitly convertible to an integral type to be observed
|
||||
*/
|
||||
class SimpleCounter : noncopyable
|
||||
{
|
||||
public:
|
||||
typedef uint64_t rep;
|
||||
|
||||
/** \brief observe the counter
|
||||
*/
|
||||
operator rep() const noexcept
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/** \brief replace the counter value
|
||||
*/
|
||||
void
|
||||
set(rep value) noexcept
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
protected:
|
||||
rep m_value = 0;
|
||||
};
|
||||
|
||||
/** \brief represents a counter of number of packets
|
||||
*
|
||||
* \warning The counter value may wrap after exceeding the range of underlying integer type.
|
||||
*/
|
||||
class PacketCounter : public SimpleCounter
|
||||
{
|
||||
public:
|
||||
/** \brief increment the counter by one
|
||||
*/
|
||||
PacketCounter&
|
||||
operator++() noexcept
|
||||
{
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
// postfix ++ operator is not provided because it's not needed
|
||||
};
|
||||
|
||||
/** \brief represents a counter of number of bytes
|
||||
*
|
||||
* \warning The counter value may wrap after exceeding the range of underlying integer type.
|
||||
*/
|
||||
class ByteCounter : public SimpleCounter
|
||||
{
|
||||
public:
|
||||
/** \brief increase the counter
|
||||
*/
|
||||
ByteCounter&
|
||||
operator+=(rep n) noexcept
|
||||
{
|
||||
m_value += n;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/** \brief provides a counter that observes the size of a table
|
||||
* \tparam T a type that provides a size() const member function
|
||||
*
|
||||
* if table not specified in constructor, it can be added later by invoking observe()
|
||||
*/
|
||||
template<typename T>
|
||||
class SizeCounter : noncopyable
|
||||
{
|
||||
public:
|
||||
typedef size_t Rep;
|
||||
|
||||
explicit constexpr
|
||||
SizeCounter(const T* table = nullptr) noexcept
|
||||
: m_table(table)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
observe(const T* table) noexcept
|
||||
{
|
||||
m_table = table;
|
||||
}
|
||||
|
||||
/** \brief observe the counter
|
||||
*/
|
||||
operator Rep() const
|
||||
{
|
||||
BOOST_ASSERT(m_table != nullptr);
|
||||
return m_table->size();
|
||||
}
|
||||
|
||||
private:
|
||||
const T* m_table;
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_COMMON_COUNTER_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,85 +23,78 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "scheduler.hpp"
|
||||
#include "global-io.hpp"
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include "common/global.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace scheduler {
|
||||
|
||||
static boost::thread_specific_ptr<Scheduler> g_scheduler;
|
||||
static thread_local unique_ptr<boost::asio::io_service> g_ioService;
|
||||
static thread_local unique_ptr<Scheduler> g_scheduler;
|
||||
static boost::asio::io_service* g_mainIoService = nullptr;
|
||||
static boost::asio::io_service* g_ribIoService = nullptr;
|
||||
|
||||
boost::asio::io_service&
|
||||
getGlobalIoService()
|
||||
{
|
||||
if (g_ioService == nullptr) {
|
||||
g_ioService = make_unique<boost::asio::io_service>();
|
||||
}
|
||||
return *g_ioService;
|
||||
}
|
||||
|
||||
Scheduler&
|
||||
getGlobalScheduler()
|
||||
getScheduler()
|
||||
{
|
||||
if (g_scheduler.get() == nullptr) {
|
||||
g_scheduler.reset(new Scheduler(getGlobalIoService()));
|
||||
if (g_scheduler == nullptr) {
|
||||
g_scheduler = make_unique<Scheduler>(getGlobalIoService());
|
||||
}
|
||||
|
||||
return *g_scheduler;
|
||||
}
|
||||
|
||||
EventId
|
||||
schedule(const time::nanoseconds& after, const Scheduler::Event& event)
|
||||
{
|
||||
return getGlobalScheduler().scheduleEvent(after, event);
|
||||
}
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
void
|
||||
cancel(const EventId& eventId)
|
||||
{
|
||||
getGlobalScheduler().cancelEvent(eventId);
|
||||
}
|
||||
|
||||
void
|
||||
resetGlobalScheduler()
|
||||
resetGlobalIoService()
|
||||
{
|
||||
g_scheduler.reset();
|
||||
g_ioService.reset();
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::asio::io_service&
|
||||
getMainIoService()
|
||||
{
|
||||
BOOST_ASSERT(g_mainIoService != nullptr);
|
||||
return *g_mainIoService;
|
||||
}
|
||||
|
||||
ScopedEventId::ScopedEventId()
|
||||
boost::asio::io_service&
|
||||
getRibIoService()
|
||||
{
|
||||
}
|
||||
|
||||
ScopedEventId::ScopedEventId(const EventId& event)
|
||||
: m_event(event)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedEventId::ScopedEventId(ScopedEventId&& other)
|
||||
: m_event(other.m_event)
|
||||
{
|
||||
other.release();
|
||||
}
|
||||
|
||||
ScopedEventId&
|
||||
ScopedEventId::operator=(const EventId& event)
|
||||
{
|
||||
if (m_event != event) {
|
||||
scheduler::cancel(m_event);
|
||||
m_event = event;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScopedEventId::~ScopedEventId()
|
||||
{
|
||||
scheduler::cancel(m_event);
|
||||
BOOST_ASSERT(g_ribIoService != nullptr);
|
||||
return *g_ribIoService;
|
||||
}
|
||||
|
||||
void
|
||||
ScopedEventId::cancel()
|
||||
setMainIoService(boost::asio::io_service* mainIo)
|
||||
{
|
||||
scheduler::cancel(m_event);
|
||||
g_mainIoService = mainIo;
|
||||
}
|
||||
|
||||
void
|
||||
ScopedEventId::release()
|
||||
setRibIoService(boost::asio::io_service* ribIo)
|
||||
{
|
||||
m_event.reset();
|
||||
g_ribIoService = ribIo;
|
||||
}
|
||||
|
||||
void
|
||||
runOnMainIoService(const std::function<void()>& f)
|
||||
{
|
||||
getMainIoService().post(f);
|
||||
}
|
||||
|
||||
void
|
||||
runOnRibIoService(const std::function<void()>& f)
|
||||
{
|
||||
getRibIoService().post(f);
|
||||
}
|
||||
|
||||
} // namespace scheduler
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,75 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019 Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef NFD_DAEMON_COMMON_GLOBAL_HPP
|
||||
#define NFD_DAEMON_COMMON_GLOBAL_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief Returns the global io_service instance for the calling thread.
|
||||
*/
|
||||
boost::asio::io_service&
|
||||
getGlobalIoService();
|
||||
|
||||
/** \brief Returns the global Scheduler instance for the calling thread.
|
||||
*/
|
||||
Scheduler&
|
||||
getScheduler();
|
||||
|
||||
boost::asio::io_service&
|
||||
getMainIoService();
|
||||
|
||||
boost::asio::io_service&
|
||||
getRibIoService();
|
||||
|
||||
void
|
||||
setMainIoService(boost::asio::io_service* mainIo);
|
||||
|
||||
void
|
||||
setRibIoService(boost::asio::io_service* ribIo);
|
||||
|
||||
/** \brief Run a function on the main io_service instance.
|
||||
*/
|
||||
void
|
||||
runOnMainIoService(const std::function<void()>& f);
|
||||
|
||||
/** \brief Run a function on the RIB io_service instance.
|
||||
*/
|
||||
void
|
||||
runOnRibIoService(const std::function<void()>& f);
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
/** \brief Destroy the global io_service instance.
|
||||
*
|
||||
* It will be recreated at the next invocation of getGlobalIoService().
|
||||
*/
|
||||
void
|
||||
resetGlobalIoService();
|
||||
#endif
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_COMMON_GLOBAL_HPP
|
||||
@@ -0,0 +1,44 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_COMMON_LOGGER_HPP
|
||||
#define NFD_DAEMON_COMMON_LOGGER_HPP
|
||||
|
||||
#include <ndn-cxx/util/logger.hpp>
|
||||
|
||||
#define NFD_LOG_INIT(name) NDN_LOG_INIT(nfd.name)
|
||||
#define NFD_LOG_MEMBER_DECL() NDN_LOG_MEMBER_DECL()
|
||||
#define NFD_LOG_MEMBER_DECL_SPECIALIZED(cls) NDN_LOG_MEMBER_DECL_SPECIALIZED(cls)
|
||||
#define NFD_LOG_MEMBER_INIT(cls, name) NDN_LOG_MEMBER_INIT(cls, nfd.name)
|
||||
#define NFD_LOG_MEMBER_INIT_SPECIALIZED(cls, name) NDN_LOG_MEMBER_INIT_SPECIALIZED(cls, nfd.name)
|
||||
|
||||
#define NFD_LOG_TRACE NDN_LOG_TRACE
|
||||
#define NFD_LOG_DEBUG NDN_LOG_DEBUG
|
||||
#define NFD_LOG_INFO NDN_LOG_INFO
|
||||
#define NFD_LOG_WARN NDN_LOG_WARN
|
||||
#define NFD_LOG_ERROR NDN_LOG_ERROR
|
||||
#define NFD_LOG_FATAL NDN_LOG_FATAL
|
||||
|
||||
#endif // NFD_DAEMON_COMMON_LOGGER_HPP
|
||||
@@ -0,0 +1,159 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "common/privilege-helper.hpp"
|
||||
#include "common/logger.hpp"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INIT(PrivilegeHelper);
|
||||
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
uid_t PrivilegeHelper::s_normalUid = ::geteuid();
|
||||
gid_t PrivilegeHelper::s_normalGid = ::getegid();
|
||||
|
||||
uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
|
||||
gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
|
||||
void
|
||||
PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
|
||||
{
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16 KiB
|
||||
static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
|
||||
|
||||
static const size_t FALLBACK_GROUP_BUFFER_SIZE = 1024;
|
||||
static const size_t FALLBACK_PASSWD_BUFFER_SIZE = 1024;
|
||||
|
||||
NFD_LOG_TRACE("initializing with user \"" << userName << "\""
|
||||
<< " group \"" << groupName << "\"");
|
||||
|
||||
// workflow from man getpwnam_r
|
||||
|
||||
if (!groupName.empty()) {
|
||||
static long groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||
|
||||
if (groupSize == -1)
|
||||
groupSize = FALLBACK_GROUP_BUFFER_SIZE;
|
||||
|
||||
std::vector<char> groupBuffer(static_cast<size_t>(groupSize));
|
||||
group gr;
|
||||
group* grResult = nullptr;
|
||||
|
||||
int errorCode = getgrnam_r(groupName.data(), &gr, groupBuffer.data(), groupBuffer.size(), &grResult);
|
||||
|
||||
while (errorCode == ERANGE) {
|
||||
if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
|
||||
throw Error("Cannot allocate large enough buffer for struct group");
|
||||
|
||||
groupBuffer.resize(groupBuffer.size() * 2);
|
||||
errorCode = getgrnam_r(groupName.data(), &gr, groupBuffer.data(), groupBuffer.size(), &grResult);
|
||||
}
|
||||
|
||||
if (errorCode != 0 || !grResult)
|
||||
throw Error("Failed to get gid for \"" + groupName + "\"");
|
||||
|
||||
s_normalGid = gr.gr_gid;
|
||||
}
|
||||
|
||||
if (!userName.empty()) {
|
||||
static long passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
||||
if (passwdSize == -1)
|
||||
passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
|
||||
|
||||
std::vector<char> passwdBuffer(static_cast<size_t>(passwdSize));
|
||||
passwd pw;
|
||||
passwd* pwResult = nullptr;
|
||||
|
||||
int errorCode = getpwnam_r(userName.data(), &pw, passwdBuffer.data(), passwdBuffer.size(), &pwResult);
|
||||
|
||||
while (errorCode == ERANGE) {
|
||||
if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
|
||||
throw Error("Cannot allocate large enough buffer for struct passwd");
|
||||
|
||||
passwdBuffer.resize(passwdBuffer.size() * 2);
|
||||
errorCode = getpwnam_r(userName.data(), &pw, passwdBuffer.data(), passwdBuffer.size(), &pwResult);
|
||||
}
|
||||
|
||||
if (errorCode != 0 || !pwResult)
|
||||
throw Error("Failed to get uid for \"" + userName + "\"");
|
||||
|
||||
s_normalUid = pw.pw_uid;
|
||||
}
|
||||
#else
|
||||
if (!userName.empty() || !groupName.empty()) {
|
||||
throw Error("Dropping and raising privileges is not supported on this platform");
|
||||
}
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
void
|
||||
PrivilegeHelper::drop()
|
||||
{
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
if (::geteuid() == s_normalUid && ::getegid() == s_normalGid)
|
||||
return;
|
||||
|
||||
NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
|
||||
if (::setegid(s_normalGid) != 0)
|
||||
throw Error("Failed to drop to effective gid=" + to_string(s_normalGid));
|
||||
|
||||
NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
|
||||
if (::seteuid(s_normalUid) != 0)
|
||||
throw Error("Failed to drop to effective uid=" + to_string(s_normalUid));
|
||||
|
||||
NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
|
||||
#else
|
||||
NFD_LOG_WARN("Dropping privileges is not supported on this platform");
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
void
|
||||
PrivilegeHelper::raise()
|
||||
{
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
if (::geteuid() == s_privilegedUid && ::getegid() == s_privilegedGid)
|
||||
return;
|
||||
|
||||
NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
|
||||
if (::seteuid(s_privilegedUid) != 0)
|
||||
throw Error("Failed to elevate to effective uid=" + to_string(s_privilegedUid));
|
||||
|
||||
NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
|
||||
if (::setegid(s_privilegedGid) != 0)
|
||||
throw Error("Failed to elevate to effective gid=" + to_string(s_privilegedGid));
|
||||
|
||||
NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
|
||||
#else
|
||||
NFD_LOG_WARN("Elevating privileges is not supported on this platform");
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,10 +23,10 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_PRIVILEGE_HELPER_HPP
|
||||
#define NFD_CORE_PRIVILEGE_HELPER_HPP
|
||||
#ifndef NFD_DAEMON_COMMON_PRIVILEGE_HELPER_HPP
|
||||
#define NFD_DAEMON_COMMON_PRIVILEGE_HELPER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/common.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -35,11 +35,10 @@ namespace nfd {
|
||||
class PrivilegeHelper
|
||||
{
|
||||
public:
|
||||
|
||||
/** \brief represents a serious seteuid/gid failure
|
||||
*
|
||||
* This should only be caught by main as part of a graceful program termination.
|
||||
* \note This is not an std::exception and BOOST_THROW_EXCEPTION should not be used.
|
||||
* \note This is not an std::exception and NDN_THROW should not be used.
|
||||
*/
|
||||
class Error
|
||||
{
|
||||
@@ -53,7 +52,7 @@ public:
|
||||
const char*
|
||||
what() const
|
||||
{
|
||||
return m_whatMessage.c_str();
|
||||
return m_whatMessage.data();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -66,11 +65,22 @@ public:
|
||||
static void
|
||||
drop();
|
||||
|
||||
template<class F>
|
||||
static void
|
||||
runElevated(function<void()> f);
|
||||
runElevated(F&& f)
|
||||
{
|
||||
raise();
|
||||
try {
|
||||
f();
|
||||
}
|
||||
catch (...) {
|
||||
drop();
|
||||
throw;
|
||||
}
|
||||
drop();
|
||||
}
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
|
||||
static void
|
||||
raise();
|
||||
|
||||
@@ -86,4 +96,4 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_PRIVILEGE_HELPER_HPP
|
||||
#endif // NFD_DAEMON_COMMON_PRIVILEGE_HELPER_HPP
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "TokenBucket.hpp"
|
||||
#include "common/global.hpp"
|
||||
#include "common/logger.hpp"
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
NFD_LOG_INIT(QSCCPTokenBucket);
|
||||
TokenBucket::TokenBucket(uint64_t rateLimit, uint64_t bucketSize, const std::string& name): rateLimit(rateLimit), bucketSize(bucketSize), name(name) {
|
||||
this->eachStep = this->rateLimit / 250.0;
|
||||
this->currentTokenSize = 0;
|
||||
this->isStart = false;
|
||||
// NFD_LOG_DEBUG("Create tokenBucket: " << name << ", eachStep: " << this->eachStep << ", rateLimit: " << this->rateLimit);
|
||||
}
|
||||
void TokenBucket::start() {
|
||||
if (this->isStart) {
|
||||
return;
|
||||
}
|
||||
// 每 4ms 增加一次令牌
|
||||
getScheduler().schedule(time::milliseconds(4), std::bind(&TokenBucket::generateToken, this));
|
||||
}
|
||||
void TokenBucket::generateToken() {
|
||||
// NFD_LOG_DEBUG(this->name << "=> do generateToken => " << this->currentTokenSize);
|
||||
if (this->currentTokenSize + this->eachStep > this->bucketSize) {
|
||||
this->currentTokenSize = this->bucketSize;
|
||||
} else {
|
||||
this->currentTokenSize += this->eachStep;
|
||||
}
|
||||
getScheduler().schedule(time::milliseconds(4), std::bind(&TokenBucket::generateToken, this));
|
||||
}
|
||||
|
||||
void TokenBucket::generateTokenByCurrentTime(long currentTime) {
|
||||
if (this->lastGenerateTokenTime == -1) {
|
||||
this->lastGenerateTokenTime = currentTime;
|
||||
return;
|
||||
}
|
||||
if (currentTime - this->lastGenerateTokenTime < 1) {
|
||||
return;
|
||||
}
|
||||
long currentStep = (currentTime - this->lastGenerateTokenTime) * this->rateLimit / 1000.0;
|
||||
// std::cout << "currentStep: " << currentStep << "currentTime: " << currentTime << "lastGenerateTokenTime: " << this->lastGenerateTokenTime << std::endl;
|
||||
// NFD_LOG_DEBUG(this->name << "=> do generateToken => " << this->currentTokenSize);
|
||||
this->lastGenerateTokenTime = currentTime;
|
||||
if (this->currentTokenSize + currentStep > this->bucketSize) {
|
||||
this->currentTokenSize = this->bucketSize;
|
||||
} else {
|
||||
this->currentTokenSize += currentStep;
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenBucket::use(uint64_t tokenNum) {
|
||||
if(this->currentTokenSize > tokenNum) {
|
||||
this->currentTokenSize -= tokenNum;
|
||||
// NFD_LOG_DEBUG(this->name << "=> use success => " << this->currentTokenSize);
|
||||
return true;
|
||||
} else {
|
||||
// NFD_LOG_DEBUG(this->name << "=> use failed => " << this->currentTokenSize);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by gdcni21 on 3/25/22.
|
||||
//
|
||||
#ifndef NS_TOKENBUCKET_H
|
||||
#define NS_TOKENBUCKET_H
|
||||
#include <memory>
|
||||
#include <string>
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
class TokenBucket {
|
||||
public:
|
||||
explicit TokenBucket(uint64_t rateLimit, uint64_t bucketSize, const std::string& name);
|
||||
void start();
|
||||
/**
|
||||
* 周期性增加token
|
||||
**/
|
||||
void generateToken();
|
||||
|
||||
/**
|
||||
* 根据当前时间生成token
|
||||
*/
|
||||
void generateTokenByCurrentTime(long currentTime);
|
||||
|
||||
/**
|
||||
* 尝试消费n个token
|
||||
* @param tokenNum
|
||||
* @return
|
||||
*/
|
||||
bool use(uint64_t tokenNum);
|
||||
public:
|
||||
double eachStep; // 每个周期增加的令牌
|
||||
double currentTokenSize; // 当前令牌数
|
||||
uint64_t rateLimit; // 令牌生成速率
|
||||
uint64_t bucketSize; // 令牌桶容量
|
||||
std::string name;
|
||||
bool isStart; // 标识是否启动
|
||||
long lastGenerateTokenTime = -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif //NS_TOKENBUCKET_H
|
||||
@@ -0,0 +1,62 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_CHANNEL_LOG_HPP
|
||||
#define NFD_DAEMON_FACE_CHANNEL_LOG_HPP
|
||||
|
||||
#include "common/logger.hpp"
|
||||
|
||||
/** \defgroup ChannelLogging Channel logging macros
|
||||
*
|
||||
* These macros augment the log message with some channel-specific information,
|
||||
* such as the local URI, that are useful to distinguish which channel produced
|
||||
* the message. It is strongly recommended to use these macros instead of the
|
||||
* generic ones for all logging inside Channel subclasses.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \cond */
|
||||
#define NFD_LOG_CHAN(level, msg) NFD_LOG_##level( \
|
||||
"[" << this->getUri() << "] " << msg)
|
||||
/** \endcond */
|
||||
|
||||
/** \brief Log a message at TRACE level */
|
||||
#define NFD_LOG_CHAN_TRACE(msg) NFD_LOG_CHAN(TRACE, msg)
|
||||
|
||||
/** \brief Log a message at DEBUG level */
|
||||
#define NFD_LOG_CHAN_DEBUG(msg) NFD_LOG_CHAN(DEBUG, msg)
|
||||
|
||||
/** \brief Log a message at INFO level */
|
||||
#define NFD_LOG_CHAN_INFO(msg) NFD_LOG_CHAN(INFO, msg)
|
||||
|
||||
/** \brief Log a message at WARN level */
|
||||
#define NFD_LOG_CHAN_WARN(msg) NFD_LOG_CHAN(WARN, msg)
|
||||
|
||||
/** \brief Log a message at ERROR level */
|
||||
#define NFD_LOG_CHAN_ERROR(msg) NFD_LOG_CHAN(ERROR, msg)
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif // NFD_DAEMON_FACE_CHANNEL_LOG_HPP
|
||||
+23
-11
@@ -1,11 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014 Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -20,15 +21,15 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
*/
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
Channel::~Channel()
|
||||
{
|
||||
}
|
||||
Channel::~Channel() = default;
|
||||
|
||||
void
|
||||
Channel::setUri(const FaceUri& uri)
|
||||
@@ -36,4 +37,15 @@ Channel::setUri(const FaceUri& uri)
|
||||
m_uri = uri;
|
||||
}
|
||||
|
||||
void
|
||||
connectFaceClosedSignal(Face& face, std::function<void()> f)
|
||||
{
|
||||
face.afterStateChange.connect([f = std::move(f)] (auto, FaceState newState) {
|
||||
if (newState == FaceState::CLOSED) {
|
||||
f();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
+52
-29
@@ -1,11 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014 Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -20,36 +21,44 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_CHANNEL_HPP
|
||||
#define NFD_DAEMON_FACE_CHANNEL_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "channel-log.hpp"
|
||||
#include "face-common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class Face;
|
||||
|
||||
class Channel : noncopyable
|
||||
/** \brief Represents a channel that listens on a local endpoint.
|
||||
* \sa FaceSystem
|
||||
*
|
||||
* A channel can listen on a local endpoint and initiate outgoing connection from a local endpoint.
|
||||
* A channel creates Face objects and retains shared ownership of them.
|
||||
*/
|
||||
class Channel : public std::enable_shared_from_this<Channel>, noncopyable
|
||||
{
|
||||
public:
|
||||
/** \brief Prototype for the callback called when face is created
|
||||
* (as a response to incoming connection or after connection
|
||||
* is established)
|
||||
*/
|
||||
typedef function<void(const shared_ptr<Face>& newFace)> FaceCreatedCallback;
|
||||
|
||||
/** \brief Prototype for the callback that is called when face is failed to
|
||||
* get created
|
||||
*/
|
||||
typedef function<void(const std::string& reason)> ConnectFailedCallback;
|
||||
|
||||
virtual
|
||||
~Channel();
|
||||
|
||||
const FaceUri&
|
||||
getUri() const;
|
||||
getUri() const
|
||||
{
|
||||
return m_uri;
|
||||
}
|
||||
|
||||
/** \brief Returns whether the channel is listening
|
||||
*/
|
||||
virtual bool
|
||||
isListening() const = 0;
|
||||
|
||||
/** \brief Returns the number of faces in the channel
|
||||
*/
|
||||
virtual size_t
|
||||
size() const = 0;
|
||||
|
||||
protected:
|
||||
void
|
||||
@@ -59,12 +68,26 @@ private:
|
||||
FaceUri m_uri;
|
||||
};
|
||||
|
||||
inline const FaceUri&
|
||||
Channel::getUri() const
|
||||
{
|
||||
return m_uri;
|
||||
}
|
||||
/** \brief Prototype for the callback that is invoked when a face is created
|
||||
* (in response to an incoming connection or after a connection is established).
|
||||
*/
|
||||
using FaceCreatedCallback = std::function<void(const shared_ptr<Face>&)>;
|
||||
|
||||
/** \brief Prototype for the callback that is invoked when a face fails to be created.
|
||||
*/
|
||||
using FaceCreationFailedCallback = std::function<void(uint32_t status, const std::string& reason)>;
|
||||
|
||||
/** \brief Invokes a callback when a face is closed.
|
||||
* \param face the face
|
||||
* \param f the callback to be invoked when the face enters CLOSED state
|
||||
*
|
||||
* This function connects a callback to the afterStateChange signal of \p face,
|
||||
* and invokes \p f when the state becomes CLOSED.
|
||||
*/
|
||||
void
|
||||
connectFaceClosedSignal(Face& face, std::function<void()> f);
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_CHANNEL_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,7 +27,8 @@
|
||||
#define NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
|
||||
|
||||
#include "transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "socket-utils.hpp"
|
||||
#include "common/global.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -54,11 +55,8 @@ public:
|
||||
explicit
|
||||
DatagramTransport(typename protocol::socket&& socket);
|
||||
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
ssize_t
|
||||
getSendQueueLength() override;
|
||||
|
||||
/** \brief Receive datagram, translate buffer into packet, deliver to parent class.
|
||||
*/
|
||||
@@ -68,59 +66,76 @@ public:
|
||||
|
||||
protected:
|
||||
void
|
||||
handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived);
|
||||
doClose() override;
|
||||
|
||||
void
|
||||
handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent, const Block& payload);
|
||||
doSend(const Block& packet) override;
|
||||
|
||||
void
|
||||
handleSend(const boost::system::error_code& error, size_t nBytesSent);
|
||||
|
||||
void
|
||||
handleReceive(const boost::system::error_code& error, size_t nBytesReceived);
|
||||
|
||||
void
|
||||
processErrorCode(const boost::system::error_code& error);
|
||||
|
||||
bool
|
||||
hasBeenUsedRecently() const;
|
||||
hasRecentlyReceived() const;
|
||||
|
||||
void
|
||||
resetRecentUsage();
|
||||
resetRecentlyReceived();
|
||||
|
||||
static EndpointId
|
||||
makeEndpointId(const typename protocol::endpoint& ep);
|
||||
|
||||
protected:
|
||||
typename protocol::socket m_socket;
|
||||
typename protocol::endpoint m_sender;
|
||||
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
NFD_LOG_MEMBER_DECL();
|
||||
|
||||
private:
|
||||
std::array<uint8_t, ndn::MAX_NDN_PACKET_SIZE> m_receiveBuffer;
|
||||
bool m_hasBeenUsedRecently;
|
||||
bool m_hasRecentlyReceived;
|
||||
};
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
inline
|
||||
DatagramTransport<T, U>::DatagramTransport(typename DatagramTransport::protocol::socket&& socket)
|
||||
: m_socket(std::move(socket))
|
||||
, m_hasRecentlyReceived(false)
|
||||
{
|
||||
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer),
|
||||
bind(&DatagramTransport<T, U>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
boost::asio::socket_base::send_buffer_size sendBufferSizeOption;
|
||||
boost::system::error_code error;
|
||||
m_socket.get_option(sendBufferSizeOption, error);
|
||||
if (error) {
|
||||
NFD_LOG_FACE_WARN("Failed to obtain send queue capacity from socket: " << error.message());
|
||||
this->setSendQueueCapacity(QUEUE_ERROR);
|
||||
}
|
||||
else {
|
||||
this->setSendQueueCapacity(sendBufferSizeOption.value());
|
||||
}
|
||||
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
|
||||
[this] (auto&&... args) {
|
||||
this->handleReceive(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
|
||||
ssize_t
|
||||
DatagramTransport<T, U>::getSendQueueLength()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
m_socket.async_send(boost::asio::buffer(packet.packet),
|
||||
bind(&DatagramTransport<T, U>::handleSend, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred,
|
||||
packet.packet));
|
||||
ssize_t queueLength = getTxQueueLength(m_socket.native_handle());
|
||||
if (queueLength == QUEUE_ERROR) {
|
||||
NFD_LOG_FACE_WARN("Failed to obtain send queue length from socket: " << std::strerror(errno));
|
||||
}
|
||||
return queueLength;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::doClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
@@ -141,20 +156,33 @@ DatagramTransport<T, U>::doClose()
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
m_socket.async_send(boost::asio::buffer(packet),
|
||||
// 'packet' is copied into the lambda to retain the underlying Buffer
|
||||
[this, packet] (auto&&... args) {
|
||||
this->handleSend(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
void
|
||||
DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
|
||||
const boost::system::error_code& error)
|
||||
{
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
|
||||
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes from " << m_sender);
|
||||
|
||||
bool isOk = false;
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Failed to parse incoming packet");
|
||||
NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << m_sender);
|
||||
// This packet won't extend the face lifetime
|
||||
return;
|
||||
}
|
||||
@@ -163,30 +191,27 @@ DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesRec
|
||||
// This packet won't extend the face lifetime
|
||||
return;
|
||||
}
|
||||
m_hasRecentlyReceived = true;
|
||||
|
||||
m_hasBeenUsedRecently = true;
|
||||
this->receive(Transport::Packet(std::move(element)));
|
||||
this->receive(element, makeEndpointId(m_sender));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived)
|
||||
void
|
||||
DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error, size_t nBytesReceived)
|
||||
{
|
||||
receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
|
||||
|
||||
if (m_socket.is_open())
|
||||
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer),
|
||||
bind(&DatagramTransport<T, U>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
|
||||
[this] (auto&&... args) {
|
||||
this->handleReceive(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
DatagramTransport<T, U>::handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent, const Block& payload)
|
||||
// 'payload' is unused; it's needed to retain the underlying Buffer
|
||||
void
|
||||
DatagramTransport<T, U>::handleSend(const boost::system::error_code& error, size_t nBytesSent)
|
||||
{
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
@@ -195,7 +220,7 @@ DatagramTransport<T, U>::handleSend(const boost::system::error_code& error,
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::processErrorCode(const boost::system::error_code& error)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
@@ -203,34 +228,40 @@ DatagramTransport<T, U>::processErrorCode(const boost::system::error_code& error
|
||||
if (getState() == TransportState::CLOSING ||
|
||||
getState() == TransportState::FAILED ||
|
||||
getState() == TransportState::CLOSED ||
|
||||
error == boost::asio::error::operation_aborted)
|
||||
error == boost::asio::error::operation_aborted) {
|
||||
// transport is shutting down, ignore any errors
|
||||
return;
|
||||
}
|
||||
|
||||
if (getPersistency() == ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERMANENT) {
|
||||
if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
NFD_LOG_FACE_DEBUG("Permanent face ignores error: " << error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
if (error != boost::asio::error::eof)
|
||||
NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
|
||||
|
||||
NFD_LOG_FACE_ERROR("Send or receive operation failed: " << error.message());
|
||||
this->setState(TransportState::FAILED);
|
||||
doClose();
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool
|
||||
DatagramTransport<T, U>::hasBeenUsedRecently() const
|
||||
bool
|
||||
DatagramTransport<T, U>::hasRecentlyReceived() const
|
||||
{
|
||||
return m_hasBeenUsedRecently;
|
||||
return m_hasRecentlyReceived;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
DatagramTransport<T, U>::resetRecentUsage()
|
||||
void
|
||||
DatagramTransport<T, U>::resetRecentlyReceived()
|
||||
{
|
||||
m_hasBeenUsedRecently = false;
|
||||
m_hasRecentlyReceived = false;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
EndpointId
|
||||
DatagramTransport<T, U>::makeEndpointId(const typename protocol::endpoint&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ethernet-channel.hpp"
|
||||
#include "ethernet-protocol.hpp"
|
||||
#include "face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "unicast-ethernet-transport.hpp"
|
||||
#include "common/global.hpp"
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <pcap/pcap.h>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT(EthernetChannel);
|
||||
|
||||
EthernetChannel::EthernetChannel(shared_ptr<const ndn::net::NetworkInterface> localEndpoint,
|
||||
time::nanoseconds idleTimeout)
|
||||
: m_localEndpoint(std::move(localEndpoint))
|
||||
, m_isListening(false)
|
||||
, m_socket(getGlobalIoService())
|
||||
, m_pcap(m_localEndpoint->getName())
|
||||
, m_idleFaceTimeout(idleTimeout)
|
||||
#ifdef _DEBUG
|
||||
, m_nDropped(0)
|
||||
#endif
|
||||
{
|
||||
setUri(FaceUri::fromDev(m_localEndpoint->getName()));
|
||||
NFD_LOG_CHAN_INFO("Creating channel");
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::connect(const ethernet::Address& remoteEndpoint,
|
||||
const FaceParams& params,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
shared_ptr<Face> face;
|
||||
try {
|
||||
face = createFace(remoteEndpoint, params).second;
|
||||
}
|
||||
catch (const boost::system::system_error& e) {
|
||||
NFD_LOG_CHAN_DEBUG("Face creation for " << remoteEndpoint << " failed: " << e.what());
|
||||
if (onConnectFailed)
|
||||
onConnectFailed(504, "Face creation failed: "s + e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to invoke the callback regardless of whether or not we had already
|
||||
// created the face so that control responses and such can be sent
|
||||
onFaceCreated(face);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onFaceCreationFailed)
|
||||
{
|
||||
if (isListening()) {
|
||||
NFD_LOG_CHAN_WARN("Already listening");
|
||||
return;
|
||||
}
|
||||
m_isListening = true;
|
||||
|
||||
try {
|
||||
m_pcap.activate(DLT_EN10MB);
|
||||
m_socket.assign(m_pcap.getFd());
|
||||
}
|
||||
catch (const PcapHelper::Error& e) {
|
||||
NDN_THROW_NESTED(Error(e.what()));
|
||||
}
|
||||
updateFilter();
|
||||
|
||||
asyncRead(onFaceCreated, onFaceCreationFailed);
|
||||
NFD_LOG_CHAN_DEBUG("Started listening");
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::asyncRead(const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed)
|
||||
{
|
||||
m_socket.async_read_some(boost::asio::null_buffers(),
|
||||
[=] (const auto& e, auto) { this->handleRead(e, onFaceCreated, onReceiveFailed); });
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::handleRead(const boost::system::error_code& error,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed)
|
||||
{
|
||||
if (error) {
|
||||
if (error != boost::asio::error::operation_aborted) {
|
||||
NFD_LOG_CHAN_DEBUG("Receive failed: " << error.message());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(500, "Receive failed: " + error.message());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t* pkt;
|
||||
size_t len;
|
||||
std::string err;
|
||||
std::tie(pkt, len, err) = m_pcap.readNextPacket();
|
||||
|
||||
if (pkt == nullptr) {
|
||||
NFD_LOG_CHAN_WARN("Read error: " << err);
|
||||
}
|
||||
else {
|
||||
const ether_header* eh;
|
||||
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_localEndpoint->getEthernetAddress(),
|
||||
m_localEndpoint->getEthernetAddress());
|
||||
if (eh == nullptr) {
|
||||
NFD_LOG_CHAN_DEBUG(err);
|
||||
}
|
||||
else {
|
||||
ethernet::Address sender(eh->ether_shost);
|
||||
pkt += ethernet::HDR_LEN;
|
||||
len -= ethernet::HDR_LEN;
|
||||
processIncomingPacket(pkt, len, sender, onFaceCreated, onReceiveFailed);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
size_t nDropped = m_pcap.getNDropped();
|
||||
if (nDropped - m_nDropped > 0)
|
||||
NFD_LOG_CHAN_DEBUG("Detected " << nDropped - m_nDropped << " dropped frame(s)");
|
||||
m_nDropped = nDropped;
|
||||
#endif
|
||||
|
||||
asyncRead(onFaceCreated, onReceiveFailed);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::processIncomingPacket(const uint8_t* packet, size_t length,
|
||||
const ethernet::Address& sender,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed)
|
||||
{
|
||||
NFD_LOG_CHAN_TRACE("New peer " << sender);
|
||||
|
||||
bool isCreated = false;
|
||||
shared_ptr<Face> face;
|
||||
try {
|
||||
FaceParams params;
|
||||
params.persistency = ndn::nfd::FACE_PERSISTENCY_ON_DEMAND;
|
||||
std::tie(isCreated, face) = createFace(sender, params);
|
||||
}
|
||||
catch (const EthernetTransport::Error& e) {
|
||||
NFD_LOG_CHAN_DEBUG("Face creation for " << sender << " failed: " << e.what());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(504, "Face creation failed: "s + e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCreated)
|
||||
onFaceCreated(face);
|
||||
else
|
||||
NFD_LOG_CHAN_DEBUG("Received frame for existing face");
|
||||
|
||||
// dispatch the packet to the face for processing
|
||||
auto* transport = static_cast<UnicastEthernetTransport*>(face->getTransport());
|
||||
transport->receivePayload(packet, length, sender);
|
||||
}
|
||||
|
||||
std::pair<bool, shared_ptr<Face>>
|
||||
EthernetChannel::createFace(const ethernet::Address& remoteEndpoint,
|
||||
const FaceParams& params)
|
||||
{
|
||||
auto it = m_channelFaces.find(remoteEndpoint);
|
||||
if (it != m_channelFaces.end()) {
|
||||
// we already have a face for this endpoint, so reuse it
|
||||
NFD_LOG_CHAN_TRACE("Reusing existing face for " << remoteEndpoint);
|
||||
return {false, it->second};
|
||||
}
|
||||
|
||||
// else, create a new face
|
||||
GenericLinkService::Options options;
|
||||
options.allowFragmentation = true;
|
||||
options.allowReassembly = true;
|
||||
options.reliabilityOptions.isEnabled = params.wantLpReliability;
|
||||
if (params.mtu) {
|
||||
options.overrideMtu = *params.mtu;
|
||||
}
|
||||
if (params.bandwidth) {
|
||||
options.C = *params.bandwidth;
|
||||
}
|
||||
|
||||
auto linkService = make_unique<GenericLinkService>(options);
|
||||
auto transport = make_unique<UnicastEthernetTransport>(*m_localEndpoint, remoteEndpoint,
|
||||
params.persistency, m_idleFaceTimeout);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
|
||||
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, remoteEndpoint] {
|
||||
m_channelFaces.erase(remoteEndpoint);
|
||||
updateFilter();
|
||||
});
|
||||
updateFilter();
|
||||
|
||||
return {true, face};
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::updateFilter()
|
||||
{
|
||||
if (!isListening())
|
||||
return;
|
||||
|
||||
std::string filter = "(ether proto " + to_string(ethernet::ETHERTYPE_NDN) +
|
||||
") && (ether dst " + m_localEndpoint->getEthernetAddress().toString() + ")";
|
||||
for (const auto& addr : m_channelFaces | boost::adaptors::map_keys) {
|
||||
filter += " && (not ether src " + addr.toString() + ")";
|
||||
}
|
||||
// "not vlan" must appear last in the filter expression, or the
|
||||
// rest of the filter won't work as intended, see pcap-filter(7)
|
||||
filter += " && (not vlan)";
|
||||
|
||||
NFD_LOG_CHAN_TRACE("Updating filter: " << filter);
|
||||
m_pcap.setPacketFilter(filter.data());
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,142 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_ETHERNET_CHANNEL_HPP
|
||||
#define NFD_DAEMON_FACE_ETHERNET_CHANNEL_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "ethernet-protocol.hpp"
|
||||
#include "pcap-helper.hpp"
|
||||
#include <ndn-cxx/net/network-interface.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* \brief Class implementing Ethernet-based channel to create faces
|
||||
*/
|
||||
class EthernetChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief EthernetChannel-related error
|
||||
*/
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Create an Ethernet channel on the given \p localEndpoint (network interface)
|
||||
*
|
||||
* To enable creation of faces upon incoming connections,
|
||||
* one needs to explicitly call EthernetChannel::listen method.
|
||||
*/
|
||||
EthernetChannel(shared_ptr<const ndn::net::NetworkInterface> localEndpoint,
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
bool
|
||||
isListening() const override
|
||||
{
|
||||
return m_isListening;
|
||||
}
|
||||
|
||||
size_t
|
||||
size() const override
|
||||
{
|
||||
return m_channelFaces.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a unicast Ethernet face toward \p remoteEndpoint
|
||||
*/
|
||||
void
|
||||
connect(const ethernet::Address& remoteEndpoint,
|
||||
const FaceParams& params,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed);
|
||||
|
||||
/**
|
||||
* \brief Start listening
|
||||
*
|
||||
* Enable listening on the local endpoint, waiting for incoming frames,
|
||||
* and creating a face when a frame is received from a new remote host.
|
||||
*
|
||||
* Faces created in this way will have on-demand persistency.
|
||||
*
|
||||
* \param onFaceCreated Callback to notify successful creation of a face
|
||||
* \param onFaceCreationFailed Callback to notify errors
|
||||
* \throw Error
|
||||
*/
|
||||
void
|
||||
listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onFaceCreationFailed);
|
||||
|
||||
private:
|
||||
void
|
||||
asyncRead(const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
void
|
||||
handleRead(const boost::system::error_code& error,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
void
|
||||
processIncomingPacket(const uint8_t* packet, size_t length,
|
||||
const ethernet::Address& sender,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
std::pair<bool, shared_ptr<Face>>
|
||||
createFace(const ethernet::Address& remoteEndpoint,
|
||||
const FaceParams& params);
|
||||
|
||||
void
|
||||
updateFilter();
|
||||
|
||||
private:
|
||||
shared_ptr<const ndn::net::NetworkInterface> m_localEndpoint;
|
||||
bool m_isListening;
|
||||
boost::asio::posix::stream_descriptor m_socket;
|
||||
PcapHelper m_pcap;
|
||||
std::map<ethernet::Address, shared_ptr<Face>> m_channelFaces;
|
||||
const time::nanoseconds m_idleFaceTimeout; ///< Timeout for automatic closure of idle on-demand faces
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// number of frames dropped by the kernel, as reported by libpcap
|
||||
size_t m_nDropped;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_CHANNEL_HPP
|
||||
@@ -1,468 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ethernet-face.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstring> // for std::strerror() and std::strncpy()
|
||||
#include <stdio.h> // for snprintf()
|
||||
#include <arpa/inet.h> // for htons() and ntohs()
|
||||
#include <net/ethernet.h> // for struct ether_header
|
||||
#include <net/if.h> // for struct ifreq
|
||||
#include <sys/ioctl.h> // for ioctl()
|
||||
#include <unistd.h> // for dup()
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <netpacket/packet.h> // for struct packet_mreq
|
||||
#include <sys/socket.h> // for setsockopt()
|
||||
#endif
|
||||
|
||||
#ifdef SIOCADDMULTI
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <net/if_dl.h> // for struct sockaddr_dl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(PCAP_NETMASK_UNKNOWN)
|
||||
/*
|
||||
* Value to pass to pcap_compile() as the netmask if you don't know what
|
||||
* the netmask is.
|
||||
*/
|
||||
#define PCAP_NETMASK_UNKNOWN 0xffffffff
|
||||
#endif
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INIT("EthernetFace");
|
||||
|
||||
const time::nanoseconds EthernetFace::REASSEMBLER_LIFETIME = time::seconds(60);
|
||||
|
||||
EthernetFace::EthernetFace(boost::asio::posix::stream_descriptor socket,
|
||||
const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address)
|
||||
: Face(FaceUri(address), FaceUri::fromDev(interface.name), false, true)
|
||||
, m_pcap(nullptr, pcap_close)
|
||||
, m_socket(std::move(socket))
|
||||
#if defined(__linux__)
|
||||
, m_interfaceIndex(interface.index)
|
||||
#endif
|
||||
, m_interfaceName(interface.name)
|
||||
, m_srcAddress(interface.etherAddress)
|
||||
, m_destAddress(address)
|
||||
#ifdef _DEBUG
|
||||
, m_nDropped(0)
|
||||
#endif
|
||||
{
|
||||
NFD_LOG_FACE_INFO("Creating face on " << m_interfaceName << "/" << m_srcAddress);
|
||||
pcapInit();
|
||||
|
||||
int fd = pcap_get_selectable_fd(m_pcap.get());
|
||||
if (fd < 0)
|
||||
BOOST_THROW_EXCEPTION(Error("pcap_get_selectable_fd failed"));
|
||||
|
||||
// need to duplicate the fd, otherwise both pcap_close()
|
||||
// and stream_descriptor::close() will try to close the
|
||||
// same fd and one of them will fail
|
||||
m_socket.assign(::dup(fd));
|
||||
|
||||
m_interfaceMtu = getInterfaceMtu();
|
||||
NFD_LOG_FACE_DEBUG("Interface MTU is: " << m_interfaceMtu);
|
||||
|
||||
m_slicer.reset(new ndnlp::Slicer(m_interfaceMtu));
|
||||
|
||||
char filter[100];
|
||||
// std::snprintf not found in some environments
|
||||
// http://redmine.named-data.net/issues/2299 for more information
|
||||
snprintf(filter, sizeof(filter),
|
||||
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s)",
|
||||
ethernet::ETHERTYPE_NDN,
|
||||
m_destAddress.toString().c_str(),
|
||||
m_srcAddress.toString().c_str());
|
||||
setPacketFilter(filter);
|
||||
|
||||
if (!m_destAddress.isBroadcast() && !joinMulticastGroup())
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Falling back to promiscuous mode");
|
||||
pcap_set_promisc(m_pcap.get(), 1);
|
||||
}
|
||||
|
||||
m_socket.async_read_some(boost::asio::null_buffers(),
|
||||
bind(&EthernetFace::handleRead, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::sendInterest(const Interest& interest)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
this->emitSignal(onSendInterest, interest);
|
||||
|
||||
ndnlp::PacketArray pa = m_slicer->slice(interest.wireEncode());
|
||||
for (const auto& packet : *pa) {
|
||||
sendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::sendData(const Data& data)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
this->emitSignal(onSendData, data);
|
||||
|
||||
ndnlp::PacketArray pa = m_slicer->slice(data.wireEncode());
|
||||
for (const auto& packet : *pa) {
|
||||
sendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::close()
|
||||
{
|
||||
if (!m_pcap)
|
||||
return;
|
||||
|
||||
NFD_LOG_FACE_INFO("Closing face");
|
||||
|
||||
boost::system::error_code error;
|
||||
m_socket.cancel(error); // ignore errors
|
||||
m_socket.close(error); // ignore errors
|
||||
m_pcap.reset();
|
||||
|
||||
fail("Face closed");
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::pcapInit()
|
||||
{
|
||||
char errbuf[PCAP_ERRBUF_SIZE] = {};
|
||||
m_pcap.reset(pcap_create(m_interfaceName.c_str(), errbuf));
|
||||
if (!m_pcap)
|
||||
BOOST_THROW_EXCEPTION(Error("pcap_create: " + std::string(errbuf)));
|
||||
|
||||
#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
|
||||
// Enable "immediate mode", effectively disabling any read buffering in the kernel.
|
||||
// This corresponds to the BIOCIMMEDIATE ioctl on BSD-like systems (including OS X)
|
||||
// where libpcap uses a BPF device. On Linux this forces libpcap not to use TPACKET_V3,
|
||||
// even if the kernel supports it, thus preventing bug #1511.
|
||||
pcap_set_immediate_mode(m_pcap.get(), 1);
|
||||
#endif
|
||||
|
||||
if (pcap_activate(m_pcap.get()) < 0)
|
||||
BOOST_THROW_EXCEPTION(Error("pcap_activate failed"));
|
||||
|
||||
if (pcap_set_datalink(m_pcap.get(), DLT_EN10MB) < 0)
|
||||
BOOST_THROW_EXCEPTION(Error("pcap_set_datalink: " + std::string(pcap_geterr(m_pcap.get()))));
|
||||
|
||||
if (pcap_setdirection(m_pcap.get(), PCAP_D_IN) < 0)
|
||||
// no need to throw on failure, BPF will filter unwanted packets anyway
|
||||
NFD_LOG_FACE_WARN("pcap_setdirection failed: " << pcap_geterr(m_pcap.get()));
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::setPacketFilter(const char* filterString)
|
||||
{
|
||||
bpf_program filter;
|
||||
if (pcap_compile(m_pcap.get(), &filter, filterString, 1, PCAP_NETMASK_UNKNOWN) < 0)
|
||||
BOOST_THROW_EXCEPTION(Error("pcap_compile: " + std::string(pcap_geterr(m_pcap.get()))));
|
||||
|
||||
int ret = pcap_setfilter(m_pcap.get(), &filter);
|
||||
pcap_freecode(&filter);
|
||||
if (ret < 0)
|
||||
BOOST_THROW_EXCEPTION(Error("pcap_setfilter: " + std::string(pcap_geterr(m_pcap.get()))));
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetFace::joinMulticastGroup()
|
||||
{
|
||||
#if defined(__linux__)
|
||||
packet_mreq mr{};
|
||||
mr.mr_ifindex = m_interfaceIndex;
|
||||
mr.mr_type = PACKET_MR_MULTICAST;
|
||||
mr.mr_alen = m_destAddress.size();
|
||||
std::copy(m_destAddress.begin(), m_destAddress.end(), mr.mr_address);
|
||||
|
||||
if (::setsockopt(m_socket.native_handle(), SOL_PACKET,
|
||||
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == 0)
|
||||
return true; // success
|
||||
|
||||
NFD_LOG_FACE_WARN("setsockopt(PACKET_ADD_MEMBERSHIP) failed: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
#if defined(SIOCADDMULTI)
|
||||
ifreq ifr{};
|
||||
std::strncpy(ifr.ifr_name, m_interfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// see bug #2327
|
||||
using boost::asio::ip::udp;
|
||||
udp::socket sock(ref(getGlobalIoService()), udp::v4());
|
||||
int fd = sock.native_handle();
|
||||
|
||||
/*
|
||||
* Differences between Linux and the BSDs (including OS X):
|
||||
* o BSD does not have ifr_hwaddr; use ifr_addr instead.
|
||||
* o While OS X seems to accept both AF_LINK and AF_UNSPEC as the address
|
||||
* family, FreeBSD explicitly requires AF_LINK, so we have to use AF_LINK
|
||||
* and sockaddr_dl instead of the generic sockaddr structure.
|
||||
* o BSD's sockaddr (and sockaddr_dl in particular) contains an additional
|
||||
* field, sa_len (sdl_len), which must be set to the total length of the
|
||||
* structure, including the length field itself.
|
||||
* o We do not specify the interface name, thus sdl_nlen is left at 0 and
|
||||
* LLADDR is effectively the same as sdl_data.
|
||||
*/
|
||||
sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(&ifr.ifr_addr);
|
||||
sdl->sdl_len = sizeof(ifr.ifr_addr);
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_alen = m_destAddress.size();
|
||||
std::copy(m_destAddress.begin(), m_destAddress.end(), LLADDR(sdl));
|
||||
|
||||
static_assert(sizeof(ifr.ifr_addr) >= offsetof(sockaddr_dl, sdl_data) + ethernet::ADDR_LEN,
|
||||
"ifr_addr in struct ifreq is too small on this platform");
|
||||
#else
|
||||
int fd = m_socket.native_handle();
|
||||
|
||||
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
||||
std::copy(m_destAddress.begin(), m_destAddress.end(), ifr.ifr_hwaddr.sa_data);
|
||||
|
||||
static_assert(sizeof(ifr.ifr_hwaddr) >= offsetof(sockaddr, sa_data) + ethernet::ADDR_LEN,
|
||||
"ifr_hwaddr in struct ifreq is too small on this platform");
|
||||
#endif
|
||||
|
||||
if (::ioctl(fd, SIOCADDMULTI, &ifr) == 0)
|
||||
return true; // success
|
||||
|
||||
NFD_LOG_FACE_WARN("ioctl(SIOCADDMULTI) failed: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::sendPacket(const ndn::Block& block)
|
||||
{
|
||||
if (!m_pcap)
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Trying to send on closed face");
|
||||
return fail("Face closed");
|
||||
}
|
||||
|
||||
BOOST_ASSERT(block.size() <= m_interfaceMtu);
|
||||
|
||||
/// \todo Right now there is no reserve when packet is received, but
|
||||
/// we should reserve some space at the beginning and at the end
|
||||
ndn::EncodingBuffer buffer(block);
|
||||
|
||||
// pad with zeroes if the payload is too short
|
||||
if (block.size() < ethernet::MIN_DATA_LEN)
|
||||
{
|
||||
static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
|
||||
buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
|
||||
}
|
||||
|
||||
// construct and prepend the ethernet header
|
||||
static uint16_t ethertype = htons(ethernet::ETHERTYPE_NDN);
|
||||
buffer.prependByteArray(reinterpret_cast<const uint8_t*>(ðertype), ethernet::TYPE_LEN);
|
||||
buffer.prependByteArray(m_srcAddress.data(), m_srcAddress.size());
|
||||
buffer.prependByteArray(m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
// send the packet
|
||||
int sent = pcap_inject(m_pcap.get(), buffer.buf(), buffer.size());
|
||||
if (sent < 0)
|
||||
{
|
||||
return fail("pcap_inject: " + std::string(pcap_geterr(m_pcap.get())));
|
||||
}
|
||||
else if (static_cast<size_t>(sent) < buffer.size())
|
||||
{
|
||||
return fail("Failed to inject frame");
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << block.size() << " bytes");
|
||||
this->getMutableCounters().getNOutBytes() += block.size();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::handleRead(const boost::system::error_code& error, size_t)
|
||||
{
|
||||
if (!m_pcap)
|
||||
return fail("Face closed");
|
||||
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
pcap_pkthdr* header;
|
||||
const uint8_t* packet;
|
||||
int ret = pcap_next_ex(m_pcap.get(), &header, &packet);
|
||||
if (ret < 0)
|
||||
{
|
||||
return fail("pcap_next_ex: " + std::string(pcap_geterr(m_pcap.get())));
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Read timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
processIncomingPacket(header, packet);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
pcap_stat ps{};
|
||||
ret = pcap_stats(m_pcap.get(), &ps);
|
||||
if (ret < 0)
|
||||
{
|
||||
NFD_LOG_FACE_DEBUG("pcap_stats failed: " << pcap_geterr(m_pcap.get()));
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
if (ps.ps_drop - m_nDropped > 0)
|
||||
NFD_LOG_FACE_DEBUG("Detected " << ps.ps_drop - m_nDropped << " dropped packet(s)");
|
||||
m_nDropped = ps.ps_drop;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_socket.async_read_some(boost::asio::null_buffers(),
|
||||
bind(&EthernetFace::handleRead, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet)
|
||||
{
|
||||
size_t length = header->caplen;
|
||||
if (length < ethernet::HDR_LEN + ethernet::MIN_DATA_LEN) {
|
||||
NFD_LOG_FACE_WARN("Received frame is too short (" << length << " bytes)");
|
||||
return;
|
||||
}
|
||||
|
||||
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
|
||||
const ethernet::Address sourceAddress(eh->ether_shost);
|
||||
|
||||
// assert in case BPF fails to filter unwanted frames
|
||||
BOOST_ASSERT_MSG(ethernet::Address(eh->ether_dhost) == m_destAddress,
|
||||
"Received frame addressed to a different multicast group");
|
||||
BOOST_ASSERT_MSG(sourceAddress != m_srcAddress,
|
||||
"Received frame sent by this host");
|
||||
BOOST_ASSERT_MSG(ntohs(eh->ether_type) == ethernet::ETHERTYPE_NDN,
|
||||
"Received frame with unrecognized ethertype");
|
||||
|
||||
packet += ethernet::HDR_LEN;
|
||||
length -= ethernet::HDR_LEN;
|
||||
|
||||
/// \todo Reserve space in front and at the back of the underlying buffer
|
||||
bool isOk = false;
|
||||
Block fragmentBlock;
|
||||
std::tie(isOk, fragmentBlock) = Block::fromBuffer(packet, length);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Block received from " << sourceAddress.toString()
|
||||
<< " is invalid or too large to process");
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_TRACE("Received: " << fragmentBlock.size() << " bytes from "
|
||||
<< sourceAddress.toString());
|
||||
this->getMutableCounters().getNInBytes() += fragmentBlock.size();
|
||||
|
||||
Reassembler& reassembler = m_reassemblers[sourceAddress];
|
||||
if (!reassembler.pms) {
|
||||
// new sender, setup a PartialMessageStore for it
|
||||
reassembler.pms.reset(new ndnlp::PartialMessageStore);
|
||||
reassembler.pms->onReceive.connect(
|
||||
[this, sourceAddress] (const Block& block) {
|
||||
NFD_LOG_FACE_TRACE("All fragments received from " << sourceAddress.toString());
|
||||
if (!decodeAndDispatchInput(block))
|
||||
NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << block.type()
|
||||
<< " from " << sourceAddress.toString());
|
||||
});
|
||||
}
|
||||
|
||||
scheduler::cancel(reassembler.expireEvent);
|
||||
reassembler.expireEvent = scheduler::schedule(REASSEMBLER_LIFETIME,
|
||||
[this, sourceAddress] {
|
||||
BOOST_VERIFY(m_reassemblers.erase(sourceAddress) == 1);
|
||||
});
|
||||
|
||||
ndnlp::NdnlpData fragment;
|
||||
std::tie(isOk, fragment) = ndnlp::NdnlpData::fromBlock(fragmentBlock);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Received invalid NDNLP fragment from " << sourceAddress.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
reassembler.pms->receive(fragment);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::processErrorCode(const boost::system::error_code& error)
|
||||
{
|
||||
if (error == boost::asio::error::operation_aborted)
|
||||
// cancel() has been called on the socket
|
||||
return;
|
||||
|
||||
std::string msg;
|
||||
if (error == boost::asio::error::eof)
|
||||
{
|
||||
msg = "Face closed";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "Receive operation failed: " + error.message();
|
||||
NFD_LOG_FACE_WARN(msg);
|
||||
}
|
||||
fail(msg);
|
||||
}
|
||||
|
||||
size_t
|
||||
EthernetFace::getInterfaceMtu()
|
||||
{
|
||||
#ifdef SIOCGIFMTU
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// see bug #2328
|
||||
using boost::asio::ip::udp;
|
||||
udp::socket sock(ref(getGlobalIoService()), udp::v4());
|
||||
int fd = sock.native_handle();
|
||||
#else
|
||||
int fd = m_socket.native_handle();
|
||||
#endif
|
||||
|
||||
ifreq ifr{};
|
||||
std::strncpy(ifr.ifr_name, m_interfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
if (::ioctl(fd, SIOCGIFMTU, &ifr) == 0)
|
||||
return static_cast<size_t>(ifr.ifr_mtu);
|
||||
|
||||
NFD_LOG_FACE_WARN("Failed to get interface MTU: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
return ethernet::MAX_DATA_LEN;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,171 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_ETHERNET_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_ETHERNET_FACE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "face.hpp"
|
||||
#include "ndnlp-partial-message-store.hpp"
|
||||
#include "ndnlp-slicer.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef HAVE_LIBPCAP
|
||||
#error "Cannot include this file when libpcap is not available"
|
||||
#endif
|
||||
|
||||
// forward declarations
|
||||
struct pcap;
|
||||
typedef pcap pcap_t;
|
||||
struct pcap_pkthdr;
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/**
|
||||
* @brief Implementation of Face abstraction that uses raw
|
||||
* Ethernet frames as underlying transport mechanism
|
||||
*/
|
||||
class EthernetFace : public Face
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief EthernetFace-related error
|
||||
*/
|
||||
struct Error : public Face::Error
|
||||
{
|
||||
Error(const std::string& what) : Face::Error(what) {}
|
||||
};
|
||||
|
||||
EthernetFace(boost::asio::posix::stream_descriptor socket,
|
||||
const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address);
|
||||
|
||||
/// send an Interest
|
||||
void
|
||||
sendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
|
||||
/// send a Data
|
||||
void
|
||||
sendData(const Data& data) DECL_OVERRIDE;
|
||||
|
||||
/**
|
||||
* @brief Closes the face
|
||||
*
|
||||
* This terminates all communication on the face and triggers the onFail() event.
|
||||
*/
|
||||
void
|
||||
close() DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Allocates and initializes a libpcap context for live capture
|
||||
*/
|
||||
void
|
||||
pcapInit();
|
||||
|
||||
/**
|
||||
* @brief Installs a BPF filter on the receiving socket
|
||||
*
|
||||
* @param filterString string containing the source BPF program
|
||||
*/
|
||||
void
|
||||
setPacketFilter(const char* filterString);
|
||||
|
||||
/**
|
||||
* @brief Enables receiving frames addressed to our MAC multicast group
|
||||
*
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
bool
|
||||
joinMulticastGroup();
|
||||
|
||||
/**
|
||||
* @brief Sends the specified TLV block on the network wrapped in an Ethernet frame
|
||||
*/
|
||||
void
|
||||
sendPacket(const ndn::Block& block);
|
||||
|
||||
/**
|
||||
* @brief Receive callback
|
||||
*/
|
||||
void
|
||||
handleRead(const boost::system::error_code& error, size_t nBytesRead);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/**
|
||||
* @brief Processes an incoming frame as captured by libpcap
|
||||
*
|
||||
* @param header pointer to capture metadata
|
||||
* @param packet pointer to the received frame, including the link-layer header
|
||||
*/
|
||||
void
|
||||
processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Handles errors encountered by Boost.Asio on the receive path
|
||||
*/
|
||||
void
|
||||
processErrorCode(const boost::system::error_code& error);
|
||||
|
||||
/**
|
||||
* @brief Returns the MTU of the underlying network interface
|
||||
*/
|
||||
size_t
|
||||
getInterfaceMtu();
|
||||
|
||||
private:
|
||||
struct Reassembler
|
||||
{
|
||||
unique_ptr<ndnlp::PartialMessageStore> pms;
|
||||
scheduler::EventId expireEvent;
|
||||
};
|
||||
|
||||
unique_ptr<pcap_t, void(*)(pcap_t*)> m_pcap;
|
||||
boost::asio::posix::stream_descriptor m_socket;
|
||||
|
||||
#if defined(__linux__)
|
||||
int m_interfaceIndex;
|
||||
#endif
|
||||
std::string m_interfaceName;
|
||||
ethernet::Address m_srcAddress;
|
||||
ethernet::Address m_destAddress;
|
||||
|
||||
size_t m_interfaceMtu;
|
||||
unique_ptr<ndnlp::Slicer> m_slicer;
|
||||
std::unordered_map<ethernet::Address, Reassembler> m_reassemblers;
|
||||
static const time::nanoseconds REASSEMBLER_LIFETIME;
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// number of packets dropped by the kernel, as reported by libpcap
|
||||
unsigned int m_nDropped;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_FACE_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,60 +24,358 @@
|
||||
*/
|
||||
|
||||
#include "ethernet-factory.hpp"
|
||||
#include "face/ethernet-face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "multicast-ethernet-transport.hpp"
|
||||
|
||||
#include "core/logger.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
shared_ptr<EthernetFace>
|
||||
EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address &address)
|
||||
NFD_LOG_INIT(EthernetFactory);
|
||||
NFD_REGISTER_PROTOCOL_FACTORY(EthernetFactory);
|
||||
|
||||
const std::string&
|
||||
EthernetFactory::getId() noexcept
|
||||
{
|
||||
if (!address.isMulticast())
|
||||
BOOST_THROW_EXCEPTION(Error(address.toString() + " is not a multicast address"));
|
||||
static std::string id("ether");
|
||||
return id;
|
||||
}
|
||||
|
||||
auto face = findMulticastFace(interface.name, address);
|
||||
if (face)
|
||||
return face;
|
||||
|
||||
face = make_shared<EthernetFace>(boost::asio::posix::stream_descriptor(getGlobalIoService()),
|
||||
interface, address);
|
||||
|
||||
auto key = std::make_pair(interface.name, address);
|
||||
face->onFail.connectSingleShot([this, key] (const std::string& reason) {
|
||||
m_multicastFaces.erase(key);
|
||||
EthernetFactory::EthernetFactory(const CtorParams& params)
|
||||
: ProtocolFactory(params)
|
||||
{
|
||||
m_netifAddConn = netmon->onInterfaceAdded.connect([this] (const auto& netif) {
|
||||
this->applyUnicastConfigToNetif(netif);
|
||||
this->applyMcastConfigToNetif(*netif);
|
||||
});
|
||||
m_multicastFaces[key] = face;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFactory::doProcessConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// ether
|
||||
// {
|
||||
// listen yes
|
||||
// idle_timeout 600
|
||||
// mcast yes
|
||||
// mcast_group 01:00:5E:00:17:AA
|
||||
// mcast_ad_hoc no
|
||||
// whitelist
|
||||
// {
|
||||
// *
|
||||
// }
|
||||
// blacklist
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
|
||||
UnicastConfig unicastConfig;
|
||||
MulticastConfig mcastConfig;
|
||||
|
||||
if (configSection) {
|
||||
// listen and mcast default to 'yes' but only if face_system.ether section is present
|
||||
unicastConfig.isEnabled = unicastConfig.wantListen = mcastConfig.isEnabled = true;
|
||||
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
const ConfigSection& value = pair.second;
|
||||
|
||||
if (key == "listen") {
|
||||
unicastConfig.wantListen = ConfigFile::parseYesNo(pair, "face_system.ether");
|
||||
}
|
||||
else if (key == "idle_timeout") {
|
||||
unicastConfig.idleTimeout = time::seconds(ConfigFile::parseNumber<uint32_t>(pair, "face_system.ether"));
|
||||
}
|
||||
else if (key == "mcast") {
|
||||
mcastConfig.isEnabled = ConfigFile::parseYesNo(pair, "face_system.ether");
|
||||
}
|
||||
else if (key == "mcast_group") {
|
||||
const std::string& valueStr = value.get_value<std::string>();
|
||||
mcastConfig.group = ethernet::Address::fromString(valueStr);
|
||||
if (mcastConfig.group.isNull()) {
|
||||
NDN_THROW(ConfigFile::Error("face_system.ether.mcast_group: '" +
|
||||
valueStr + "' cannot be parsed as an Ethernet address"));
|
||||
}
|
||||
else if (!mcastConfig.group.isMulticast()) {
|
||||
NDN_THROW(ConfigFile::Error("face_system.ether.mcast_group: '" +
|
||||
valueStr + "' is not a multicast address"));
|
||||
}
|
||||
}
|
||||
else if (key == "mcast_ad_hoc") {
|
||||
bool wantAdHoc = ConfigFile::parseYesNo(pair, "face_system.ether");
|
||||
mcastConfig.linkType = wantAdHoc ? ndn::nfd::LINK_TYPE_AD_HOC : ndn::nfd::LINK_TYPE_MULTI_ACCESS;
|
||||
}
|
||||
else if (key == "whitelist") {
|
||||
mcastConfig.netifPredicate.parseWhitelist(value);
|
||||
}
|
||||
else if (key == "blacklist") {
|
||||
mcastConfig.netifPredicate.parseBlacklist(value);
|
||||
}
|
||||
else {
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option face_system.ether." + key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.isDryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unicastConfig.isEnabled) {
|
||||
if (m_unicastConfig.wantListen && !unicastConfig.wantListen && !m_channels.empty()) {
|
||||
NFD_LOG_WARN("Cannot stop listening on Ethernet channels");
|
||||
}
|
||||
if (m_unicastConfig.idleTimeout != unicastConfig.idleTimeout && !m_channels.empty()) {
|
||||
NFD_LOG_WARN("Idle timeout setting applies to new Ethernet channels only");
|
||||
}
|
||||
}
|
||||
else if (m_unicastConfig.isEnabled && !m_channels.empty()) {
|
||||
NFD_LOG_WARN("Cannot disable Ethernet channels after initialization");
|
||||
}
|
||||
|
||||
if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
|
||||
if (mcastConfig.isEnabled) {
|
||||
NFD_LOG_INFO("enabling multicast on " << mcastConfig.group);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_INFO("disabling multicast");
|
||||
}
|
||||
}
|
||||
else if (mcastConfig.isEnabled) {
|
||||
if (m_mcastConfig.linkType != mcastConfig.linkType && !m_mcastFaces.empty()) {
|
||||
NFD_LOG_WARN("Cannot change ad hoc setting on existing faces");
|
||||
}
|
||||
if (m_mcastConfig.group != mcastConfig.group) {
|
||||
NFD_LOG_INFO("changing multicast group from " << m_mcastConfig.group <<
|
||||
" to " << mcastConfig.group);
|
||||
}
|
||||
if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
|
||||
NFD_LOG_INFO("changing whitelist/blacklist");
|
||||
}
|
||||
}
|
||||
|
||||
// Even if there's no configuration change, we still need to re-apply configuration because
|
||||
// netifs may have changed.
|
||||
m_unicastConfig = unicastConfig;
|
||||
m_mcastConfig = mcastConfig;
|
||||
this->applyConfig(context);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFactory::doCreateFace(const CreateFaceRequest& req,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure)
|
||||
{
|
||||
if (!req.localUri || req.localUri->getScheme() != "dev") {
|
||||
NFD_LOG_TRACE("Cannot create unicast Ethernet face without dev:// LocalUri");
|
||||
onFailure(406, "Creation of unicast Ethernet faces requires a LocalUri with dev:// scheme");
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.params.persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
|
||||
NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
|
||||
onFailure(406, "Outgoing Ethernet faces do not support on-demand persistency");
|
||||
return;
|
||||
}
|
||||
|
||||
ethernet::Address remoteEndpoint(ethernet::Address::fromString(req.remoteUri.getHost()));
|
||||
std::string localEndpoint(req.localUri->getHost());
|
||||
|
||||
if (remoteEndpoint.isMulticast()) {
|
||||
NFD_LOG_TRACE("createFace does not support multicast faces");
|
||||
onFailure(406, "Cannot create multicast Ethernet faces");
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.params.wantLocalFields) {
|
||||
// Ethernet faces are never local
|
||||
NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
|
||||
onFailure(406, "Local fields can only be enabled on faces with local scope");
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.params.mtu && *req.params.mtu < MIN_MTU) {
|
||||
// The specified MTU must be greater than the minimum possible
|
||||
NFD_LOG_TRACE("createFace: override MTU cannot be less than " << MIN_MTU);
|
||||
onFailure(406, "Override MTU cannot be less than " + to_string(MIN_MTU));
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& i : m_channels) {
|
||||
if (i.first == localEndpoint) {
|
||||
i.second->connect(remoteEndpoint, req.params, onCreated, onFailure);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NFD_LOG_TRACE("No channels available to connect to " << remoteEndpoint);
|
||||
onFailure(504, "No channels available to connect");
|
||||
}
|
||||
|
||||
shared_ptr<EthernetChannel>
|
||||
EthernetFactory::createChannel(const shared_ptr<const ndn::net::NetworkInterface>& localEndpoint,
|
||||
time::nanoseconds idleTimeout)
|
||||
{
|
||||
auto it = m_channels.find(localEndpoint->getName());
|
||||
if (it != m_channels.end())
|
||||
return it->second;
|
||||
|
||||
auto channel = std::make_shared<EthernetChannel>(localEndpoint, idleTimeout);
|
||||
m_channels[localEndpoint->getName()] = channel;
|
||||
return channel;
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
EthernetFactory::doGetChannels() const
|
||||
{
|
||||
return getChannelsFromMap(m_channels);
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
EthernetFactory::createMulticastFace(const ndn::net::NetworkInterface& netif,
|
||||
const ethernet::Address& address)
|
||||
{
|
||||
BOOST_ASSERT(address.isMulticast());
|
||||
|
||||
auto key = std::make_pair(netif.getName(), address);
|
||||
auto found = m_mcastFaces.find(key);
|
||||
if (found != m_mcastFaces.end()) {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
GenericLinkService::Options opts;
|
||||
opts.allowFragmentation = true;
|
||||
opts.allowReassembly = true;
|
||||
|
||||
auto linkService = make_unique<GenericLinkService>(opts);
|
||||
auto transport = make_unique<MulticastEthernetTransport>(netif, address, m_mcastConfig.linkType);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
m_mcastFaces[key] = face;
|
||||
connectFaceClosedSignal(*face, [this, key] { m_mcastFaces.erase(key); });
|
||||
|
||||
auto channelIt = m_channels.find(netif.getName());
|
||||
face->setChannel(channelIt != m_channels.end() ? channelIt->second : nullptr);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
shared_ptr<EthernetChannel>
|
||||
EthernetFactory::applyUnicastConfigToNetif(const shared_ptr<const ndn::net::NetworkInterface>& netif)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(Error("EthernetFactory does not support 'createFace' operation"));
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
EthernetFactory::getChannels() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
shared_ptr<EthernetFace>
|
||||
EthernetFactory::findMulticastFace(const std::string& interfaceName,
|
||||
const ethernet::Address& address) const
|
||||
{
|
||||
auto i = m_multicastFaces.find({interfaceName, address});
|
||||
if (i != m_multicastFaces.end())
|
||||
return i->second;
|
||||
else
|
||||
if (!m_unicastConfig.isEnabled) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (netif->getType() != ndn::net::InterfaceType::ETHERNET) {
|
||||
NFD_LOG_DEBUG("Not creating channel on " << netif->getName() << ": incompatible netif type");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!netif->isUp()) {
|
||||
NFD_LOG_DEBUG("Not creating channel on " << netif->getName() << ": netif is down");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (netif->getEthernetAddress().isNull()) {
|
||||
NFD_LOG_DEBUG("Not creating channel on " << netif->getName() << ": invalid Ethernet address");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto channel = this->createChannel(netif, m_unicastConfig.idleTimeout);
|
||||
if (m_unicastConfig.wantListen && !channel->isListening()) {
|
||||
try {
|
||||
channel->listen(this->addFace, nullptr);
|
||||
}
|
||||
catch (const EthernetChannel::Error& e) {
|
||||
NFD_LOG_WARN("Cannot listen on " << netif->getName() << ": " << e.what());
|
||||
}
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
EthernetFactory::applyMcastConfigToNetif(const ndn::net::NetworkInterface& netif)
|
||||
{
|
||||
if (!m_mcastConfig.isEnabled) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (netif.getType() != ndn::net::InterfaceType::ETHERNET) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": incompatible netif type");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!netif.isUp()) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": netif is down");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!netif.canMulticast()) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": netif cannot multicast");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (netif.getEthernetAddress().isNull()) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": invalid Ethernet address");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!m_mcastConfig.netifPredicate(netif)) {
|
||||
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": rejected by whitelist/blacklist");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("Creating multicast face on " << netif.getName());
|
||||
shared_ptr<Face> face;
|
||||
try {
|
||||
face = this->createMulticastFace(netif, m_mcastConfig.group);
|
||||
}
|
||||
catch (const EthernetTransport::Error& e) {
|
||||
NFD_LOG_WARN("Cannot create multicast face on " << netif.getName() << ": " << e.what());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (face->getId() == face::INVALID_FACEID) {
|
||||
// new face: register with forwarding
|
||||
this->addFace(face);
|
||||
}
|
||||
return face;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFactory::applyConfig(const FaceSystem::ConfigContext&)
|
||||
{
|
||||
if (m_unicastConfig.isEnabled) {
|
||||
providedSchemes.insert("ether");
|
||||
}
|
||||
else {
|
||||
providedSchemes.erase("ether");
|
||||
}
|
||||
|
||||
// collect old multicast faces
|
||||
std::set<shared_ptr<Face>> oldFaces;
|
||||
boost::copy(m_mcastFaces | boost::adaptors::map_values, std::inserter(oldFaces, oldFaces.end()));
|
||||
|
||||
// create channels and multicast faces if requested by config
|
||||
for (const auto& netif : netmon->listNetworkInterfaces()) {
|
||||
this->applyUnicastConfigToNetif(netif);
|
||||
|
||||
auto face = this->applyMcastConfigToNetif(*netif);
|
||||
if (face != nullptr) {
|
||||
// don't destroy face
|
||||
oldFaces.erase(face);
|
||||
}
|
||||
}
|
||||
|
||||
// destroy old multicast faces that are not needed in new configuration
|
||||
for (const auto& face : oldFaces) {
|
||||
face->close();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,87 +27,108 @@
|
||||
#define NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
|
||||
|
||||
#include "protocol-factory.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
#include "ethernet-channel.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class EthernetFace;
|
||||
|
||||
/** \brief Protocol factory for Ethernet
|
||||
*/
|
||||
class EthernetFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
static const std::string&
|
||||
getId() noexcept;
|
||||
|
||||
explicit
|
||||
EthernetFactory(const CtorParams& params);
|
||||
|
||||
/**
|
||||
* \brief Exception of EthernetFactory
|
||||
* \brief Create Ethernet-based channel on the specified network interface
|
||||
*
|
||||
* If this method is called twice with the same endpoint, only one channel
|
||||
* will be created. The second call will just return the existing channel.
|
||||
*
|
||||
* \return always a valid pointer to a EthernetChannel object, an exception
|
||||
* is thrown if it cannot be created.
|
||||
* \throw PcapHelper::Error channel creation failed
|
||||
*/
|
||||
class Error : public ProtocolFactory::Error
|
||||
shared_ptr<EthernetChannel>
|
||||
createChannel(const shared_ptr<const ndn::net::NetworkInterface>& localEndpoint,
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
/**
|
||||
* \brief Create a face to communicate on the given Ethernet multicast group
|
||||
*
|
||||
* If this method is called twice with the same arguments, only one face
|
||||
* will be created. The second call will just return the existing face.
|
||||
*
|
||||
* \param localEndpoint local network interface
|
||||
* \param group multicast group address
|
||||
*
|
||||
* \throw EthernetTransport::Error transport creation fails
|
||||
*/
|
||||
shared_ptr<Face>
|
||||
createMulticastFace(const ndn::net::NetworkInterface& localEndpoint,
|
||||
const ethernet::Address& group);
|
||||
|
||||
private:
|
||||
/** \brief process face_system.ether config section
|
||||
*/
|
||||
void
|
||||
doProcessConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
void
|
||||
doCreateFace(const CreateFaceRequest& req,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
doGetChannels() const override;
|
||||
|
||||
/** \brief Create EthernetChannel on \p netif if requested by \p m_unicastConfig.
|
||||
* \return new or existing channel, or nullptr if no channel should be created
|
||||
*/
|
||||
shared_ptr<EthernetChannel>
|
||||
applyUnicastConfigToNetif(const shared_ptr<const ndn::net::NetworkInterface>& netif);
|
||||
|
||||
/** \brief Create Ethernet multicast face on \p netif if requested by \p m_mcastConfig.
|
||||
* \return new or existing face, or nullptr if no face should be created
|
||||
*/
|
||||
shared_ptr<Face>
|
||||
applyMcastConfigToNetif(const ndn::net::NetworkInterface& netif);
|
||||
|
||||
void
|
||||
applyConfig(const FaceSystem::ConfigContext& context);
|
||||
|
||||
private:
|
||||
std::map<std::string, shared_ptr<EthernetChannel>> m_channels; ///< ifname => channel
|
||||
|
||||
struct UnicastConfig
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: ProtocolFactory::Error(what)
|
||||
{
|
||||
}
|
||||
bool isEnabled = false;
|
||||
bool wantListen = false;
|
||||
time::nanoseconds idleTimeout = 10_min;
|
||||
};
|
||||
UnicastConfig m_unicastConfig;
|
||||
|
||||
typedef std::map<std::pair<std::string, ethernet::Address>,
|
||||
shared_ptr<EthernetFace>> MulticastFaceMap;
|
||||
struct MulticastConfig
|
||||
{
|
||||
bool isEnabled = false;
|
||||
ethernet::Address group = ethernet::getDefaultMulticastAddress();
|
||||
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_MULTI_ACCESS;
|
||||
NetworkInterfacePredicate netifPredicate;
|
||||
};
|
||||
MulticastConfig m_mcastConfig;
|
||||
|
||||
/**
|
||||
* \brief Create an EthernetFace to communicate with the given multicast group
|
||||
*
|
||||
* If this method is called twice with the same interface and group, only
|
||||
* one face will be created. Instead, the second call will just retrieve
|
||||
* the existing face.
|
||||
*
|
||||
* \param interface Local network interface
|
||||
* \param address Ethernet broadcast/multicast destination address
|
||||
*
|
||||
* \returns always a valid shared pointer to an EthernetFace object,
|
||||
* an exception will be thrown if the creation fails
|
||||
*
|
||||
* \throws EthernetFactory::Error or EthernetFace::Error
|
||||
*/
|
||||
shared_ptr<EthernetFace>
|
||||
createMulticastFace(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address);
|
||||
/// (ifname, group) => face
|
||||
std::map<std::pair<std::string, ethernet::Address>, shared_ptr<Face>> m_mcastFaces;
|
||||
|
||||
/**
|
||||
* \brief Get map of configured multicast faces
|
||||
*/
|
||||
const MulticastFaceMap&
|
||||
getMulticastFaces() const;
|
||||
|
||||
public: // from ProtocolFactory
|
||||
virtual void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
|
||||
|
||||
virtual std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Look up EthernetFace using specified interface and address
|
||||
*
|
||||
* \returns shared pointer to the existing EthernetFace object
|
||||
* or nullptr when such face does not exist
|
||||
*/
|
||||
shared_ptr<EthernetFace>
|
||||
findMulticastFace(const std::string& interfaceName,
|
||||
const ethernet::Address& address) const;
|
||||
|
||||
private:
|
||||
MulticastFaceMap m_multicastFaces;
|
||||
signal::ScopedConnection m_netifAddConn;
|
||||
};
|
||||
|
||||
inline const EthernetFactory::MulticastFaceMap&
|
||||
EthernetFactory::getMulticastFaces() const
|
||||
{
|
||||
return m_multicastFaces;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
|
||||
@@ -0,0 +1,62 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ethernet-protocol.hpp"
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace ethernet {
|
||||
|
||||
std::pair<const ether_header*, std::string>
|
||||
checkFrameHeader(const uint8_t* packet, size_t length,
|
||||
const Address& localAddr, const Address& destAddr)
|
||||
{
|
||||
if (length < HDR_LEN + MIN_DATA_LEN)
|
||||
return {nullptr, "Received frame too short: " + to_string(length) + " bytes"};
|
||||
|
||||
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
|
||||
|
||||
// in some cases VLAN-tagged frames may survive the BPF filter,
|
||||
// make sure we do not process those frames (see #3348)
|
||||
uint16_t ethertype = boost::endian::big_to_native(eh->ether_type);
|
||||
if (ethertype != ETHERTYPE_NDN)
|
||||
return {nullptr, "Received frame with wrong ethertype: " + to_string(ethertype)};
|
||||
|
||||
#ifdef _DEBUG
|
||||
Address shost(eh->ether_shost);
|
||||
if (shost == localAddr)
|
||||
return {nullptr, "Received frame sent by this host"};
|
||||
|
||||
Address dhost(eh->ether_dhost);
|
||||
if (dhost != destAddr)
|
||||
return {nullptr, "Received frame addressed to another host or multicast group: " + dhost.toString()};
|
||||
#endif
|
||||
|
||||
return {eh, ""};
|
||||
}
|
||||
|
||||
} // namespace ethernet
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,45 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
|
||||
#define NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
#include <ndn-cxx/net/ethernet.hpp>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
namespace nfd {
|
||||
namespace ethernet {
|
||||
|
||||
using namespace ndn::ethernet;
|
||||
|
||||
std::pair<const ether_header*, std::string>
|
||||
checkFrameHeader(const uint8_t* packet, size_t length,
|
||||
const Address& localAddr, const Address& destAddr);
|
||||
|
||||
} // namespace ethernet
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
|
||||
@@ -0,0 +1,243 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ethernet-transport.hpp"
|
||||
#include "ethernet-protocol.hpp"
|
||||
#include "common/global.hpp"
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
|
||||
#include <cstring> // for memcpy()
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT(EthernetTransport);
|
||||
|
||||
EthernetTransport::EthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint)
|
||||
: m_socket(getGlobalIoService())
|
||||
, m_pcap(localEndpoint.getName())
|
||||
, m_srcAddress(localEndpoint.getEthernetAddress())
|
||||
, m_destAddress(remoteEndpoint)
|
||||
, m_interfaceName(localEndpoint.getName())
|
||||
, m_hasRecentlyReceived(false)
|
||||
#ifdef _DEBUG
|
||||
, m_nDropped(0)
|
||||
#endif
|
||||
{
|
||||
try {
|
||||
m_pcap.activate(DLT_EN10MB);
|
||||
m_socket.assign(m_pcap.getFd());
|
||||
}
|
||||
catch (const PcapHelper::Error& e) {
|
||||
NDN_THROW_NESTED(Error(e.what()));
|
||||
}
|
||||
|
||||
// Set initial transport state based upon the state of the underlying NetworkInterface
|
||||
handleNetifStateChange(localEndpoint.getState());
|
||||
|
||||
m_netifStateChangedConn = localEndpoint.onStateChanged.connect(
|
||||
[this] (ndn::net::InterfaceState, ndn::net::InterfaceState newState) {
|
||||
handleNetifStateChange(newState);
|
||||
});
|
||||
|
||||
m_netifMtuChangedConn = localEndpoint.onMtuChanged.connect(
|
||||
[this] (uint32_t, uint32_t mtu) {
|
||||
setMtu(mtu);
|
||||
});
|
||||
|
||||
asyncRead();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::doClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
if (m_socket.is_open()) {
|
||||
// Cancel all outstanding operations and close the socket.
|
||||
// Use the non-throwing variants and ignore errors, if any.
|
||||
boost::system::error_code error;
|
||||
m_socket.cancel(error);
|
||||
m_socket.close(error);
|
||||
}
|
||||
m_pcap.close();
|
||||
|
||||
// Ensure that the Transport stays alive at least
|
||||
// until all pending handlers are dispatched
|
||||
getGlobalIoService().post([this] {
|
||||
this->setState(TransportState::CLOSED);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::handleNetifStateChange(ndn::net::InterfaceState netifState)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE("netif is " << netifState);
|
||||
if (netifState == ndn::net::InterfaceState::RUNNING) {
|
||||
if (getState() == TransportState::DOWN) {
|
||||
this->setState(TransportState::UP);
|
||||
}
|
||||
}
|
||||
else if (getState() == TransportState::UP) {
|
||||
this->setState(TransportState::DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::sendPacket(const ndn::Block& block)
|
||||
{
|
||||
ndn::EncodingBuffer buffer(block);
|
||||
|
||||
// pad with zeroes if the payload is too short
|
||||
if (block.size() < ethernet::MIN_DATA_LEN) {
|
||||
static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
|
||||
buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
|
||||
}
|
||||
|
||||
// construct and prepend the ethernet header
|
||||
uint16_t ethertype = boost::endian::native_to_big(ethernet::ETHERTYPE_NDN);
|
||||
buffer.prependByteArray(reinterpret_cast<const uint8_t*>(ðertype), ethernet::TYPE_LEN);
|
||||
buffer.prependByteArray(m_srcAddress.data(), m_srcAddress.size());
|
||||
buffer.prependByteArray(m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
// send the frame
|
||||
int sent = pcap_inject(m_pcap, buffer.buf(), buffer.size());
|
||||
if (sent < 0)
|
||||
handleError("Send operation failed: " + m_pcap.getLastError());
|
||||
else if (static_cast<size_t>(sent) < buffer.size())
|
||||
handleError("Failed to send the full frame: size=" + to_string(buffer.size()) +
|
||||
" sent=" + to_string(sent));
|
||||
else
|
||||
// print block size because we don't want to count the padding in buffer
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << block.size() << " bytes");
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::asyncRead()
|
||||
{
|
||||
m_socket.async_read_some(boost::asio::null_buffers(),
|
||||
[this] (const auto& e, auto) { this->handleRead(e); });
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::handleRead(const boost::system::error_code& error)
|
||||
{
|
||||
if (error) {
|
||||
// boost::asio::error::operation_aborted must be checked first: in that case, the Transport
|
||||
// may already have been destructed, therefore it's unsafe to call getState() or do logging.
|
||||
if (error != boost::asio::error::operation_aborted &&
|
||||
getState() != TransportState::CLOSING &&
|
||||
getState() != TransportState::FAILED &&
|
||||
getState() != TransportState::CLOSED) {
|
||||
handleError("Receive operation failed: " + error.message());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t* pkt;
|
||||
size_t len;
|
||||
std::string err;
|
||||
std::tie(pkt, len, err) = m_pcap.readNextPacket();
|
||||
|
||||
if (pkt == nullptr) {
|
||||
NFD_LOG_FACE_WARN("Read error: " << err);
|
||||
}
|
||||
else {
|
||||
const ether_header* eh;
|
||||
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_srcAddress,
|
||||
m_destAddress.isMulticast() ? m_destAddress : m_srcAddress);
|
||||
if (eh == nullptr) {
|
||||
NFD_LOG_FACE_WARN(err);
|
||||
}
|
||||
else {
|
||||
ethernet::Address sender(eh->ether_shost);
|
||||
pkt += ethernet::HDR_LEN;
|
||||
len -= ethernet::HDR_LEN;
|
||||
receivePayload(pkt, len, sender);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
size_t nDropped = m_pcap.getNDropped();
|
||||
if (nDropped - m_nDropped > 0)
|
||||
NFD_LOG_FACE_DEBUG("Detected " << nDropped - m_nDropped << " dropped frame(s)");
|
||||
m_nDropped = nDropped;
|
||||
#endif
|
||||
|
||||
asyncRead();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::receivePayload(const uint8_t* payload, size_t length,
|
||||
const ethernet::Address& sender)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE("Received: " << length << " bytes from " << sender);
|
||||
|
||||
bool isOk = false;
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(payload, length);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << sender);
|
||||
// This packet won't extend the face lifetime
|
||||
return;
|
||||
}
|
||||
m_hasRecentlyReceived = true;
|
||||
|
||||
static_assert(sizeof(EndpointId) >= ethernet::ADDR_LEN, "EndpointId is too small");
|
||||
EndpointId endpoint = 0;
|
||||
if (m_destAddress.isMulticast()) {
|
||||
std::memcpy(&endpoint, sender.data(), sender.size());
|
||||
}
|
||||
|
||||
this->receive(element, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::handleError(const std::string& errorMessage)
|
||||
{
|
||||
if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
NFD_LOG_FACE_DEBUG("Permanent face ignores error: " << errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_ERROR(errorMessage);
|
||||
this->setState(TransportState::FAILED);
|
||||
doClose();
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,121 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
|
||||
#include "ethernet-protocol.hpp"
|
||||
#include "pcap-helper.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
#include <ndn-cxx/net/network-interface.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* @brief Base class for Ethernet-based Transports
|
||||
*/
|
||||
class EthernetTransport : public Transport
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Processes the payload of an incoming frame
|
||||
* @param payload Pointer to the first byte of data after the Ethernet header
|
||||
* @param length Payload length
|
||||
* @param sender Sender address
|
||||
*/
|
||||
void
|
||||
receivePayload(const uint8_t* payload, size_t length,
|
||||
const ethernet::Address& sender);
|
||||
|
||||
protected:
|
||||
EthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint);
|
||||
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
bool
|
||||
hasRecentlyReceived() const
|
||||
{
|
||||
return m_hasRecentlyReceived;
|
||||
}
|
||||
|
||||
void
|
||||
resetRecentlyReceived()
|
||||
{
|
||||
m_hasRecentlyReceived = false;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
handleNetifStateChange(ndn::net::InterfaceState netifState);
|
||||
|
||||
void
|
||||
doSend(const Block& packet) final;
|
||||
|
||||
/**
|
||||
* @brief Sends the specified TLV block on the network wrapped in an Ethernet frame
|
||||
*/
|
||||
void
|
||||
sendPacket(const ndn::Block& block);
|
||||
|
||||
void
|
||||
asyncRead();
|
||||
|
||||
void
|
||||
handleRead(const boost::system::error_code& error);
|
||||
|
||||
void
|
||||
handleError(const std::string& errorMessage);
|
||||
|
||||
protected:
|
||||
boost::asio::posix::stream_descriptor m_socket;
|
||||
PcapHelper m_pcap;
|
||||
ethernet::Address m_srcAddress;
|
||||
ethernet::Address m_destAddress;
|
||||
std::string m_interfaceName;
|
||||
|
||||
private:
|
||||
signal::ScopedConnection m_netifStateChangedConn;
|
||||
signal::ScopedConnection m_netifMtuChangedConn;
|
||||
bool m_hasRecentlyReceived;
|
||||
#ifdef _DEBUG
|
||||
/// number of frames dropped by the kernel, as reported by libpcap
|
||||
size_t m_nDropped;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,28 +23,84 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_FACE_LOG_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_LOG_HPP
|
||||
#ifndef NFD_DAEMON_FACE_FACE_COMMON_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_COMMON_HPP
|
||||
|
||||
#include "core/logger.hpp"
|
||||
#include "core/common.hpp"
|
||||
#include "common/logger.hpp"
|
||||
|
||||
#include <ndn-cxx/encoding/nfd-constants.hpp>
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief for internal use by FaceLogging macros
|
||||
class Face;
|
||||
class LinkService;
|
||||
|
||||
/** \brief Identifies a face.
|
||||
*/
|
||||
using FaceId = uint64_t;
|
||||
|
||||
/// indicates an invalid FaceId
|
||||
const FaceId INVALID_FACEID = ndn::nfd::INVALID_FACE_ID;
|
||||
/// identifies the InternalFace used in management
|
||||
const FaceId FACEID_INTERNAL_FACE = 1;
|
||||
/// identifies a packet comes from the ContentStore
|
||||
const FaceId FACEID_CONTENT_STORE = 254;
|
||||
/// identifies the NullFace that drops every packet
|
||||
const FaceId FACEID_NULL = 255;
|
||||
/// upper bound of reserved FaceIds
|
||||
const FaceId FACEID_RESERVED_MAX = 255;
|
||||
|
||||
/** \brief Minimum MTU that may be set
|
||||
*
|
||||
* FaceLogHelper wraps a Face, LinkService, or Transport object.
|
||||
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
|
||||
*/
|
||||
const ssize_t MIN_MTU = 64;
|
||||
|
||||
/** \brief Identifies a remote endpoint on the link.
|
||||
*
|
||||
* std::ostream& operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
|
||||
* This ID is only meaningful in the context of the same Transport.
|
||||
* Incoming packets from the same remote endpoint have the same EndpointId,
|
||||
* and incoming packets from different remote endpoints have different EndpointIds.
|
||||
*
|
||||
* Typically, a point-to-point Transport has only one meaningful EndpointId (usually 0).
|
||||
*/
|
||||
using EndpointId = uint64_t;
|
||||
|
||||
/** \brief Parameters used to set Transport properties or LinkService options on a newly created face.
|
||||
*
|
||||
* Parameters are passed as a struct rather than individually, so that a future change in the list
|
||||
* of parameters does not require an update to the method signature in all subclasses.
|
||||
*/
|
||||
struct FaceParams
|
||||
{
|
||||
ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
|
||||
optional<time::nanoseconds> baseCongestionMarkingInterval;
|
||||
optional<uint64_t> defaultCongestionThreshold;
|
||||
optional<ssize_t> mtu;
|
||||
optional<uint64_t> bandwidth;
|
||||
bool wantLocalFields = false;
|
||||
bool wantLpReliability = false;
|
||||
boost::logic::tribool wantCongestionMarking = boost::logic::indeterminate;
|
||||
};
|
||||
|
||||
/** \brief For internal use by FaceLogging macros.
|
||||
*
|
||||
* FaceLogHelper wraps a reference to Face, LinkService, or Transport object.
|
||||
*
|
||||
* `std::ostream& operator<<(std::ostream& os, const FaceLogHelper<T>& flh)`
|
||||
* should be specialized to print "[id=888,local=scheme://local/uri,remote=scheme://remote/uri] "
|
||||
* which appears as part of the log message.
|
||||
* which will appear as part of the log message.
|
||||
*/
|
||||
template<typename T>
|
||||
class FaceLogHelper
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
FaceLogHelper(const T& obj1)
|
||||
FaceLogHelper(const T& obj1) noexcept
|
||||
: obj(obj1)
|
||||
{
|
||||
}
|
||||
@@ -53,6 +109,13 @@ public:
|
||||
const T& obj;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
using face::EndpointId;
|
||||
using face::FaceId;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
/** \defgroup FaceLogging Face logging macros
|
||||
*
|
||||
* These macros augment the log message with some face-specific information,
|
||||
@@ -62,6 +125,8 @@ public:
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \cond */
|
||||
// implementation detail
|
||||
#define NFD_LOG_FACE(level, msg) NFD_LOG_##level( \
|
||||
::nfd::face::FaceLogHelper< \
|
||||
typename std::remove_cv< \
|
||||
@@ -69,6 +134,7 @@ public:
|
||||
>::type \
|
||||
>(*this) \
|
||||
<< msg)
|
||||
/** \endcond */
|
||||
|
||||
/** \brief Log a message at TRACE level */
|
||||
#define NFD_LOG_FACE_TRACE(msg) NFD_LOG_FACE(TRACE, msg)
|
||||
@@ -87,7 +153,4 @@ public:
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_LOG_HPP
|
||||
#endif // NFD_DAEMON_FACE_FACE_COMMON_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,34 +23,28 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_EXTENDED_ERROR_MESSAGE_HPP
|
||||
#define NFD_CORE_EXTENDED_ERROR_MESSAGE_HPP
|
||||
|
||||
#include <boost/exception/get_error_info.hpp>
|
||||
#include "face-counters.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
template<typename E>
|
||||
std::string
|
||||
getExtendedErrorMessage(const E& exception)
|
||||
FaceCounters::FaceCounters(const LinkService::Counters& linkServiceCounters,
|
||||
const Transport::Counters& transportCounters)
|
||||
: nInInterests(linkServiceCounters.nInInterests)
|
||||
, nOutInterests(linkServiceCounters.nOutInterests)
|
||||
, nInterestsExceededRetx(linkServiceCounters.nInterestsExceededRetx)
|
||||
, nInData(linkServiceCounters.nInData)
|
||||
, nOutData(linkServiceCounters.nOutData)
|
||||
, nInNacks(linkServiceCounters.nInNacks)
|
||||
, nOutNacks(linkServiceCounters.nOutNacks)
|
||||
, nInPackets(transportCounters.nInPackets)
|
||||
, nOutPackets(transportCounters.nOutPackets)
|
||||
, nInBytes(transportCounters.nInBytes)
|
||||
, nOutBytes(transportCounters.nOutBytes)
|
||||
, m_linkServiceCounters(linkServiceCounters)
|
||||
, m_transportCounters(transportCounters)
|
||||
{
|
||||
std::ostringstream errorMessage;
|
||||
errorMessage << exception.what();
|
||||
|
||||
const char* const* file = boost::get_error_info<boost::throw_file>(exception);
|
||||
const int* line = boost::get_error_info<boost::throw_line>(exception);
|
||||
const char* const* func = boost::get_error_info<boost::throw_function>(exception);
|
||||
if (file && line) {
|
||||
errorMessage << " [from " << *file << ":" << *line;
|
||||
if (func) {
|
||||
errorMessage << " in " << *func;
|
||||
}
|
||||
errorMessage << "]";
|
||||
}
|
||||
|
||||
return errorMessage.str();
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_EXTENDED_ERROR_MESSAGE_HPP
|
||||
+63
-214
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -26,226 +26,75 @@
|
||||
#ifndef NFD_DAEMON_FACE_FACE_COUNTERS_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_COUNTERS_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief represents a counter of number of packets
|
||||
/** \brief gives access to counters provided by Face
|
||||
*
|
||||
* This type is a facade that exposes common counters of a Face.
|
||||
*
|
||||
* get<T>() can be used to access extended counters provided by
|
||||
* LinkService or Transport of the Face.
|
||||
*/
|
||||
// PacketCounter is noncopyable, because increment should be called on the counter,
|
||||
// not a copy of it; it's implicitly convertible to uint64_t to be observed
|
||||
class PacketCounter : noncopyable
|
||||
class FaceCounters
|
||||
{
|
||||
public:
|
||||
typedef uint64_t rep;
|
||||
FaceCounters(const LinkService::Counters& linkServiceCounters,
|
||||
const Transport::Counters& transportCounters);
|
||||
|
||||
PacketCounter()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
operator rep() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
operator++()
|
||||
{
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
// postfix ++ operator is not provided because it's not needed
|
||||
|
||||
void
|
||||
set(rep value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
private:
|
||||
rep m_value;
|
||||
};
|
||||
|
||||
/** \brief represents a counter of number of bytes
|
||||
*/
|
||||
// ByteCounter is noncopyable, because increment should be called on the counter,
|
||||
// not a copy of it; it's implicitly convertible to uint64_t to be observed
|
||||
class ByteCounter : noncopyable
|
||||
{
|
||||
public:
|
||||
typedef uint64_t rep;
|
||||
|
||||
ByteCounter()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
operator rep() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
ByteCounter&
|
||||
operator+=(rep n)
|
||||
{
|
||||
m_value += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
set(rep value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
private:
|
||||
rep m_value;
|
||||
};
|
||||
|
||||
/** \brief contains network layer packet counters
|
||||
*/
|
||||
class NetworkLayerCounters : noncopyable
|
||||
{
|
||||
public:
|
||||
/// incoming Interest
|
||||
const PacketCounter&
|
||||
getNInInterests() const
|
||||
{
|
||||
return m_nInInterests;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNInInterests()
|
||||
{
|
||||
return m_nInInterests;
|
||||
}
|
||||
|
||||
/// incoming Data
|
||||
const PacketCounter&
|
||||
getNInDatas() const
|
||||
{
|
||||
return m_nInDatas;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNInDatas()
|
||||
{
|
||||
return m_nInDatas;
|
||||
}
|
||||
|
||||
/// outgoing Interest
|
||||
const PacketCounter&
|
||||
getNOutInterests() const
|
||||
{
|
||||
return m_nOutInterests;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNOutInterests()
|
||||
{
|
||||
return m_nOutInterests;
|
||||
}
|
||||
|
||||
/// outgoing Data
|
||||
const PacketCounter&
|
||||
getNOutDatas() const
|
||||
{
|
||||
return m_nOutDatas;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNOutDatas()
|
||||
{
|
||||
return m_nOutDatas;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief copy current obseverations to a struct
|
||||
* \param recipient an object with set methods for counters
|
||||
/** \return counters provided by LinkService
|
||||
* \tparam T LinkService counters type
|
||||
* \throw std::bad_cast counters type mismatch
|
||||
*/
|
||||
template<typename R>
|
||||
void
|
||||
copyTo(R& recipient) const
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<LinkService::Counters, T>::value, const T&>::type
|
||||
get() const
|
||||
{
|
||||
recipient.setNInInterests(this->getNInInterests());
|
||||
recipient.setNInDatas(this->getNInDatas());
|
||||
recipient.setNOutInterests(this->getNOutInterests());
|
||||
recipient.setNOutDatas(this->getNOutDatas());
|
||||
return dynamic_cast<const T&>(m_linkServiceCounters);
|
||||
}
|
||||
|
||||
/** \return counters provided by Transport
|
||||
* \tparam T Transport counters type
|
||||
* \throw std::bad_cast counters type mismatch
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<Transport::Counters, T>::value, const T&>::type
|
||||
get() const
|
||||
{
|
||||
return dynamic_cast<const T&>(m_transportCounters);
|
||||
}
|
||||
|
||||
public:
|
||||
const PacketCounter& nInInterests;
|
||||
const PacketCounter& nOutInterests;
|
||||
const PacketCounter& nInterestsExceededRetx;
|
||||
const PacketCounter& nInData;
|
||||
const PacketCounter& nOutData;
|
||||
const PacketCounter& nInNacks;
|
||||
const PacketCounter& nOutNacks;
|
||||
|
||||
const PacketCounter& nInPackets;
|
||||
const PacketCounter& nOutPackets;
|
||||
const ByteCounter& nInBytes;
|
||||
const ByteCounter& nOutBytes;
|
||||
|
||||
/** \brief count of incoming Interests dropped due to HopLimit == 0
|
||||
*/
|
||||
PacketCounter nInHopLimitZero;
|
||||
|
||||
/** \brief count of outgoing Interests dropped due to HopLimit == 0 on non-local faces
|
||||
*/
|
||||
PacketCounter nOutHopLimitZero;
|
||||
|
||||
private:
|
||||
PacketCounter m_nInInterests;
|
||||
PacketCounter m_nInDatas;
|
||||
PacketCounter m_nOutInterests;
|
||||
PacketCounter m_nOutDatas;
|
||||
};
|
||||
|
||||
/** \brief contains link layer byte counters
|
||||
*/
|
||||
class LinkLayerCounters : noncopyable
|
||||
{
|
||||
public:
|
||||
/// received bytes
|
||||
const ByteCounter&
|
||||
getNInBytes() const
|
||||
{
|
||||
return m_nInBytes;
|
||||
}
|
||||
|
||||
ByteCounter&
|
||||
getNInBytes()
|
||||
{
|
||||
return m_nInBytes;
|
||||
}
|
||||
|
||||
/// sent bytes
|
||||
const ByteCounter&
|
||||
getNOutBytes() const
|
||||
{
|
||||
return m_nOutBytes;
|
||||
}
|
||||
|
||||
ByteCounter&
|
||||
getNOutBytes()
|
||||
{
|
||||
return m_nOutBytes;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief copy current obseverations to a struct
|
||||
* \param recipient an object with set methods for counters
|
||||
*/
|
||||
template<typename R>
|
||||
void
|
||||
copyTo(R& recipient) const
|
||||
{
|
||||
recipient.setNInBytes(this->getNInBytes());
|
||||
recipient.setNOutBytes(this->getNOutBytes());
|
||||
}
|
||||
|
||||
private:
|
||||
ByteCounter m_nInBytes;
|
||||
ByteCounter m_nOutBytes;
|
||||
};
|
||||
|
||||
/** \brief contains counters on face
|
||||
*/
|
||||
class FaceCounters : public NetworkLayerCounters, public LinkLayerCounters
|
||||
{
|
||||
public:
|
||||
/** \brief copy current obseverations to a struct
|
||||
* \param recipient an object with set methods for counters
|
||||
*/
|
||||
template<typename R>
|
||||
void
|
||||
copyTo(R& recipient) const
|
||||
{
|
||||
this->NetworkLayerCounters::copyTo(recipient);
|
||||
this->LinkLayerCounters::copyTo(recipient);
|
||||
}
|
||||
const LinkService::Counters& m_linkServiceCounters;
|
||||
const Transport::Counters& m_transportCounters;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_COUNTERS_HPP
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
|
||||
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief Represents a face-endpoint pair in the forwarder.
|
||||
* \sa face::Face, face::EndpointId
|
||||
*/
|
||||
class FaceEndpoint
|
||||
{
|
||||
public:
|
||||
FaceEndpoint(const Face& face, EndpointId endpoint)
|
||||
: face(const_cast<Face&>(face))
|
||||
, endpoint(endpoint)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
Face& face;
|
||||
const EndpointId endpoint;
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, const FaceEndpoint& fe)
|
||||
{
|
||||
return os << '(' << fe.face.getId() << ',' << fe.endpoint << ')';
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
|
||||
@@ -0,0 +1,168 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "face-system.hpp"
|
||||
#include "protocol-factory.hpp"
|
||||
#include "netdev-bound.hpp"
|
||||
#include "common/global.hpp"
|
||||
#include "fw/face-table.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT(FaceSystem);
|
||||
|
||||
const std::string CFGSEC_FACESYSTEM = "face_system";
|
||||
const std::string CFGSEC_GENERAL = "general";
|
||||
const std::string CFGSEC_GENERAL_FQ = CFGSEC_FACESYSTEM + ".general";
|
||||
const std::string CFGSEC_NETDEVBOUND = "netdev_bound";
|
||||
|
||||
FaceSystem::FaceSystem(FaceTable& faceTable, shared_ptr<ndn::net::NetworkMonitor> netmon)
|
||||
: m_faceTable(faceTable)
|
||||
, m_netmon(std::move(netmon))
|
||||
{
|
||||
auto pfCtorParams = this->makePFCtorParams();
|
||||
for (const auto& id : ProtocolFactory::listRegistered()) {
|
||||
NFD_LOG_TRACE("creating factory " << id);
|
||||
m_factories[id] = ProtocolFactory::create(id, pfCtorParams);
|
||||
}
|
||||
|
||||
m_netdevBound = make_unique<NetdevBound>(pfCtorParams, *this);
|
||||
}
|
||||
|
||||
ProtocolFactoryCtorParams
|
||||
FaceSystem::makePFCtorParams()
|
||||
{
|
||||
auto addFace = [this] (auto face) { m_faceTable.add(std::move(face)); };
|
||||
return {addFace, m_netmon};
|
||||
}
|
||||
|
||||
FaceSystem::~FaceSystem() = default;
|
||||
|
||||
std::set<const ProtocolFactory*>
|
||||
FaceSystem::listProtocolFactories() const
|
||||
{
|
||||
std::set<const ProtocolFactory*> factories;
|
||||
for (const auto& p : m_factories) {
|
||||
factories.insert(p.second.get());
|
||||
}
|
||||
return factories;
|
||||
}
|
||||
|
||||
ProtocolFactory*
|
||||
FaceSystem::getFactoryById(const std::string& id)
|
||||
{
|
||||
auto found = m_factories.find(id);
|
||||
return found == m_factories.end() ? nullptr : found->second.get();
|
||||
}
|
||||
|
||||
ProtocolFactory*
|
||||
FaceSystem::getFactoryByScheme(const std::string& scheme)
|
||||
{
|
||||
auto found = m_factoryByScheme.find(scheme);
|
||||
return found == m_factoryByScheme.end() ? nullptr : found->second;
|
||||
}
|
||||
|
||||
bool
|
||||
FaceSystem::hasFactoryForScheme(const std::string& scheme) const
|
||||
{
|
||||
return m_factoryByScheme.count(scheme) > 0;
|
||||
}
|
||||
|
||||
void
|
||||
FaceSystem::setConfigFile(ConfigFile& configFile)
|
||||
{
|
||||
configFile.addSectionHandler(CFGSEC_FACESYSTEM, bind(&FaceSystem::processConfig, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
void
|
||||
FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string&)
|
||||
{
|
||||
ConfigContext context;
|
||||
context.isDryRun = isDryRun;
|
||||
|
||||
// process general protocol factory config section
|
||||
auto generalSection = configSection.get_child_optional(CFGSEC_GENERAL);
|
||||
if (generalSection) {
|
||||
for (const auto& pair : *generalSection) {
|
||||
const std::string& key = pair.first;
|
||||
if (key == "enable_congestion_marking") {
|
||||
context.generalConfig.wantCongestionMarking = ConfigFile::parseYesNo(pair, CFGSEC_GENERAL_FQ);
|
||||
}
|
||||
else {
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option " + CFGSEC_GENERAL_FQ + "." + key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process in protocol factories
|
||||
for (const auto& pair : m_factories) {
|
||||
const std::string& sectionName = pair.first;
|
||||
ProtocolFactory* factory = pair.second.get();
|
||||
|
||||
std::set<std::string> oldProvidedSchemes = factory->getProvidedSchemes();
|
||||
factory->processConfig(configSection.get_child_optional(sectionName), context);
|
||||
|
||||
if (!isDryRun) {
|
||||
for (const std::string& scheme : factory->getProvidedSchemes()) {
|
||||
m_factoryByScheme[scheme] = factory;
|
||||
if (oldProvidedSchemes.erase(scheme) == 0) {
|
||||
NFD_LOG_TRACE("factory " << sectionName <<
|
||||
" provides " << scheme << " FaceUri scheme");
|
||||
}
|
||||
}
|
||||
for (const std::string& scheme : oldProvidedSchemes) {
|
||||
m_factoryByScheme.erase(scheme);
|
||||
NFD_LOG_TRACE("factory " << sectionName <<
|
||||
" no longer provides " << scheme << " FaceUri scheme");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process netdev_bound section, after factories start providing *+dev schemes
|
||||
auto netdevBoundSection = configSection.get_child_optional(CFGSEC_NETDEVBOUND);
|
||||
m_netdevBound->processConfig(netdevBoundSection, context);
|
||||
|
||||
// process other sections
|
||||
std::set<std::string> seenSections;
|
||||
for (const auto& pair : configSection) {
|
||||
const std::string& sectionName = pair.first;
|
||||
// const ConfigSection& subSection = pair.second;
|
||||
|
||||
if (!seenSections.insert(sectionName).second) {
|
||||
NDN_THROW(ConfigFile::Error("Duplicate section " + CFGSEC_FACESYSTEM + "." + sectionName));
|
||||
}
|
||||
|
||||
if (sectionName == CFGSEC_GENERAL || sectionName == CFGSEC_NETDEVBOUND ||
|
||||
m_factories.count(sectionName) > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option " + CFGSEC_FACESYSTEM + "." + sectionName));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,135 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
|
||||
#include "network-predicate.hpp"
|
||||
#include "common/config-file.hpp"
|
||||
|
||||
#include <ndn-cxx/net/network-address.hpp>
|
||||
#include <ndn-cxx/net/network-interface.hpp>
|
||||
#include <ndn-cxx/net/network-monitor.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class FaceTable;
|
||||
|
||||
namespace face {
|
||||
|
||||
class NetdevBound;
|
||||
class ProtocolFactory;
|
||||
struct ProtocolFactoryCtorParams;
|
||||
|
||||
/** \brief entry point of the face system
|
||||
*
|
||||
* NFD's face system is organized as a FaceSystem-ProtocolFactory-Channel-Face hierarchy.
|
||||
* FaceSystem class is the entry point of NFD's face system and owns ProtocolFactory objects.
|
||||
*/
|
||||
class FaceSystem : noncopyable
|
||||
{
|
||||
public:
|
||||
FaceSystem(FaceTable& faceTable, shared_ptr<ndn::net::NetworkMonitor> netmon);
|
||||
|
||||
~FaceSystem();
|
||||
|
||||
/** \return ProtocolFactory objects owned by the FaceSystem
|
||||
*/
|
||||
std::set<const ProtocolFactory*>
|
||||
listProtocolFactories() const;
|
||||
|
||||
/** \return ProtocolFactory for the specified registered factory id or nullptr if not found
|
||||
*/
|
||||
ProtocolFactory*
|
||||
getFactoryById(const std::string& id);
|
||||
|
||||
/** \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found
|
||||
*/
|
||||
ProtocolFactory*
|
||||
getFactoryByScheme(const std::string& scheme);
|
||||
|
||||
bool
|
||||
hasFactoryForScheme(const std::string& scheme) const;
|
||||
|
||||
FaceTable&
|
||||
getFaceTable()
|
||||
{
|
||||
return m_faceTable;
|
||||
}
|
||||
|
||||
/** \brief register handler for face_system section of NFD configuration file
|
||||
*/
|
||||
void
|
||||
setConfigFile(ConfigFile& configFile);
|
||||
|
||||
/** \brief configuration options from "general" section
|
||||
*/
|
||||
struct GeneralConfig
|
||||
{
|
||||
bool wantCongestionMarking = true;
|
||||
};
|
||||
|
||||
/** \brief context for processing a config section in ProtocolFactory
|
||||
*/
|
||||
class ConfigContext : noncopyable
|
||||
{
|
||||
public:
|
||||
GeneralConfig generalConfig;
|
||||
bool isDryRun;
|
||||
};
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
ProtocolFactoryCtorParams
|
||||
makePFCtorParams();
|
||||
|
||||
private:
|
||||
void
|
||||
processConfig(const ConfigSection& configSection, bool isDryRun,
|
||||
const std::string& filename);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief config section name => protocol factory
|
||||
*/
|
||||
std::map<std::string, unique_ptr<ProtocolFactory>> m_factories;
|
||||
unique_ptr<NetdevBound> m_netdevBound;
|
||||
|
||||
private:
|
||||
/** \brief scheme => protocol factory
|
||||
*
|
||||
* The same protocol factory may be available under multiple schemes.
|
||||
*/
|
||||
std::map<std::string, ProtocolFactory*> m_factoryByScheme;
|
||||
|
||||
FaceTable& m_faceTable;
|
||||
shared_ptr<ndn::net::NetworkMonitor> m_netmon;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
using face::FaceSystem;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
+22
-93
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -25,103 +25,32 @@
|
||||
|
||||
#include "face.hpp"
|
||||
|
||||
#include <ndn-cxx/management/nfd-face-event-notification.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
Face::Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal, bool isMultiAccess)
|
||||
: m_id(INVALID_FACEID)
|
||||
, m_remoteUri(remoteUri)
|
||||
, m_localUri(localUri)
|
||||
, m_isLocal(isLocal)
|
||||
, m_persistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
|
||||
, m_isMultiAccess(isMultiAccess)
|
||||
, m_isFailed(false)
|
||||
Face::Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
|
||||
: afterReceiveInterest(service->afterReceiveInterest)
|
||||
, afterReceiveData(service->afterReceiveData)
|
||||
, afterReceiveNack(service->afterReceiveNack)
|
||||
, onDroppedInterest(service->onDroppedInterest)
|
||||
, afterStateChange(transport->afterStateChange)
|
||||
, m_id(INVALID_FACEID)
|
||||
, m_service(std::move(service))
|
||||
, m_transport(std::move(transport))
|
||||
, m_counters(m_service->getCounters(), m_transport->getCounters())
|
||||
{
|
||||
onReceiveInterest.connect([this] (const ndn::Interest&) { ++m_counters.getNInInterests(); });
|
||||
onReceiveData .connect([this] (const ndn::Data&) { ++m_counters.getNInDatas(); });
|
||||
onSendInterest .connect([this] (const ndn::Interest&) { ++m_counters.getNOutInterests(); });
|
||||
onSendData .connect([this] (const ndn::Data&) { ++m_counters.getNOutDatas(); });
|
||||
m_service->setFaceAndTransport(*this, *m_transport);
|
||||
m_transport->setFaceAndLinkService(*this, *m_service);
|
||||
}
|
||||
|
||||
Face::~Face()
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<Face>& flh)
|
||||
{
|
||||
const Face& face = flh.obj;
|
||||
os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
|
||||
",remote=" << face.getRemoteUri() << "] ";
|
||||
return os;
|
||||
}
|
||||
|
||||
bool
|
||||
Face::isUp() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Face::decodeAndDispatchInput(const Block& element)
|
||||
{
|
||||
try {
|
||||
/// \todo Ensure lazy field decoding process
|
||||
|
||||
if (element.type() == tlv::Interest)
|
||||
{
|
||||
shared_ptr<Interest> i = make_shared<Interest>();
|
||||
i->wireDecode(element);
|
||||
this->onReceiveInterest(*i);
|
||||
}
|
||||
else if (element.type() == tlv::Data)
|
||||
{
|
||||
shared_ptr<Data> d = make_shared<Data>();
|
||||
d->wireDecode(element);
|
||||
this->onReceiveData(*d);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const tlv::Error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Face::fail(const std::string& reason)
|
||||
{
|
||||
if (m_isFailed) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_isFailed = true;
|
||||
this->onFail(reason);
|
||||
}
|
||||
|
||||
template<typename FaceTraits>
|
||||
void
|
||||
Face::copyStatusTo(FaceTraits& traits) const
|
||||
{
|
||||
traits.setFaceId(getId())
|
||||
.setRemoteUri(getRemoteUri().toString())
|
||||
.setLocalUri(getLocalUri().toString())
|
||||
.setFaceScope(isLocal() ? ndn::nfd::FACE_SCOPE_LOCAL
|
||||
: ndn::nfd::FACE_SCOPE_NON_LOCAL)
|
||||
.setFacePersistency(getPersistency())
|
||||
.setLinkType(isMultiAccess() ? ndn::nfd::LINK_TYPE_MULTI_ACCESS
|
||||
: ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
}
|
||||
|
||||
template void
|
||||
Face::copyStatusTo<ndn::nfd::FaceStatus>(ndn::nfd::FaceStatus&) const;
|
||||
|
||||
template void
|
||||
Face::copyStatusTo<ndn::nfd::FaceEventNotification>(ndn::nfd::FaceEventNotification&) const;
|
||||
|
||||
ndn::nfd::FaceStatus
|
||||
Face::getFaceStatus() const
|
||||
{
|
||||
ndn::nfd::FaceStatus status;
|
||||
|
||||
copyStatusTo(status);
|
||||
this->getCounters().copyTo(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
+203
-197
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,206 +26,215 @@
|
||||
#ifndef NFD_DAEMON_FACE_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "face-common.hpp"
|
||||
#include "face-counters.hpp"
|
||||
#include "face-log.hpp"
|
||||
|
||||
#include <ndn-cxx/management/nfd-face-status.hpp>
|
||||
#include "link-service.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \class FaceId
|
||||
* \brief identifies a face
|
||||
class Channel;
|
||||
|
||||
/** \brief indicates the state of a face
|
||||
*/
|
||||
typedef int FaceId;
|
||||
typedef TransportState FaceState;
|
||||
|
||||
/// indicates an invalid FaceId
|
||||
const FaceId INVALID_FACEID = -1;
|
||||
|
||||
/// identifies the InternalFace used in management
|
||||
const FaceId FACEID_INTERNAL_FACE = 1;
|
||||
/// identifies a packet comes from the ContentStore, in LocalControlHeader incomingFaceId
|
||||
const FaceId FACEID_CONTENT_STORE = 254;
|
||||
/// identifies the NullFace that drops every packet
|
||||
const FaceId FACEID_NULL = 255;
|
||||
/// upper bound of reserved FaceIds
|
||||
const FaceId FACEID_RESERVED_MAX = 255;
|
||||
|
||||
|
||||
/** \brief represents a face
|
||||
/** \brief generalization of a network interface
|
||||
*
|
||||
* A face generalizes a network interface.
|
||||
* It provides best-effort network-layer packet delivery services
|
||||
* on a physical interface, an overlay tunnel, or a link to a local application.
|
||||
*
|
||||
* A face combines two parts: LinkService and Transport.
|
||||
* Transport is the lower part, which provides best-effort TLV block deliveries.
|
||||
* LinkService is the upper part, which translates between network-layer packets
|
||||
* and TLV blocks, and may provide additional services such as fragmentation and reassembly.
|
||||
*/
|
||||
class Face : noncopyable, public enable_shared_from_this<Face>
|
||||
class Face FINAL_UNLESS_WITH_TESTS : public std::enable_shared_from_this<Face>, noncopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Face-related error
|
||||
*/
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
|
||||
|
||||
Face(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
bool isLocal = false, bool isMultiAccess = false);
|
||||
LinkService*
|
||||
getLinkService() const;
|
||||
|
||||
virtual
|
||||
~Face();
|
||||
Transport*
|
||||
getTransport() const;
|
||||
|
||||
/// fires when an Interest is received
|
||||
signal::Signal<Face, Interest> onReceiveInterest;
|
||||
|
||||
/// fires when a Data is received
|
||||
signal::Signal<Face, Data> onReceiveData;
|
||||
|
||||
/// fires when a Nack is received
|
||||
signal::Signal<Face, lp::Nack> onReceiveNack;
|
||||
|
||||
/// fires when an Interest is sent out
|
||||
signal::Signal<Face, Interest> onSendInterest;
|
||||
|
||||
/// fires when a Data is sent out
|
||||
signal::Signal<Face, Data> onSendData;
|
||||
|
||||
/// fires when a Nack is sent out
|
||||
signal::Signal<Face, lp::Nack> onSendNack;
|
||||
|
||||
/// fires when face disconnects or fails to perform properly
|
||||
signal::Signal<Face, std::string/*reason*/> onFail;
|
||||
|
||||
/// send an Interest
|
||||
virtual void
|
||||
sendInterest(const Interest& interest) = 0;
|
||||
|
||||
/// send a Data
|
||||
virtual void
|
||||
sendData(const Data& data) = 0;
|
||||
|
||||
/// send a Nack
|
||||
virtual void
|
||||
sendNack(const ndn::lp::Nack& nack)
|
||||
{
|
||||
}
|
||||
|
||||
/** \brief Close the face
|
||||
/** \brief Request that the face be closed
|
||||
*
|
||||
* This terminates all communication on the face and cause
|
||||
* onFail() method event to be invoked
|
||||
* This operation is effective only if face is in the UP or DOWN state; otherwise, it has no effect.
|
||||
* The face will change state to CLOSING, and then perform a cleanup procedure.
|
||||
* When the cleanup is complete, the state will be changed to CLOSED, which may happen
|
||||
* synchronously or asynchronously.
|
||||
*
|
||||
* \warning The face must not be deallocated until its state changes to CLOSED.
|
||||
*/
|
||||
virtual void
|
||||
close() = 0;
|
||||
void
|
||||
close();
|
||||
|
||||
public: // attributes
|
||||
public: // upper interface connected to forwarding
|
||||
/** \brief send Interest
|
||||
*/
|
||||
void
|
||||
sendInterest(const Interest& interest);
|
||||
|
||||
/** \brief send Data
|
||||
*/
|
||||
void
|
||||
sendData(const Data& data);
|
||||
|
||||
/** \brief send Nack
|
||||
*/
|
||||
void
|
||||
sendNack(const lp::Nack& nack);
|
||||
|
||||
/** \brief signals on Interest received
|
||||
*/
|
||||
signal::Signal<LinkService, Interest, EndpointId>& afterReceiveInterest;
|
||||
|
||||
/** \brief signals on Data received
|
||||
*/
|
||||
signal::Signal<LinkService, Data, EndpointId>& afterReceiveData;
|
||||
|
||||
/** \brief signals on Nack received
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack, EndpointId>& afterReceiveNack;
|
||||
|
||||
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
|
||||
*/
|
||||
signal::Signal<LinkService, Interest>& onDroppedInterest;
|
||||
|
||||
public: // properties
|
||||
/** \return face ID
|
||||
*/
|
||||
FaceId
|
||||
getId() const;
|
||||
|
||||
/** \brief Get the description
|
||||
*/
|
||||
const std::string&
|
||||
getDescription() const;
|
||||
|
||||
/** \brief Set the face description
|
||||
*
|
||||
* This is typically invoked by management on set description command
|
||||
/** \brief sets face ID
|
||||
* \note Normally, this should only be invoked by FaceTable.
|
||||
*/
|
||||
void
|
||||
setDescription(const std::string& description);
|
||||
setId(FaceId id);
|
||||
|
||||
/** \brief Get whether face is connected to a local app
|
||||
/** \return a FaceUri representing local endpoint
|
||||
*/
|
||||
bool
|
||||
isLocal() const;
|
||||
FaceUri
|
||||
getLocalUri() const;
|
||||
|
||||
/** \brief Get the persistency setting
|
||||
/** \return a FaceUri representing remote endpoint
|
||||
*/
|
||||
FaceUri
|
||||
getRemoteUri() const;
|
||||
|
||||
/** \return whether face is local or non-local for scope control purpose
|
||||
*/
|
||||
ndn::nfd::FaceScope
|
||||
getScope() const;
|
||||
|
||||
/** \return face persistency setting
|
||||
*/
|
||||
ndn::nfd::FacePersistency
|
||||
getPersistency() const;
|
||||
|
||||
// 'virtual' to allow override in LpFaceWrapper
|
||||
virtual void
|
||||
/** \brief changes face persistency setting
|
||||
*/
|
||||
void
|
||||
setPersistency(ndn::nfd::FacePersistency persistency);
|
||||
|
||||
/** \brief Get whether packets sent by this face may reach multiple peers
|
||||
/** \return whether face is point-to-point or multi-access
|
||||
*/
|
||||
bool
|
||||
isMultiAccess() const;
|
||||
ndn::nfd::LinkType
|
||||
getLinkType() const;
|
||||
|
||||
/** \brief Get whether underlying communication is up
|
||||
/** \brief Returns face effective MTU
|
||||
*
|
||||
* In this base class this property is always true.
|
||||
* This function is a wrapper. The effective MTU of a face is determined by the link service.
|
||||
*/
|
||||
virtual bool
|
||||
isUp() const;
|
||||
ssize_t
|
||||
getMtu() const;
|
||||
|
||||
// 'virtual' to allow override in LpFaceWrapper
|
||||
virtual const FaceCounters&
|
||||
/** \return face state
|
||||
*/
|
||||
FaceState
|
||||
getState() const;
|
||||
|
||||
/** \brief signals after face state changed
|
||||
*/
|
||||
signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
|
||||
|
||||
/** \return expiration time of the face
|
||||
* \retval time::steady_clock::TimePoint::max() the face has an indefinite lifetime
|
||||
*/
|
||||
time::steady_clock::TimePoint
|
||||
getExpirationTime() const;
|
||||
|
||||
const FaceCounters&
|
||||
getCounters() const;
|
||||
|
||||
/** \return a FaceUri that represents the remote endpoint
|
||||
/**
|
||||
* \brief Get channel on which face was created (unicast) or the associated channel (multicast)
|
||||
*/
|
||||
const FaceUri&
|
||||
getRemoteUri() const;
|
||||
weak_ptr<Channel>
|
||||
getChannel() const
|
||||
{
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
/** \return a FaceUri that represents the local endpoint (NFD side)
|
||||
*/
|
||||
const FaceUri&
|
||||
getLocalUri() const;
|
||||
|
||||
/** \return FaceTraits data structure filled with the current FaceTraits status
|
||||
*/
|
||||
template<typename FaceTraits>
|
||||
void
|
||||
copyStatusTo(FaceTraits& traits) const;
|
||||
|
||||
/** \return FaceStatus data structure filled with the current Face status
|
||||
*/
|
||||
virtual ndn::nfd::FaceStatus
|
||||
getFaceStatus() const;
|
||||
|
||||
protected:
|
||||
bool
|
||||
decodeAndDispatchInput(const Block& element);
|
||||
|
||||
/** \brief fail the face and raise onFail event if it's UP; otherwise do nothing
|
||||
/**
|
||||
* \brief Set channel on which face was created (unicast) or the associated channel (multicast)
|
||||
*/
|
||||
void
|
||||
fail(const std::string& reason);
|
||||
|
||||
FaceCounters&
|
||||
getMutableCounters();
|
||||
|
||||
DECLARE_SIGNAL_EMIT(onReceiveInterest)
|
||||
DECLARE_SIGNAL_EMIT(onReceiveData)
|
||||
DECLARE_SIGNAL_EMIT(onReceiveNack)
|
||||
DECLARE_SIGNAL_EMIT(onSendInterest)
|
||||
DECLARE_SIGNAL_EMIT(onSendData)
|
||||
DECLARE_SIGNAL_EMIT(onSendNack)
|
||||
|
||||
// this method should be used only by the FaceTable
|
||||
// 'virtual' to allow override in LpFaceWrapper
|
||||
virtual void
|
||||
setId(FaceId faceId);
|
||||
setChannel(weak_ptr<Channel> channel)
|
||||
{
|
||||
m_channel = std::move(channel);
|
||||
}
|
||||
|
||||
private:
|
||||
FaceId m_id;
|
||||
std::string m_description;
|
||||
unique_ptr<LinkService> m_service;
|
||||
unique_ptr<Transport> m_transport;
|
||||
FaceCounters m_counters;
|
||||
const FaceUri m_remoteUri;
|
||||
const FaceUri m_localUri;
|
||||
const bool m_isLocal;
|
||||
ndn::nfd::FacePersistency m_persistency;
|
||||
const bool m_isMultiAccess;
|
||||
bool m_isFailed;
|
||||
|
||||
// allow setting FaceId
|
||||
friend class FaceTable;
|
||||
weak_ptr<Channel> m_channel;
|
||||
};
|
||||
|
||||
inline LinkService*
|
||||
Face::getLinkService() const
|
||||
{
|
||||
return m_service.get();
|
||||
}
|
||||
|
||||
inline Transport*
|
||||
Face::getTransport() const
|
||||
{
|
||||
return m_transport.get();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::close()
|
||||
{
|
||||
m_transport->close();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::sendInterest(const Interest& interest)
|
||||
{
|
||||
m_service->sendInterest(interest);
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::sendData(const Data& data)
|
||||
{
|
||||
m_service->sendData(data);
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::sendNack(const lp::Nack& nack)
|
||||
{
|
||||
m_service->sendNack(nack);
|
||||
}
|
||||
|
||||
inline FaceId
|
||||
Face::getId() const
|
||||
{
|
||||
@@ -233,45 +242,63 @@ Face::getId() const
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::setId(FaceId faceId)
|
||||
Face::setId(FaceId id)
|
||||
{
|
||||
m_id = faceId;
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
inline const std::string&
|
||||
Face::getDescription() const
|
||||
inline FaceUri
|
||||
Face::getLocalUri() const
|
||||
{
|
||||
return m_description;
|
||||
return m_transport->getLocalUri();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::setDescription(const std::string& description)
|
||||
inline FaceUri
|
||||
Face::getRemoteUri() const
|
||||
{
|
||||
m_description = description;
|
||||
return m_transport->getRemoteUri();
|
||||
}
|
||||
|
||||
inline bool
|
||||
Face::isLocal() const
|
||||
inline ndn::nfd::FaceScope
|
||||
Face::getScope() const
|
||||
{
|
||||
return m_isLocal;
|
||||
return m_transport->getScope();
|
||||
}
|
||||
|
||||
inline ndn::nfd::FacePersistency
|
||||
Face::getPersistency() const
|
||||
{
|
||||
return m_persistency;
|
||||
return m_transport->getPersistency();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::setPersistency(ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
m_persistency = persistency;
|
||||
return m_transport->setPersistency(persistency);
|
||||
}
|
||||
|
||||
inline bool
|
||||
Face::isMultiAccess() const
|
||||
inline ndn::nfd::LinkType
|
||||
Face::getLinkType() const
|
||||
{
|
||||
return m_isMultiAccess;
|
||||
return m_transport->getLinkType();
|
||||
}
|
||||
|
||||
inline ssize_t
|
||||
Face::getMtu() const
|
||||
{
|
||||
return m_service->getEffectiveMtu();
|
||||
}
|
||||
|
||||
inline FaceState
|
||||
Face::getState() const
|
||||
{
|
||||
return m_transport->getState();
|
||||
}
|
||||
|
||||
inline time::steady_clock::TimePoint
|
||||
Face::getExpirationTime() const
|
||||
{
|
||||
return m_transport->getExpirationTime();
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
@@ -280,33 +307,12 @@ Face::getCounters() const
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
inline FaceCounters&
|
||||
Face::getMutableCounters()
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<Face>& flh);
|
||||
|
||||
inline const FaceUri&
|
||||
Face::getRemoteUri() const
|
||||
{
|
||||
return m_remoteUri;
|
||||
}
|
||||
} // namespace face
|
||||
|
||||
inline const FaceUri&
|
||||
Face::getLocalUri() const
|
||||
{
|
||||
return m_localUri;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<Face, T>::value, std::ostream&>::type
|
||||
operator<<(std::ostream& os, const face::FaceLogHelper<T>& flh)
|
||||
{
|
||||
const Face& face = flh.obj;
|
||||
os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
|
||||
",remote=" << face.getRemoteUri() << "] ";
|
||||
return os;
|
||||
}
|
||||
using face::Face;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,44 +24,169 @@
|
||||
*/
|
||||
|
||||
#include "generic-link-service.hpp"
|
||||
#include <iostream>
|
||||
#include <ndn-cxx/lp/pit-token.hpp>
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("GenericLinkService");
|
||||
NFD_LOG_INIT(GenericLinkService);
|
||||
|
||||
GenericLinkService::Options::Options()
|
||||
: allowLocalFields(false)
|
||||
{
|
||||
}
|
||||
constexpr size_t CONGESTION_MARK_SIZE = tlv::sizeOfVarNumber(lp::tlv::CongestionMark) + // type
|
||||
tlv::sizeOfVarNumber(sizeof(uint64_t)) + // length
|
||||
tlv::sizeOfNonNegativeInteger(UINT64_MAX); // value
|
||||
|
||||
GenericLinkService::GenericLinkService(const GenericLinkService::Options& options)
|
||||
: m_options(options)
|
||||
, m_fragmenter(m_options.fragmenterOptions, this)
|
||||
, m_reassembler(m_options.reassemblerOptions, this)
|
||||
, m_reliability(m_options.reliabilityOptions, this)
|
||||
, m_lastSeqNo(-2)
|
||||
, m_nextMarkTime(time::steady_clock::TimePoint::max())
|
||||
, m_nMarkedSinceInMarkingState(0)
|
||||
, globalSp(options.C * 0.99, options.vqSize)
|
||||
{
|
||||
std::cout << "C: " << options.C << std::endl;
|
||||
m_reassembler.beforeTimeout.connect([this] (auto...) { ++this->nReassemblyTimeouts; });
|
||||
m_reliability.onDroppedInterest.connect([this] (const auto& i) { this->notifyDroppedInterest(i); });
|
||||
nReassembling.observe(&m_reassembler);
|
||||
this->sendPacketCallback = [this](std::shared_ptr<VirtualQueueItem> taskPtr) {
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
if (taskPtr != nullptr) {
|
||||
const Block &block = taskPtr->item->wireEncode();
|
||||
// std::cout << "interest wireEncode size: " << block.size() << std::endl;
|
||||
lp::Packet lpPacket(block);
|
||||
// std::cout << "Interest lppacket size before encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
encodeLpFields(*(taskPtr->item), lpPacket);
|
||||
// std::cout << "Interest lppacket size after encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
this->sendNetPacket(std::move(lpPacket), true);
|
||||
// lp::Packet lpPacket(taskPtr->item->wireEncode());
|
||||
// encodeLpFields(*(taskPtr->item), lpPacket);
|
||||
// this->sendNetPacket(std::move(lpPacket), taskPtr->endpointId, true);
|
||||
}
|
||||
// 得到下一个需要调度的包
|
||||
auto newTaskPtr = this->globalSp.scheduleNext();
|
||||
if (newTaskPtr == nullptr) {
|
||||
//NFD_LOG_ERROR("FUCK");
|
||||
// std::cout << "FUCK" << std::endl;
|
||||
// 如果没有可调度的包,则 1 ms 之后再调度
|
||||
this->canScheduler = true;
|
||||
// getScheduler().schedule(time::milliseconds(1), std::bind(this->sendPacketCallback, nullptr));
|
||||
} else {
|
||||
// 等待足够的 token 再发送
|
||||
this->canScheduler = false;
|
||||
// std::cout << "Route waitTime: " << newTaskPtr->waitNsTime << std::endl;
|
||||
// NFD_LOG_DEBUG("Route waitTime: " << newTaskPtr->waitNsTime);
|
||||
getScheduler().schedule(time::nanoseconds((uint32_t)(0)),
|
||||
std::bind(this->sendPacketCallback, newTaskPtr));
|
||||
}
|
||||
};
|
||||
// getScheduler().schedule(time::nanoseconds(0), std::bind(this->sendPacketCallback, nullptr));
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::setOptions(const GenericLinkService::Options& options)
|
||||
{
|
||||
m_options = options;
|
||||
m_fragmenter.setOptions(m_options.fragmenterOptions);
|
||||
m_reassembler.setOptions(m_options.reassemblerOptions);
|
||||
m_reliability.setOptions(m_options.reliabilityOptions);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
GenericLinkService::getEffectiveMtu() const
|
||||
{
|
||||
// Since MTU_UNLIMITED is negative, it will implicitly override any finite override MTU
|
||||
return std::min(m_options.overrideMtu, getTransport()->getMtu());
|
||||
}
|
||||
|
||||
bool
|
||||
GenericLinkService::canOverrideMtuTo(ssize_t mtu) const
|
||||
{
|
||||
// Not allowed to override unlimited transport MTU
|
||||
if (getTransport()->getMtu() == MTU_UNLIMITED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Override MTU must be at least MIN_MTU (also implicitly forbids MTU_UNLIMITED and MTU_INVALID)
|
||||
return mtu >= MIN_MTU;
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::requestIdlePacket()
|
||||
{
|
||||
// No need to request Acks to attach to this packet from LpReliability, as they are already
|
||||
// attached in sendLpPacket
|
||||
NFD_LOG_FACE_TRACE("IDLE packet requested");
|
||||
this->sendLpPacket({});
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::sendLpPacket(lp::Packet&& pkt)
|
||||
{
|
||||
const ssize_t mtu = getEffectiveMtu();
|
||||
|
||||
if (m_options.reliabilityOptions.isEnabled) {
|
||||
m_reliability.piggyback(pkt, mtu);
|
||||
}
|
||||
|
||||
if (m_options.allowCongestionMarking) {
|
||||
checkCongestionLevel(pkt);
|
||||
}
|
||||
|
||||
auto block = pkt.wireEncode();
|
||||
if (mtu != MTU_UNLIMITED && block.size() > static_cast<size_t>(mtu)) {
|
||||
++this->nOutOverMtu;
|
||||
NFD_LOG_FACE_WARN("attempted to send packet over MTU limit");
|
||||
return;
|
||||
}
|
||||
this->sendPacket(block);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doSendInterest(const Interest& interest)
|
||||
{
|
||||
lp::Packet lpPacket(interest.wireEncode());
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(interest, lpPacket);
|
||||
}
|
||||
Transport::Packet packet;
|
||||
packet.packet = lpPacket.wireEncode();
|
||||
sendPacket(std::move(packet));
|
||||
if (interest.getName().getPrefix(1).toUri() == "/localhost") {
|
||||
const Block &block = interest.wireEncode();
|
||||
// // std::cout << "interest wireEncode size: " << block.size() << std::endl;
|
||||
lp::Packet lpPacket(block);
|
||||
// // std::cout << "lppacket size before encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
encodeLpFields(interest, lpPacket);
|
||||
// // std::cout << "lppacket size after encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
this->sendNetPacket(std::move(lpPacket), true);
|
||||
} else {
|
||||
this->globalSp.appendInterest(interest);
|
||||
if (this->canScheduler) {
|
||||
this->sendPacketCallback(nullptr);
|
||||
}
|
||||
//if (!success) {
|
||||
// // send Nack
|
||||
// lp::Nack nack(interest);
|
||||
// nack.setReason(lp::NackReason::CONGESTION);
|
||||
// if (this->nwfq.canMark(nack)) {
|
||||
// // 拥塞标记
|
||||
// nack.getInterest().setTag(make_shared<lp::CongestionMarkTag>(1));
|
||||
// }
|
||||
// this->receiveNack(nack, endpointId);
|
||||
//}
|
||||
}
|
||||
|
||||
// encodeLpFields(interest, lpPacket);
|
||||
|
||||
// this->sendNetPacket(std::move(lpPacket), true);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doSendData(const Data& data)
|
||||
{
|
||||
lp::Packet lpPacket(data.wireEncode());
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(data, lpPacket);
|
||||
}
|
||||
Transport::Packet packet;
|
||||
packet.packet = lpPacket.wireEncode();
|
||||
sendPacket(std::move(packet));
|
||||
|
||||
encodeLpFields(data, lpPacket);
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket), false);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -69,98 +194,227 @@ GenericLinkService::doSendNack(const lp::Nack& nack)
|
||||
{
|
||||
lp::Packet lpPacket(nack.getInterest().wireEncode());
|
||||
lpPacket.add<lp::NackField>(nack.getHeader());
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(nack.getInterest(), lpPacket);
|
||||
}
|
||||
Transport::Packet packet;
|
||||
packet.packet = lpPacket.wireEncode();
|
||||
sendPacket(std::move(packet));
|
||||
}
|
||||
|
||||
bool
|
||||
GenericLinkService::encodeLocalFields(const Interest& interest, lp::Packet& lpPacket)
|
||||
{
|
||||
if (interest.getLocalControlHeader().hasIncomingFaceId()) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(interest.getIncomingFaceId());
|
||||
}
|
||||
encodeLpFields(nack, lpPacket);
|
||||
|
||||
if (interest.getLocalControlHeader().hasCachingPolicy()) {
|
||||
// Packet must be dropped
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GenericLinkService::encodeLocalFields(const Data& data, lp::Packet& lpPacket)
|
||||
{
|
||||
if (data.getLocalControlHeader().hasIncomingFaceId()) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(data.getIncomingFaceId());
|
||||
}
|
||||
|
||||
if (data.getLocalControlHeader().hasCachingPolicy()) {
|
||||
switch (data.getCachingPolicy()) {
|
||||
case ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE: {
|
||||
lp::CachePolicy cachePolicy;
|
||||
cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE);
|
||||
lpPacket.add<lp::CachePolicyField>(cachePolicy);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
this->sendNetPacket(std::move(lpPacket), false);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doReceivePacket(Transport::Packet&& packet)
|
||||
GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
|
||||
{
|
||||
std::for_each(pkts.begin(), pkts.end(), [this] (lp::Packet& pkt) {
|
||||
pkt.set<lp::SequenceField>(++m_lastSeqNo);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket)
|
||||
{
|
||||
if (m_options.allowLocalFields) {
|
||||
auto incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
|
||||
if (incomingFaceIdTag != nullptr) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
|
||||
}
|
||||
}
|
||||
|
||||
auto congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
|
||||
if (congestionMarkTag != nullptr) {
|
||||
lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
|
||||
}
|
||||
|
||||
if (m_options.allowSelfLearning) {
|
||||
auto nonDiscoveryTag = netPkt.getTag<lp::NonDiscoveryTag>();
|
||||
if (nonDiscoveryTag != nullptr) {
|
||||
lpPacket.add<lp::NonDiscoveryField>(*nonDiscoveryTag);
|
||||
}
|
||||
|
||||
auto prefixAnnouncementTag = netPkt.getTag<lp::PrefixAnnouncementTag>();
|
||||
if (prefixAnnouncementTag != nullptr) {
|
||||
lpPacket.add<lp::PrefixAnnouncementField>(*prefixAnnouncementTag);
|
||||
}
|
||||
}
|
||||
|
||||
auto pitToken = netPkt.getTag<lp::PitToken>();
|
||||
if (pitToken != nullptr) {
|
||||
lpPacket.add<lp::PitTokenField>(*pitToken);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
|
||||
{
|
||||
std::vector<lp::Packet> frags;
|
||||
ssize_t mtu = getEffectiveMtu();
|
||||
|
||||
// Make space for feature fields in fragments
|
||||
if (m_options.reliabilityOptions.isEnabled && mtu != MTU_UNLIMITED) {
|
||||
mtu -= LpReliability::RESERVED_HEADER_SPACE;
|
||||
}
|
||||
|
||||
if (m_options.allowCongestionMarking && mtu != MTU_UNLIMITED) {
|
||||
mtu -= CONGESTION_MARK_SIZE;
|
||||
}
|
||||
|
||||
// An MTU of 0 is allowed but will cause all packets to be dropped before transmission
|
||||
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu >= 0);
|
||||
|
||||
if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
|
||||
bool isOk = false;
|
||||
std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
|
||||
if (!isOk) {
|
||||
// fragmentation failed (warning is logged by LpFragmenter)
|
||||
++this->nFragmentationErrors;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_options.reliabilityOptions.isEnabled) {
|
||||
frags.push_back(pkt);
|
||||
}
|
||||
else {
|
||||
frags.push_back(std::move(pkt));
|
||||
}
|
||||
}
|
||||
|
||||
if (frags.size() == 1) {
|
||||
// even if indexed fragmentation is enabled, the fragmenter should not
|
||||
// fragment the packet if it can fit in MTU
|
||||
BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
|
||||
BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
|
||||
}
|
||||
|
||||
// Only assign sequences to fragments if reliability enabled or if packet contains >1 fragment
|
||||
if (m_options.reliabilityOptions.isEnabled || frags.size() > 1) {
|
||||
// Assign sequences to all fragments
|
||||
this->assignSequences(frags);
|
||||
}
|
||||
|
||||
if (m_options.reliabilityOptions.isEnabled && frags.front().has<lp::FragmentField>()) {
|
||||
m_reliability.handleOutgoing(frags, std::move(pkt), isInterest);
|
||||
}
|
||||
|
||||
for (lp::Packet& frag : frags) {
|
||||
this->sendLpPacket(std::move(frag));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
|
||||
{
|
||||
ssize_t sendQueueLength = getTransport()->getSendQueueLength();
|
||||
// The transport must support retrieving the current send queue length
|
||||
if (sendQueueLength < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendQueueLength > 0) {
|
||||
NFD_LOG_FACE_TRACE("txqlen=" << sendQueueLength << " threshold=" <<
|
||||
m_options.defaultCongestionThreshold << " capacity=" <<
|
||||
getTransport()->getSendQueueCapacity());
|
||||
}
|
||||
|
||||
// sendQueue is above target
|
||||
if (static_cast<size_t>(sendQueueLength) > m_options.defaultCongestionThreshold) {
|
||||
const auto now = time::steady_clock::now();
|
||||
|
||||
if (m_nextMarkTime == time::steady_clock::TimePoint::max()) {
|
||||
m_nextMarkTime = now + m_options.baseCongestionMarkingInterval;
|
||||
}
|
||||
// Mark packet if sendQueue stays above target for one interval
|
||||
else if (now >= m_nextMarkTime) {
|
||||
pkt.set<lp::CongestionMarkField>(1);
|
||||
++nCongestionMarked;
|
||||
NFD_LOG_FACE_DEBUG("LpPacket was marked as congested");
|
||||
|
||||
++m_nMarkedSinceInMarkingState;
|
||||
// Decrease the marking interval by the inverse of the square root of the number of packets
|
||||
// marked in this incident of congestion
|
||||
time::nanoseconds interval(static_cast<time::nanoseconds::rep>(
|
||||
m_options.baseCongestionMarkingInterval.count() /
|
||||
std::sqrt(m_nMarkedSinceInMarkingState + 1)));
|
||||
m_nextMarkTime += interval;
|
||||
}
|
||||
}
|
||||
else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {
|
||||
// Congestion incident has ended, so reset
|
||||
NFD_LOG_FACE_DEBUG("Send queue length dropped below congestion threshold");
|
||||
m_nextMarkTime = time::steady_clock::TimePoint::max();
|
||||
m_nMarkedSinceInMarkingState = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpoint)
|
||||
{
|
||||
try {
|
||||
lp::Packet pkt(packet.packet);
|
||||
lp::Packet pkt(packet);
|
||||
|
||||
if (m_options.reliabilityOptions.isEnabled) {
|
||||
if (!m_reliability.processIncomingPacket(pkt)) {
|
||||
NFD_LOG_FACE_TRACE("received duplicate fragment: DROP");
|
||||
++this->nDuplicateSequence;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkt.has<lp::FragmentField>()) {
|
||||
NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) {
|
||||
NFD_LOG_FACE_WARN("received fragment, but reassembly not implemented: DROP");
|
||||
if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
|
||||
!m_options.allowReassembly) {
|
||||
NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
ndn::Buffer::const_iterator fragBegin, fragEnd;
|
||||
std::tie(fragBegin, fragEnd) = pkt.get<lp::FragmentField>();
|
||||
Block netPkt(&*fragBegin, std::distance(fragBegin, fragEnd));
|
||||
bool isReassembled = false;
|
||||
Block netPkt;
|
||||
lp::Packet firstPkt;
|
||||
std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(endpoint, pkt);
|
||||
if (isReassembled) {
|
||||
this->decodeNetPacket(netPkt, firstPkt, endpoint);
|
||||
}
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
++this->nInLpInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
try {
|
||||
switch (netPkt.type()) {
|
||||
case tlv::Interest:
|
||||
if (pkt.has<lp::NackField>()) {
|
||||
this->decodeNack(netPkt, pkt);
|
||||
if (firstPkt.has<lp::NackField>()) {
|
||||
this->decodeNack(netPkt, firstPkt, endpointId);
|
||||
}
|
||||
else {
|
||||
this->decodeInterest(netPkt, pkt);
|
||||
this->decodeInterest(netPkt, firstPkt, endpointId);
|
||||
}
|
||||
break;
|
||||
case tlv::Data:
|
||||
this->decodeData(netPkt, pkt);
|
||||
this->decodeData(netPkt, firstPkt, endpointId);
|
||||
break;
|
||||
default:
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP" << netPkt.type());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
BOOST_ASSERT(netPkt.type() == tlv::Interest);
|
||||
BOOST_ASSERT(!firstPkt.has<lp::NackField>());
|
||||
@@ -170,7 +424,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
if (m_options.allowLocalFields) {
|
||||
interest->setNextHopFaceId(firstPkt.get<lp::NextHopFaceIdField>());
|
||||
interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
|
||||
}
|
||||
else {
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
|
||||
@@ -179,6 +433,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -187,11 +442,37 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
|
||||
}
|
||||
|
||||
this->receiveInterest(*interest);
|
||||
if (firstPkt.has<lp::CongestionMarkField>()) {
|
||||
interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NonDiscoveryField>()) {
|
||||
if (m_options.allowSelfLearning) {
|
||||
interest->setTag(make_shared<lp::NonDiscoveryTag>(firstPkt.get<lp::NonDiscoveryField>()));
|
||||
}
|
||||
else {
|
||||
NFD_LOG_FACE_WARN("received NonDiscovery, but self-learning disabled: IGNORE");
|
||||
}
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Interest: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::PitTokenField>()) {
|
||||
interest->setTag(make_shared<lp::PitToken>(firstPkt.get<lp::PitTokenField>()));
|
||||
}
|
||||
|
||||
this->globalSp.receiveInterest(*interest);
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
this->receiveInterest(*interest, endpointId);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
BOOST_ASSERT(netPkt.type() == tlv::Data);
|
||||
|
||||
@@ -199,41 +480,60 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
auto data = make_shared<Data>(netPkt);
|
||||
|
||||
if (firstPkt.has<lp::NackField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received Nack with Data: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
if (m_options.allowLocalFields) {
|
||||
lp::CachePolicyType policy = firstPkt.get<lp::CachePolicyField>().getPolicy();
|
||||
switch (policy) {
|
||||
case lp::CachePolicyType::NO_CACHE:
|
||||
data->setCachingPolicy(ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE);
|
||||
break;
|
||||
default:
|
||||
NFD_LOG_FACE_WARN("unrecognized CachePolicyType " << policy << ": DROP");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NFD_LOG_FACE_WARN("received CachePolicy, but local fields disabled: IGNORE");
|
||||
}
|
||||
// CachePolicy is unprivileged and does not require allowLocalFields option.
|
||||
// In case of an invalid CachePolicyType, get<lp::CachePolicyField> will throw,
|
||||
// so it's unnecessary to check here.
|
||||
data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::IncomingFaceIdField>()) {
|
||||
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
|
||||
}
|
||||
|
||||
this->receiveData(*data);
|
||||
if (firstPkt.has<lp::CongestionMarkField>()) {
|
||||
data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NonDiscoveryField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NonDiscovery with Data: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
|
||||
if (m_options.allowSelfLearning) {
|
||||
data->setTag(make_shared<lp::PrefixAnnouncementTag>(firstPkt.get<lp::PrefixAnnouncementField>()));
|
||||
}
|
||||
else {
|
||||
NFD_LOG_FACE_WARN("received PrefixAnnouncement, but self-learning disabled: IGNORE");
|
||||
}
|
||||
}
|
||||
|
||||
// 不处理本地命令通信
|
||||
if (data->getName().getPrefix(1).toUri() != "/localhost") {
|
||||
// TR = min(TR, OR)
|
||||
this->globalSp.assignObjectRate(*data);
|
||||
}
|
||||
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
this->receiveData(*data, endpointId);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
BOOST_ASSERT(netPkt.type() == tlv::Interest);
|
||||
BOOST_ASSERT(firstPkt.has<lp::NackField>());
|
||||
@@ -242,11 +542,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
nack.setHeader(firstPkt.get<lp::NackField>());
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -255,7 +557,23 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
|
||||
}
|
||||
|
||||
this->receiveNack(nack);
|
||||
if (firstPkt.has<lp::CongestionMarkField>()) {
|
||||
nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NonDiscoveryField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NonDiscovery with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
this->receiveNack(nack, endpointId);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,20 +26,76 @@
|
||||
#ifndef NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
|
||||
#define NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
#include "link-service.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
#include "lp-fragmenter.hpp"
|
||||
#include "lp-reassembler.hpp"
|
||||
#include "lp-reliability.hpp"
|
||||
#include "queues.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol
|
||||
* \sa http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
/** \brief counters provided by GenericLinkService
|
||||
* \note The type name 'GenericLinkServiceCounters' is implementation detail.
|
||||
* Use 'GenericLinkService::Counters' in public API.
|
||||
*/
|
||||
class GenericLinkService : public LinkService
|
||||
class GenericLinkServiceCounters : public virtual LinkService::Counters
|
||||
{
|
||||
public:
|
||||
/** \brief count of failed fragmentations
|
||||
*/
|
||||
PacketCounter nFragmentationErrors;
|
||||
|
||||
/** \brief count of outgoing LpPackets dropped due to exceeding MTU limit
|
||||
*
|
||||
* If this counter is non-zero, the operator should enable fragmentation.
|
||||
*/
|
||||
PacketCounter nOutOverMtu;
|
||||
|
||||
/** \brief count of invalid LpPackets dropped before reassembly
|
||||
*/
|
||||
PacketCounter nInLpInvalid;
|
||||
|
||||
/** \brief count of network-layer packets currently being reassembled
|
||||
*/
|
||||
SizeCounter<LpReassembler> nReassembling;
|
||||
|
||||
/** \brief count of dropped partial network-layer packets due to reassembly timeout
|
||||
*/
|
||||
PacketCounter nReassemblyTimeouts;
|
||||
|
||||
/** \brief count of invalid reassembled network-layer packets dropped
|
||||
*/
|
||||
PacketCounter nInNetInvalid;
|
||||
|
||||
/** \brief count of network-layer packets that did not require retransmission of a fragment
|
||||
*/
|
||||
PacketCounter nAcknowledged;
|
||||
|
||||
/** \brief count of network-layer packets that had at least one fragment retransmitted, but were
|
||||
* eventually received in full
|
||||
*/
|
||||
PacketCounter nRetransmitted;
|
||||
|
||||
/** \brief count of network-layer packets dropped because a fragment reached the maximum number
|
||||
* of retransmissions
|
||||
*/
|
||||
PacketCounter nRetxExhausted;
|
||||
|
||||
/** \brief count of LpPackets dropped due to duplicate Sequence numbers
|
||||
*/
|
||||
PacketCounter nDuplicateSequence;
|
||||
|
||||
/** \brief count of outgoing LpPackets that were marked with congestion marks
|
||||
*/
|
||||
PacketCounter nCongestionMarked;
|
||||
};
|
||||
|
||||
/** \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol
|
||||
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
*/
|
||||
class GenericLinkService FINAL_UNLESS_WITH_TESTS : public LinkService
|
||||
, protected virtual GenericLinkServiceCounters
|
||||
{
|
||||
public:
|
||||
/** \brief Options that control the behavior of GenericLinkService
|
||||
@@ -47,18 +103,79 @@ public:
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
Options();
|
||||
Options() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
// TODO #3171: fragmentation and reassembly options
|
||||
|
||||
/** \brief enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy
|
||||
*/
|
||||
bool allowLocalFields;
|
||||
bool allowLocalFields = false;
|
||||
|
||||
/** \brief enables fragmentation
|
||||
*/
|
||||
bool allowFragmentation = false;
|
||||
|
||||
/** \brief options for fragmentation
|
||||
*/
|
||||
LpFragmenter::Options fragmenterOptions;
|
||||
|
||||
/** \brief enables reassembly
|
||||
*/
|
||||
bool allowReassembly = false;
|
||||
|
||||
/** \brief options for reassembly
|
||||
*/
|
||||
LpReassembler::Options reassemblerOptions;
|
||||
|
||||
/** \brief options for reliability
|
||||
*/
|
||||
LpReliability::Options reliabilityOptions;
|
||||
|
||||
/** \brief enables send queue congestion detection and marking
|
||||
*/
|
||||
bool allowCongestionMarking = false;
|
||||
|
||||
/** \brief starting value for congestion marking interval
|
||||
*
|
||||
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
|
||||
*
|
||||
* The default value (100 ms) is taken from RFC 8289 (CoDel).
|
||||
*/
|
||||
time::nanoseconds baseCongestionMarkingInterval = 100_ms;
|
||||
|
||||
/** \brief default congestion threshold in bytes
|
||||
*
|
||||
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
|
||||
*
|
||||
* The default value (64 KiB) works well for a queue capacity of 200 KiB.
|
||||
*/
|
||||
size_t defaultCongestionThreshold = 65536;
|
||||
|
||||
/** \brief enables self-learning forwarding support
|
||||
*/
|
||||
bool allowSelfLearning = true;
|
||||
|
||||
/** \brief overrides MTU provided by Transport
|
||||
*
|
||||
* This MTU value will be used instead of the MTU provided by the transport if it is less than
|
||||
* the transport MTU. However, it will not be utilized when the transport MTU is unlimited.
|
||||
*
|
||||
* Acceptable values for the override MTU are values >= MIN_MTU, which can be validated before
|
||||
* being set with canOverrideMtuTo().
|
||||
*/
|
||||
ssize_t overrideMtu = std::numeric_limits<ssize_t>::max();
|
||||
|
||||
uint64_t C = 100000000; // 100Mbps
|
||||
size_t vqSize = 20;
|
||||
};
|
||||
|
||||
/** \brief counters provided by GenericLinkService
|
||||
*/
|
||||
using Counters = GenericLinkServiceCounters;
|
||||
|
||||
explicit
|
||||
GenericLinkService(const Options& options = Options());
|
||||
GenericLinkService(const Options& options = {});
|
||||
|
||||
/** \brief get Options used by GenericLinkService
|
||||
*/
|
||||
@@ -70,43 +187,85 @@ public:
|
||||
void
|
||||
setOptions(const Options& options);
|
||||
|
||||
private: // send path entrypoint
|
||||
/** \brief sends Interest
|
||||
const Counters&
|
||||
getCounters() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
ssize_t
|
||||
getEffectiveMtu() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief Whether MTU can be overridden to the specified value
|
||||
*
|
||||
* If the transport MTU is unlimited, then this will always return false.
|
||||
*/
|
||||
bool
|
||||
canOverrideMtuTo(ssize_t mtu) const;
|
||||
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
|
||||
/** \brief request an IDLE packet to transmit pending service fields
|
||||
*/
|
||||
void
|
||||
doSendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
requestIdlePacket();
|
||||
|
||||
/** \brief sends Data
|
||||
/** \brief send an LpPacket
|
||||
*/
|
||||
void
|
||||
doSendData(const Data& data) DECL_OVERRIDE;
|
||||
sendLpPacket(lp::Packet&& pkt);
|
||||
|
||||
/** \brief sends Nack
|
||||
* This class does not send out a Nack.
|
||||
void
|
||||
doSendInterest(const Interest& interest) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
void
|
||||
doSendData(const Data& data) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
void
|
||||
doSendNack(const ndn::lp::Nack& nack) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief assign consecutive sequence numbers to LpPackets
|
||||
*/
|
||||
void
|
||||
doSendNack(const ndn::lp::Nack& nack) DECL_OVERRIDE;
|
||||
assignSequences(std::vector<lp::Packet>& pkts);
|
||||
|
||||
private: // receive path entrypoint
|
||||
/** \brief receives Packet
|
||||
private: // send path
|
||||
/** \brief encode link protocol fields from tags onto an outgoing LpPacket
|
||||
* \param netPkt network-layer packet to extract tags from
|
||||
* \param lpPacket LpPacket to add link protocol fields to
|
||||
*/
|
||||
void
|
||||
doReceivePacket(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket);
|
||||
|
||||
private: // encoding and decoding
|
||||
/** \brief encode IncomingFaceId into LpPacket and verify local fields
|
||||
/** \brief send a complete network layer packet
|
||||
* \param pkt LpPacket containing a complete network layer packet
|
||||
* \param isInterest whether the network layer packet is an Interest
|
||||
*/
|
||||
static bool
|
||||
encodeLocalFields(const Interest& interest, lp::Packet& lpPacket);
|
||||
void
|
||||
sendNetPacket(lp::Packet&& pkt, bool isInterest);
|
||||
|
||||
/** \brief encode CachingPolicy and IncomingFaceId into LpPacket and verify local fields
|
||||
/** \brief if the send queue is found to be congested, add a congestion mark to the packet
|
||||
* according to CoDel
|
||||
* \sa https://tools.ietf.org/html/rfc8289
|
||||
*/
|
||||
static bool
|
||||
encodeLocalFields(const Data& data, lp::Packet& lpPacket);
|
||||
void
|
||||
checkCongestionLevel(lp::Packet& pkt);
|
||||
|
||||
private: // receive path
|
||||
void
|
||||
doReceivePacket(const Block& packet, const EndpointId& endpoint) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief decode incoming network-layer packet
|
||||
* \param netPkt reassembled network-layer packet
|
||||
* \param firstPkt LpPacket of first fragment
|
||||
* \param endpointId endpoint of peer who sent the packet
|
||||
*
|
||||
* If decoding is successful, a receive signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
*/
|
||||
void
|
||||
decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
/** \brief decode incoming Interest
|
||||
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
|
||||
* \param firstPkt LpPacket of first fragment; must not have Nack field
|
||||
* \param endpointId endpoint of peer who sent the Interest
|
||||
*
|
||||
* If decoding is successful, receiveInterest signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
@@ -114,11 +273,12 @@ private: // encoding and decoding
|
||||
* \throw tlv::Error parse error in an LpHeader field
|
||||
*/
|
||||
void
|
||||
decodeInterest(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
decodeInterest(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
/** \brief decode incoming Interest
|
||||
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Data
|
||||
* \param firstPkt LpPacket of first fragment
|
||||
* \param endpointId endpoint of peer who sent the Data
|
||||
*
|
||||
* If decoding is successful, receiveData signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
@@ -126,11 +286,12 @@ private: // encoding and decoding
|
||||
* \throw tlv::Error parse error in an LpHeader field
|
||||
*/
|
||||
void
|
||||
decodeData(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
decodeData(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
/** \brief decode incoming Interest
|
||||
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
|
||||
* \param firstPkt LpPacket of first fragment; must have Nack field
|
||||
* \param endpointId endpoint of peer who sent the Nack
|
||||
*
|
||||
* If decoding is successful, receiveNack signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
@@ -138,10 +299,25 @@ private: // encoding and decoding
|
||||
* \throw tlv::Error parse error in an LpHeader field
|
||||
*/
|
||||
void
|
||||
decodeNack(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
decodeNack(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
private:
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
Options m_options;
|
||||
LpFragmenter m_fragmenter;
|
||||
LpReassembler m_reassembler;
|
||||
LpReliability m_reliability;
|
||||
lp::Sequence m_lastSeqNo;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/// Time to mark next packet due to send queue congestion
|
||||
time::steady_clock::TimePoint m_nextMarkTime;
|
||||
/// number of marked packets in the current incident of congestion
|
||||
size_t m_nMarkedSinceInMarkingState;
|
||||
|
||||
GlobalSP globalSp;
|
||||
bool canScheduler = true;
|
||||
std::function<void(std::shared_ptr<VirtualQueueItem>)> sendPacketCallback;
|
||||
friend class LpReliability;
|
||||
};
|
||||
|
||||
inline const GenericLinkService::Options&
|
||||
@@ -150,10 +326,10 @@ GenericLinkService::getOptions() const
|
||||
return m_options;
|
||||
}
|
||||
|
||||
inline void
|
||||
GenericLinkService::setOptions(const GenericLinkService::Options& options)
|
||||
inline const GenericLinkService::Counters&
|
||||
GenericLinkService::getCounters() const
|
||||
{
|
||||
m_options = options;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,8 +26,7 @@
|
||||
#include "internal-face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "internal-transport.hpp"
|
||||
#include "lp-face-wrapper.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "common/global.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -38,19 +37,16 @@ makeInternalFace(ndn::KeyChain& clientKeyChain)
|
||||
GenericLinkService::Options serviceOpts;
|
||||
serviceOpts.allowLocalFields = true;
|
||||
|
||||
auto face = make_unique<LpFace>(make_unique<GenericLinkService>(serviceOpts),
|
||||
make_unique<InternalForwarderTransport>());
|
||||
auto faceW = make_shared<LpFaceWrapper>(std::move(face));
|
||||
// TODO#3172 eliminate wrapper
|
||||
auto face = make_shared<Face>(make_unique<GenericLinkService>(serviceOpts),
|
||||
make_unique<InternalForwarderTransport>());
|
||||
|
||||
InternalForwarderTransport* forwarderTransport =
|
||||
static_cast<InternalForwarderTransport*>(faceW->getLpFace()->getTransport());
|
||||
auto forwarderTransport = static_cast<InternalForwarderTransport*>(face->getTransport());
|
||||
auto clientTransport = make_shared<InternalClientTransport>();
|
||||
clientTransport->connectToForwarder(forwarderTransport);
|
||||
|
||||
auto clientFace = make_shared<ndn::Face>(clientTransport, getGlobalIoService(), clientKeyChain);
|
||||
|
||||
return std::make_tuple(faceW, clientFace);
|
||||
return std::make_tuple(face, clientFace);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,42 +24,43 @@
|
||||
*/
|
||||
|
||||
#include "internal-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "common/global.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INCLASS_DEFINE(InternalForwarderTransport, "InternalForwarderTransport");
|
||||
NFD_LOG_MEMBER_INIT(InternalForwarderTransport, InternalForwarderTransport);
|
||||
NFD_LOG_MEMBER_INIT(InternalClientTransport, InternalClientTransport);
|
||||
|
||||
InternalForwarderTransport::InternalForwarderTransport(
|
||||
const FaceUri& localUri, const FaceUri& remoteUri,
|
||||
ndn::nfd::FaceScope scope, ndn::nfd::LinkType linkType)
|
||||
InternalForwarderTransport::InternalForwarderTransport(const FaceUri& localUri, const FaceUri& remoteUri,
|
||||
ndn::nfd::FaceScope scope, ndn::nfd::LinkType linkType)
|
||||
{
|
||||
this->setLocalUri(localUri);
|
||||
this->setRemoteUri(remoteUri);
|
||||
this->setScope(scope);
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
this->setLinkType(linkType);
|
||||
this->setMtu(MTU_UNLIMITED);
|
||||
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
NFD_LOG_FACE_DEBUG("Creating transport");
|
||||
}
|
||||
|
||||
void
|
||||
InternalForwarderTransport::receiveFromLink(const Block& packet)
|
||||
InternalForwarderTransport::receivePacket(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
Packet p;
|
||||
p.packet = packet;
|
||||
this->receive(std::move(p));
|
||||
getGlobalIoService().post([this, packet] {
|
||||
NFD_LOG_FACE_TRACE("Received: " << packet.size() << " bytes");
|
||||
receive(packet);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
InternalForwarderTransport::doSend(Packet&& packet)
|
||||
InternalForwarderTransport::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
NFD_LOG_FACE_TRACE("Sending to " << m_peer);
|
||||
|
||||
this->emitSignal(afterSend, packet.packet);
|
||||
if (m_peer)
|
||||
m_peer->receivePacket(packet);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -67,52 +68,59 @@ InternalForwarderTransport::doClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
this->setState(TransportState::CLOSED);
|
||||
setState(TransportState::CLOSED);
|
||||
}
|
||||
|
||||
NFD_LOG_INCLASS_DEFINE(InternalClientTransport, "InternalClientTransport");
|
||||
|
||||
static void
|
||||
asyncReceive(InternalTransportBase* recipient, const Block& packet)
|
||||
InternalClientTransport::~InternalClientTransport()
|
||||
{
|
||||
getGlobalIoService().post([packet, recipient] {
|
||||
recipient->receiveFromLink(packet);
|
||||
});
|
||||
if (m_forwarder != nullptr) {
|
||||
m_forwarder->setPeer(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalClientTransport::connectToForwarder(InternalForwarderTransport* forwarderTransport)
|
||||
InternalClientTransport::connectToForwarder(InternalForwarderTransport* forwarder)
|
||||
{
|
||||
NFD_LOG_DEBUG(__func__ << " " << forwarderTransport);
|
||||
NFD_LOG_DEBUG(__func__ << " " << forwarder);
|
||||
|
||||
m_fwToClientTransmitConn.disconnect();
|
||||
m_clientToFwTransmitConn.disconnect();
|
||||
m_fwTransportStateConn.disconnect();
|
||||
if (m_forwarder != nullptr) {
|
||||
// disconnect from the old forwarder transport
|
||||
m_forwarder->setPeer(nullptr);
|
||||
m_fwTransportStateConn.disconnect();
|
||||
}
|
||||
|
||||
if (forwarderTransport != nullptr) {
|
||||
m_fwToClientTransmitConn = forwarderTransport->afterSend.connect(bind(&asyncReceive, this, _1));
|
||||
m_clientToFwTransmitConn = this->afterSend.connect(bind(&asyncReceive, forwarderTransport, _1));
|
||||
m_fwTransportStateConn = forwarderTransport->afterStateChange.connect(
|
||||
m_forwarder = forwarder;
|
||||
|
||||
if (m_forwarder != nullptr) {
|
||||
// connect to the new forwarder transport
|
||||
m_forwarder->setPeer(this);
|
||||
m_fwTransportStateConn = m_forwarder->afterStateChange.connect(
|
||||
[this] (TransportState oldState, TransportState newState) {
|
||||
if (newState == TransportState::CLOSED) {
|
||||
this->connectToForwarder(nullptr);
|
||||
connectToForwarder(nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalClientTransport::receiveFromLink(const Block& packet)
|
||||
InternalClientTransport::receivePacket(const Block& packet)
|
||||
{
|
||||
if (m_receiveCallback) {
|
||||
m_receiveCallback(packet);
|
||||
}
|
||||
getGlobalIoService().post([this, packet] {
|
||||
NFD_LOG_TRACE("Received: " << packet.size() << " bytes");
|
||||
if (m_receiveCallback) {
|
||||
m_receiveCallback(packet);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
InternalClientTransport::send(const Block& wire)
|
||||
{
|
||||
this->emitSignal(afterSend, wire);
|
||||
NFD_LOG_TRACE("Sending to " << m_forwarder);
|
||||
|
||||
if (m_forwarder)
|
||||
m_forwarder->receivePacket(wire);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -122,7 +130,7 @@ InternalClientTransport::send(const Block& header, const Block& payload)
|
||||
encoder.appendByteArray(header.wire(), header.size());
|
||||
encoder.appendByteArray(payload.wire(), payload.size());
|
||||
|
||||
this->send(encoder.block());
|
||||
send(encoder.block());
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,59 +27,67 @@
|
||||
#define NFD_DAEMON_FACE_INTERNAL_TRANSPORT_HPP
|
||||
|
||||
#include "transport.hpp"
|
||||
|
||||
#include <ndn-cxx/transport/transport.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief abstracts a transport that can be paired with another
|
||||
/** \brief Abstracts a transport that can be paired with another.
|
||||
*/
|
||||
class InternalTransportBase
|
||||
{
|
||||
public:
|
||||
/** \brief causes the transport to receive a link-layer packet
|
||||
*/
|
||||
virtual
|
||||
~InternalTransportBase() = default;
|
||||
|
||||
virtual void
|
||||
receiveFromLink(const Block& packet) = 0;
|
||||
|
||||
signal::Signal<InternalTransportBase, Block> afterSend;
|
||||
|
||||
protected:
|
||||
DECLARE_SIGNAL_EMIT(afterSend)
|
||||
receivePacket(const Block& packet) = 0;
|
||||
};
|
||||
|
||||
/** \brief implements a forwarder-side transport that can be paired with another
|
||||
/** \brief Implements a forwarder-side transport that can be paired with another transport.
|
||||
*/
|
||||
class InternalForwarderTransport : public face::Transport, public InternalTransportBase
|
||||
class InternalForwarderTransport final : public Transport, public InternalTransportBase
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
InternalForwarderTransport(const FaceUri& localUri = FaceUri("internal://"),
|
||||
const FaceUri& remoteUri = FaceUri("internal://"),
|
||||
ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_LOCAL,
|
||||
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
|
||||
virtual void
|
||||
receiveFromLink(const Block& packet) DECL_OVERRIDE;
|
||||
void
|
||||
setPeer(InternalTransportBase* peer)
|
||||
{
|
||||
m_peer = peer;
|
||||
}
|
||||
|
||||
void
|
||||
receivePacket(const Block& packet) final;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Packet&& packet) DECL_OVERRIDE;
|
||||
void
|
||||
doSend(const Block& packet) final;
|
||||
|
||||
private:
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
NFD_LOG_MEMBER_DECL();
|
||||
|
||||
InternalTransportBase* m_peer = nullptr;
|
||||
};
|
||||
|
||||
/** \brief implements a client-side transport that can be paired with another
|
||||
/** \brief Implements a client-side transport that can be paired with an InternalForwarderTransport.
|
||||
*/
|
||||
class InternalClientTransport : public ndn::Transport, public InternalTransportBase
|
||||
class InternalClientTransport final : public ndn::Transport, public InternalTransportBase
|
||||
{
|
||||
public:
|
||||
/** \brief connect to a forwarder-side transport
|
||||
* \param forwarderTransport the forwarder-side transport to connect to; may be nullptr
|
||||
~InternalClientTransport() final;
|
||||
|
||||
/** \brief Connect to a forwarder-side transport.
|
||||
* \param forwarder the forwarder-side transport to connect to; may be nullptr
|
||||
*
|
||||
* The connected forwarder-side transport will be disconnected automatically if this method
|
||||
* is called again, or if that transport is closed.
|
||||
@@ -87,37 +95,36 @@ public:
|
||||
* all sent packets would be lost, and nothing would be received.
|
||||
*/
|
||||
void
|
||||
connectToForwarder(InternalForwarderTransport* forwarderTransport);
|
||||
connectToForwarder(InternalForwarderTransport* forwarder);
|
||||
|
||||
virtual void
|
||||
receiveFromLink(const Block& packet) DECL_OVERRIDE;
|
||||
void
|
||||
receivePacket(const Block& packet) final;
|
||||
|
||||
virtual void
|
||||
close() DECL_OVERRIDE
|
||||
void
|
||||
send(const Block& wire) final;
|
||||
|
||||
void
|
||||
send(const Block& header, const Block& payload) final;
|
||||
|
||||
void
|
||||
close() final
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
pause() DECL_OVERRIDE
|
||||
void
|
||||
pause() final
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
resume() DECL_OVERRIDE
|
||||
void
|
||||
resume() final
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
send(const Block& wire) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
send(const Block& header, const Block& payload) DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
NFD_LOG_MEMBER_DECL();
|
||||
|
||||
signal::ScopedConnection m_fwToClientTransmitConn;
|
||||
signal::ScopedConnection m_clientToFwTransmitConn;
|
||||
InternalForwarderTransport* m_forwarder = nullptr;
|
||||
signal::ScopedConnection m_fwTransportStateConn;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,18 +24,16 @@
|
||||
*/
|
||||
|
||||
#include "link-service.hpp"
|
||||
#include "lp-face.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("LinkService");
|
||||
NFD_LOG_INIT(LinkService);
|
||||
|
||||
LinkService::LinkService()
|
||||
: m_face(nullptr)
|
||||
, m_transport(nullptr)
|
||||
, m_counters(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -44,14 +42,13 @@ LinkService::~LinkService()
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::setFaceAndTransport(LpFace& face, Transport& transport)
|
||||
LinkService::setFaceAndTransport(Face& face, Transport& transport)
|
||||
{
|
||||
BOOST_ASSERT(m_face == nullptr);
|
||||
BOOST_ASSERT(m_transport == nullptr);
|
||||
|
||||
m_face = &face;
|
||||
m_transport = &transport;
|
||||
m_counters = &m_face->getMutableCounters();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -60,7 +57,7 @@ LinkService::sendInterest(const Interest& interest)
|
||||
BOOST_ASSERT(m_transport != nullptr);
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNOutInterests();
|
||||
++this->nOutInterests;
|
||||
|
||||
doSendInterest(interest);
|
||||
}
|
||||
@@ -71,7 +68,7 @@ LinkService::sendData(const Data& data)
|
||||
BOOST_ASSERT(m_transport != nullptr);
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNOutDatas();
|
||||
++this->nOutData;
|
||||
|
||||
doSendData(data);
|
||||
}
|
||||
@@ -82,45 +79,52 @@ LinkService::sendNack(const ndn::lp::Nack& nack)
|
||||
BOOST_ASSERT(m_transport != nullptr);
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
// TODO#3177 increment counter
|
||||
++this->nOutNacks;
|
||||
|
||||
doSendNack(nack);
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::receiveInterest(const Interest& interest)
|
||||
LinkService::receiveInterest(const Interest& interest, const EndpointId& endpoint)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNInInterests();
|
||||
++this->nInInterests;
|
||||
|
||||
afterReceiveInterest(interest);
|
||||
afterReceiveInterest(interest, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::receiveData(const Data& data)
|
||||
LinkService::receiveData(const Data& data, const EndpointId& endpoint)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNInDatas();
|
||||
++this->nInData;
|
||||
|
||||
afterReceiveData(data);
|
||||
afterReceiveData(data, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::receiveNack(const ndn::lp::Nack& nack)
|
||||
LinkService::receiveNack(const ndn::lp::Nack& nack, const EndpointId& endpoint)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
// TODO#3177 increment counter
|
||||
++this->nInNacks;
|
||||
|
||||
afterReceiveNack(nack);
|
||||
afterReceiveNack(nack, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::notifyDroppedInterest(const Interest& interest)
|
||||
{
|
||||
++this->nInterestsExceededRetx;
|
||||
onDroppedInterest(interest);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh)
|
||||
{
|
||||
const LpFace* face = flh.obj.getFace();
|
||||
const Face* face = flh.obj.getFace();
|
||||
if (face == nullptr) {
|
||||
os << "[id=0,local=unknown,remote=unknown] ";
|
||||
}
|
||||
|
||||
+118
-53
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,19 +26,59 @@
|
||||
#ifndef NFD_DAEMON_FACE_LINK_SERVICE_HPP
|
||||
#define NFD_DAEMON_FACE_LINK_SERVICE_HPP
|
||||
|
||||
#include "face-common.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "face-log.hpp"
|
||||
#include "common/counter.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class LpFace;
|
||||
|
||||
/** \brief the upper part of an LpFace
|
||||
* \sa LpFace
|
||||
/** \brief counters provided by LinkService
|
||||
* \note The type name 'LinkServiceCounters' is implementation detail.
|
||||
* Use 'LinkService::Counters' in public API.
|
||||
*/
|
||||
class LinkService : noncopyable
|
||||
class LinkServiceCounters
|
||||
{
|
||||
public:
|
||||
/** \brief count of incoming Interests
|
||||
*/
|
||||
PacketCounter nInInterests;
|
||||
|
||||
/** \brief count of outgoing Interests
|
||||
*/
|
||||
PacketCounter nOutInterests;
|
||||
|
||||
/** \brief count of Interests dropped by reliability system for exceeding allowed number of retx
|
||||
*/
|
||||
PacketCounter nInterestsExceededRetx;
|
||||
|
||||
/** \brief count of incoming Data packets
|
||||
*/
|
||||
PacketCounter nInData;
|
||||
|
||||
/** \brief count of outgoing Data packets
|
||||
*/
|
||||
PacketCounter nOutData;
|
||||
|
||||
/** \brief count of incoming Nacks
|
||||
*/
|
||||
PacketCounter nInNacks;
|
||||
|
||||
/** \brief count of outgoing Nacks
|
||||
*/
|
||||
PacketCounter nOutNacks;
|
||||
};
|
||||
|
||||
/** \brief the upper part of a Face
|
||||
* \sa Face
|
||||
*/
|
||||
class LinkService : protected virtual LinkServiceCounters, noncopyable
|
||||
{
|
||||
public:
|
||||
/** \brief counters provided by LinkService
|
||||
*/
|
||||
typedef LinkServiceCounters Counters;
|
||||
|
||||
public:
|
||||
LinkService();
|
||||
|
||||
@@ -49,11 +89,11 @@ public:
|
||||
* \pre setFaceAndTransport has not been called
|
||||
*/
|
||||
void
|
||||
setFaceAndTransport(LpFace& face, Transport& transport);
|
||||
setFaceAndTransport(Face& face, Transport& transport);
|
||||
|
||||
/** \return Face to which this LinkService is attached
|
||||
*/
|
||||
const LpFace*
|
||||
const Face*
|
||||
getFace() const;
|
||||
|
||||
/** \return Transport to which this LinkService is attached
|
||||
@@ -66,20 +106,26 @@ public:
|
||||
Transport*
|
||||
getTransport();
|
||||
|
||||
virtual const Counters&
|
||||
getCounters() const;
|
||||
|
||||
virtual ssize_t
|
||||
getEffectiveMtu() const;
|
||||
|
||||
public: // upper interface to be used by forwarding
|
||||
/** \brief send Interest
|
||||
/** \brief Send Interest
|
||||
* \pre setTransport has been called
|
||||
*/
|
||||
void
|
||||
sendInterest(const Interest& interest);
|
||||
|
||||
/** \brief send Data
|
||||
/** \brief Send Data
|
||||
* \pre setTransport has been called
|
||||
*/
|
||||
void
|
||||
sendData(const Data& data);
|
||||
|
||||
/** \brief send Nack
|
||||
/** \brief Send Nack
|
||||
* \pre setTransport has been called
|
||||
*/
|
||||
void
|
||||
@@ -87,15 +133,51 @@ public: // upper interface to be used by forwarding
|
||||
|
||||
/** \brief signals on Interest received
|
||||
*/
|
||||
signal::Signal<LinkService, Interest> afterReceiveInterest;
|
||||
signal::Signal<LinkService, Interest, EndpointId> afterReceiveInterest;
|
||||
|
||||
/** \brief signals on Data received
|
||||
*/
|
||||
signal::Signal<LinkService, Data> afterReceiveData;
|
||||
signal::Signal<LinkService, Data, EndpointId> afterReceiveData;
|
||||
|
||||
/** \brief signals on Nack received
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack> afterReceiveNack;
|
||||
signal::Signal<LinkService, lp::Nack, EndpointId> afterReceiveNack;
|
||||
|
||||
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
|
||||
*/
|
||||
signal::Signal<LinkService, Interest> onDroppedInterest;
|
||||
|
||||
public: // lower interface to be invoked by Transport
|
||||
/** \brief performs LinkService specific operations to receive a lower-layer packet
|
||||
*/
|
||||
void
|
||||
receivePacket(const Block& packet, const EndpointId& endpoint);
|
||||
|
||||
protected: // upper interface to be invoked in subclass (receive path termination)
|
||||
/** \brief delivers received Interest to forwarding
|
||||
*/
|
||||
void
|
||||
receiveInterest(const Interest& interest, const EndpointId& endpoint);
|
||||
|
||||
/** \brief delivers received Data to forwarding
|
||||
*/
|
||||
void
|
||||
receiveData(const Data& data, const EndpointId& endpoint);
|
||||
|
||||
/** \brief delivers received Nack to forwarding
|
||||
*/
|
||||
void
|
||||
receiveNack(const lp::Nack& nack, const EndpointId& endpoint);
|
||||
|
||||
protected: // lower interface to be invoked in subclass (send path termination)
|
||||
/** \brief send a lower-layer packet via Transport
|
||||
*/
|
||||
void
|
||||
sendPacket(const Block& packet);
|
||||
|
||||
protected:
|
||||
void
|
||||
notifyDroppedInterest(const Interest& packet);
|
||||
|
||||
private: // upper interface to be overridden in subclass (send path entrypoint)
|
||||
/** \brief performs LinkService specific operations to send an Interest
|
||||
@@ -113,45 +195,16 @@ private: // upper interface to be overridden in subclass (send path entrypoint)
|
||||
virtual void
|
||||
doSendNack(const lp::Nack& nack) = 0;
|
||||
|
||||
protected: // upper interface to be invoked in subclass (receive path termination)
|
||||
/** \brief delivers received Interest to forwarding
|
||||
*/
|
||||
void
|
||||
receiveInterest(const Interest& interest);
|
||||
|
||||
/** \brief delivers received Data to forwarding
|
||||
*/
|
||||
void
|
||||
receiveData(const Data& data);
|
||||
|
||||
/** \brief delivers received Nack to forwarding
|
||||
*/
|
||||
void
|
||||
receiveNack(const lp::Nack& nack);
|
||||
|
||||
public: // lower interface to be invoked by Transport
|
||||
/** \brief performs LinkService specific operations to receive a lower-layer packet
|
||||
*/
|
||||
void
|
||||
receivePacket(Transport::Packet&& packet);
|
||||
|
||||
protected: // lower interface to be invoked in subclass (send path termination)
|
||||
/** \brief sends a lower-layer packet via Transport
|
||||
*/
|
||||
void
|
||||
sendPacket(Transport::Packet&& packet);
|
||||
|
||||
private: // lower interface to be overridden in subclass
|
||||
virtual void
|
||||
doReceivePacket(Transport::Packet&& packet) = 0;
|
||||
doReceivePacket(const Block& packet, const EndpointId& endpoint) = 0;
|
||||
|
||||
private:
|
||||
LpFace* m_face;
|
||||
Face* m_face;
|
||||
Transport* m_transport;
|
||||
NetworkLayerCounters* m_counters; // TODO#3177 change into NetCounters
|
||||
};
|
||||
|
||||
inline const LpFace*
|
||||
inline const Face*
|
||||
LinkService::getFace() const
|
||||
{
|
||||
return m_face;
|
||||
@@ -169,16 +222,28 @@ LinkService::getTransport()
|
||||
return m_transport;
|
||||
}
|
||||
|
||||
inline void
|
||||
LinkService::receivePacket(Transport::Packet&& packet)
|
||||
inline const LinkService::Counters&
|
||||
LinkService::getCounters() const
|
||||
{
|
||||
doReceivePacket(std::move(packet));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline ssize_t
|
||||
LinkService::getEffectiveMtu() const
|
||||
{
|
||||
return m_transport->getMtu();
|
||||
}
|
||||
|
||||
inline void
|
||||
LinkService::sendPacket(Transport::Packet&& packet)
|
||||
LinkService::receivePacket(const Block& packet, const EndpointId& endpoint)
|
||||
{
|
||||
m_transport->send(std::move(packet));
|
||||
doReceivePacket(packet, endpoint);
|
||||
}
|
||||
|
||||
inline void
|
||||
LinkService::sendPacket(const Block& packet)
|
||||
{
|
||||
m_transport->send(packet);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_LOCAL_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_LOCAL_FACE_HPP
|
||||
|
||||
#include "face.hpp"
|
||||
#include <ndn-cxx/management/nfd-control-parameters.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
using ndn::nfd::LocalControlFeature;
|
||||
using ndn::nfd::LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID;
|
||||
using ndn::nfd::LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID;
|
||||
|
||||
/** \brief represents a face
|
||||
*/
|
||||
class LocalFace : public Face
|
||||
{
|
||||
public:
|
||||
LocalFace(const FaceUri& remoteUri, const FaceUri& localUri);
|
||||
|
||||
/** \brief get whether any LocalControlHeader feature is enabled
|
||||
*
|
||||
* \returns true if any feature is enabled.
|
||||
*/
|
||||
bool
|
||||
isLocalControlHeaderEnabled() const;
|
||||
|
||||
/** \brief get whether a specific LocalControlHeader feature is enabled
|
||||
*
|
||||
* \param feature The feature.
|
||||
* \returns true if the specified feature is enabled.
|
||||
*/
|
||||
bool
|
||||
isLocalControlHeaderEnabled(LocalControlFeature feature) const;
|
||||
|
||||
/** \brief enable or disable a LocalControlHeader feature
|
||||
*
|
||||
* \param feature The feature. Cannot be LOCAL_CONTROL_FEATURE_ANY
|
||||
* or LOCAL_CONTROL_FEATURE_MAX
|
||||
* \param enabled true/false enable/disable the feature
|
||||
*/
|
||||
void
|
||||
setLocalControlHeaderFeature(LocalControlFeature feature, bool enabled = true);
|
||||
|
||||
public:
|
||||
|
||||
static const size_t LOCAL_CONTROL_FEATURE_MAX = 3; /// upper bound of LocalControlFeature enum
|
||||
static const size_t LOCAL_CONTROL_FEATURE_ANY = 0; /// any feature
|
||||
|
||||
protected:
|
||||
// statically overridden from Face
|
||||
|
||||
/** \brief Decode block into Interest/Data, considering potential LocalControlHeader
|
||||
*
|
||||
* If LocalControlHeader is present, the encoded data is filtered out, based
|
||||
* on enabled features on the face.
|
||||
*/
|
||||
bool
|
||||
decodeAndDispatchInput(const Block& element);
|
||||
|
||||
// LocalFace-specific methods
|
||||
|
||||
/** \brief Check if LocalControlHeader needs to be included, taking into account
|
||||
* both set parameters in supplied LocalControlHeader and features
|
||||
* enabled on the local face.
|
||||
*/
|
||||
bool
|
||||
isEmptyFilteredLocalControlHeader(const ndn::nfd::LocalControlHeader& header) const;
|
||||
|
||||
/** \brief Create LocalControlHeader, considering enabled features
|
||||
*/
|
||||
template<class Packet>
|
||||
Block
|
||||
filterAndEncodeLocalControlHeader(const Packet& packet);
|
||||
|
||||
private:
|
||||
std::vector<bool> m_localControlHeaderFeatures;
|
||||
};
|
||||
|
||||
inline
|
||||
LocalFace::LocalFace(const FaceUri& remoteUri, const FaceUri& localUri)
|
||||
: Face(remoteUri, localUri, true)
|
||||
, m_localControlHeaderFeatures(LocalFace::LOCAL_CONTROL_FEATURE_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::isLocalControlHeaderEnabled() const
|
||||
{
|
||||
return m_localControlHeaderFeatures[LOCAL_CONTROL_FEATURE_ANY];
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::isLocalControlHeaderEnabled(LocalControlFeature feature) const
|
||||
{
|
||||
BOOST_ASSERT(0 < feature &&
|
||||
static_cast<size_t>(feature) < m_localControlHeaderFeatures.size());
|
||||
return m_localControlHeaderFeatures[feature];
|
||||
}
|
||||
|
||||
inline void
|
||||
LocalFace::setLocalControlHeaderFeature(LocalControlFeature feature, bool enabled/* = true*/)
|
||||
{
|
||||
BOOST_ASSERT(0 < feature &&
|
||||
static_cast<size_t>(feature) < m_localControlHeaderFeatures.size());
|
||||
|
||||
m_localControlHeaderFeatures[feature] = enabled;
|
||||
|
||||
m_localControlHeaderFeatures[LOCAL_CONTROL_FEATURE_ANY] =
|
||||
std::find(m_localControlHeaderFeatures.begin() + 1,
|
||||
m_localControlHeaderFeatures.end(), true) <
|
||||
m_localControlHeaderFeatures.end();
|
||||
// 'find(..) < .end()' instead of 'find(..) != .end()' due to LLVM Bug 16816
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::decodeAndDispatchInput(const Block& element)
|
||||
{
|
||||
try {
|
||||
const Block& payload = ndn::nfd::LocalControlHeader::getPayload(element);
|
||||
|
||||
// If received LocalControlHeader, but it is not enabled on the face
|
||||
if ((&payload != &element) && !this->isLocalControlHeaderEnabled())
|
||||
return false;
|
||||
|
||||
if (payload.type() == tlv::Interest)
|
||||
{
|
||||
shared_ptr<Interest> i = make_shared<Interest>();
|
||||
i->wireDecode(payload);
|
||||
if (&payload != &element)
|
||||
{
|
||||
uint8_t mask = 0;
|
||||
if (this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID)) {
|
||||
mask |= ndn::nfd::LocalControlHeader::ENCODE_NEXT_HOP;
|
||||
}
|
||||
i->getLocalControlHeader().wireDecode(element, mask);
|
||||
}
|
||||
|
||||
this->emitSignal(onReceiveInterest, *i);
|
||||
}
|
||||
else if (payload.type() == tlv::Data)
|
||||
{
|
||||
shared_ptr<Data> d = make_shared<Data>();
|
||||
d->wireDecode(payload);
|
||||
|
||||
/// \todo Uncomment and correct the following when we have more
|
||||
/// options in LocalControlHeader that apply for incoming
|
||||
/// Data packets (if ever)
|
||||
// if (&payload != &element)
|
||||
// {
|
||||
//
|
||||
// d->getLocalControlHeader().wireDecode(element,
|
||||
// false,
|
||||
// false);
|
||||
// }
|
||||
|
||||
this->emitSignal(onReceiveData, *d);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const tlv::Error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::isEmptyFilteredLocalControlHeader(const ndn::nfd::LocalControlHeader& header) const
|
||||
{
|
||||
if (!this->isLocalControlHeaderEnabled())
|
||||
return true;
|
||||
|
||||
uint8_t mask = 0;
|
||||
if (this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID)) {
|
||||
mask |= ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID;
|
||||
}
|
||||
return header.empty(mask);
|
||||
}
|
||||
|
||||
template<class Packet>
|
||||
inline Block
|
||||
LocalFace::filterAndEncodeLocalControlHeader(const Packet& packet)
|
||||
{
|
||||
uint8_t mask = 0;
|
||||
if (this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID)) {
|
||||
mask |= ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID;
|
||||
}
|
||||
return packet.getLocalControlHeader().wireEncode(packet, mask);
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_LOCAL_FACE_HPP
|
||||
@@ -1,102 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "lp-face-wrapper.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
LpFaceWrapper::LpFaceWrapper(unique_ptr<LpFace> face)
|
||||
: Face(face->getRemoteUri(), face->getLocalUri(),
|
||||
face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL,
|
||||
face->getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS)
|
||||
, m_face(std::move(face))
|
||||
{
|
||||
this->Face::setPersistency(m_face->getPersistency());
|
||||
m_face->afterReceiveInterest.connect(bind(&LpFaceWrapper::dispatchInterest, this, _1));
|
||||
m_face->afterReceiveData.connect(bind(&LpFaceWrapper::dispatchData, this, _1));
|
||||
m_face->afterReceiveNack.connect(bind(&LpFaceWrapper::dispatchNack, this, _1));
|
||||
m_face->afterStateChange.connect(bind(&LpFaceWrapper::handleStateChange, this, _1, _2));
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::setPersistency(ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
this->Face::setPersistency(persistency);
|
||||
m_face->setPersistency(persistency);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::setId(nfd::FaceId faceId)
|
||||
{
|
||||
this->Face::setId(faceId);
|
||||
|
||||
FaceId lpId = static_cast<FaceId>(faceId);
|
||||
if (faceId == nfd::INVALID_FACEID) {
|
||||
lpId = INVALID_FACEID;
|
||||
}
|
||||
m_face->setId(lpId);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::dispatchInterest(const Interest& interest)
|
||||
{
|
||||
this->emitSignal(onReceiveInterest, interest);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::dispatchData(const Data& data)
|
||||
{
|
||||
this->emitSignal(onReceiveData, data);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::dispatchNack(const ndn::lp::Nack& nack)
|
||||
{
|
||||
this->emitSignal(onReceiveNack, nack);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::handleStateChange(FaceState oldState, FaceState newState)
|
||||
{
|
||||
if (newState != FaceState::CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (oldState) {
|
||||
case FaceState::CLOSING:
|
||||
this->fail("LpFace closed");
|
||||
break;
|
||||
case FaceState::FAILED:
|
||||
this->fail("LpFace failed");
|
||||
break;
|
||||
default:
|
||||
BOOST_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,140 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_LP_FACE_WRAPPER_HPP
|
||||
#define NFD_DAEMON_FACE_LP_FACE_WRAPPER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "face.hpp"
|
||||
#include "lp-face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief an adaptor to provide old Face APIs from an LpFace
|
||||
* \sa LpFace
|
||||
* \note When LpFace is adapted by LpFaceWrapper,
|
||||
* FaceId and counters will come from old Face rather than LpFace.
|
||||
*/
|
||||
class LpFaceWrapper : public Face
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
LpFaceWrapper(unique_ptr<LpFace> face);
|
||||
|
||||
LpFace*
|
||||
getLpFace();
|
||||
|
||||
virtual void
|
||||
sendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
sendData(const Data& data) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
sendNack(const lp::Nack& nack) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
close() DECL_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
isUp() const DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
setPersistency(ndn::nfd::FacePersistency persistency) DECL_OVERRIDE;
|
||||
|
||||
virtual const FaceCounters&
|
||||
getCounters() const DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
setId(nfd::FaceId faceId) DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
void
|
||||
dispatchInterest(const Interest& interest);
|
||||
|
||||
void
|
||||
dispatchData(const Data& data);
|
||||
|
||||
void
|
||||
dispatchNack(const lp::Nack& nack);
|
||||
|
||||
void
|
||||
handleStateChange(FaceState oldState, FaceState newState);
|
||||
|
||||
private:
|
||||
unique_ptr<LpFace> m_face;
|
||||
};
|
||||
|
||||
inline LpFace*
|
||||
LpFaceWrapper::getLpFace()
|
||||
{
|
||||
return m_face.get();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::sendInterest(const Interest& interest)
|
||||
{
|
||||
this->emitSignal(onSendInterest, interest);
|
||||
m_face->sendInterest(interest);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::sendData(const Data& data)
|
||||
{
|
||||
this->emitSignal(onSendData, data);
|
||||
m_face->sendData(data);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::sendNack(const lp::Nack& nack)
|
||||
{
|
||||
this->emitSignal(onSendNack, nack);
|
||||
m_face->sendNack(nack);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::close()
|
||||
{
|
||||
m_face->close();
|
||||
}
|
||||
|
||||
inline bool
|
||||
LpFaceWrapper::isUp() const
|
||||
{
|
||||
return m_face->getState() == FaceState::UP;
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
LpFaceWrapper::getCounters() const
|
||||
{
|
||||
return m_face->getCounters();
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_LP_FACE_WRAPPER_HPP
|
||||
@@ -1,311 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_LP_FACE_HPP
|
||||
#define NFD_DAEMON_LP_FACE_HPP
|
||||
|
||||
#include "transport.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include "face-log.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief identifies a face
|
||||
*/
|
||||
typedef uint64_t FaceId;
|
||||
|
||||
/// indicates an invalid FaceId
|
||||
const FaceId INVALID_FACEID = 0;
|
||||
/// identifies the InternalFace used in management
|
||||
const FaceId FACEID_INTERNAL_FACE = 1;
|
||||
/// identifies a packet comes from the ContentStore, in LocalControlHeader incomingFaceId
|
||||
const FaceId FACEID_CONTENT_STORE = 254;
|
||||
/// identifies the NullFace that drops every packet
|
||||
const FaceId FACEID_NULL = 255;
|
||||
/// upper bound of reserved FaceIds
|
||||
const FaceId FACEID_RESERVED_MAX = 255;
|
||||
|
||||
/** \brief indicates the state of a face
|
||||
*/
|
||||
typedef TransportState FaceState;
|
||||
|
||||
/** \brief generalization of a network interface
|
||||
*
|
||||
* A face generalizes a network interface.
|
||||
* It provides network-layer packet delivery services on a physical interface,
|
||||
* an overlay tunnel, or a link to a local application, with best-effort.
|
||||
*
|
||||
* A face combines two parts: LinkService and Transport.
|
||||
* Transport is the lower part, which provides TLV block delivery services with best-effort.
|
||||
* LinkService is the upper part, which translates between network-layer packets
|
||||
* and TLV blocks, and may provide additional services such as fragmentation and reassembly.
|
||||
*
|
||||
* We are in the process of refactoring face system to use this LinkService+Transport
|
||||
* architecture. During this process, the "face" is named LpFace, and we implement a
|
||||
* LpFaceWrapper class as an adaptor to the old Face APIs. After the completion of refactoring,
|
||||
* LpFace will be renamed to Face.
|
||||
*/
|
||||
class LpFace
|
||||
#ifndef WITH_TESTS
|
||||
DECL_CLASS_FINAL
|
||||
#endif
|
||||
: noncopyable
|
||||
{
|
||||
public:
|
||||
LpFace(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
|
||||
|
||||
LinkService*
|
||||
getLinkService();
|
||||
|
||||
Transport*
|
||||
getTransport();
|
||||
|
||||
public: // upper interface connected to forwarding
|
||||
/** \brief sends Interest on Face
|
||||
*/
|
||||
void
|
||||
sendInterest(const Interest& interest);
|
||||
|
||||
/** \brief sends Data on Face
|
||||
*/
|
||||
void
|
||||
sendData(const Data& data);
|
||||
|
||||
/** \brief sends Nack on Face
|
||||
*/
|
||||
void
|
||||
sendNack(const lp::Nack& nack);
|
||||
|
||||
/** \brief signals on Interest received
|
||||
*/
|
||||
signal::Signal<LinkService, Interest>& afterReceiveInterest;
|
||||
|
||||
/** \brief signals on Data received
|
||||
*/
|
||||
signal::Signal<LinkService, Data>& afterReceiveData;
|
||||
|
||||
/** \brief signals on Nack received
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack>& afterReceiveNack;
|
||||
|
||||
public: // static properties
|
||||
/** \return face ID
|
||||
*/
|
||||
FaceId
|
||||
getId() const;
|
||||
|
||||
/** \brief sets face ID
|
||||
* \note Normally, this should only be invoked by FaceTable.
|
||||
*/
|
||||
void
|
||||
setId(FaceId id);
|
||||
|
||||
/** \return a FaceUri representing local endpoint
|
||||
*/
|
||||
FaceUri
|
||||
getLocalUri() const;
|
||||
|
||||
/** \return a FaceUri representing remote endpoint
|
||||
*/
|
||||
FaceUri
|
||||
getRemoteUri() const;
|
||||
|
||||
/** \return whether face is local or non-local for scope control purpose
|
||||
*/
|
||||
ndn::nfd::FaceScope
|
||||
getScope() const;
|
||||
|
||||
/** \return face persistency setting
|
||||
*/
|
||||
ndn::nfd::FacePersistency
|
||||
getPersistency() const;
|
||||
|
||||
/** \brief changes face persistency setting
|
||||
*/
|
||||
void
|
||||
setPersistency(ndn::nfd::FacePersistency persistency);
|
||||
|
||||
/** \return whether face is point-to-point or multi-access
|
||||
*/
|
||||
ndn::nfd::LinkType
|
||||
getLinkType() const;
|
||||
|
||||
public: // dynamic properties
|
||||
/** \return face state
|
||||
*/
|
||||
FaceState
|
||||
getState() const;
|
||||
|
||||
/** \brief signals after face state changed
|
||||
*/
|
||||
signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
|
||||
|
||||
/** \brief request the face to be closed
|
||||
*
|
||||
* This operation is effective only if face is in UP or DOWN state,
|
||||
* otherwise it has no effect.
|
||||
* The face changes state to CLOSING, and performs cleanup procedure.
|
||||
* The state will be changed to CLOSED when cleanup is complete, which may
|
||||
* happen synchronously or asynchronously.
|
||||
*
|
||||
* \warning the face must not be deallocated until its state changes to CLOSED
|
||||
*/
|
||||
void
|
||||
close();
|
||||
|
||||
const FaceCounters&
|
||||
getCounters() const;
|
||||
|
||||
FaceCounters&
|
||||
getMutableCounters();
|
||||
|
||||
private:
|
||||
FaceId m_id;
|
||||
unique_ptr<LinkService> m_service;
|
||||
unique_ptr<Transport> m_transport;
|
||||
FaceCounters m_counters;
|
||||
};
|
||||
|
||||
inline LinkService*
|
||||
LpFace::getLinkService()
|
||||
{
|
||||
return m_service.get();
|
||||
}
|
||||
|
||||
inline Transport*
|
||||
LpFace::getTransport()
|
||||
{
|
||||
return m_transport.get();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::sendInterest(const Interest& interest)
|
||||
{
|
||||
m_service->sendInterest(interest);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::sendData(const Data& data)
|
||||
{
|
||||
m_service->sendData(data);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::sendNack(const lp::Nack& nack)
|
||||
{
|
||||
m_service->sendNack(nack);
|
||||
}
|
||||
|
||||
inline FaceId
|
||||
LpFace::getId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::setId(FaceId id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
inline FaceUri
|
||||
LpFace::getLocalUri() const
|
||||
{
|
||||
return m_transport->getLocalUri();
|
||||
}
|
||||
|
||||
inline FaceUri
|
||||
LpFace::getRemoteUri() const
|
||||
{
|
||||
return m_transport->getRemoteUri();
|
||||
}
|
||||
|
||||
inline ndn::nfd::FaceScope
|
||||
LpFace::getScope() const
|
||||
{
|
||||
return m_transport->getScope();
|
||||
}
|
||||
|
||||
inline ndn::nfd::FacePersistency
|
||||
LpFace::getPersistency() const
|
||||
{
|
||||
return m_transport->getPersistency();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::setPersistency(ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
return m_transport->setPersistency(persistency);
|
||||
}
|
||||
|
||||
inline ndn::nfd::LinkType
|
||||
LpFace::getLinkType() const
|
||||
{
|
||||
return m_transport->getLinkType();
|
||||
}
|
||||
|
||||
inline FaceState
|
||||
LpFace::getState() const
|
||||
{
|
||||
return m_transport->getState();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::close()
|
||||
{
|
||||
m_transport->close();
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
LpFace::getCounters() const
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
inline FaceCounters&
|
||||
LpFace::getMutableCounters()
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<LpFace, T>::value, std::ostream&>::type
|
||||
operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
|
||||
{
|
||||
const LpFace& face = flh.obj;
|
||||
os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
|
||||
",remote=" << face.getRemoteUri() << "] ";
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
// using face::FaceId; // TODO uncomment in #3172
|
||||
using face::LpFace;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_LP_FACE_HPP
|
||||
@@ -0,0 +1,158 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "lp-fragmenter.hpp"
|
||||
#include "link-service.hpp"
|
||||
|
||||
#include <ndn-cxx/encoding/tlv.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT(LpFragmenter);
|
||||
|
||||
static_assert(lp::tlv::LpPacket < 253, "LpPacket TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::Sequence < 253, "Sequence TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::FragIndex < 253, "FragIndex TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::FragCount < 253, "FragCount TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::Fragment < 253, "Fragment TLV-TYPE must fit in 1 octet");
|
||||
|
||||
/** \brief maximum overhead on a single fragment,
|
||||
* not counting other NDNLPv2 headers
|
||||
*/
|
||||
static const size_t MAX_SINGLE_FRAG_OVERHEAD =
|
||||
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
|
||||
1 + 1 + 8 + // Sequence TLV
|
||||
1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
|
||||
|
||||
/** \brief maximum overhead of adding fragmentation to payload,
|
||||
* not counting other NDNLPv2 headers
|
||||
*/
|
||||
static const size_t MAX_FRAG_OVERHEAD =
|
||||
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
|
||||
1 + 1 + 8 + // Sequence TLV
|
||||
1 + 1 + 8 + // FragIndex TLV
|
||||
1 + 1 + 8 + // FragCount TLV
|
||||
1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
|
||||
|
||||
LpFragmenter::LpFragmenter(const LpFragmenter::Options& options, const LinkService* linkService)
|
||||
: m_options(options)
|
||||
, m_linkService(linkService)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
LpFragmenter::setOptions(const Options& options)
|
||||
{
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
const LinkService*
|
||||
LpFragmenter::getLinkService() const
|
||||
{
|
||||
return m_linkService;
|
||||
}
|
||||
|
||||
std::tuple<bool, std::vector<lp::Packet>>
|
||||
LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
|
||||
{
|
||||
BOOST_ASSERT(packet.has<lp::FragmentField>());
|
||||
BOOST_ASSERT(!packet.has<lp::FragIndexField>());
|
||||
BOOST_ASSERT(!packet.has<lp::FragCountField>());
|
||||
|
||||
if (MAX_SINGLE_FRAG_OVERHEAD + packet.wireEncode().size() <= mtu) {
|
||||
// fast path: fragmentation not needed
|
||||
// To qualify for fast path, the packet must have space for adding a sequence number,
|
||||
// because another NDNLPv2 feature may require the sequence number.
|
||||
return std::make_tuple(true, std::vector<lp::Packet>{packet});
|
||||
}
|
||||
|
||||
ndn::Buffer::const_iterator netPktBegin, netPktEnd;
|
||||
std::tie(netPktBegin, netPktEnd) = packet.get<lp::FragmentField>();
|
||||
size_t netPktSize = std::distance(netPktBegin, netPktEnd);
|
||||
|
||||
// compute size of other NDNLPv2 headers to be placed on the first fragment
|
||||
size_t firstHeaderSize = 0;
|
||||
const Block& packetWire = packet.wireEncode();
|
||||
if (packetWire.type() == lp::tlv::LpPacket) {
|
||||
for (const Block& element : packetWire.elements()) {
|
||||
if (element.type() != lp::tlv::Fragment) {
|
||||
firstHeaderSize += element.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute payload size
|
||||
if (MAX_FRAG_OVERHEAD + firstHeaderSize + 1 > mtu) { // 1-octet fragment
|
||||
NFD_LOG_FACE_WARN("fragmentation error, MTU too small for first fragment: DROP");
|
||||
return std::make_tuple(false, std::vector<lp::Packet>{});
|
||||
}
|
||||
size_t firstPayloadSize = std::min(netPktSize, mtu - firstHeaderSize - MAX_FRAG_OVERHEAD);
|
||||
size_t payloadSize = mtu - MAX_FRAG_OVERHEAD;
|
||||
size_t fragCount = 1 + ((netPktSize - firstPayloadSize) / payloadSize) +
|
||||
((netPktSize - firstPayloadSize) % payloadSize != 0);
|
||||
|
||||
// compute FragCount
|
||||
if (fragCount > m_options.nMaxFragments) {
|
||||
NFD_LOG_FACE_WARN("fragmentation error, FragCount over limit: DROP");
|
||||
return std::make_tuple(false, std::vector<lp::Packet>{});
|
||||
}
|
||||
|
||||
// populate fragments
|
||||
std::vector<lp::Packet> frags(fragCount);
|
||||
frags.front() = packet; // copy input packet to preserve other NDNLPv2 fields
|
||||
size_t fragIndex = 0;
|
||||
auto fragBegin = netPktBegin,
|
||||
fragEnd = fragBegin + firstPayloadSize;
|
||||
while (fragBegin < netPktEnd) {
|
||||
lp::Packet& frag = frags[fragIndex];
|
||||
frag.add<lp::FragIndexField>(fragIndex);
|
||||
frag.add<lp::FragCountField>(fragCount);
|
||||
frag.set<lp::FragmentField>({fragBegin, fragEnd});
|
||||
BOOST_ASSERT(frag.wireEncode().size() <= mtu);
|
||||
|
||||
++fragIndex;
|
||||
fragBegin = fragEnd;
|
||||
fragEnd = std::min(netPktEnd, fragBegin + payloadSize);
|
||||
}
|
||||
BOOST_ASSERT(fragIndex == fragCount);
|
||||
|
||||
return std::make_tuple(true, frags);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh)
|
||||
{
|
||||
if (flh.obj.getLinkService() == nullptr) {
|
||||
os << "[id=0,local=unknown,remote=unknown] ";
|
||||
}
|
||||
else {
|
||||
os << FaceLogHelper<LinkService>(*flh.obj.getLinkService());
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
Loaded 100 of 702 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user