mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-11-02 03:37:57 +00:00
Compare commits
950 Commits
release/v2
...
v2.8.0-RC3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3101cb1205 | ||
|
|
cb5613ce7f | ||
|
|
45b25c4e75 | ||
|
|
ea311f70a0 | ||
|
|
e3265c86a5 | ||
|
|
e537259208 | ||
|
|
b9c7990344 | ||
|
|
d5c1cfe2f1 | ||
|
|
1a4f27cbbf | ||
|
|
11ad381534 | ||
|
|
0b548a40f3 | ||
|
|
28e5463196 | ||
|
|
37ea632ac7 | ||
|
|
2f641077e6 | ||
|
|
78318f47c6 | ||
|
|
c83c73a3ae | ||
|
|
6305be8c55 | ||
|
|
4b325ef22c | ||
|
|
a422dff7ae | ||
|
|
271ff4f6c4 | ||
|
|
4cdd275d0b | ||
|
|
9a36e86949 | ||
|
|
fa806ed16c | ||
|
|
57c270973e | ||
|
|
17ebfb24f2 | ||
|
|
26072691ab | ||
|
|
e8b3ea56e0 | ||
|
|
2b1a72b838 | ||
|
|
352afc487a | ||
|
|
6fae29981a | ||
|
|
9569de1b21 | ||
|
|
1a952946b2 | ||
|
|
3b52cf6111 | ||
|
|
74197e2aee | ||
|
|
7152067b09 | ||
|
|
ac3d061eee | ||
|
|
8ee67713bf | ||
|
|
e57cd4fea2 | ||
|
|
5e3a71a6e7 | ||
|
|
a602b8f844 | ||
|
|
89da7d187a | ||
|
|
6c5533aa8b | ||
|
|
66249b258c | ||
|
|
e03512ebf3 | ||
|
|
b152c8477a | ||
|
|
a298c4254b | ||
|
|
b8f04c6d4a | ||
|
|
753dc5c068 | ||
|
|
bf70d6b512 | ||
|
|
760f11ca70 | ||
|
|
2bcd0ccbcb | ||
|
|
0aee258af4 | ||
|
|
9e879f306c | ||
|
|
fb4a4d935a | ||
|
|
282552cdfa | ||
|
|
1d316ff28a | ||
|
|
1da866a7da | ||
|
|
1c628c28fa | ||
|
|
a350b30a9c | ||
|
|
cf6c3f9337 | ||
|
|
2388eac41d | ||
|
|
f0e0f2ba5b | ||
|
|
0c8b9caaf3 | ||
|
|
c0edeb8b23 | ||
|
|
fdcf74788d | ||
|
|
df9c82a4ae | ||
|
|
2963cec1fb | ||
|
|
8053e32c9c | ||
|
|
1750ac5fb5 | ||
|
|
b4d775db0c | ||
|
|
3031483209 | ||
|
|
97b990581d | ||
|
|
98fa4799cc | ||
|
|
95a853fc0e | ||
|
|
7a14cadbf5 | ||
|
|
ab5efcc8c1 | ||
|
|
bb71ff2bad | ||
|
|
c1a2efd32c | ||
|
|
ca4d92fd66 | ||
|
|
efb354031a | ||
|
|
180d01c89d | ||
|
|
f6c1a5e97f | ||
|
|
54e7caafc1 | ||
|
|
e76c97540c | ||
|
|
3f01ef6d5e | ||
|
|
8e118c7f7b | ||
|
|
6dc5622bf2 | ||
|
|
27a9ef01b6 | ||
|
|
9390b9a646 | ||
|
|
871f3c3436 | ||
|
|
a41095a797 | ||
|
|
bb94c9a813 | ||
|
|
fcd991b8d6 | ||
|
|
2df43cfd62 | ||
|
|
014aafbd3d | ||
|
|
d1d058a848 | ||
|
|
d492396182 | ||
|
|
2c710412a1 | ||
|
|
7dcade3d79 | ||
|
|
dc73a2d54b | ||
|
|
6c2bb5b395 | ||
|
|
fccf99cca5 | ||
|
|
0d91dd9a6e | ||
|
|
d84af0f18e | ||
|
|
6b6c9ce0ae | ||
|
|
5a31d6427f | ||
|
|
8b3ff4a560 | ||
|
|
53c81d2c76 | ||
|
|
518bfc0b2c | ||
|
|
c6851819d4 | ||
|
|
d5851753c2 | ||
|
|
379b1446f6 | ||
|
|
86a254e1b3 | ||
|
|
de260ecddc | ||
|
|
6d50ef72b7 | ||
|
|
f0954081c1 | ||
|
|
9653d0affb | ||
|
|
dd626461e8 | ||
|
|
048b33e134 | ||
|
|
eff7a70f6b | ||
|
|
5f73966010 | ||
|
|
911c9ac210 | ||
|
|
f59c369b61 | ||
|
|
526d239fe9 | ||
|
|
939d704460 | ||
|
|
b7e8da5e76 | ||
|
|
ad20736a14 | ||
|
|
c5d68e5397 | ||
|
|
a2bbe71e53 | ||
|
|
1c0cf65145 | ||
|
|
60d41e8569 | ||
|
|
76698476b6 | ||
|
|
4e4ac89401 | ||
|
|
e3e6a27348 | ||
|
|
b419472fd7 | ||
|
|
8f43f5945d | ||
|
|
bd2af4df1d | ||
|
|
bbbb4cd4fe | ||
|
|
445568152c | ||
|
|
ce70ff0f21 | ||
|
|
6dbf16793e | ||
|
|
eba69c8c35 | ||
|
|
ae2e6c5ce6 | ||
|
|
5a2a0cd074 | ||
|
|
9c3a23a8a1 | ||
|
|
b6f0f07bec | ||
|
|
e060e11cd2 | ||
|
|
883245de68 | ||
|
|
9cfc411a51 | ||
|
|
fb3a785227 | ||
|
|
3fe8958323 | ||
|
|
117f0e1637 | ||
|
|
b09b1d5690 | ||
|
|
e073e2b713 | ||
|
|
8343443bd7 | ||
|
|
c5ed66c40c | ||
|
|
de65b2396c | ||
|
|
c85cef57c8 | ||
|
|
6c9bae518a | ||
|
|
7232168037 | ||
|
|
9da06d8384 | ||
|
|
296a4721db | ||
|
|
f2badf7b6d | ||
|
|
766be1aa3c | ||
|
|
4812219e0d | ||
|
|
7b4e39aad2 | ||
|
|
fbff951e22 | ||
|
|
09198d5ec2 | ||
|
|
3666995f7f | ||
|
|
0572674279 | ||
|
|
19f2265161 | ||
|
|
f613449dff | ||
|
|
a1291b1b16 | ||
|
|
39ebc28396 | ||
|
|
6017714363 | ||
|
|
bff7092ce1 | ||
|
|
1741742617 | ||
|
|
b4a6bea1b4 | ||
|
|
57e06b2d2f | ||
|
|
0bc7363dae | ||
|
|
44b2140230 | ||
|
|
49bc934066 | ||
|
|
53d337f462 | ||
|
|
66e7791b95 | ||
|
|
2180c5ff23 | ||
|
|
2f4fa7572e | ||
|
|
5923506237 | ||
|
|
b9600654f8 | ||
|
|
6b0a082ac9 | ||
|
|
c5a108d672 | ||
|
|
23c2925baf | ||
|
|
fa4c72d59c | ||
|
|
d66d901204 | ||
|
|
b09eaf98cc | ||
|
|
7f9bf85958 | ||
|
|
d1d89fcd74 | ||
|
|
bc3f5700d4 | ||
|
|
3a938fd615 | ||
|
|
dc3729aec2 | ||
|
|
dd214ae5d1 | ||
|
|
8f7f8c5736 | ||
|
|
00701a8de4 | ||
|
|
fc41c9aa2f | ||
|
|
a5442eee0d | ||
|
|
9dcf5b5320 | ||
|
|
28b5295a6e | ||
|
|
8261ae34bd | ||
|
|
02baa9329c | ||
|
|
7f01c7b861 | ||
|
|
8d0f0c227a | ||
|
|
c8170bc9f3 | ||
|
|
83003b66b9 | ||
|
|
cbdb15bc32 | ||
|
|
712e15407d | ||
|
|
e424e19d1c | ||
|
|
546d8dee98 | ||
|
|
60b9fc679a | ||
|
|
79a4f24bc2 | ||
|
|
02b8ecf300 | ||
|
|
bdbc5a7a9d | ||
|
|
680fe18bac | ||
|
|
dd08b2e426 | ||
|
|
285b1630ee | ||
|
|
fdcaf9054f | ||
|
|
65b5585797 | ||
|
|
b31fdb202c | ||
|
|
d13d906d11 | ||
|
|
6a403ac916 | ||
|
|
eff54e3202 | ||
|
|
0a7dd7c3f7 | ||
|
|
cf7f962ed1 | ||
|
|
f412df29b5 | ||
|
|
31204bae6a | ||
|
|
a57cf08c00 | ||
|
|
c0171156fa | ||
|
|
a456e95139 | ||
|
|
7f8e2d0f7f | ||
|
|
d80aa68c40 | ||
|
|
81c9090ec9 | ||
|
|
0fa5c46f4b | ||
|
|
d75977140a | ||
|
|
b65440ba4e | ||
|
|
ee15f8b8c2 | ||
|
|
aebf8ba783 | ||
|
|
9f2436b123 | ||
|
|
cd774ea2df | ||
|
|
007f54bc26 | ||
|
|
9c03f3a9e3 | ||
|
|
292365a837 | ||
|
|
1091478e11 | ||
|
|
47b94b3c5a | ||
|
|
7cd62e7b26 | ||
|
|
3397f2407a | ||
|
|
52799659c8 | ||
|
|
86e88942b0 | ||
|
|
11592ebb98 | ||
|
|
83f4bfc53d | ||
|
|
43ed818015 | ||
|
|
fd7f5b991a | ||
|
|
feebcb339a | ||
|
|
0368d4e435 | ||
|
|
a57bad5bb9 | ||
|
|
a0ee1a40d4 | ||
|
|
5c5aa3551b | ||
|
|
bd7daf4072 | ||
|
|
dad844795f | ||
|
|
1ef20f232a | ||
|
|
78deaf8b38 | ||
|
|
41107af0d0 | ||
|
|
a1aec29ffd | ||
|
|
07dc8617a4 | ||
|
|
34cef1ae0a | ||
|
|
144841d88d | ||
|
|
b46a713968 | ||
|
|
4ec7c30e28 | ||
|
|
16c5825e3a | ||
|
|
0f1129e51e | ||
|
|
3e54201be8 | ||
|
|
c34fba4c22 | ||
|
|
625f8c7a2b | ||
|
|
41a4a98c0a | ||
|
|
c858d954a9 | ||
|
|
aa0410edb3 | ||
|
|
97cb61b7cf | ||
|
|
0408d98538 | ||
|
|
69e2f9640e | ||
|
|
efd20dc370 | ||
|
|
7a42598150 | ||
|
|
7a45d96d9a | ||
|
|
468a2553f8 | ||
|
|
a4f7ccdba1 | ||
|
|
a0b47aa4b3 | ||
|
|
ee6dd54ab3 | ||
|
|
518ca7cc9d | ||
|
|
37053a40b7 | ||
|
|
7eff8c9699 | ||
|
|
49d9030bf4 | ||
|
|
9e741c0348 | ||
|
|
95dc3c1a6c | ||
|
|
2fa7081f3f | ||
|
|
288773a727 | ||
|
|
06079115e6 | ||
|
|
5db21677dc | ||
|
|
5c7db88f10 | ||
|
|
0060e81fae | ||
|
|
1a6bf2d71b | ||
|
|
59a6de92d0 | ||
|
|
b7b013f669 | ||
|
|
d8be1eca90 | ||
|
|
d04f8965c3 | ||
|
|
ffdbe6f4da | ||
|
|
fafa915613 | ||
|
|
f5f0af0dcd | ||
|
|
23eb4d6b0b | ||
|
|
f9d6020c4f | ||
|
|
b9dfbdd5e8 | ||
|
|
8f9d708285 | ||
|
|
05b06d3eac | ||
|
|
8b68ab8ac7 | ||
|
|
80021d520f | ||
|
|
363cfa1998 | ||
|
|
9ea1a5cde6 | ||
|
|
faeb6bf6b8 | ||
|
|
1917b1346b | ||
|
|
3feaf9221d | ||
|
|
943b735150 | ||
|
|
02ce04261d | ||
|
|
eae5f4f5f9 | ||
|
|
8ec8a02924 | ||
|
|
12c34ef63d | ||
|
|
a54848b636 | ||
|
|
35c09940b4 | ||
|
|
cb4fdaab28 | ||
|
|
3501de22ed | ||
|
|
1f59fccc97 | ||
|
|
4307d23b00 | ||
|
|
b83345c91a | ||
|
|
76feb208bc | ||
|
|
efa49593da | ||
|
|
361d6fa22f | ||
|
|
f7d1b8f972 | ||
|
|
a9afc2dc2b | ||
|
|
8d949b97ea | ||
|
|
0d5a07ffe1 | ||
|
|
11972c2511 | ||
|
|
3081efebd8 | ||
|
|
b27039dcc8 | ||
|
|
847f107ac2 | ||
|
|
ec9766a544 | ||
|
|
7bdc148063 | ||
|
|
7284e9f100 | ||
|
|
03ecfbea25 | ||
|
|
eb1716e078 | ||
|
|
b11b8a2f22 | ||
|
|
845bb37c8c | ||
|
|
6f9f6495a0 | ||
|
|
04ef327a86 | ||
|
|
913b595587 | ||
|
|
7628af35ba | ||
|
|
cad8b7752b | ||
|
|
7175546f54 | ||
|
|
6186f46ec2 | ||
|
|
2413867bf3 | ||
|
|
545c539a08 | ||
|
|
b0cfed809f | ||
|
|
d5502e1527 | ||
|
|
714d02060c | ||
|
|
c8d0739692 | ||
|
|
d4b9d61e2b | ||
|
|
1f7f2f64ad | ||
|
|
f26ca31dbc | ||
|
|
92b6edc9a4 | ||
|
|
e1a2b46333 | ||
|
|
5744905f5a | ||
|
|
d7c27150d3 | ||
|
|
76a8260f1c | ||
|
|
0d8f43dba2 | ||
|
|
104c07cf6d | ||
|
|
43f244a076 | ||
|
|
e4bc41ed56 | ||
|
|
1c2275537d | ||
|
|
a062ff084e | ||
|
|
7a78cd33eb | ||
|
|
ff2dff5a51 | ||
|
|
d122b86913 | ||
|
|
43e45f7c28 | ||
|
|
ba93725f62 | ||
|
|
c32f0dfb02 | ||
|
|
73dcd49d92 | ||
|
|
56c2640900 | ||
|
|
b33c52616d | ||
|
|
7edc427ea7 | ||
|
|
3c8549b872 | ||
|
|
471b992d2d | ||
|
|
ab2ed7492b | ||
|
|
330cb7552c | ||
|
|
b31fb67eda | ||
|
|
874b8a5510 | ||
|
|
624899b65c | ||
|
|
d0bc6b96c4 | ||
|
|
1781e58189 | ||
|
|
9e536b5235 | ||
|
|
208956d5c6 | ||
|
|
60aba09614 | ||
|
|
da1c3346d1 | ||
|
|
ea4ee0d0f6 | ||
|
|
d940bebb90 | ||
|
|
77c6ce8a1e | ||
|
|
98c761c375 | ||
|
|
7166ad2ce7 | ||
|
|
7f24aee8fa | ||
|
|
8b16c08baa | ||
|
|
f7045d6b40 | ||
|
|
6b64b02192 | ||
|
|
43f37a6e12 | ||
|
|
9fc6d4efee | ||
|
|
ac375e468d | ||
|
|
1c8ce086df | ||
|
|
8b73e4b232 | ||
|
|
7c10d83b6b | ||
|
|
99259cc6c5 | ||
|
|
8062bb8bf7 | ||
|
|
0bb51d2ac0 | ||
|
|
cd9a30be4d | ||
|
|
98fd924bd1 | ||
|
|
20e0fe860f | ||
|
|
10d87dab92 | ||
|
|
cfb7ad21a2 | ||
|
|
cc90306052 | ||
|
|
b8f781b890 | ||
|
|
f4af3da4c2 | ||
|
|
a3f4143a67 | ||
|
|
b8c1a35c3a | ||
|
|
cd9345a54f | ||
|
|
159d8112da | ||
|
|
fc58822dd8 | ||
|
|
ce4c47f568 | ||
|
|
2d026fbcd8 | ||
|
|
79f1a75a96 | ||
|
|
b5a1da8649 | ||
|
|
87511d39e7 | ||
|
|
f0921a9bee | ||
|
|
d136b77b43 | ||
|
|
b2b29fe00e | ||
|
|
5e1e6c964f | ||
|
|
c3a4b97ba9 | ||
|
|
4cb39e3ebc | ||
|
|
2be1301542 | ||
|
|
83f54c3203 | ||
|
|
d7ddd4a491 | ||
|
|
090fc89b75 | ||
|
|
e5fad8efa5 | ||
|
|
7fa0266545 | ||
|
|
a4821577d8 | ||
|
|
9f67845ba2 | ||
|
|
f9bc2f3e99 | ||
|
|
8bba101ef7 | ||
|
|
cc6cf3bdd4 | ||
|
|
b1685ad765 | ||
|
|
332fec8f9c | ||
|
|
25bc8e2b56 | ||
|
|
71bb83d7de | ||
|
|
8871151cf4 | ||
|
|
32f672698d | ||
|
|
16a2495346 | ||
|
|
426f2d81ac | ||
|
|
3be3920929 | ||
|
|
8837b23e79 | ||
|
|
fcac2065ec | ||
|
|
26b4697d61 | ||
|
|
c7fb094497 | ||
|
|
52a83e5fa1 | ||
|
|
abb8ac8575 | ||
|
|
957e1bae89 | ||
|
|
710553f224 | ||
|
|
4569b5aefc | ||
|
|
b12c060c97 | ||
|
|
1c49c05e12 | ||
|
|
956a71e21f | ||
|
|
09576ab5b2 | ||
|
|
220ca58fa3 | ||
|
|
6a4546f803 | ||
|
|
a988fbc1a5 | ||
|
|
8741a407e8 | ||
|
|
3a8b5369eb | ||
|
|
41634904e8 | ||
|
|
3beb6032e9 | ||
|
|
92e33342cb | ||
|
|
033f3fc626 | ||
|
|
4b0521e40a | ||
|
|
9144377472 | ||
|
|
ee8671876a | ||
|
|
56de1fea0b | ||
|
|
92db23751d | ||
|
|
7da8f44a8e | ||
|
|
d1d44b3aa2 | ||
|
|
cf061d0c21 | ||
|
|
85c4218a6a | ||
|
|
4cd9b47f23 | ||
|
|
86c04b185e | ||
|
|
8b1056eb59 | ||
|
|
2b6206c6c5 | ||
|
|
b5c3b101d3 | ||
|
|
f60fed173d | ||
|
|
9c08f5194b | ||
|
|
c31ea8f632 | ||
|
|
08b2d7a278 | ||
|
|
82688aa4ca | ||
|
|
96e6ebdfa1 | ||
|
|
986cb57389 | ||
|
|
a39efd3204 | ||
|
|
350eeca6ec | ||
|
|
f686179f7a | ||
|
|
33d908db96 | ||
|
|
8e90917e5f | ||
|
|
aa39497793 | ||
|
|
fe2f170f1f | ||
|
|
20cdc999f3 | ||
|
|
ad7fa81b5e | ||
|
|
5cbf25260d | ||
|
|
9c9e6cb593 | ||
|
|
81fa16fb9c | ||
|
|
82e877393d | ||
|
|
0cf6a4cf19 | ||
|
|
e1a3e40326 | ||
|
|
ecf7ab790e | ||
|
|
e743a97d39 | ||
|
|
02320b616a | ||
|
|
bf1137a99b | ||
|
|
c7bafec390 | ||
|
|
5e2d3e7c81 | ||
|
|
61ab1f7904 | ||
|
|
d6a61c45ec | ||
|
|
f6e7693e39 | ||
|
|
0e605f9ada | ||
|
|
613a2adfca | ||
|
|
6a2dcb1d29 | ||
|
|
53a7c9c78a | ||
|
|
8955c614a8 | ||
|
|
1685aefda3 | ||
|
|
c7d5cd96d3 | ||
|
|
3a70f669ee | ||
|
|
cbfb278675 | ||
|
|
57771f411a | ||
|
|
c5991bc6f8 | ||
|
|
22df3fb8ef | ||
|
|
ea369afabf | ||
|
|
26b74e503f | ||
|
|
4a450269f5 | ||
|
|
e8fe17c906 | ||
|
|
e44bb3199c | ||
|
|
f327708f83 | ||
|
|
eee680686f | ||
|
|
74522dbaf8 | ||
|
|
0e9b13f2b3 | ||
|
|
117f24e0b6 | ||
|
|
0deeb7403f | ||
|
|
f639710d38 | ||
|
|
c70daf5c9c | ||
|
|
6d59b45e6f | ||
|
|
e81f1a8fcc | ||
|
|
540205763c | ||
|
|
ec450c30e5 | ||
|
|
ef9902c75a | ||
|
|
e367aa72f0 | ||
|
|
9384bed03d | ||
|
|
29e61bf432 | ||
|
|
510e56518a | ||
|
|
82004e3f2e | ||
|
|
2620baca91 | ||
|
|
f105b9386c | ||
|
|
83e5feec49 | ||
|
|
24dffe09a4 | ||
|
|
28052bff3c | ||
|
|
c2c37ad0d2 | ||
|
|
e5ac94421e | ||
|
|
5a306f1a70 | ||
|
|
ecb58fe3ed | ||
|
|
629a3b390b | ||
|
|
071b13f401 | ||
|
|
3b5b9636f3 | ||
|
|
8e125732b3 | ||
|
|
4ed6fe70ec | ||
|
|
8e0ae5f6c8 | ||
|
|
e6ec2c65bf | ||
|
|
45a4211793 | ||
|
|
68e85d8c5a | ||
|
|
8625a81689 | ||
|
|
61deb1f589 | ||
|
|
f68ada1013 | ||
|
|
a1df232de9 | ||
|
|
3ac0875b83 | ||
|
|
658dbad1b1 | ||
|
|
94f4930bd7 | ||
|
|
0bc515e3ab | ||
|
|
f7a00e0426 | ||
|
|
81e49026f8 | ||
|
|
1ae68019d3 | ||
|
|
fde5a2c353 | ||
|
|
2e316478d7 | ||
|
|
6c23a969d0 | ||
|
|
8e900aea69 | ||
|
|
16c32e53bd | ||
|
|
fde3cfa9ce | ||
|
|
fb15504294 | ||
|
|
dc219aa34f | ||
|
|
8357cd76ed | ||
|
|
6ef36ae53d | ||
|
|
716d3755fe | ||
|
|
3299aadf57 | ||
|
|
71ed6c90d1 | ||
|
|
0cc391141b | ||
|
|
f45b2baa4b | ||
|
|
e00aa23775 | ||
|
|
83c9476720 | ||
|
|
0f38bcab99 | ||
|
|
18d9947c0e | ||
|
|
3de2dd1931 | ||
|
|
847648f1ee | ||
|
|
d77a4a6bb9 | ||
|
|
05767cc1a7 | ||
|
|
0e5c7ef5c6 | ||
|
|
bc6773ac28 | ||
|
|
d39574aa22 | ||
|
|
b6795a4f04 | ||
|
|
b8fe03c74d | ||
|
|
9e877270a4 | ||
|
|
47b182e481 | ||
|
|
f680135e53 | ||
|
|
f3aecbd034 | ||
|
|
15776c01ac | ||
|
|
8fc342770b | ||
|
|
27c1bbeb20 | ||
|
|
b5be0eb8ba | ||
|
|
277abfa036 | ||
|
|
a4bb7a1c0e | ||
|
|
89134305e8 | ||
|
|
f7b4fe84e1 | ||
|
|
eb085ea9a9 | ||
|
|
2c29200bbf | ||
|
|
1e2728423a | ||
|
|
24c9283a55 | ||
|
|
92e1afedfb | ||
|
|
b86f06b818 | ||
|
|
2f3a0cc756 | ||
|
|
713cd01b6b | ||
|
|
888cc94709 | ||
|
|
0926f57391 | ||
|
|
78396d28d7 | ||
|
|
9edcd5a330 | ||
|
|
dc9a04dbc3 | ||
|
|
1d675067fe | ||
|
|
f69bc3434a | ||
|
|
17c8d5ceaf | ||
|
|
caf133b6a2 | ||
|
|
dcfdb6d242 | ||
|
|
40535390b1 | ||
|
|
b86d7425ac | ||
|
|
907803eafa | ||
|
|
050a3e3584 | ||
|
|
f182b12f54 | ||
|
|
1052bbee57 | ||
|
|
16a970feb3 | ||
|
|
a185377258 | ||
|
|
0871045b3c | ||
|
|
4e2b1e4ecc | ||
|
|
b3f7b16f30 | ||
|
|
2b7d96728b | ||
|
|
13e5eab8f4 | ||
|
|
fd3fbb3dbf | ||
|
|
7abd8af2e6 | ||
|
|
3d97f5a9e3 | ||
|
|
d70ed3cae2 | ||
|
|
814fe872f6 | ||
|
|
354f0057c1 | ||
|
|
390e050801 | ||
|
|
f8a157ddbe | ||
|
|
8d4abd42ec | ||
|
|
4a82af2bcd | ||
|
|
bfeb9f64e2 | ||
|
|
071a2ff47f | ||
|
|
6678669188 | ||
|
|
3c6299ecc6 | ||
|
|
afe989205f | ||
|
|
5955e2e845 | ||
|
|
d75836e88f | ||
|
|
2500dfdd80 | ||
|
|
cfa496653f | ||
|
|
e4b9920b56 | ||
|
|
ec156c203e | ||
|
|
13fd91b135 | ||
|
|
123a638080 | ||
|
|
c165a1d3de | ||
|
|
40d2cdf1b3 | ||
|
|
df850c1a82 | ||
|
|
565199df70 | ||
|
|
c9599c3d86 | ||
|
|
988c90643d | ||
|
|
62951a502c | ||
|
|
05ec034f7a | ||
|
|
4e5bf7929c | ||
|
|
e39149337c | ||
|
|
d14da5612b | ||
|
|
e42852297d | ||
|
|
1501e0f037 | ||
|
|
2d3fd0b736 | ||
|
|
17a77ba02b | ||
|
|
2541e25ee6 | ||
|
|
0c831f0dd8 | ||
|
|
7799b3f904 | ||
|
|
1762fdc859 | ||
|
|
339ce4734b | ||
|
|
3f6b469c3c | ||
|
|
1db1a6c86d | ||
|
|
aca62368d9 | ||
|
|
c0bf3f8872 | ||
|
|
00f94a6d81 | ||
|
|
442f614f1b | ||
|
|
2be63c60ee | ||
|
|
039cf7a83f | ||
|
|
0b502b9f8f | ||
|
|
a77fec4475 | ||
|
|
dfa9a09ded | ||
|
|
40f9d2d4fb | ||
|
|
1da30b61ef | ||
|
|
175fab0eb5 | ||
|
|
b311fbe44d | ||
|
|
636b82c28d | ||
|
|
183f06e5fa | ||
|
|
ac7d4ef048 | ||
|
|
0c5087960e | ||
|
|
e4be8c84f3 | ||
|
|
ce93663cb5 | ||
|
|
952442b32d | ||
|
|
e06f367eb9 | ||
|
|
c0bab98714 | ||
|
|
616f3864fb | ||
|
|
5f3974aac7 | ||
|
|
98a4bfc6c5 | ||
|
|
a518f13a2d | ||
|
|
981f6f7e6d | ||
|
|
253982a63f | ||
|
|
03e342a24d | ||
|
|
7b9db4bf4d | ||
|
|
fc92130fa4 | ||
|
|
e6d56fec79 | ||
|
|
c3094ce73b | ||
|
|
330577edb0 | ||
|
|
de6d5288f4 | ||
|
|
6e96e8bc9a | ||
|
|
10f8638d73 | ||
|
|
0b25e94a68 | ||
|
|
3d769634c6 | ||
|
|
17f8ca60cf | ||
|
|
544577bad8 | ||
|
|
24a0035ac0 | ||
|
|
cdea03bbb2 | ||
|
|
2783809ae9 | ||
|
|
565c05b4f3 | ||
|
|
e1d90f8ea3 | ||
|
|
60321902ec | ||
|
|
9ac0995fd4 | ||
|
|
00551fae2c | ||
|
|
42c937848d | ||
|
|
f0d63c69c1 | ||
|
|
d09f980a64 | ||
|
|
f09a8bd0fe | ||
|
|
7dcc8cabbb | ||
|
|
a816e0d1c1 | ||
|
|
01b3daa051 | ||
|
|
2bf9bb8935 | ||
|
|
218a49cb95 | ||
|
|
66ea0cf308 | ||
|
|
99a77cdcc4 | ||
|
|
b021d80300 | ||
|
|
798c40df23 | ||
|
|
d95007fae1 | ||
|
|
2745f1cfa0 | ||
|
|
9f7b78d0f1 | ||
|
|
91b0c95101 | ||
|
|
6d193699c1 | ||
|
|
a63cd8bb7b | ||
|
|
599c8d6fd3 | ||
|
|
305ea52737 | ||
|
|
7f26d8d49e | ||
|
|
09dbad5e05 | ||
|
|
de20856cc1 | ||
|
|
5c1e7f97dd | ||
|
|
ee9fdc8d1a | ||
|
|
c5269a9a3c | ||
|
|
79599e9b06 | ||
|
|
dd47234b4e | ||
|
|
9f14dc8196 | ||
|
|
286d313e69 | ||
|
|
e69f2cabf1 | ||
|
|
246c4dc8f2 | ||
|
|
7d7a12a903 | ||
|
|
69809eb243 | ||
|
|
db85dc82b5 | ||
|
|
a291a473b5 | ||
|
|
e8ae32d6d4 | ||
|
|
1d79d26dac | ||
|
|
b1f06462da | ||
|
|
f0de5dbf80 | ||
|
|
ad0f28d9ae | ||
|
|
bb89e49856 | ||
|
|
f4952d5865 | ||
|
|
ab655910ec | ||
|
|
b0666a0efd | ||
|
|
d6540a8c1c | ||
|
|
1016a98712 | ||
|
|
1a8574ea86 | ||
|
|
eeee8b2818 | ||
|
|
f68ecd421d | ||
|
|
0e582b10ce | ||
|
|
4bfa8054cc | ||
|
|
010d1f736b | ||
|
|
c36d4bcad1 | ||
|
|
e2c71a7555 | ||
|
|
1bb6a68b4b | ||
|
|
055ea2e3f1 | ||
|
|
ad8b6163ac | ||
|
|
2c405c1cad | ||
|
|
cea975da8b | ||
|
|
217241eb6a | ||
|
|
85783e49c9 | ||
|
|
1d5e1a443b | ||
|
|
e31a5e69a2 | ||
|
|
59eae1535f | ||
|
|
622dcbaf78 | ||
|
|
bc736863dc | ||
|
|
5306cb4666 | ||
|
|
2e30a954b6 | ||
|
|
f170f5dc90 | ||
|
|
7901bca172 | ||
|
|
736a168233 | ||
|
|
556f4bd9d1 | ||
|
|
2c9fe98ab4 | ||
|
|
a8003a3f5f | ||
|
|
5a31c2be5f | ||
|
|
e32f3fc265 | ||
|
|
5a26c55ffb | ||
|
|
6aa18fa8ec | ||
|
|
995f8eedc3 | ||
|
|
ea3ba39e33 | ||
|
|
580cd0dcb0 | ||
|
|
1e95a45649 | ||
|
|
db6af2d2eb | ||
|
|
1008d10112 | ||
|
|
7b27970e64 | ||
|
|
c9c7d7194f | ||
|
|
9f364009ca | ||
|
|
58dd4f0002 | ||
|
|
4ca16d2c35 | ||
|
|
bc3b8eee00 | ||
|
|
7ea327df08 | ||
|
|
94f12c9e5b | ||
|
|
b273d0ecc9 | ||
|
|
ff44166aa4 | ||
|
|
2a06316d46 | ||
|
|
aae437df20 | ||
|
|
cfc516ce02 | ||
|
|
db6e547d3a | ||
|
|
e51fe3cd3b | ||
|
|
14a6e541e5 | ||
|
|
f9d3bc3c43 | ||
|
|
ad6f15671b | ||
|
|
f1f946c9ef | ||
|
|
38ca54ac55 | ||
|
|
341609bb39 | ||
|
|
1875d2a980 | ||
|
|
d888ba6ee4 | ||
|
|
b9fd3acf75 | ||
|
|
ed9ee69f2f | ||
|
|
d436b4b157 | ||
|
|
2855f87544 | ||
|
|
07ae3bad4d | ||
|
|
81651a4120 | ||
|
|
c456e73ab1 | ||
|
|
e919e35ea0 | ||
|
|
bea768bf8f | ||
|
|
32ec94b3b9 | ||
|
|
48553494ca | ||
|
|
163ee377c4 | ||
|
|
d3b5bd1f13 | ||
|
|
624242bbab | ||
|
|
6b49921e54 | ||
|
|
3439de3222 | ||
|
|
f74f48def7 | ||
|
|
0fd25c7089 | ||
|
|
eeb1044718 | ||
|
|
c32da56c92 | ||
|
|
02d5bce712 | ||
|
|
1baf06adea | ||
|
|
60a5049d05 | ||
|
|
692f0c0326 | ||
|
|
7ddcb36ad2 | ||
|
|
91700a3c1c | ||
|
|
5da93336fa | ||
|
|
feb1faec4f | ||
|
|
82e28f1728 | ||
|
|
bf3912a67f | ||
|
|
fe68b1e778 | ||
|
|
546ca9d0b2 | ||
|
|
14d5309637 | ||
|
|
e871708f41 | ||
|
|
135eae4931 | ||
|
|
beee84775e | ||
|
|
62a13bfaf5 | ||
|
|
42e0f67ce8 | ||
|
|
50a7d3a79e | ||
|
|
300f91db17 | ||
|
|
8fad2a1981 | ||
|
|
0e427d4799 | ||
|
|
0cb700ac7b | ||
|
|
23f03813eb | ||
|
|
44bedc6b8c | ||
|
|
4acfe59f78 | ||
|
|
cc66db4a33 | ||
|
|
cf87b00781 | ||
|
|
85b6e70132 | ||
|
|
446c2c7206 | ||
|
|
a66a472e9e | ||
|
|
d438f99f25 | ||
|
|
a2ae008755 | ||
|
|
12333b2bd3 | ||
|
|
f09106c3a9 | ||
|
|
05226c912e | ||
|
|
ef9eb0972d | ||
|
|
19b7803ca9 | ||
|
|
9f1726cc99 | ||
|
|
85c68d2fff | ||
|
|
0f924cdbba | ||
|
|
9433f337be | ||
|
|
feacd6544a | ||
|
|
0b79b180bb | ||
|
|
28bce56334 | ||
|
|
d26e7efb6a | ||
|
|
3d3b5b4404 | ||
|
|
db3cabb768 | ||
|
|
3ccf4b40b8 | ||
|
|
3c77fd1415 | ||
|
|
ff14d887bb | ||
|
|
10221f8b16 | ||
|
|
178fcccaac | ||
|
|
4f6f0aea26 | ||
|
|
332d093e72 | ||
|
|
6c275aefe8 | ||
|
|
1dd5efeb22 | ||
|
|
2ad0ec12dd |
@@ -4,4 +4,4 @@ TabWidth: 4
|
||||
IndentWidth: 4
|
||||
UseTab: Always
|
||||
ColumnLimit: 100
|
||||
Language: Cpp
|
||||
Language: Cpp
|
||||
|
||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
DOCKER_REGISTRY_USERNAME: ucentral
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
@@ -58,10 +58,10 @@ jobs:
|
||||
- name: Get base branch name and set as output
|
||||
id: get_base_branch
|
||||
run: |
|
||||
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/master/main/g')
|
||||
echo "branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/master/main/g')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
- docker
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
|
||||
2
.github/workflows/enforce-jira-issue-key.yml
vendored
2
.github/workflows/enforce-jira-issue-key.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
|
||||
41
.github/workflows/openapi-pages.yml
vendored
Normal file
41
.github/workflows/openapi-pages.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Update OpenAPI docs on GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'openapi/**'
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
docsgen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Generate static HTML page with docs from OpenAPI definition
|
||||
run: |
|
||||
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralgw/master/openapi/owgw.yaml -g html2 --skip-validate-spec -o /local/
|
||||
|
||||
- name: Update OpenAPI docs
|
||||
run: |
|
||||
mkdir tmp-docs
|
||||
mv index.html tmp-docs/index.html
|
||||
mkdir -p ~/.ssh
|
||||
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
||||
echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
|
||||
git config --global credential.helper store
|
||||
git config --global user.email "tip-automation@telecominfraproject.com"
|
||||
git config --global user.name "TIP Automation User"
|
||||
git pull
|
||||
git checkout gh-pages || git checkout -b gh-pages
|
||||
rm -rf docs
|
||||
mv tmp-docs docs
|
||||
git add docs
|
||||
git commit -m'Update OpenAPI docs for GitHub pages'
|
||||
git push --set-upstream origin gh-pages
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
HELM_REPO_USERNAME: ucentral
|
||||
steps:
|
||||
- name: Checkout uCentral assembly chart repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: wlan-cloud-ucentralgw
|
||||
|
||||
|
||||
107
CMakeLists.txt
107
CMakeLists.txt
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owgw VERSION 2.6.0)
|
||||
project(owgw VERSION 2.8.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -30,19 +30,26 @@ else()
|
||||
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
|
||||
endif()
|
||||
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
add_compile_options(-fsanitize=undefined)
|
||||
add_link_options(-fsanitize=undefined)
|
||||
endif()
|
||||
|
||||
find_package(Git QUIET)
|
||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_RESULT
|
||||
OUTPUT_VARIABLE GIT_HASH)
|
||||
if(NOT GIT_RESULT EQUAL "0")
|
||||
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
|
||||
message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
|
||||
endif()
|
||||
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
||||
endif()
|
||||
|
||||
add_definitions(-DTIP_GATEWAY_SERVICE="1")
|
||||
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -64,12 +71,6 @@ include_directories(/usr/local/include /usr/local/opt/openssl/include src inclu
|
||||
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
|
||||
|
||||
add_compile_options(-Wall -Wextra)
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
add_compile_options(-fsanitize=undefined)
|
||||
add_link_options(-fsanitize=undefined)
|
||||
endif()
|
||||
|
||||
add_executable( owgw
|
||||
build
|
||||
@@ -80,10 +81,54 @@ add_executable( owgw
|
||||
src/framework/OpenWifiTypes.h
|
||||
src/framework/orm.h
|
||||
src/framework/StorageClass.h
|
||||
src/framework/MicroServiceErrorHandler.h
|
||||
src/framework/UI_WebSocketClientServer.cpp
|
||||
src/framework/UI_WebSocketClientServer.h
|
||||
src/framework/UI_WebSocketClientNotifications.cpp
|
||||
src/framework/UI_WebSocketClientNotifications.h
|
||||
src/framework/utils.h
|
||||
src/framework/utils.cpp
|
||||
src/framework/AppServiceRegistry.h
|
||||
src/framework/SubSystemServer.cpp
|
||||
src/framework/SubSystemServer.h
|
||||
src/framework/RESTAPI_utils.h
|
||||
src/framework/AuthClient.cpp
|
||||
src/framework/AuthClient.h
|
||||
src/framework/MicroServiceNames.h
|
||||
src/framework/MicroServiceFuncs.h
|
||||
src/framework/OpenAPIRequests.cpp
|
||||
src/framework/OpenAPIRequests.h
|
||||
src/framework/MicroServiceFuncs.cpp
|
||||
src/framework/ALBserver.cpp
|
||||
src/framework/ALBserver.h
|
||||
src/framework/KafkaManager.cpp
|
||||
src/framework/KafkaManager.h
|
||||
src/framework/RESTAPI_RateLimiter.h
|
||||
src/framework/WebSocketLogger.h
|
||||
src/framework/RESTAPI_GenericServerAccounting.h
|
||||
src/framework/CIDR.h
|
||||
src/framework/RESTAPI_Handler.cpp
|
||||
src/framework/RESTAPI_Handler.h
|
||||
src/framework/RESTAPI_ExtServer.h
|
||||
src/framework/RESTAPI_ExtServer.cpp
|
||||
src/framework/RESTAPI_IntServer.cpp
|
||||
src/framework/RESTAPI_IntServer.h
|
||||
src/framework/RESTAPI_SystemCommand.h
|
||||
src/framework/RESTAPI_WebSocketServer.h
|
||||
src/framework/RESTAPI_SystemConfiguration.h
|
||||
src/framework/EventBusManager.cpp
|
||||
src/framework/EventBusManager.h
|
||||
src/framework/RESTAPI_PartHandler.h
|
||||
src/framework/MicroService.cpp
|
||||
src/framework/MicroServiceExtra.h
|
||||
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
|
||||
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
|
||||
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
|
||||
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
|
||||
src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
|
||||
src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
|
||||
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
|
||||
src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
|
||||
src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
|
||||
src/RESTAPI/RESTAPI_devices_handler.cpp src/RESTAPI/RESTAPI_devices_handler.h
|
||||
src/RESTAPI/RESTAPI_device_handler.cpp src/RESTAPI/RESTAPI_device_handler.h
|
||||
src/RESTAPI/RESTAPI_device_commandHandler.cpp src/RESTAPI/RESTAPI_device_commandHandler.h
|
||||
@@ -105,9 +150,8 @@ add_executable( owgw
|
||||
src/storage/storage_tables.cpp
|
||||
src/RESTAPI/RESTAPI_routers.cpp
|
||||
src/Daemon.cpp src/Daemon.h
|
||||
src/WS_Server.cpp src/WS_Server.h
|
||||
src/AP_WS_Server.cpp src/AP_WS_Server.h
|
||||
src/StorageService.cpp src/StorageService.h
|
||||
src/DeviceRegistry.cpp src/DeviceRegistry.h
|
||||
src/CommandManager.cpp src/CommandManager.h
|
||||
src/CentralConfig.cpp src/CentralConfig.h
|
||||
src/FileUploader.cpp src/FileUploader.h
|
||||
@@ -118,7 +162,40 @@ add_executable( owgw
|
||||
src/TelemetryStream.cpp src/TelemetryStream.h
|
||||
src/framework/ConfigurationValidator.cpp src/framework/ConfigurationValidator.h
|
||||
src/ConfigurationCache.h
|
||||
src/CapabilitiesCache.h src/FindCountry.h src/rttys/RTTYS_server.cpp src/rttys/RTTYS_server.h src/rttys/RTTYS_device.cpp src/rttys/RTTYS_device.h src/rttys/RTTYS_ClientConnection.cpp src/rttys/RTTYS_ClientConnection.h src/rttys/RTTYS_WebServer.cpp src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h src/SDKcalls.cpp src/SDKcalls.h src/StateUtils.cpp src/StateUtils.h src/WS_ReactorPool.h src/WS_Connection.h src/WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h src/framework/ow_constants.h src/GwWebSocketClient.cpp src/GwWebSocketClient.h src/framework/WebSocketClientNotifications.h src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h src/ParseWifiScan.h src/RADIUS_helpers.h src/VenueBroadcaster.h src/sdks/sdk_prov.h)
|
||||
src/CapabilitiesCache.h src/FindCountry.h
|
||||
src/rttys/RTTYS_server.cpp
|
||||
src/rttys/RTTYS_server.h
|
||||
src/rttys/RTTYS_WebServer.cpp
|
||||
src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h
|
||||
src/SDKcalls.cpp
|
||||
src/SDKcalls.h
|
||||
src/StateUtils.cpp src/StateUtils.h
|
||||
src/AP_WS_ReactorPool.h
|
||||
src/AP_WS_Connection.h
|
||||
src/AP_WS_Connection.cpp
|
||||
src/TelemetryClient.h src/TelemetryClient.cpp
|
||||
src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h
|
||||
src/framework/ow_constants.h
|
||||
src/GwWebSocketClient.cpp src/GwWebSocketClient.h
|
||||
src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h
|
||||
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h
|
||||
src/ParseWifiScan.h
|
||||
src/RADIUS_helpers.h
|
||||
src/VenueBroadcaster.h
|
||||
src/sdks/sdk_prov.h
|
||||
src/AP_WS_Process_connect.cpp
|
||||
src/AP_WS_Process_state.cpp
|
||||
src/AP_WS_Process_healthcheck.cpp
|
||||
src/AP_WS_Process_log.cpp
|
||||
src/AP_WS_Process_crashlog.cpp
|
||||
src/AP_WS_Process_ping.cpp
|
||||
src/AP_WS_Process_cfgpending.cpp
|
||||
src/AP_WS_Process_recovery.cpp
|
||||
src/AP_WS_Process_deviceupdate.cpp
|
||||
src/AP_WS_Process_telemetry.cpp
|
||||
src/AP_WS_Process_venuebroadcast.cpp
|
||||
src/RADSEC_server.h
|
||||
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h src/framework/RESTAPI_SystemConfiguration.h src/ScriptManager.cpp src/ScriptManager.h src/RESTAPI/RESTAPI_scripts_handler.cpp src/RESTAPI/RESTAPI_scripts_handler.h src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h src/storage/storage_scripts.cpp src/storage/storage_scripts.h src/SignatureMgr.cpp src/SignatureMgr.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
|
||||
@@ -142,4 +219,4 @@ if(NOT SMALL_BUILD)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(owgw PUBLIC PocoJSON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
63
Dockerfile
63
Dockerfile
@@ -1,15 +1,22 @@
|
||||
FROM alpine:3.15 AS build-base
|
||||
ARG DEBIAN_VERSION=11.5-slim
|
||||
ARG POCO_VERSION=poco-tip-v2
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
ARG JSON_VALIDATOR_VERSION=2.1.0
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
FROM debian:$DEBIAN_VERSION AS build-base
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
make cmake g++ git \
|
||||
unixodbc-dev postgresql-dev mariadb-dev \
|
||||
librdkafka-dev boost-dev openssl-dev \
|
||||
zlib-dev nlohmann-json
|
||||
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
|
||||
librdkafka-dev libboost-all-dev libssl-dev \
|
||||
zlib1g-dev nlohmann-json3-dev ca-certificates libfmt-dev
|
||||
|
||||
FROM build-base AS poco-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
ARG POCO_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -18,22 +25,12 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS cppkafka-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
ARG CPPKAFKA_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -44,8 +41,10 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
ARG JSON_VALIDATOR_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
@@ -67,8 +66,6 @@ COPY --from=cppkafka-build /usr/local/include /usr/local/include
|
||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
|
||||
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
|
||||
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
|
||||
COPY --from=fmtlib-build /usr/local/include /usr/local/include
|
||||
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
|
||||
|
||||
WORKDIR /owgw
|
||||
RUN mkdir cmake-build
|
||||
@@ -76,21 +73,21 @@ WORKDIR /owgw/cmake-build
|
||||
RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM alpine:3.15
|
||||
FROM debian:$DEBIAN_VERSION
|
||||
|
||||
ENV OWGW_USER=owgw \
|
||||
OWGW_ROOT=/owgw-data \
|
||||
OWGW_CONFIG=/owgw-data
|
||||
|
||||
RUN addgroup -S "$OWGW_USER" && \
|
||||
adduser -S -G "$OWGW_USER" "$OWGW_USER"
|
||||
RUN useradd "$OWGW_USER"
|
||||
|
||||
RUN mkdir /openwifi
|
||||
RUN mkdir -p "$OWGW_ROOT" "$OWGW_CONFIG" && \
|
||||
chown "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
|
||||
|
||||
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
|
||||
mariadb-connector-c libpq unixodbc postgresql-client
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
||||
libmariadb-dev-compat libpq5 unixodbc postgresql-client libfmt7 sqlite3
|
||||
|
||||
COPY readiness_check /readiness_check
|
||||
COPY test_scripts/curl/cli /cli
|
||||
@@ -100,11 +97,13 @@ COPY docker-entrypoint.sh /
|
||||
COPY wait-for-postgres.sh /
|
||||
COPY rtty_ui /dist/rtty_ui
|
||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
|
||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
|
||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
|
||||
|
||||
COPY --from=owgw-build /owgw/cmake-build/owgw /openwifi/owgw
|
||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib /usr/local/lib/
|
||||
COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib
|
||||
COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib/
|
||||
|
||||
RUN ldconfig
|
||||
|
||||
EXPOSE 15002 16002 16003 17002 16102
|
||||
|
||||
|
||||
@@ -18,17 +18,29 @@ System messages are what maintains the collection of micro-services working on t
|
||||
}
|
||||
```
|
||||
|
||||
### Responsibilities
|
||||
Each micro service is responsible to generate its own messages and keep track of messages coming from other
|
||||
micro services. This is necessary so that any micro service may reach our any other micro service. This provides
|
||||
discovery for any micro service. All current micro services provided in OpenWiFi perform these functions. If you leverage
|
||||
the C++ framework, this functionality if performed automatically.
|
||||
|
||||
### `event-type`
|
||||
When a service joins the bus, it should generate an event-type of `join`. When a service shutdown, it should generate a `leave` event-type. Every 30 seconds, a service
|
||||
should generate a `keep-alive` message.
|
||||
Each micro service is responsible to generate and consume these events
|
||||
|
||||
#### `join` event
|
||||
When a service start and joins the bus, it should generate an event-type of `join`.
|
||||
|
||||
### `leave` event
|
||||
When a service shuts down, it should generate a `leave` event-type.
|
||||
|
||||
### `keep-alive` event
|
||||
Every 30 seconds, a service should generate a `keep-alive` message.
|
||||
|
||||
|
||||
### `id`
|
||||
You should generate a random number from some unique factor for the system. This ID is used to identify different services. You should reuse that ID
|
||||
when you restart.
|
||||
|
||||
## Micro-service maintaining bus state
|
||||
A micro-service should maintain its own lists of available micro-services by looking at the messages it receives and keep a list.
|
||||
|
||||
## The `type`
|
||||
The `type` in the system message is oen of the following:
|
||||
```c++
|
||||
@@ -47,11 +59,11 @@ The `type` in the system message is oen of the following:
|
||||
The `type` is what you should use to find the `privateEndPoint` you are looking to communicate with.
|
||||
|
||||
### Example
|
||||
Assume you want to communicate with the gateway t pconfigure a device.
|
||||
Assume you want to communicate with the gateway to configure a device.
|
||||
|
||||
```text
|
||||
1. Look into my list of current Micro-services for the type=owgw.
|
||||
2. Use the priovateEndPoint associated with that entry
|
||||
2. Use the privateEndPoint associated with that entry
|
||||
```
|
||||
|
||||
## REST API calls on the private interface
|
||||
@@ -72,9 +84,9 @@ This is the `publicEndPoint` you included in your `system-messages`.
|
||||
This method can _only_ be used to any another `privateEndPoint` in the system. You can use the exact same EndPoints provided in the OpenAPI files for any of the services.
|
||||
|
||||
## OpenAPI Integration
|
||||
To appear in the UI consoles, a micro-service should ne able to handle a get to the `/api/v1/system` endpoint on its `publicEndPoint` interface.
|
||||
To appear in the UI consoles, a microservice should be able to handle a get to the `/api/v1/system` endpoint on its `publicEndPoint` interface.
|
||||
|
||||
Here is a brief description of what the micro-service should answer:
|
||||
Here is a brief description of what the microservice should answer:
|
||||
```yaml
|
||||
/system:
|
||||
get:
|
||||
|
||||
@@ -5,6 +5,11 @@ This document will describe how the API is built and how to use it.
|
||||
This uses OpenAPI definition 3.0 and can be found [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/openapi/ucentral/owgw.yaml).
|
||||
All endpoints begin with `/api/v1`.
|
||||
|
||||
## OpenAPI docs
|
||||
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralgw).
|
||||
|
||||
Also you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralgw/master/openapi/owgw.yaml)) to get interactive docs page.
|
||||
|
||||
## The flow
|
||||
In order to use any of the API calls, you must obtain a token (I know - shocking). You do so by calling the end-point
|
||||
`/oauth2`. Once you obtain that `access-token`, you will need to pass it in the headers under `Authorization: Bearer <place your token here>`.
|
||||
|
||||
64
PROTOCOL.md
64
PROTOCOL.md
@@ -298,7 +298,8 @@ Controller sends this command when it believes the device should upgrade its fir
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
|
||||
"uri" : <URI to download the firmware>
|
||||
"uri" : <URI to download the firmware>,
|
||||
"FWsignature" : <string representation of the signature for the FW> (optional)
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
@@ -318,6 +319,13 @@ The device should answer:
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
Here are the error values
|
||||
```text
|
||||
0: No error
|
||||
1: Bad firmware
|
||||
2: Missing signature
|
||||
```
|
||||
|
||||
|
||||
#### Controller wants the device to perform a factory reset
|
||||
Controller sends this command when it believes the device should upgrade its firmware.
|
||||
@@ -423,44 +431,6 @@ The device should answer:
|
||||
- 1 : device cannot flash LEDs because it does not have any.
|
||||
- 2 : device rejects the request. `text` should include information as to why.
|
||||
|
||||
#### Controller sends a device specific command
|
||||
Controller sends this command specific to this device. The command is proprietary and must be agreed upon by the device
|
||||
and the controller.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "perform" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"when" : Optional - <UTC time when to perform this command, 0 mean immediate, this is a suggestion>,
|
||||
"command" : <this is device specific and is TEXT only>,
|
||||
"payload" : <JSON Document: containing additional information about the command>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : 0 or an error number,
|
||||
"text" : <description of the error or success>,
|
||||
"when" : <in UTC time in seconds>,
|
||||
"resultCode" : <0 or an appropriate error code>,
|
||||
"resultText" : <any text resulting from the command. This is propietary to each command>
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
##### The device answer
|
||||
The device should answer with teh above message. The `error` value should be interpreted the following way:
|
||||
- 0 : the command was performed as requested and the reults of the command is available in the `resultCode` and `resultText` parameters.
|
||||
- 1 : the command will be performed in the future and `when` shows that time. The `resultCode` and `resultText` dod not contain anything relevant.
|
||||
- 2 : the command cannot be performed as indicated. `resultCode` and `resultText` may contain some indication as to why.
|
||||
|
||||
#### Controller wants the device to perform a trace
|
||||
Controller sends this command when it needs the device to perform a trace (i.e. tcpdump).
|
||||
```json
|
||||
@@ -711,9 +681,11 @@ Controller sends this command to run a predefined script. Extreme care must be t
|
||||
"method" : "script" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"type" : <one of "shell", "ucode">,
|
||||
"script" : <text blob containing the script>,
|
||||
"timeout" : <max timeout in seconds, default is 30>,
|
||||
"type" : <one of "shell", "ucode", "bundle">,
|
||||
"script" : <text blob containing the script, This must be vase64 encoded>,
|
||||
"timeout" : <max timeout in seconds, default is 30, unused if URI is supplied>,
|
||||
"uri": "<upload script results using this URI>",
|
||||
"signature" : "<signature for script>: must be supplied to restricted devices",
|
||||
"when" : <time when this will be performed as UTC seconds>
|
||||
},
|
||||
"id" : <some number>
|
||||
@@ -749,7 +721,10 @@ Should other messages get larger, the client may decide to compress the. Only me
|
||||
|
||||
#### Identifying a compressed message
|
||||
A compressed message has a single member to the `params` field. It's only parameter must be called `compress_64`. Any other elements under
|
||||
params will be dropped. Additional compression schemes may be developed later.
|
||||
params will be dropped. Additional compression schemes may be developed later. The device should also include
|
||||
a hint to the actual size of the uncompressed data. This would allow listeners to create sufficiently sized
|
||||
buffers right away instead of guessing. If the device includes `compressed_sz` as the second field in the
|
||||
params objects. This should be an unsigned int representing the total size of the uncompressed data.
|
||||
|
||||
#### How to compress
|
||||
The original `params` element should be run through `zlib:compress` and then encoded using base64, and passed as a string. Here is an example
|
||||
@@ -759,7 +734,8 @@ of the completed message. The following should how the `state` event could be co
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "state" ,
|
||||
"params" : {
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk"
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk",
|
||||
"compress_sz" : 212322
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
147
README.md
147
README.md
@@ -11,16 +11,16 @@ In order to build the uCentralGW, you will need to install its dependencies, whi
|
||||
- boost
|
||||
- POCO 1.10.1 or later
|
||||
- a C++17 compiler
|
||||
- libyaml
|
||||
- openssl
|
||||
- libpq-dev (PortgreSQL development libraries)
|
||||
- mysql-client (MySQL client)
|
||||
- librdkafka
|
||||
- cppkafka
|
||||
-
|
||||
|
||||
The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
|
||||
framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
|
||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/stephb9959/poco). Building
|
||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/AriliaWireless/poco). Building
|
||||
Poco may take several minutes depending on the platform you are building on.
|
||||
|
||||
### Ubuntu
|
||||
@@ -29,9 +29,10 @@ These instructions have proven to work on Ubuntu 20.4.
|
||||
sudo apt install git cmake g++ libssl-dev libmariadb-dev
|
||||
sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
|
||||
sudo apt install librdkafka-dev // default-libmysqlclient-dev
|
||||
sudo apt install nlohmann-json-dev
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -40,7 +41,7 @@ cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -49,17 +50,7 @@ cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/nlohmann/json.git
|
||||
cd json
|
||||
git checkout tags/v3.10.2
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -67,6 +58,14 @@ cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
|
||||
cd fmtlib
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -81,12 +80,12 @@ make -j 8
|
||||
### Fedora
|
||||
The following instructions have proven to work on Fedora 33
|
||||
```
|
||||
sudo yum install cmake g++ openssl-devel unixODBC-devel mysql-devel mysql apr-util-devel boost boost-devel
|
||||
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
|
||||
sudo yum install yaml-cpp-devel lua-devel
|
||||
sudo dnf install postgresql.x86_64 librdkafka-devel
|
||||
sudo dnf install postgresql-devel
|
||||
sudo dnf install postgresql-devel json-devel
|
||||
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -94,7 +93,7 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -102,6 +101,15 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -111,45 +119,61 @@ cmake ..
|
||||
make
|
||||
|
||||
```
|
||||
|
||||
### OSX Build
|
||||
The following instructions have proven to work on OSX Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
|
||||
|
||||
### macOS Build
|
||||
The following instructions have proven to work on macOS Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
|
||||
```
|
||||
brew install openssl
|
||||
brew install cmake
|
||||
brew install libpq
|
||||
brew install mysql-client
|
||||
brew install apr
|
||||
brew install apr-util
|
||||
brew install boost
|
||||
brew install yaml-cpp
|
||||
brew install postgresql
|
||||
brew install unixodbc
|
||||
brew install librdkafka
|
||||
brew install openssl \
|
||||
cmake \
|
||||
libpq \
|
||||
mysql-client \
|
||||
apr \
|
||||
apr-util \
|
||||
boost \
|
||||
yaml-cpp \
|
||||
postgresql \
|
||||
librdkafka \
|
||||
nlohmann-json \
|
||||
fmt
|
||||
|
||||
git clone https://github.com/stephb9959/poco
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release -j
|
||||
sudo cmake --build . --target install
|
||||
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
cd cppkafka
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
pushd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
push cmake-build
|
||||
cmake -DOPENSSL_ROOT_DIR=</path/to/openssl> -DENABLE_NETSSL=1 -DENABLE_JWT=1 -DENABLE_CRYPTO=1 ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
popd
|
||||
popd
|
||||
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
pushd cppkafka
|
||||
mkdir cmake-build
|
||||
pushd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
popd
|
||||
popd
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
pushd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
pushd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
popd
|
||||
popd
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
pushd wlan-cloud-ucentralgw
|
||||
mkdir cmake-build
|
||||
pushd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
### Raspberry
|
||||
@@ -249,7 +273,7 @@ little changes if you keep the suggested directory structure. For the sample con
|
||||
environment variables.
|
||||
```
|
||||
export OWGW_ROOT=`pwd`
|
||||
export UCENTRALGW_CONFIG=`pwd`
|
||||
export OWGW_CONFIG=`pwd`
|
||||
```
|
||||
If you current working directory is the root of the project, this will set the variables properly. Otherwise, you can set the variables
|
||||
to point to wherever is necessary.
|
||||
@@ -561,6 +585,31 @@ Toe read more about Kafka, follow the [document](https://github.com/Telecominfra
|
||||
#### Securing `kafka`
|
||||
This is beyond the scope of this document. As it stands today, the communication between the gateway and `kafka` is expected to be behind a firewall.
|
||||
|
||||
#### `iptocountry` feature
|
||||
In the UI, you will notice the presence of small flags showing where the device connections are from. This feature is
|
||||
available through the `iptocountry` settings in the configuration. This feature is then also available through the `OpenAPI` for the CLI
|
||||
and other applications.
|
||||
|
||||
##### Config file entries
|
||||
In the configuration file, you must include the following lines:
|
||||
|
||||
```asm
|
||||
iptocountry.default = US
|
||||
iptocountry.provider = ipinfo
|
||||
#iptocountry.provider = ipdata
|
||||
#iptocountry.provider = ipdata
|
||||
iptocountry.ipinfo.token =
|
||||
#ip2location.ipinfo.token =
|
||||
#iptocountry.ipdata.apikey =
|
||||
#iptocountry.ip2location.apikey =
|
||||
```
|
||||
So you select your provider with the `iptocountry.provider` be specifying ipinfo, or ipdata, or ip2location.
|
||||
And then you provide the corresponding api key or token.
|
||||
Only select one. If you select 2, undefined behaviour. All the line you do not need, just put a `#` before to comment it
|
||||
out.
|
||||
You will find the supported providers at: `ip2location.com`, `ipinfo.io`, or `ipdata.co`. You MUST supply a valid default
|
||||
country code in `iptocountry.default`.
|
||||
|
||||
## Contributors
|
||||
We love ya! We need more of ya! If you want to contribute, make sure you review
|
||||
the [coding style](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CODING_STYLE.md) document.
|
||||
|
||||
82
RESTRICTED_DEVICES.md
Normal file
82
RESTRICTED_DEVICES.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Restricted devices
|
||||
|
||||
## What is a restricted device?
|
||||
A restricted device is one that because of regulations or a desire for utmost security, requires signatures to access restricted or blocked
|
||||
features. The restriction process is burnt in the device at manufacturing or later by running a specific command on the device. Once a device
|
||||
is restricted, it cannot be unlocked.
|
||||
|
||||
## Current restrictions
|
||||
Restrictions are stored on the AP in a protected partition. They are contained in a file called `restrictions.json`. Here is a sample:
|
||||
```json
|
||||
{
|
||||
"country": [
|
||||
"US", "CA"
|
||||
],
|
||||
"dfs": true,
|
||||
"rtty": true,
|
||||
"tty": true,
|
||||
"developer": true,
|
||||
"sysupgrade": true,
|
||||
"commands": true,
|
||||
"key_info": {
|
||||
"vendor": "dummy",
|
||||
"algo": "static"
|
||||
}
|
||||
}
|
||||
```
|
||||
- country
|
||||
- List of countries where this device may be used
|
||||
- dfs
|
||||
- Disallow DFS Override during wifi-scan. If set to `true`, device will not allow to override DFS channels
|
||||
- rtty
|
||||
- Disallow the use of the RTTY command for this device
|
||||
- tty
|
||||
- Do not allow the AP to accept `tty` connection
|
||||
- developer
|
||||
- Internal use only.
|
||||
- sysupgrade
|
||||
- If set to `true`, only signed firmware upgrade command will be allowed.
|
||||
- commands
|
||||
- If set to `true`, do not allow commands.
|
||||
- key_info
|
||||
- This structure defines how signatures should be generated and verified in a secure system
|
||||
- vendor
|
||||
- An identified that must match the vendor name provided in the controller
|
||||
- algo
|
||||
- The signature algorithm. Here are the supported algorithms
|
||||
- `static`
|
||||
- A test algorithm that always returns and uses a value of `aaaaaaaaaa`. This should never be used in the field.
|
||||
- `dgst-sha256`
|
||||
- The default OpenSSL RSA signature generation and verification. The controller will use the following command to generate the signature
|
||||
```sh
|
||||
openssl dgst -sha256 -sign private-key.pem -out signature.txt myfile
|
||||
```
|
||||
- The AP will be using the following to verify the signature
|
||||
```sh
|
||||
openssl dgst -sha256 -verify public-key.pem -signature signature.txt myfile
|
||||
```
|
||||
|
||||
## Creating signatures on the controller
|
||||
When a device is restricted and a signature is required, the controller can generate the signature
|
||||
for the specified `vendor`. However, on the controlelr side, you must configure the vendors. In
|
||||
order to do so we suggest the following.
|
||||
- Create a directory called `signatures` under your `certs` directory
|
||||
- Copy the public and private keys for each `vendor` name. We suggest naming them accordingly
|
||||
- `vendor`-private-key.pem
|
||||
- `vendor`-public-key.pem
|
||||
- In the `owgw.properties` file, you need to declare these signatures the following way
|
||||
```properties
|
||||
signature.manager.0.key.public = $OWGW_ROOT/certs/signatures/test1-public-key.pem
|
||||
signature.manager.0.key.private = $OWGW_ROOT/certs/signatures/test1-private-key.pem
|
||||
signature.manager.0.vendor = test1
|
||||
|
||||
signature.manager.1.key.public = $OWGW_ROOT/certs/signatures/test2-public-key.pem
|
||||
signature.manager.1.key.private = $OWGW_ROOT/certs/signatures/test2-private-key.pem
|
||||
signature.manager.1.vendor = test2
|
||||
```
|
||||
|
||||
## How do you use the signatures?
|
||||
There is nothing to do really. Now the controller will use the proper key to create the signatures
|
||||
when it sends commands to the AP. It will use the algorithm that the device understands too. This is transparent
|
||||
to the user. The `vendor` name used in the controller configuration must match the `vendor` name provided in the
|
||||
`restrictions.json` file.
|
||||
0
ap_scripts/Author 1/AUTHORS.md
Normal file
0
ap_scripts/Author 1/AUTHORS.md
Normal file
0
ap_scripts/Author 1/LICENSE.md
Normal file
0
ap_scripts/Author 1/LICENSE.md
Normal file
0
ap_scripts/Author 1/README.md
Normal file
0
ap_scripts/Author 1/README.md
Normal file
36
ap_scripts/Author 1/content.yaml
Normal file
36
ap_scripts/Author 1/content.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
scripts:
|
||||
- name: List Antennas
|
||||
description: A script to list all antennas on a device
|
||||
type: shell
|
||||
runtype:
|
||||
timeout: 30
|
||||
filename: listantennas.sh
|
||||
readme: listantennas.md
|
||||
help: https://authors.com/scripts/index.html
|
||||
- name: List AP Noise
|
||||
description: A script to list all noise values on all APs
|
||||
type: shell
|
||||
runtype:
|
||||
deferred: true
|
||||
filename: listnoise.sh
|
||||
readme: listnoise.md
|
||||
help: https://authors.com/scripts/index.html
|
||||
- name: Reset AP Statistics
|
||||
description: A script to reset the statistics on a given AP
|
||||
type: shell
|
||||
runtype:
|
||||
timeout: 30
|
||||
filename: resetstats.sh
|
||||
readme: resetstats.md
|
||||
help: https://authors.com/scripts/index.html
|
||||
- name: Gather kernel stats
|
||||
description: A script to all the kernel stats for an AP
|
||||
type: bundle
|
||||
runtype:
|
||||
deferred: true
|
||||
filename: kstats.uci
|
||||
readme: kstats.md
|
||||
help: https://authors.com/scripts/index.html
|
||||
|
||||
|
||||
0
ap_scripts/Author 1/kstats.md
Normal file
0
ap_scripts/Author 1/kstats.md
Normal file
0
ap_scripts/Author 1/kstats.uci
Normal file
0
ap_scripts/Author 1/kstats.uci
Normal file
0
ap_scripts/Author 1/listantennas.md
Normal file
0
ap_scripts/Author 1/listantennas.md
Normal file
1
ap_scripts/Author 1/listantennas.sh
Normal file
1
ap_scripts/Author 1/listantennas.sh
Normal file
@@ -0,0 +1 @@
|
||||
#!/bin/sh
|
||||
0
ap_scripts/Author 1/listnoise.md
Normal file
0
ap_scripts/Author 1/listnoise.md
Normal file
2
ap_scripts/Author 1/listnoise.sh
Normal file
2
ap_scripts/Author 1/listnoise.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
|
||||
0
ap_scripts/Author 1/resetstats.md
Normal file
0
ap_scripts/Author 1/resetstats.md
Normal file
2
ap_scripts/Author 1/resetstats.sh
Normal file
2
ap_scripts/Author 1/resetstats.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
|
||||
1
ap_scripts/README.md
Normal file
1
ap_scripts/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# Repo for scripts
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
#include <librdkafka/rdkafka.h>
|
||||
#if RD_KAFKA_VERSION >= 0x00090400
|
||||
int main() { }
|
||||
#endif
|
||||
26
config.yaml
26
config.yaml
@@ -1,26 +0,0 @@
|
||||
tip:
|
||||
port: 6051
|
||||
server: ssc.wlan.local
|
||||
username: support@example.com
|
||||
password: support
|
||||
|
||||
certificates:
|
||||
keyfile: keyfile.pem
|
||||
certfile: certfile.pem
|
||||
password: mypassword
|
||||
|
||||
ucentral:
|
||||
port: 1991
|
||||
listeners: 100
|
||||
|
||||
logger:
|
||||
size: 10
|
||||
days: 31
|
||||
|
||||
ui:
|
||||
port: 9771
|
||||
username: support@example.com
|
||||
password: support
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
||||
@@ -38,7 +38,12 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
|
||||
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
|
||||
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
|
||||
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
|
||||
SIMULATORID=${SIMULATORID:-""} \
|
||||
IPTOCOUNTRY_PROVIDER=${IPTOCOUNTRY_PROVIDER:-"ipinfo"} \
|
||||
IPTOCOUNTRY_IPINFO_TOKEN=${IPTOCOUNTRY_IPINFO_TOKEN:-""} \
|
||||
IPTOCOUNTRY_IPDATA_APIKEY=${IPTOCOUNTRY_IPDATA_APIKEY:-""} \
|
||||
AUTOPROVISIONING_PROCESS=${AUTOPROVISIONING_PROCESS:-"prov,default"} \
|
||||
RTTY_INTERNAL=${RTTY_INTERNAL:-"true"} \
|
||||
RTTY_ENABLED=${RTTY_ENABLED:-"true"} \
|
||||
RTTY_SERVER=${RTTY_SERVER:-"localhost"} \
|
||||
@@ -47,6 +52,10 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
|
||||
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
|
||||
RTTY_ASSETS=${RTTY_ASSETS:-"\$OWGW_ROOT/rtty_ui"} \
|
||||
RADIUS_PROXY_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
|
||||
RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
|
||||
RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \
|
||||
RADIUS_PROXY_COA_PORT=${RADIUS_PROXY_COA_PORT:-"3799"} \
|
||||
KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \
|
||||
KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \
|
||||
KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \
|
||||
@@ -64,6 +73,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
|
||||
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
|
||||
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
|
||||
CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
|
||||
envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
|
||||
fi
|
||||
|
||||
@@ -86,7 +96,7 @@ if [ "$1" = '/openwifi/owgw' -a "$(id -u)" = '0' ]; then
|
||||
if [ "$RUN_CHOWN" = 'true' ]; then
|
||||
chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
|
||||
fi
|
||||
exec su-exec "$OWGW_USER" "$@"
|
||||
exec gosu "$OWGW_USER" "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
USERNAME=arilia
|
||||
HUBNAME=tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
IMAGE_NAME=ucentralgw
|
||||
|
||||
echo "Removing docker images before build..."
|
||||
docker rmi -f $(docker images -a -q)
|
||||
echo "Building $IMAGE_NAME image..."
|
||||
docker build --no-cache --tag $IMAGE_NAME .
|
||||
IMAGE_ID=`docker images -q $IMAGE_NAME`
|
||||
docker login --username=$USERNAME $HUBNAME
|
||||
docker tag $IMAGE_ID $HUBNAME/$IMAGE_NAME:latest
|
||||
echo "Updating $HUBNAME with the latest $IMAGE_NAME image..."
|
||||
docker push $HUBNAME/$IMAGE_NAME
|
||||
docker logout $HUBNAME
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Removes all local images. This is dangerous but good when debugging
|
||||
docker rmi -f $(docker images -a -q)
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
HUBNAME=tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
IMAGE_NAME=ucentralgw
|
||||
DOCKER_NAME=$HUBNAME/$IMAGE_NAME:master
|
||||
|
||||
CONTAINER_NAME=ucentralgw
|
||||
|
||||
#stop previously running images
|
||||
docker container stop $CONTAINER_NAME
|
||||
docker container rm $CONTAINER_NAME --force
|
||||
|
||||
if [[ ! -d logs ]]
|
||||
then
|
||||
mkdir logs
|
||||
fi
|
||||
|
||||
if [[ ! -d uploads ]]
|
||||
then
|
||||
mkdir uploads
|
||||
fi
|
||||
|
||||
if [[ ! -d certs ]]
|
||||
then
|
||||
echo "certs directory does not exist. Please create and add the proper certificates."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f owgw.properties ]]
|
||||
then
|
||||
echo "Configuration file ucentral.properties is missing in the current directory"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
docker run -d -p 15002:15002 \
|
||||
-p 16001:16001 \
|
||||
-p 16003:16003 \
|
||||
--init \
|
||||
--volume="$PWD:/ucentral-data" \
|
||||
-e UCENTRALGW_ROOT="/ucentral-data" \
|
||||
-e UCENTRALGW_CONFIG="/ucentral-data" \
|
||||
--name="ucentralgw" $DOCKER_NAME
|
||||
|
||||
@@ -79,7 +79,8 @@ The following table lists the configurable parameters of the chart and their def
|
||||
| persistence.size | string | Defines PV size | `'10Gi'` |
|
||||
| public_env_variables | hash | Defines list of environment variables to be passed to the Gateway | |
|
||||
| configProperties | hash | Configuration properties that should be passed to the application in `owgw.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owgw` on where it is mounted) | |
|
||||
| existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owgw` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. | |
|
||||
| certsCAs | hash | Defines files with CAs that should be passed to the Gateway (see `volumes.owgw` on where it is mounted) | |
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{{- $root := . -}}
|
||||
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -48,6 +49,38 @@ spec:
|
||||
- tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }}
|
||||
- -timeout
|
||||
- 600s
|
||||
{{- if eq $storageType "postgresql" }}
|
||||
- name: wait-postgres
|
||||
image: "{{ .Values.images.owgw.repository }}:{{ .Values.images.owgw.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.owgw.pullPolicy }}
|
||||
command:
|
||||
- /wait-for-postgres.sh
|
||||
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
|
||||
- echo
|
||||
- "PostgreSQL is ready"
|
||||
env:
|
||||
- name: KUBERNETES_DEPLOYED
|
||||
value: "{{ now }}"
|
||||
{{- range $key, $value := .Values.public_env_variables }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := .Values.secret_env_variables }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "owgw.fullname" $root }}-env
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owgw }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
{{- if .subPath }}
|
||||
subPath: {{ .subPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
containers:
|
||||
|
||||
@@ -76,6 +109,11 @@ spec:
|
||||
containerPort: {{ $portValue.targetPort }}
|
||||
protocol: {{ $portValue.protocol }}
|
||||
{{- end }}
|
||||
{{- range $port, $portValue := .Values.services.radius.ports }}
|
||||
- name: {{ $port }}
|
||||
containerPort: {{ $portValue.targetPort }}
|
||||
protocol: {{ $portValue.protocol }}
|
||||
{{- end }}
|
||||
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owgw }}
|
||||
|
||||
198
helm/values.yaml
198
helm/values.yaml
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owgw:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
|
||||
tag: master
|
||||
tag: v2.8.0-RC3
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
@@ -46,6 +46,21 @@ services:
|
||||
rttys-view:
|
||||
servicePort: 5913
|
||||
targetPort: 5913
|
||||
radius:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
acc:
|
||||
servicePort: 1813
|
||||
targetPort: 1813
|
||||
protocol: UDP
|
||||
auth:
|
||||
servicePort: 1812
|
||||
targetPort: 1812
|
||||
protocol: UDP
|
||||
coa:
|
||||
servicePort: 3799
|
||||
targetPort: 3799
|
||||
protocol: UDP
|
||||
|
||||
checks:
|
||||
owgw:
|
||||
@@ -97,7 +112,7 @@ volumes:
|
||||
mountPath: /owgw-data/certs
|
||||
volumeDefinition: |
|
||||
secret:
|
||||
secretName: {{ include "owgw.fullname" . }}-certs
|
||||
secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owgw.fullname" . }}-certs{{ end }}
|
||||
- name: certs-cas
|
||||
mountPath: /owgw-data/certs/cas
|
||||
volumeDefinition: |
|
||||
@@ -123,7 +138,7 @@ resources: {}
|
||||
# memory: 128Mi
|
||||
|
||||
securityContext:
|
||||
fsGroup: 101
|
||||
fsGroup: 1000
|
||||
# Usage of unsafe sysctls requires multiple things:
|
||||
# - allow these unsafe sysctls on kubelet level (by adding --allowed-unsafe-sysctls flag)
|
||||
# - enabling addition of PodSecurityContext setting podSecurityPolicy.enabled to "true" below
|
||||
@@ -215,6 +230,7 @@ configProperties:
|
||||
openwifi.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2: IOT:esp32
|
||||
openwifi.certificates.allowmismatch: "false"
|
||||
oui.download.uri: https://standards-oui.ieee.org/oui/oui.txt
|
||||
firmware.autoupdate.policy.default: auto
|
||||
iptocountry.provider: ipinfo
|
||||
@@ -231,6 +247,11 @@ configProperties:
|
||||
rtty.timeout: 60
|
||||
rtty.viewport: 5913
|
||||
rtty.assets: $OWGW_ROOT/rtty_ui
|
||||
# RADIUS proxy
|
||||
radius.proxy.enable: "true"
|
||||
radius.proxy.accounting.port: 1813
|
||||
radius.proxy.authentication.port: 1812
|
||||
radius.proxy.coa.port: 3799
|
||||
# ALB
|
||||
alb.enable: "true"
|
||||
alb.port: 16102
|
||||
@@ -271,6 +292,7 @@ configProperties:
|
||||
openwifi.system.debug: "true"
|
||||
openwifi.system.uri.private: https://localhost:17002
|
||||
openwifi.system.uri.public: https://localhost:16002
|
||||
openwifi.system.uri.ui: https://localhost
|
||||
openwifi.system.commandchannel: /tmp/app_owgw
|
||||
# Logging
|
||||
logging.type: console
|
||||
@@ -310,166 +332,22 @@ configProperties:
|
||||
storage.type.mysql.username: stephb
|
||||
storage.type.mysql.password: snoopy99
|
||||
|
||||
# NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr
|
||||
existingCertsSecret: ""
|
||||
|
||||
certs:
|
||||
clientcas.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
|
||||
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
|
||||
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
|
||||
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
|
||||
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
|
||||
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
|
||||
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
|
||||
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
|
||||
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
|
||||
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
|
||||
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
|
||||
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
|
||||
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
|
||||
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
|
||||
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
|
||||
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
|
||||
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
|
||||
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
|
||||
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
|
||||
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
|
||||
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
|
||||
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
|
||||
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
|
||||
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
|
||||
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
|
||||
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
|
||||
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
issuer.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
|
||||
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
|
||||
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
|
||||
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
|
||||
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
|
||||
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
|
||||
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
|
||||
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
|
||||
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
|
||||
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
|
||||
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
|
||||
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
|
||||
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
|
||||
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
|
||||
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
|
||||
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
|
||||
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
|
||||
-----END CERTIFICATE-----
|
||||
# restapi-ca.pem: ""
|
||||
# restapi-cert.pem: ""
|
||||
# restapi-key.pem: ""
|
||||
root.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
|
||||
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
|
||||
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
|
||||
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
|
||||
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
|
||||
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
|
||||
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
|
||||
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
|
||||
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
|
||||
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
|
||||
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
# websocket-cert.pem: ""
|
||||
# websocket-key.pem: ""
|
||||
clientcas.pem: ""
|
||||
issuer.pem: ""
|
||||
restapi-ca.pem: ""
|
||||
restapi-cert.pem: ""
|
||||
restapi-key.pem: ""
|
||||
root.pem: ""
|
||||
websocket-cert.pem: ""
|
||||
websocket-key.pem: ""
|
||||
|
||||
certsCAs:
|
||||
issuer.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
|
||||
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
|
||||
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
|
||||
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
|
||||
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
|
||||
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
|
||||
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
|
||||
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
|
||||
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
|
||||
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
|
||||
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
|
||||
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
|
||||
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
|
||||
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
|
||||
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
|
||||
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
|
||||
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
|
||||
-----END CERTIFICATE-----
|
||||
root.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
|
||||
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
|
||||
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
|
||||
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
|
||||
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
|
||||
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
|
||||
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
|
||||
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
|
||||
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
|
||||
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
|
||||
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
issuer.pem: ""
|
||||
root.pem: ""
|
||||
|
||||
# PostgreSQL (https://github.com/bitnami/charts/tree/master/bitnami/postgresql)
|
||||
postgresql:
|
||||
|
||||
@@ -49,6 +49,38 @@ components:
|
||||
- IOT
|
||||
- MESH
|
||||
|
||||
DeviceRestrictionsKeyInfo:
|
||||
type: object
|
||||
properties:
|
||||
vendor:
|
||||
type: string
|
||||
algo:
|
||||
type: string
|
||||
|
||||
DeviceRestrictions:
|
||||
type: object
|
||||
properties:
|
||||
dfs:
|
||||
type: boolean
|
||||
ssh:
|
||||
type: boolean
|
||||
rtty:
|
||||
type: boolean
|
||||
tty:
|
||||
type: boolean
|
||||
developer:
|
||||
type: boolean
|
||||
upgrade:
|
||||
type: boolean
|
||||
commands:
|
||||
type: boolean
|
||||
country:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
key_info:
|
||||
$ref: '#/components/schemas/DeviceRestrictionsKeyInfo'
|
||||
|
||||
Device:
|
||||
type: object
|
||||
description: Definition of uCentral device
|
||||
@@ -107,6 +139,19 @@ components:
|
||||
type: string
|
||||
minLength: 2
|
||||
maxLength: 2
|
||||
restrictedDevice:
|
||||
type: boolean
|
||||
default: false
|
||||
certificateExpiryDate:
|
||||
type: integer
|
||||
format: int64
|
||||
pendingConfiguration:
|
||||
type: string
|
||||
pendingConfigurationCmd:
|
||||
type: string
|
||||
format: uuid
|
||||
restrictionDetails:
|
||||
$ref: '#/components/schemas/DeviceRestrictions'
|
||||
|
||||
DeviceWithStatus:
|
||||
type: object
|
||||
@@ -190,6 +235,31 @@ components:
|
||||
type: string
|
||||
minLength: 2
|
||||
maxLength: 2
|
||||
started:
|
||||
type: integer
|
||||
format: int64
|
||||
sessionId:
|
||||
type: integer
|
||||
format: int64
|
||||
connectionCompletionTime:
|
||||
type: number
|
||||
format: double
|
||||
totalConnectionTime:
|
||||
type: integer
|
||||
format: int64
|
||||
restrictedDevice:
|
||||
type: boolean
|
||||
default: false
|
||||
certificateDate:
|
||||
type: integer
|
||||
format: int64
|
||||
pendingConfiguration:
|
||||
type: string
|
||||
pendingConfigurationCmd:
|
||||
type: string
|
||||
format: uuid
|
||||
restrictionDetails:
|
||||
$ref: '#/components/schemas/DeviceRestrictions'
|
||||
|
||||
DeviceList:
|
||||
type: object
|
||||
@@ -282,6 +352,17 @@ components:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
DeviceConnectionStatistics:
|
||||
type: object
|
||||
description: Return some basic device statistics.
|
||||
properties:
|
||||
connectedDevices:
|
||||
type: integer
|
||||
format: int64
|
||||
averageConnectionTime:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
StatisticsDetails:
|
||||
type: object
|
||||
properties:
|
||||
@@ -477,18 +558,69 @@ components:
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- uci
|
||||
- ucode
|
||||
- shell
|
||||
- bundle
|
||||
- diagnostic
|
||||
script:
|
||||
type: string
|
||||
scriptId:
|
||||
type: string
|
||||
format: uuid
|
||||
when:
|
||||
type: integer
|
||||
format: int64
|
||||
default: 0
|
||||
signature:
|
||||
type: string
|
||||
deferred:
|
||||
type: boolean
|
||||
uri:
|
||||
type: string
|
||||
|
||||
ScriptEntry:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
type:
|
||||
enum:
|
||||
- shell
|
||||
- bundle
|
||||
created:
|
||||
type: integer
|
||||
modified:
|
||||
type: integer
|
||||
author:
|
||||
type: string
|
||||
restricted:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
deferred:
|
||||
type: boolean
|
||||
default: false
|
||||
timeout:
|
||||
type: integer
|
||||
default: 30
|
||||
defaultUploadURI:
|
||||
type: string
|
||||
|
||||
ScriptEntryList:
|
||||
type: object
|
||||
properties:
|
||||
scripts:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ScriptEntry'
|
||||
|
||||
FactoryRequest:
|
||||
type: object
|
||||
@@ -898,9 +1030,26 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/TagValuePair'
|
||||
|
||||
ExtraSystemConfiguration:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
parameterName:
|
||||
type: string
|
||||
parameterType:
|
||||
type: string
|
||||
enum:
|
||||
- string
|
||||
- integer
|
||||
- boolean
|
||||
- path
|
||||
parameterValue:
|
||||
{}
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## End of uCentral system wide values
|
||||
## End of uCentral system-wide values
|
||||
##
|
||||
#########################################################################################
|
||||
BlackDeviceInfo:
|
||||
@@ -1049,6 +1198,33 @@ components:
|
||||
type: string
|
||||
certificate:
|
||||
type: string
|
||||
radsec:
|
||||
type: boolean
|
||||
default: false
|
||||
radsecPort:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 65535
|
||||
radsecSecret:
|
||||
type: string
|
||||
radsecCacerts:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
radsecCert:
|
||||
type: string
|
||||
description: this must be the base64 encoded of the entire content of the certificate file, including the -----BEGIN lines
|
||||
radsecKey:
|
||||
type: string
|
||||
description: this must be the base64 encoded of the entire content of the key file, including the -----BEGIN lines
|
||||
radsecRealms:
|
||||
description: each entry must be the base64 encoded of the entire content of the ca files, including the -----BEGIN lines
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ignore:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
RadiusProxyServerConfig:
|
||||
type: object
|
||||
@@ -1162,6 +1338,13 @@ paths:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: connectionStatistics
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List devices
|
||||
@@ -1173,6 +1356,7 @@ paths:
|
||||
- $ref: '#/components/schemas/DeviceListWithStatus'
|
||||
- $ref: '#/components/schemas/SerialNumberList'
|
||||
- $ref: '#/components/schemas/DeviceCount'
|
||||
- $ref: '#/components/schemas/DeviceConnectionStatistics'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
@@ -1832,6 +2016,12 @@ paths:
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
description: Return the number of matching records.
|
||||
name: countOnly
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
|
||||
responses:
|
||||
200:
|
||||
@@ -1841,6 +2031,8 @@ paths:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/StatisticsRecords'
|
||||
- $ref: '#/components/schemas/DeviceCount'
|
||||
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
@@ -2018,6 +2210,11 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: FWsignature
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
requestBody:
|
||||
description: Command details
|
||||
content:
|
||||
@@ -2372,6 +2569,148 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/scripts:
|
||||
get:
|
||||
tags:
|
||||
- Scripting
|
||||
summary: Returns a list scripts.
|
||||
description: Get a list of scripts.
|
||||
operationId: getScripts
|
||||
parameters:
|
||||
- in: query
|
||||
description: Pagination start (starts at 0. If not specified, 0 is assumed)
|
||||
name: offset
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
- in: query
|
||||
description: Maximum number of entries to return (if absent, no limit is assumed)
|
||||
name: limit
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
- in: query
|
||||
description: Filter the results
|
||||
name: filter
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List all scripts
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScriptEntryList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/script/{uuid}:
|
||||
get:
|
||||
tags:
|
||||
- Scripting
|
||||
summary: Returns a script entry.
|
||||
description: Get a specific script entry.
|
||||
operationId: getScript
|
||||
parameters:
|
||||
- in: path
|
||||
description: The UUID of the script
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
description: A script entry
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScriptEntry'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
post:
|
||||
tags:
|
||||
- Scripting
|
||||
summary: Create a new script.
|
||||
operationId: createScript
|
||||
parameters:
|
||||
- in: path
|
||||
description: The UUID of the script. Must be set to 0 for creation
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
requestBody:
|
||||
description: Complet script entry
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScriptEntry'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ScriptEntry'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- Scripting
|
||||
summary: Modify a script.
|
||||
operationId: modifyScript
|
||||
parameters:
|
||||
- in: path
|
||||
description: The UUID of the script.
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
requestBody:
|
||||
description: Complete script entry. You may only modify the name, description, version, uri, and content
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScriptEntry'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ScriptEntry'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- Scripting
|
||||
summary: Delete a script.
|
||||
operationId: deleteScript
|
||||
parameters:
|
||||
- in: path
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
|
||||
|
||||
/blacklist:
|
||||
get:
|
||||
tags:
|
||||
@@ -2673,4 +3012,51 @@ paths:
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/systemConfiguration:
|
||||
get:
|
||||
tags:
|
||||
- SystemConfiguration
|
||||
summary: Retrieve system configuration items
|
||||
operationId: getSystemConfiguration
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ExtraSystemConfiguration'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- SystemConfiguration
|
||||
summary: Set some or all system configuration
|
||||
operationId: setSystemConfiguration
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ExtraSystemConfiguration'
|
||||
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ExtraSystemConfiguration'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- SystemConfiguration
|
||||
summary: Delete all additional system configuration
|
||||
operationId: deleteSystemConfiguration
|
||||
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
@@ -65,6 +65,7 @@ openwifi.system.debug = true
|
||||
openwifi.system.uri.private = https://localhost:17002
|
||||
openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16002
|
||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
|
||||
openwifi.security.restapi.disable = false
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralgw
|
||||
|
||||
#
|
||||
@@ -177,4 +178,4 @@ archiver.db.3.keep = 7
|
||||
########################################################################
|
||||
logging.type = file
|
||||
logging.path = $OWGW_ROOT/logs
|
||||
logging.level = debug
|
||||
logging.level = information
|
||||
|
||||
@@ -52,8 +52,8 @@ openwifi.fileuploader.host.0.cert = ${FILEUPLOADER_HOST_CERT}
|
||||
openwifi.fileuploader.host.0.key = ${FILEUPLOADER_HOST_KEY}
|
||||
openwifi.fileuploader.host.0.key.password = ${FILEUPLOADER_HOST_KEY_PASSWORD}
|
||||
openwifi.fileuploader.path = ${FILEUPLOADER_PATH}
|
||||
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
|
||||
openwifi.fileuploader.maxsize = 10000
|
||||
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
|
||||
|
||||
#
|
||||
# Generic section that all microservices must have
|
||||
@@ -65,6 +65,7 @@ openwifi.system.debug = true
|
||||
openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
|
||||
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
|
||||
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
|
||||
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralgw
|
||||
|
||||
#
|
||||
@@ -74,9 +75,15 @@ openwifi.autoprovisioning = true
|
||||
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2 = IOT:esp32
|
||||
openwifi.certificates.allowmismatch = ${CERTIFICATES_ALLOWMISMATCH}
|
||||
oui.download.uri = https://standards-oui.ieee.org/oui/oui.txt
|
||||
firmware.autoupdate.policy.default = auto
|
||||
simulatorid = ${SIMULATORID}
|
||||
iptocountry.default = US
|
||||
iptocountry.provider = ${IPTOCOUNTRY_PROVIDER}
|
||||
iptocountry.ipinfo.token = ${IPTOCOUNTRY_IPINFO_TOKEN}
|
||||
iptocountry.ipdata.apikey = ${IPTOCOUNTRY_IPDATA_APIKEY}
|
||||
|
||||
autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
|
||||
|
||||
#
|
||||
# rtty
|
||||
@@ -90,6 +97,12 @@ rtty.timeout = ${RTTY_TIMEOUT}
|
||||
rtty.viewport = ${RTTY_VIEWPORT}
|
||||
rtty.assets = ${RTTY_ASSETS}
|
||||
|
||||
### RADIUS proxy config
|
||||
radius.proxy.enable = ${RADIUS_PROXY_ENABLE}
|
||||
radius.proxy.accounting.port = ${RADIUS_PROXY_ACCOUNTING_PORT}
|
||||
radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
|
||||
radius.proxy.coa.port = ${RADIUS_PROXY_COA_PORT}
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
#############################
|
||||
@@ -108,6 +121,7 @@ openwifi.kafka.enable = ${KAFKA_ENABLE}
|
||||
openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST}
|
||||
openwifi.kafka.auto.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
|
||||
openwifi.kafka.ssl.ca.location = ${KAFKA_SSL_CA_LOCATION}
|
||||
openwifi.kafka.ssl.certificate.location = ${KAFKA_SSL_CERTIFICATE_LOCATION}
|
||||
openwifi.kafka.ssl.key.location = ${KAFKA_SSL_KEY_LOCATION}
|
||||
@@ -161,4 +175,4 @@ archiver.db.3.keep = 7
|
||||
########################################################################
|
||||
logging.type = console
|
||||
logging.path = $OWGW_ROOT/logs
|
||||
logging.level = debug
|
||||
logging.level = information
|
||||
|
||||
41
pcap/radius
41
pcap/radius
@@ -1,41 +0,0 @@
|
||||
/* Frame (255 bytes) */
|
||||
static const unsigned char pkt41[255] = {
|
||||
0x14, 0x98, 0x77, 0x71, 0xc6, 0xe7, 0x34, 0xef, /* ..wq..4. */
|
||||
0xb6, 0xaf, 0x4a, 0x5c, 0x08, 0x00, 0x45, 0x00, /* ..J\..E. */
|
||||
0x00, 0xf1, 0x87, 0x50, 0x00, 0x00, 0x40, 0x11, /* ...P..@. */
|
||||
0x0c, 0xdf, 0xc0, 0xa8, 0xb2, 0x1b, 0xc0, 0xa8, /* ........ */
|
||||
0xb2, 0x60, 0xc3, 0xfe, 0x07, 0x14, 0x00, 0xdd, /* .`...... */
|
||||
0x26, 0x63, 0x01, 0x04, 0x00, 0xd5, 0xcc, 0x29, /* &c.....) */
|
||||
0x82, 0x36, 0xd6, 0x57, 0x3d, 0xa7, 0xd5, 0x62, /* .6.W=..b */
|
||||
0x70, 0x12, 0x00, 0xc0, 0xf2, 0x19, 0x01, 0x03, /* p....... */
|
||||
0x61, 0x1e, 0x1c, 0x33, 0x34, 0x2d, 0x45, 0x46, /* a..34-EF */
|
||||
0x2d, 0x42, 0x36, 0x2d, 0x41, 0x46, 0x2d, 0x34, /* -B6-AF-4 */
|
||||
0x41, 0x2d, 0x36, 0x30, 0x3a, 0x4f, 0x70, 0x65, /* A-60:Ope */
|
||||
0x6e, 0x57, 0x69, 0x66, 0x69, 0x3d, 0x06, 0x00, /* nWifi=.. */
|
||||
0x00, 0x00, 0x13, 0x06, 0x06, 0x00, 0x00, 0x00, /* ........ */
|
||||
0x02, 0x05, 0x06, 0x00, 0x00, 0x00, 0x01, 0x1f, /* ........ */
|
||||
0x13, 0x42, 0x36, 0x2d, 0x43, 0x34, 0x2d, 0x30, /* .B6-C4-0 */
|
||||
0x36, 0x2d, 0x30, 0x39, 0x2d, 0x31, 0x35, 0x2d, /* 6-09-15- */
|
||||
0x42, 0x37, 0x4d, 0x18, 0x43, 0x4f, 0x4e, 0x4e, /* B7M.CONN */
|
||||
0x45, 0x43, 0x54, 0x20, 0x35, 0x34, 0x4d, 0x62, /* ECT 54Mb */
|
||||
0x70, 0x73, 0x20, 0x38, 0x30, 0x32, 0x2e, 0x31, /* ps 802.1 */
|
||||
0x31, 0x61, 0x2c, 0x12, 0x33, 0x42, 0x45, 0x44, /* 1a,.3BED */
|
||||
0x37, 0x32, 0x39, 0x30, 0x44, 0x30, 0x43, 0x38, /* 7290D0C8 */
|
||||
0x35, 0x36, 0x44, 0x33, 0xba, 0x06, 0x00, 0x0f, /* 56D3.... */
|
||||
0xac, 0x04, 0xbb, 0x06, 0x00, 0x0f, 0xac, 0x04, /* ........ */
|
||||
0xbc, 0x06, 0x00, 0x0f, 0xac, 0x05, 0xbd, 0x06, /* ........ */
|
||||
0x00, 0x0f, 0xac, 0x06, 0x1a, 0x1b, 0x00, 0x00, /* ........ */
|
||||
0xe6, 0x08, 0x47, 0x15, 0x01, 0x13, 0x33, 0x34, /* ..G...34 */
|
||||
0x2d, 0x65, 0x66, 0x2d, 0x62, 0x36, 0x2d, 0x61, /* -ef-b6-a */
|
||||
0x66, 0x2d, 0x34, 0x61, 0x2d, 0x35, 0x63, 0x0c, /* f-4a-5c. */
|
||||
0x06, 0x00, 0x00, 0x05, 0x78, 0x4f, 0x08, 0x02, /* ....xO.. */
|
||||
0x01, 0x00, 0x06, 0x01, 0x61, 0x50, 0x12, 0x20, /* ....aP. */
|
||||
0x9c, 0xae, 0xe5, 0xe3, 0x77, 0xaf, 0x0b, 0x1b, /* ....w... */
|
||||
0xaf, 0x0e, 0xb5, 0x08, 0x82, 0x9e, 0xeb /* ....... */
|
||||
};
|
||||
|
||||
/* Reassembled EAP (6 bytes) */
|
||||
static const unsigned char pkt41_1[6] = {
|
||||
0x02, 0x01, 0x00, 0x06, 0x01, 0x61 /* .....a */
|
||||
};
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
192.168.178.1
|
||||
Binary file not shown.
205
radius-proxy-orion.json
Normal file
205
radius-proxy-orion.json
Normal file
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "wan",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh"
|
||||
],
|
||||
"ssids": []
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 100,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"gateway": "192.168.1.1",
|
||||
"send-hostname": true,
|
||||
"subnet": "192.168.1.1/24",
|
||||
"use-dns": []
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "lan",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"wifi-steering",
|
||||
"ssh"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "required",
|
||||
"proto": "wpa"
|
||||
},
|
||||
"hidden-ssid": false,
|
||||
"isolate-clients": false,
|
||||
"maximum-clients": 64,
|
||||
"name": "arilia-rad",
|
||||
"radius": {
|
||||
"authentication": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1812,
|
||||
"secret": "radsec"
|
||||
},
|
||||
"accounting": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1813,
|
||||
"secret": "radsec"
|
||||
}
|
||||
},
|
||||
"services": [
|
||||
"radius-gw-proxy"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G",
|
||||
"5G"
|
||||
],
|
||||
"pass-point": {
|
||||
"venue-name": [
|
||||
"eng:Example passpoint_venue",
|
||||
"fra:Exemple de lieu"
|
||||
],
|
||||
"domain-name": [
|
||||
"onboard.almondlabs.net",
|
||||
"test.com"
|
||||
],
|
||||
"asra": false,
|
||||
"internet": true,
|
||||
"esr": false,
|
||||
"uesa": false,
|
||||
"access-network-type": 0,
|
||||
"hessid":"11:22:33:44:55:66",
|
||||
"venue-group": 2,
|
||||
"venue-type": 8,
|
||||
"connection-capability":[
|
||||
"1:0:2",
|
||||
"6:22:1",
|
||||
"17:5060:0"
|
||||
],
|
||||
"roaming-consortium": [
|
||||
"F4F5E8F5F4",
|
||||
"BAA2D00100",
|
||||
"BAA2D00000"
|
||||
],
|
||||
"disable-dgaf": true,
|
||||
"anqp-domain": 8888,
|
||||
"ipaddr-type-available": 14,
|
||||
"nai-realm": [
|
||||
],
|
||||
"osen": false,
|
||||
"anqp-3gpp-cell-net": [
|
||||
],
|
||||
"friendly-name": [
|
||||
"eng:AlmondLabs",
|
||||
"fra:AlmondLabs"
|
||||
],
|
||||
"venue-url": [
|
||||
"http://www.example.com/info-fra",
|
||||
"http://www.example.com/info-eng"
|
||||
],
|
||||
"auth-type": {
|
||||
"type": "terms-and-conditions"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 60
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"bandwidth": 10,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HT",
|
||||
"channel-width": 20,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 0
|
||||
},
|
||||
{
|
||||
"band": "5G",
|
||||
"bandwidth": 20,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"channel-width": 40,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 0
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"ssh": {
|
||||
"password-authentication": true,
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 1661312631
|
||||
}
|
||||
33
radsec-config-sample.json
Normal file
33
radsec-config-sample.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"pools" : [
|
||||
{
|
||||
"name" : "master" ,
|
||||
"description" : "master pool",
|
||||
"useByDefault" : true,
|
||||
"authConfig" : {
|
||||
"strategy" : "weighted",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "orion",
|
||||
"ip" : "216.239.32.91",
|
||||
"port" : 2083,
|
||||
"weight" : 10,
|
||||
"radsec" : true,
|
||||
"radsecPort" : 2083,
|
||||
"allowSelfSigned" : false,
|
||||
"radsecSecret" : "radsec",
|
||||
"radsecKey" : "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUR6RnpXeTZlYXg0QVoxTySG9VUURRZ0FFS3BnWVBHMktPTVd2S0w1Z3NMRXpUc09rREg1M3NHaEQyS3RsRXBDTXVnNDNIZlFnTFVpUgpTR1R2S1l0bDFmbmJaU1lnY0RJdncxdjNYRy9hVDhOY2JBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=",
|
||||
"radsecCert" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNRVENDQWVpZ0F3SUJBZ0lVY3BKS3pVM0Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa0oxZEhSdmJuZHZiMlF4SFRBYkJnTlZCQU1URkVKMQpkSFJ2Ym5kdmIyUWdVbUZrYzJWaklFTkJNQjRYRFRJeU1EY3dNekExTWpVeE5Gb1hEVEkzTURVeE9UQTFNalV4Ck5Gb3dkVEVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFvVENrSjFkSFJ2Ym5kdmIyUXhOakEwQmdOVkJBTVQKTFdGeWFXeHBZUzVqWWpFd2FtTnVjemgxYlhCbk9HWnBjRFowTUM1dmNtbHZiaTVoY21WaE1USXdMbU52YlRFWgpNQmNHQ2dtU0pvbVQ4aXhrQVFFVENVZHZiMmRzWlRwVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQ3FZR0R4dGlqakZyeWkrWUxDeE0wN0RwQXgrZDdCb1E5aXJaUktRakxvT054MzBJQzFJa1Voazd5bUwKWmRYNTIyVW1JSEF5TDhOYjkxeHYyay9EWEd5amdZa3dnWVl3RGdZRFZSMFBBUUgvQkFRREFnZUFNQk1HQTFVZApKUVFNTUFvR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3T0FZRFZSMFJCREV3TDRJdFlYSnBiR2xoCkxtTmlNVEJxWTI1ek9IVnRjR2M0Wm1sd05uUXdMbTl5YVc5dUxtRnlaV0V4TWpBdVkyOXRNQmNHQTFVZElBUVEKTUE0d0RBWUtLd1lCQkFIdUtnRUJCVEFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFwTmM1dUNBSkp6KzVyakdqdwpCWGtOdHE3UU83bWU5dUg5bkNsTDZnSVE5Z0lnUHM2VkVKVW5CcEZ0RktXbFF4eWJ1YlBxYnpJNjBPSERHQ0ExCmhXUk1PS1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
|
||||
"radsecCacerts" : [
|
||||
"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ0akNDQVZ1Z0F3SUJBZ0lCQyOXZaREVkTUJzR0ExVUVBeE1VUW5WMGRHOXVkMjl2WkNCU1lXUnpaV01nUTBFdwpJQmNOTVRrd05qQTJNVFV4TlRNeVdoZ1BNalV4T1RBMk1EY3hOVEUxTXpKYU1FRXhDekFKQmdOVkJBWVRBbFZUCk1STXdFUVlEVlFRS0V3cENkWFIwYjI1M2IyOWtNUjB3R3dZRFZRUURFeFJDZFhSMGIyNTNiMjlrSUZKaFpITmwKWXlCRFFUQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJJUW40QVBKaXdvUVFQblR1cFgrZTk1Ugp0ZzVoQVFVbUhCN1E0UkpwSG4welF6TUJpMDdSejkxV05RamFHeERydktLVlQ1OThIM2dxYkI4TTViOHN3aytqClFqQkFNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBZ1lJS3dZQkJRVUgKQXdFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQTkrbHUwN2NlaGc1OQpxSi81dWtzN05oL3F2aXFHWCs1WDFwSVVxdENGVlJjQ0lRREZmUGhwZzZJOFE0SUdBbzNuamlHRTdDWC9nMm56CkRzSW5FcG9vRlkxV0xRPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
|
||||
],
|
||||
"radsecRealms" : [],
|
||||
"ignore" : false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
24
run.sh
24
run.sh
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
daemon=ucentralgw
|
||||
|
||||
if [[ "$1" == "aws" ]]
|
||||
then
|
||||
cp ${daemon}.properties.aws ${daemon}.properties
|
||||
. ./set_env.sh
|
||||
cd cmake-build
|
||||
./${daemon} --daemon
|
||||
echo "Running AWS version as daemon..."
|
||||
fi
|
||||
|
||||
if [[ "$1" == "priv" ]]
|
||||
then
|
||||
cp ${daemon}.properties.priv ${daemon}.properties
|
||||
. ./set_env.sh
|
||||
cd cmake-build
|
||||
./${daemon} --daemon
|
||||
echo "Running private version as daemon..."
|
||||
fi
|
||||
|
||||
|
||||
|
||||
808
src/AP_WS_Connection.cpp
Normal file
808
src/AP_WS_Connection.cpp
Normal file
@@ -0,0 +1,808 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/HTTPServerResponseImpl.h"
|
||||
#include "Poco/Net/HTTPServerRequestImpl.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/Net/WebSocketImpl.h"
|
||||
#include "Poco/zlib.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "CommandManager.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
#define DBL { std::cout << __LINE__ << " ID: " << ConnectionId_ << " Ser: " << SerialNumber_ << std::endl; }
|
||||
|
||||
void AP_WS_Connection::LogException(const Poco::Exception &E) {
|
||||
poco_information(Logger_,fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
|
||||
}
|
||||
|
||||
AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
uint64_t connection_id,
|
||||
Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R)
|
||||
: Logger_(L) ,
|
||||
Reactor_(R)
|
||||
{
|
||||
State_.sessionId = connection_id;
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request,response);
|
||||
|
||||
auto TS = Poco::Timespan(360, 0);
|
||||
|
||||
WS_->setMaxPayloadSize(BufSize);
|
||||
WS_->setReceiveTimeout(TS);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
WS_->setBlocking(false);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
Registered_ = true;
|
||||
Valid_ = true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::ValidatedDevice() {
|
||||
if(DeviceValidated_)
|
||||
return true;
|
||||
|
||||
if(!Valid_)
|
||||
return false;
|
||||
|
||||
std::lock_guard Lock(ConnectionMutex_);
|
||||
try {
|
||||
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(SockImpl->streamSocketImpl());
|
||||
|
||||
PeerAddress_ = SS->peerAddress().host();
|
||||
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
|
||||
|
||||
State_.started = Utils::Now();
|
||||
|
||||
if (!SS->secure()) {
|
||||
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is NOT secure. Device is not allowed.", CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
poco_debug(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is secure.", CId_, State_.sessionId ));
|
||||
|
||||
if (!SS->havePeerCertificate()) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
|
||||
if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not valid. Device is not allowed.",
|
||||
CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_debug(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_, State_.sessionId , CN_));
|
||||
|
||||
if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is not allowed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(CN_)) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
poco_debug(Logger_, fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, State_.sessionId , CN_, ConcurrentStartingDevices_));
|
||||
DeviceValidated_ = true;
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate Validation failed during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket error during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionAbortedException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}):Session:{} Poco::ConnectionAbortedException Connection was aborted during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection was reset during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(Logger_,fmt::format(
|
||||
"CONNECTION({}): Session:{} Poco::InvalidCertificateException Invalid certificate. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::Exception caught during device connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. Device will have to retry. Unsecure connect denied.",
|
||||
CId_, State_.sessionId ));
|
||||
}
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string & SerialNumber) {
|
||||
try {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(Disconnect, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
Valid_=false;
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection() {
|
||||
Valid_=false;
|
||||
if(!Dead_.test_and_set()) {
|
||||
|
||||
if (Registered_) {
|
||||
Registered_ = false;
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
}
|
||||
WS_->close();
|
||||
|
||||
if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
|
||||
std::string s(SerialNumber_);
|
||||
std::thread t([s]() { NotifyKafkaDisconnect(s); });
|
||||
t.detach();
|
||||
}
|
||||
|
||||
auto SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
if (SessionDeleted) {
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
N.content.serialNumber = SerialNumber_;
|
||||
GWWebSocketNotifications::DeviceDisconnected(N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::LookForUpgrade(const uint64_t UUID, uint64_t & UpgradedUUID) {
|
||||
|
||||
// A UUID of zero means ignore updates for that connection.
|
||||
if (UUID == 0)
|
||||
return false;
|
||||
|
||||
uint64_t GoodConfig = ConfigurationCache().CurrentConfig(SerialNumberInt_);
|
||||
if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) {
|
||||
UpgradedUUID = UUID;
|
||||
return false;
|
||||
}
|
||||
|
||||
GWObjects::Device D;
|
||||
if (StorageService()->GetDevice(SerialNumber_, D)) {
|
||||
|
||||
// This is the case where the cache is empty after a restart. So GoodConfig will 0. If the device already has the right UUID, we just return.
|
||||
if (D.UUID == UUID) {
|
||||
UpgradedUUID = UUID;
|
||||
ConfigurationCache().Add(SerialNumberInt_, UUID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(UUID>D.UUID) {
|
||||
// so we have a problem, the device has a newer config than we have. So we need to make sure our config
|
||||
// is newer.
|
||||
Config::Config Cfg(D.Configuration);
|
||||
D.UUID = UUID+2;
|
||||
UpgradedUUID = D.UUID;
|
||||
Cfg.SetUUID(D.UUID);
|
||||
D.Configuration = Cfg.get();
|
||||
StorageService()->UpdateDevice(D);
|
||||
}
|
||||
|
||||
UpgradedUUID = D.UUID;
|
||||
State_.PendingUUID = D.UUID;
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroServiceCreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::CONFIGURE;
|
||||
Poco::JSON::Parser P;
|
||||
auto ParsedConfig = P.parse(D.Configuration).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::UUID, D.UUID);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
|
||||
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
poco_information(Logger_,fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
|
||||
CId_, UUID, D.UUID));
|
||||
bool Sent;
|
||||
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
CommandManager()->PostCommand(CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
|
||||
GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
|
||||
Notification.content.serialNumber = D.SerialNumber;
|
||||
Notification.content.oldUUID = UUID;
|
||||
Notification.content.newUUID = UpgradedUUID;
|
||||
GWWebSocketNotifications::DeviceConfigurationChange(Notification);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
|
||||
poco_debug(Logger_,fmt::format("RECEIVED-RPC({}): {}.", CId_, Doc->get(uCentralProtocol::ID).toString()));
|
||||
CommandManager()->PostCommandResult(SerialNumber_, Doc);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc) {
|
||||
auto Method = Doc->get(uCentralProtocol::METHOD).toString();
|
||||
auto EventType = uCentralProtocol::Events::EventFromString(Method);
|
||||
if (EventType == uCentralProtocol::Events::ET_UNKNOWN) {
|
||||
poco_warning(Logger_,fmt::format("ILLEGAL-PROTOCOL({}): Unknown message type '{}'", CId_, Method));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Doc->isObject(uCentralProtocol::PARAMS)) {
|
||||
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): params must be an object.", CId_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
// expand params if necessary
|
||||
auto ParamsObj = Doc->get(uCentralProtocol::PARAMS).extract<Poco::JSON::Object::Ptr>();
|
||||
if (ParamsObj->has(uCentralProtocol::COMPRESS_64)) {
|
||||
std::string UncompressedData;
|
||||
try {
|
||||
auto CompressedData = ParamsObj->get(uCentralProtocol::COMPRESS_64).toString();
|
||||
uint64_t compress_sz = 0 ;
|
||||
if(ParamsObj->has("compress_sz")) {
|
||||
compress_sz = ParamsObj->get("compress_sz");
|
||||
}
|
||||
|
||||
if (Utils::ExtractBase64CompressedData(CompressedData, UncompressedData, compress_sz)) {
|
||||
poco_trace(Logger_,fmt::format("EVENT({}): Found compressed payload expanded to '{}'.",
|
||||
CId_, UncompressedData));
|
||||
Poco::JSON::Parser Parser;
|
||||
ParamsObj = Parser.parse(UncompressedData).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-DATA({}): Compressed cannot be uncompressed - content must be corrupt..: size={}",
|
||||
CId_, CompressedData.size()));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-JSON-DATA({}): Compressed cannot be parsed - JSON must be corrupt..",
|
||||
CId_));
|
||||
Logger_.log(E);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParamsObj->has(uCentralProtocol::SERIAL)) {
|
||||
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): Serial number is missing in message.", CId_));
|
||||
return;
|
||||
}
|
||||
|
||||
auto Serial = Poco::trim(Poco::toLower(ParamsObj->get(uCentralProtocol::SERIAL).toString()));
|
||||
if (!Utils::ValidSerialNumber(Serial)) {
|
||||
Poco::Exception E(
|
||||
fmt::format(
|
||||
"ILLEGAL-DEVICE-NAME({}): device name is illegal and not allowed to connect.",
|
||||
Serial),
|
||||
EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
if (StorageService()->IsBlackListed(Serial)) {
|
||||
Poco::Exception E(
|
||||
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
|
||||
Serial),
|
||||
EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
switch (EventType) {
|
||||
case uCentralProtocol::Events::ET_CONNECT: {
|
||||
Process_connect(ParamsObj, Serial);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_STATE: {
|
||||
Process_state(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_HEALTHCHECK: {
|
||||
Process_healthcheck(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_LOG: {
|
||||
Process_log(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_CRASHLOG: {
|
||||
Process_crashlog(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_PING: {
|
||||
Process_ping(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_CFGPENDING: {
|
||||
Process_cfgpending(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_RECOVERY: {
|
||||
Process_recovery(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_DEVICEUPDATE: {
|
||||
Process_deviceupdate(ParamsObj, Serial);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_TELEMETRY: {
|
||||
Process_telemetry(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_VENUEBROADCAST: {
|
||||
Process_venuebroadcast(ParamsObj);
|
||||
} break;
|
||||
|
||||
// this will never be called but some compilers will complain if we do not have a case for
|
||||
// every single values of an enum
|
||||
case uCentralProtocol::Events::ET_UNKNOWN: {
|
||||
poco_warning(Logger_, fmt::format("ILLEGAL-EVENT({}): Event '{}' unknown. CN={}", CId_, Method, CN_));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StartTelemetry(uint64_t RPCID) {
|
||||
poco_information(Logger_, fmt::format("TELEMETRY({}): Starting.", CId_));
|
||||
Poco::JSON::Object StartMessage;
|
||||
StartMessage.set("jsonrpc", "2.0");
|
||||
StartMessage.set("method", "telemetry");
|
||||
Poco::JSON::Object Params;
|
||||
Params.set("serial", SerialNumber_);
|
||||
Params.set("interval", (uint64_t)TelemetryInterval_);
|
||||
Poco::JSON::Array Types;
|
||||
Types.add("wifi-frames");
|
||||
Types.add("dhcp-snooping");
|
||||
Types.add("state");
|
||||
Params.set(RESTAPI::Protocol::TYPES, Types);
|
||||
StartMessage.set("id", RPCID);
|
||||
StartMessage.set("params", Params);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(StartMessage, OS);
|
||||
return Send(OS.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopTelemetry(uint64_t RPCID) {
|
||||
poco_information(Logger_, fmt::format("TELEMETRY({}): Stopping.", CId_));
|
||||
Poco::JSON::Object StopMessage;
|
||||
StopMessage.set("jsonrpc", "2.0");
|
||||
StopMessage.set("method", "telemetry");
|
||||
Poco::JSON::Object Params;
|
||||
Params.set("serial", SerialNumber_);
|
||||
Params.set("interval", 0);
|
||||
StopMessage.set("id", RPCID);
|
||||
StopMessage.set("params", Params);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(StopMessage, OS);
|
||||
TelemetryKafkaPackets_ = TelemetryWebSocketPackets_ = TelemetryInterval_ =
|
||||
TelemetryKafkaTimer_ = TelemetryWebSocketTimer_ = 0;
|
||||
return Send(OS.str());
|
||||
}
|
||||
|
||||
void AP_WS_Connection::UpdateCounts() {
|
||||
State_.kafkaClients = TelemetryKafkaRefCount_;
|
||||
State_.webSocketClients = TelemetryWebSocketRefCount_;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t Interval,
|
||||
uint64_t LifeTime) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryWebSocketRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? ( Interval< TelemetryInterval_ ? Interval : TelemetryInterval_) : Interval;
|
||||
auto TelemetryWebSocketTimer = LifeTime + Utils::Now();
|
||||
TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > TelemetryWebSocketTimer_ ? TelemetryWebSocketTimer : TelemetryWebSocketTimer_;
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
return StartTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t Interval, uint64_t LifeTime) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryKafkaRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? ( Interval<TelemetryInterval_ ? Interval : TelemetryInterval_) : Interval;
|
||||
auto TelemetryKafkaTimer = LifeTime + Utils::Now();
|
||||
TelemetryKafkaTimer_ = TelemetryKafkaTimer > TelemetryKafkaTimer_ ? TelemetryKafkaTimer : TelemetryKafkaTimer_;
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
return StartTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopWebSocketTelemetry(uint64_t RPCID) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
if (TelemetryWebSocketRefCount_)
|
||||
TelemetryWebSocketRefCount_--;
|
||||
UpdateCounts();
|
||||
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
|
||||
TelemetryReporting_ = false;
|
||||
StopTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopKafkaTelemetry(uint64_t RPCID) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
if (TelemetryKafkaRefCount_)
|
||||
TelemetryKafkaRefCount_--;
|
||||
UpdateCounts();
|
||||
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
|
||||
TelemetryReporting_ = false;
|
||||
StopTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
|
||||
if(!Valid_)
|
||||
return;
|
||||
|
||||
if(!AP_WS_Server()->Running())
|
||||
return EndConnection();
|
||||
|
||||
if(!ValidatedDevice())
|
||||
return;
|
||||
|
||||
try {
|
||||
return ProcessIncomingFrame();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
return EndConnection();
|
||||
} catch (const std::exception &E) {
|
||||
std::string W = E.what();
|
||||
poco_information(Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_));
|
||||
return EndConnection();
|
||||
} catch (...) {
|
||||
poco_information(Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingFrame() {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
try {
|
||||
int Op, flags;
|
||||
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
|
||||
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
poco_information(Logger_, fmt::format("DISCONNECT({}): device has disconnected. Session={}", CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
IncomingFrame.append(0);
|
||||
|
||||
State_.RX += IncomingSize;
|
||||
State_.MessageCount++;
|
||||
State_.LastContact = Utils::Now();
|
||||
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Object PingObject;
|
||||
Poco::JSON::Object PingDetails;
|
||||
PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware);
|
||||
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
|
||||
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
PingDetails.set("locale", State_.locale );
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(PingObject, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
poco_trace(Logger_, fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", CId_,
|
||||
IncomingSize, flags, IncomingFrame.begin()));
|
||||
|
||||
Poco::JSON::Parser parser;
|
||||
auto ParsedMessage = parser.parse(IncomingFrame.begin());
|
||||
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
|
||||
if (IncomingJSON->has(uCentralProtocol::METHOD) &&
|
||||
IncomingJSON->has(uCentralProtocol::PARAMS)) {
|
||||
ProcessJSONRPCEvent(IncomingJSON);
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
|
||||
IncomingJSON->has(uCentralProtocol::ID)) {
|
||||
poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, IncomingFrame.begin()));
|
||||
ProcessJSONRPCResult(IncomingJSON);
|
||||
} else {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
|
||||
CId_, IncomingFrame.begin()));
|
||||
}
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
|
||||
ProcessIncomingRadiusData(IncomingJSON);
|
||||
} else {
|
||||
std::ostringstream iS;
|
||||
IncomingJSON->stringify(iS);
|
||||
std::cout << iS.str() << std::endl;
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"FRAME({}): illegal transaction header, missing 'jsonrpc'", CId_));
|
||||
Errors_++;
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
poco_information(Logger_,
|
||||
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
|
||||
return EndConnection();
|
||||
} break;
|
||||
|
||||
default: {
|
||||
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", CId_,
|
||||
std::to_string(Op)));
|
||||
} break;
|
||||
}
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_warning(Logger_, fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
poco_warning(Logger_, fmt::format("JSONException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_warning(Logger_, fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_warning(Logger_, fmt::format("SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_warning(Logger_, fmt::format("SSLException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_, fmt::format("NetException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::IOException &E) {
|
||||
poco_warning(Logger_, fmt::format("IOException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_, fmt::format("Exception({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const std::exception &E) {
|
||||
poco_warning(Logger_, fmt::format("std::exception({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.what(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("UnknownException({}): Device must be disconnected. Unknown exception. Session:{}", CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
if (Errors_ < 10)
|
||||
return;
|
||||
|
||||
poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::Send(const std::string &Payload) {
|
||||
try {
|
||||
size_t BytesSent = WS_->sendFrame(Payload.c_str(), (int)Payload.size());
|
||||
State_.TX += BytesSent;
|
||||
return BytesSent == Payload.size();
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Base64Encode(const unsigned char *buffer, std::size_t size) {
|
||||
return Utils::base64encode(buffer,size);
|
||||
}
|
||||
|
||||
std::string Base64Decode(const std::string &F) {
|
||||
std::istringstream ifs(F);
|
||||
Poco::Base64Decoder b64in(ifs);
|
||||
std::ostringstream ofs;
|
||||
Poco::StreamCopier::copyStream(b64in, ofs);
|
||||
return ofs.str();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSAUTH);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusAccountingData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSACCT);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusCoAData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSCOA);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
|
||||
if( Doc->has(uCentralProtocol::RADIUSDATA)) {
|
||||
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();
|
||||
if(Type==uCentralProtocol::RADIUSACCT) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAccountingData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
} else if(Type==uCentralProtocol::RADIUSAUTH) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
} else if(Type==uCentralProtocol::RADIUSCOA) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendCoAData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
161
src/AP_WS_Connection.h
Normal file
161
src/AP_WS_Connection.h
Normal file
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_Connection {
|
||||
static constexpr int BufSize = 256000;
|
||||
public:
|
||||
explicit AP_WS_Connection( Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
uint64_t connection_id,
|
||||
Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R);
|
||||
~AP_WS_Connection();
|
||||
|
||||
void EndConnection();
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr & Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
|
||||
void ProcessIncomingFrame();
|
||||
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
|
||||
|
||||
bool Send(const std::string &Payload);
|
||||
|
||||
bool SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusCoAData(const unsigned char * buffer, std::size_t size);
|
||||
|
||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);
|
||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf);
|
||||
bool LookForUpgrade(uint64_t UUID, uint64_t & UpgradedUUID);
|
||||
static bool ExtractBase64CompressedData(const std::string & CompressedData, std::string & UnCompressedData, uint64_t compress_sz);
|
||||
void LogException(const Poco::Exception &E);
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval, uint64_t TelemetryWebSocketTimer);
|
||||
bool SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t interval, uint64_t TelemetryKafkaTimer);
|
||||
bool StopWebSocketTelemetry(uint64_t RPCID);
|
||||
bool StopKafkaTelemetry(uint64_t RPCID);
|
||||
|
||||
inline void GetLastStats(std::string &LastStats) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
LastStats = RawLastStats_;
|
||||
}
|
||||
|
||||
inline void SetLastStats(const std::string &LastStats) {
|
||||
std::unique_lock G(ConnectionMutex_);
|
||||
RawLastStats_ = LastStats;
|
||||
}
|
||||
|
||||
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
|
||||
std::unique_lock G(ConnectionMutex_);
|
||||
RawLastHealthcheck_ = H;
|
||||
}
|
||||
|
||||
inline void GetLastHealthCheck(GWObjects::HealthCheck &H) {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
H = RawLastHealthcheck_;
|
||||
}
|
||||
|
||||
inline void GetState(GWObjects::ConnectionState &State) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
State = State_;
|
||||
}
|
||||
|
||||
inline void GetRestrictions(GWObjects::DeviceRestrictions & R) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
R = Restrictions_;
|
||||
}
|
||||
|
||||
void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
|
||||
void Process_state(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
|
||||
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
bool ValidatedDevice();
|
||||
|
||||
inline bool GetTelemetryParameters(bool & Reporting, uint64_t & Interval,
|
||||
uint64_t & WebSocketTimer, uint64_t & KafkaTimer,
|
||||
uint64_t &WebSocketCount, uint64_t & KafkaCount,
|
||||
uint64_t &WebSocketPackets,
|
||||
uint64_t &KafkaPackets ) const {
|
||||
Reporting = TelemetryReporting_;
|
||||
WebSocketTimer = TelemetryWebSocketTimer_;
|
||||
KafkaTimer = TelemetryKafkaTimer_;
|
||||
WebSocketCount = TelemetryWebSocketRefCount_;
|
||||
KafkaCount = TelemetryKafkaRefCount_;
|
||||
Interval = TelemetryInterval_;
|
||||
WebSocketPackets = TelemetryWebSocketPackets_;
|
||||
KafkaPackets = TelemetryKafkaPackets_;
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class AP_WS_Server;
|
||||
|
||||
inline GWObjects::DeviceRestrictions Restrictions() const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
return Restrictions_;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex ConnectionMutex_;
|
||||
std::shared_mutex TelemetryMutex_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
std::string SerialNumber_;
|
||||
uint64_t SerialNumberInt_=0;
|
||||
std::string Compatible_;
|
||||
std::atomic_bool Registered_ = false ;
|
||||
std::string CId_;
|
||||
std::string CN_;
|
||||
uint64_t Errors_=0;
|
||||
Poco::Net::IPAddress PeerAddress_;
|
||||
volatile bool TelemetryReporting_ = false;
|
||||
volatile uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
volatile uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
volatile uint64_t TelemetryKafkaTimer_ = 0 ;
|
||||
volatile uint64_t TelemetryInterval_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketPackets_=0;
|
||||
volatile uint64_t TelemetryKafkaPackets_=0;
|
||||
GWObjects::ConnectionState State_;
|
||||
std::string RawLastStats_;
|
||||
GWObjects::HealthCheck RawLastHealthcheck_;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
|
||||
std::atomic_flag Dead_=false;
|
||||
std::atomic_bool DeviceValidated_=false;
|
||||
std::atomic_bool Valid_=false;
|
||||
OpenWifi::GWObjects::DeviceRestrictions Restrictions_;
|
||||
|
||||
static inline std::atomic_uint64_t ConcurrentStartingDevices_=0;
|
||||
|
||||
bool StartTelemetry(uint64_t RPCID);
|
||||
bool StopTelemetry(uint64_t RPCID);
|
||||
void UpdateCounts();
|
||||
};
|
||||
|
||||
}
|
||||
26
src/AP_WS_Process_cfgpending.cpp
Normal file
26
src/AP_WS_Process_cfgpending.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "fmt/format.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::ACTIVE)) {
|
||||
|
||||
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
[[maybe_unused]] uint64_t Active = ParamsObj->get(uCentralProtocol::ACTIVE);
|
||||
poco_trace(Logger_, fmt::format("CFG-PENDING({}): Active: {} Target: {}", CId_, Active, UUID));
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("CFG-PENDING({}): Missing some parameters", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
162
src/AP_WS_Process_connect.cpp
Normal file
162
src/AP_WS_Process_connect.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
#include "FindCountry.h"
|
||||
#include "Daemon.h"
|
||||
#include "CentralConfig.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::FIRMWARE) &&
|
||||
ParamsObj->has(uCentralProtocol::CAPABILITIES)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
|
||||
auto Capabilities = ParamsObj->getObject(uCentralProtocol::CAPABILITIES);
|
||||
|
||||
SerialNumber_ = Serial;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
CommandManager()->ClearQueue(SerialNumberInt_);
|
||||
|
||||
AP_WS_Server()->SetSessionDetails(State_.sessionId,SerialNumberInt_);
|
||||
|
||||
std::lock_guard Lock(ConnectionMutex_);
|
||||
Config::Capabilities Caps(Capabilities);
|
||||
|
||||
Compatible_ = Caps.Compatible();
|
||||
|
||||
State_.UUID = UUID;
|
||||
State_.Firmware = Firmware;
|
||||
State_.PendingUUID = 0;
|
||||
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
|
||||
CId_ = SerialNumber_ + "@" + CId_;
|
||||
|
||||
auto IP = PeerAddress_.toString();
|
||||
if(IP.substr(0,7)=="::ffff:") {
|
||||
IP = IP.substr(7);
|
||||
}
|
||||
|
||||
bool RestrictedDevice = false;
|
||||
if(Capabilities->has("restrictions")){
|
||||
RestrictedDevice = true;
|
||||
Poco::JSON::Object::Ptr RestrictionObject = Capabilities->getObject("restrictions");
|
||||
Restrictions_.from_json(RestrictionObject);
|
||||
}
|
||||
|
||||
State_.locale = FindCountryFromIP()->Get(IP);
|
||||
GWObjects::Device DeviceInfo;
|
||||
auto DeviceExists = StorageService()->GetDevice(SerialNumber_,DeviceInfo);
|
||||
if (Daemon()->AutoProvisioning() && !DeviceExists) {
|
||||
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_);
|
||||
} else if (DeviceExists) {
|
||||
StorageService()->UpdateDeviceCapabilities(SerialNumber_, Caps );
|
||||
int Updated{0};
|
||||
if(!Firmware.empty()) {
|
||||
if(Firmware!=DeviceInfo.Firmware) {
|
||||
DeviceInfo.Firmware = Firmware;
|
||||
DeviceInfo.LastFWUpdate = Utils::Now();
|
||||
++Updated;
|
||||
|
||||
GWWebSocketNotifications::SingleDeviceFirmwareChange_t Notification;
|
||||
Notification.content.serialNumber = SerialNumber_;
|
||||
Notification.content.newFirmware = Firmware;
|
||||
GWWebSocketNotifications::DeviceFirmwareUpdated(Notification);
|
||||
} else if(DeviceInfo.LastFWUpdate==0) {
|
||||
DeviceInfo.LastFWUpdate = Utils::Now();
|
||||
++Updated;
|
||||
}
|
||||
}
|
||||
|
||||
if(DeviceInfo.locale != State_.locale) {
|
||||
DeviceInfo.locale = State_.locale;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if(Compatible_ != DeviceInfo.DeviceType) {
|
||||
DeviceInfo.DeviceType = Compatible_;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if(RestrictedDevice != DeviceInfo.restrictedDevice) {
|
||||
DeviceInfo.restrictedDevice = RestrictedDevice;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if(Restrictions_ != DeviceInfo.restrictionDetails) {
|
||||
DeviceInfo.restrictionDetails = Restrictions_;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if(Updated) {
|
||||
StorageService()->UpdateDevice(DeviceInfo);
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID=0;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
}
|
||||
|
||||
State_.Compatible = Compatible_;
|
||||
State_.Connected = true;
|
||||
ConnectionCompletionTime_ = std::chrono::high_resolution_clock::now() - ConnectionStart_;
|
||||
State_.connectionCompletionTime = ConnectionCompletionTime_.count();
|
||||
|
||||
if(State_.VerifiedCertificate == GWObjects::VALID_CERTIFICATE) {
|
||||
if (( Utils::SerialNumberMatch(CN_, SerialNumber_, (int)AP_WS_Server()->MismatchDepth())) ||
|
||||
AP_WS_Server()->IsSimSerialNumber(CN_)) {
|
||||
State_.VerifiedCertificate = GWObjects::VERIFIED;
|
||||
poco_information(Logger_, fmt::format("CONNECT({}): Fully validated and authenticated device. Session={} ConnectionCompletion Time={}",
|
||||
CId_,
|
||||
State_.sessionId,
|
||||
State_.connectionCompletionTime ));
|
||||
} else {
|
||||
State_.VerifiedCertificate = GWObjects::MISMATCH_SERIAL;
|
||||
if(AP_WS_Server()->AllowSerialNumberMismatch()) {
|
||||
poco_information(
|
||||
Logger_, fmt::format("CONNECT({}): Serial number mismatch allowed. CN={} Serial={} Session={} ConnectionCompletion Time={}",
|
||||
CId_, CN_, SerialNumber_, State_.sessionId,
|
||||
State_.connectionCompletionTime));
|
||||
} else {
|
||||
poco_information(
|
||||
Logger_, fmt::format("CONNECT({}): Serial number mismatch disallowed. Device rejected. CN={} Serial={} Session={}",
|
||||
CId_, CN_, SerialNumber_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::SingleDevice_t Notification;
|
||||
Notification.content.serialNumber = SerialNumber_;
|
||||
GWWebSocketNotifications::DeviceConnected(Notification);
|
||||
|
||||
// std::cout << "Serial: " << SerialNumber_ << "Session: " << State_.sessionId << std::endl;
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
ParamsObj->set("locale", State_.locale );
|
||||
ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,fmt::format("INVALID-PROTOCOL({}): Missing one of uuid, firmware, or capabilities", CId_));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
38
src/AP_WS_Process_crashlog.cpp
Normal file
38
src/AP_WS_Process_crashlog.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "framework/utils.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
poco_trace(Logger_, fmt::format("CRASH-LOG({}): new entry.", CId_));
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/AP_WS_Process_deviceupdate.cpp
Normal file
27
src/AP_WS_Process_deviceupdate.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has("currentPassword")) {
|
||||
auto Password = ParamsObj->get("currentPassword").toString();
|
||||
|
||||
StorageService()->SetDevicePassword(Serial, Password);
|
||||
poco_trace(Logger_, fmt::format("DEVICEUPDATE({}): Device is updating its login password.", Serial));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
74
src/AP_WS_Process_healthcheck.cpp
Normal file
74
src/AP_WS_Process_healthcheck.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/utils.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
|
||||
ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
|
||||
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
|
||||
if (CheckData.empty())
|
||||
CheckData = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("HEALTHCHECK({}): UUID={} Updating.", CId_, UUID));
|
||||
} else {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("HEALTHCHECK({}): UUID={} Updating for CMD={}.", CId_,
|
||||
UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
|
||||
GWObjects::HealthCheck Check;
|
||||
|
||||
Check.SerialNumber = SerialNumber_;
|
||||
Check.Recorded = Utils::Now();
|
||||
Check.UUID = UUID;
|
||||
Check.Data = CheckData;
|
||||
Check.Sanity = Sanity;
|
||||
|
||||
StorageService()->AddHealthCheckData(Check);
|
||||
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, CheckData);
|
||||
}
|
||||
|
||||
SetLastHealthCheck(Check);
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
ParamsObj->set("timestamp", Utils::Now());
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
44
src/AP_WS_Process_log.cpp
Normal file
44
src/AP_WS_Process_log.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::LOG) && ParamsObj->has(uCentralProtocol::SEVERITY)) {
|
||||
poco_trace(Logger_, fmt::format("LOG({}): new entry.", CId_));
|
||||
auto Log = ParamsObj->get(uCentralProtocol::LOG).toString();
|
||||
auto Severity = ParamsObj->get(uCentralProtocol::SEVERITY);
|
||||
std::string DataStr = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
if (ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
auto DataObj = ParamsObj->get(uCentralProtocol::DATA);
|
||||
if (DataObj.isStruct())
|
||||
DataStr = DataObj.toString();
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = Log,
|
||||
.Data = DataStr,
|
||||
.Severity = Severity,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 0,
|
||||
.UUID = State_.UUID};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/AP_WS_Process_ping.cpp
Normal file
18
src/AP_WS_Process_ping.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "fmt/format.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_ping(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID)) {
|
||||
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
poco_trace(Logger_, fmt::format("PING({}): Current config is {}", CId_, UUID));
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("PING({}): Missing parameter.", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/AP_WS_Process_recovery.cpp
Normal file
67
src/AP_WS_Process_recovery.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "fmt/format.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_recovery(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::SERIAL) &&
|
||||
ParamsObj->has(uCentralProtocol::FIRMWARE) && ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::REBOOT) &&
|
||||
ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
|
||||
LogText = "Firmware: " + ParamsObj->get(uCentralProtocol::FIRMWARE).toString() + "\r\n";
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
|
||||
if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroServiceCreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::REBOOT;
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
bool Sent;
|
||||
CommandManager()->PostCommand(CommandManager()->Next_RPC_ID(), APCommands::Commands::reboot, SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
poco_information(Logger_, fmt::format("RECOVERY({}): Recovery mode received, need for a reboot.", CId_));
|
||||
} else {
|
||||
poco_information(Logger_, fmt::format(
|
||||
"RECOVERY({}): Recovery mode received, no need for a reboot.", CId_));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("RECOVERY({}): Recovery missing one of serialnumber, firmware, uuid, loglines, reboot",
|
||||
CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/AP_WS_Process_state.cpp
Normal file
74
src/AP_WS_Process_state.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
#include "StateUtils.h"
|
||||
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_state(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::STATE)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto StateStr = ParamsObj->get(uCentralProtocol::STATE).toString();
|
||||
auto StateObj = ParamsObj->getObject(uCentralProtocol::STATE);
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty()) {
|
||||
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating.", CId_, UUID));
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating for CMD={}.",
|
||||
CId_, UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
SetLastStats(StateStr);
|
||||
|
||||
GWObjects::Statistics Stats{
|
||||
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
|
||||
Stats.Recorded = Utils::Now();
|
||||
StorageService()->AddStatisticsData(Stats);
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, StateStr);
|
||||
}
|
||||
|
||||
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
|
||||
State_.Associations_5G,
|
||||
State_.Associations_6G
|
||||
);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
N.content.serialNumber = SerialNumber_;
|
||||
GWWebSocketNotifications::DeviceStatistics(N);
|
||||
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("STATE({}): Invalid request. Missing serial, uuid, or state", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/AP_WS_Process_telemetry.cpp
Normal file
59
src/AP_WS_Process_telemetry.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/utils.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_telemetry(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
poco_trace(Logger_,fmt::format("Telemetry data received for {}", SerialNumber_));
|
||||
if (TelemetryReporting_) {
|
||||
if (ParamsObj->has("data")) {
|
||||
auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
|
||||
Payload->set("timestamp", Utils::Now());
|
||||
std::ostringstream SS;
|
||||
Payload->stringify(SS);
|
||||
auto now=Utils::Now();
|
||||
if (TelemetryWebSocketRefCount_) {
|
||||
if(now<TelemetryWebSocketTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
|
||||
TelemetryWebSocketPackets_++;
|
||||
State_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, SS.str());
|
||||
} else {
|
||||
StopWebSocketTelemetry(CommandManager()->Next_RPC_ID());
|
||||
}
|
||||
}
|
||||
if (TelemetryKafkaRefCount_) {
|
||||
if(KafkaManager()->Enabled() && now<TelemetryKafkaTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl;
|
||||
TelemetryKafkaPackets_++;
|
||||
State_.kafkaPackets = TelemetryKafkaPackets_;
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
|
||||
SS.str());
|
||||
} else {
|
||||
StopKafkaTelemetry(CommandManager()->Next_RPC_ID());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poco_debug(Logger_,fmt::format("TELEMETRY({}): Invalid telemetry packet.",SerialNumber_));
|
||||
}
|
||||
} else {
|
||||
// if we are ignoring telemetry, then close it down on the device.
|
||||
poco_debug(Logger_,fmt::format("TELEMETRY({}): Stopping runaway telemetry.",SerialNumber_));
|
||||
StopTelemetry(CommandManager()->Next_RPC_ID());
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/AP_WS_Process_venuebroadcast.cpp
Normal file
17
src/AP_WS_Process_venuebroadcast.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "VenueBroadcaster.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if(ParamsObj->has("data") && ParamsObj->has("serial") && ParamsObj->has("timestamp")) {
|
||||
VenueBroadcaster()->Broadcast(
|
||||
ParamsObj->get("serial").toString(),
|
||||
ParamsObj->get("data").toString(),
|
||||
ParamsObj->get("timestamp"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,63 +5,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include "Poco/Environment.h"
|
||||
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ReactorThreadPool {
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit ReactorThreadPool() {
|
||||
if(Poco::Environment::processorCount()>8)
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()/2;
|
||||
else
|
||||
NumberOfThreads_ = 2;
|
||||
Start("ReactorThreadPool");
|
||||
explicit AP_WS_ReactorThreadPool() {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()*2;
|
||||
if(NumberOfThreads_==0)
|
||||
NumberOfThreads_=4;
|
||||
}
|
||||
|
||||
~ ReactorThreadPool() {
|
||||
~ AP_WS_ReactorThreadPool() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Start(const std::string & ThreadNamePrefix) {
|
||||
void Start() {
|
||||
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
|
||||
auto NewReactor = std::make_unique<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->setStackSize(2000000);
|
||||
NewThread->start(*NewReactor);
|
||||
std::string ThreadName{ThreadNamePrefix + "#" + std::to_string(i)};
|
||||
std::string ThreadName{"ap:react:" + std::to_string(i)};
|
||||
Utils::SetThreadName(*NewThread,ThreadName.c_str());
|
||||
Reactors_.emplace_back(std::move(NewReactor));
|
||||
Threads_.emplace_back(std::move(NewThread));
|
||||
}
|
||||
}
|
||||
|
||||
inline static auto instance() {
|
||||
static auto instance_ = new ReactorThreadPool;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for (auto &i : Reactors_)
|
||||
i->stop();
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor &NextReactor() {
|
||||
std::lock_guard G(Mutex_);
|
||||
std::shared_lock Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
std::shared_mutex Mutex_;
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
|
||||
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
|
||||
};
|
||||
inline auto ReactorThreadPool() { return ReactorThreadPool::instance(); }
|
||||
}
|
||||
477
src/AP_WS_Server.cpp
Normal file
477
src/AP_WS_Server.cpp
Normal file
@@ -0,0 +1,477 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "TelemetryStream.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) {
|
||||
try {
|
||||
AP_WS_Server()->AddConnection(id_,std::make_shared<AP_WS_Connection>(request,response,id_, Logger_, AP_WS_Server()->NextReactor()));
|
||||
} catch (...) {
|
||||
poco_warning(Logger_,"Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
bool AP_WS_Server::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
|
||||
if(IsCertOk()) {
|
||||
if(!Certificate.issuedBy(*IssuerCert_)) {
|
||||
poco_warning(Logger(),fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AP_WS_Server::Start() {
|
||||
|
||||
AllowSerialNumberMismatch_ = MicroServiceConfigGetBool("openwifi.certificates.allowmismatch",true);
|
||||
MismatchDepth_ = MicroServiceConfigGetInt("openwifi.certificates.mismatchdepth",2);
|
||||
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
|
||||
Reactor_pool_->Start();
|
||||
|
||||
for(const auto & Svr : ConfigServersList_ ) {
|
||||
|
||||
poco_notice(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(),
|
||||
Svr.Port(), Svr.KeyFile(), Svr.CertFile()));
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if (!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
|
||||
if (!IsCertOk()) {
|
||||
IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
|
||||
poco_information(Logger(),
|
||||
fmt::format("Certificate Issuer Name:{}", IssuerCert_->issuerName()));
|
||||
}
|
||||
|
||||
Poco::Net::Context::Params P;
|
||||
|
||||
P.verificationMode = Poco::Net::Context::VERIFY_ONCE;
|
||||
P.verificationDepth = 9;
|
||||
P.loadDefaultCAs = Svr.RootCA().empty();
|
||||
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
|
||||
P.dhUse2048Bits = true;
|
||||
P.caLocation = Svr.Cas();
|
||||
|
||||
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
|
||||
|
||||
/* if(!Svr.KeyFilePassword().empty()) {
|
||||
auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(Svr.KeyFilePassword(),Logger()));
|
||||
Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr,Context);
|
||||
}
|
||||
*/
|
||||
Poco::Crypto::X509Certificate Cert(Svr.CertFile());
|
||||
Poco::Crypto::X509Certificate Root(Svr.RootCA());
|
||||
|
||||
Context->useCertificate(Cert);
|
||||
Context->addChainCertificate(Root);
|
||||
|
||||
Context->addCertificateAuthority(Root);
|
||||
Poco::Crypto::X509Certificate Issuing(Svr.IssuerCertFile());
|
||||
Context->addChainCertificate(Issuing);
|
||||
Context->addCertificateAuthority(Issuing);
|
||||
|
||||
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
|
||||
Context->usePrivateKey(Key);
|
||||
|
||||
Context->setSessionCacheSize(0);
|
||||
Context->setSessionTimeout(120);
|
||||
Context->flushSessionCache();
|
||||
Context->enableSessionCache(true);
|
||||
Context->enableExtendedCertificateVerification(false);
|
||||
// Context->disableStatelessSessionResumption();
|
||||
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 | Poco::Net::Context::PROTO_TLSV1_1);
|
||||
|
||||
auto WebServerHttpParams = new Poco::Net::HTTPServerParams;
|
||||
WebServerHttpParams->setMaxThreads(50);
|
||||
WebServerHttpParams->setMaxQueued(200);
|
||||
WebServerHttpParams->setKeepAlive(true);
|
||||
WebServerHttpParams->setName("ws:ap_dispatch");
|
||||
|
||||
if (Svr.Address() == "*") {
|
||||
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
|
||||
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
|
||||
: Poco::Net::AddressFamily::IPv4));
|
||||
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
|
||||
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
} else {
|
||||
Poco::Net::IPAddress Addr(Svr.Address());
|
||||
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
|
||||
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &server:WebServers_) {
|
||||
server->start();
|
||||
}
|
||||
|
||||
ReactorThread_.start(Reactor_);
|
||||
|
||||
auto ProvString = MicroServiceConfigGetString("autoprovisioning.process","default");
|
||||
if(ProvString!="default") {
|
||||
auto Tokens = Poco::StringTokenizer(ProvString, ",");
|
||||
for (const auto &i : Tokens) {
|
||||
if (i == "prov")
|
||||
LookAtProvisioning_ = true;
|
||||
else
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
} else {
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
|
||||
SimulatorId_ = MicroServiceConfigGetString("simulatorid","");
|
||||
SimulatorEnabled_ = !SimulatorId_.empty();
|
||||
Utils::SetThreadName(ReactorThread_,"dev:react:head");
|
||||
|
||||
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(*this,&AP_WS_Server::onGarbageCollecting);
|
||||
Timer_.setStartInterval(10 * 1000);
|
||||
Timer_.setPeriodicInterval(5 * 1000); // every minute
|
||||
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
|
||||
|
||||
Running_ = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
if(!Garbage_.empty()) {
|
||||
Garbage_.clear();
|
||||
}
|
||||
|
||||
static uint64_t last_log = Utils::Now();
|
||||
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
uint64_t total_connected_time=0;
|
||||
|
||||
auto now = Utils::Now();
|
||||
for (const auto & connection:SerialNumbers_) {
|
||||
if(connection.second.second == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (connection.second.second->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time += (now - connection.second.second->State_.started);
|
||||
} else {
|
||||
NumberOfConnectingDevices_++;
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ = (NumberOfConnectedDevices_!=0) ? total_connected_time/NumberOfConnectedDevices_ : 0;
|
||||
if((now-last_log)>120) {
|
||||
last_log = now;
|
||||
poco_information(Logger(),
|
||||
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
|
||||
NumberOfConnectedDevices_, NumberOfConnectingDevices_, AverageDeviceConnectionTime_));
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::NumberOfConnection_t Notification;
|
||||
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
|
||||
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
|
||||
GWWebSocketNotifications::NumberOfConnections(Notification);
|
||||
}
|
||||
|
||||
void AP_WS_Server::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
|
||||
Timer_.stop();
|
||||
|
||||
for(auto &server:WebServers_) {
|
||||
server->stopAll();
|
||||
}
|
||||
Reactor_pool_->Stop();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->GetLastStats(Statistics);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->GetState(State);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->GetLastHealthCheck(CheckData);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Conn = Sessions_.find(connection_id);
|
||||
if(Conn == end(Sessions_))
|
||||
return;
|
||||
|
||||
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
|
||||
if( (CurrentSerialNumber==SerialNumbers_.end()) ||
|
||||
(CurrentSerialNumber->second.first<connection_id)) {
|
||||
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t serial_number) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
|
||||
auto Session = Sessions_.find(session_id);
|
||||
if(Session==end(Sessions_))
|
||||
return false;
|
||||
|
||||
Garbage_.push_back(Session->second);
|
||||
|
||||
auto Device = SerialNumbers_.find(serial_number);
|
||||
if (Device == end(SerialNumbers_)) {
|
||||
Sessions_.erase(Session);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Device->second.first==session_id) {
|
||||
Sessions_.erase(Session);
|
||||
SerialNumbers_.erase(Device);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sessions_.erase(Session);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions & Restrictions) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->GetRestrictions(Restrictions);
|
||||
return DevicePtr->State_.Connected;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
return DevicePtr->State_.Connected;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string & Payload) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
try {
|
||||
return DevicePtr->Send(Payload);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->StopWebSocketTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
|
||||
}
|
||||
|
||||
void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
|
||||
}
|
||||
|
||||
void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->StopKafkaTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void AP_WS_Server::GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
|
||||
uint64_t & TelemetryInterval,
|
||||
uint64_t & TelemetryWebSocketTimer,
|
||||
uint64_t & TelemetryKafkaTimer,
|
||||
uint64_t & TelemetryWebSocketCount,
|
||||
uint64_t & TelemetryKafkaCount,
|
||||
uint64_t & TelemetryWebSocketPackets,
|
||||
uint64_t & TelemetryKafkaPackets) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->GetTelemetryParameters(
|
||||
TelemetryRunning, TelemetryInterval, TelemetryWebSocketTimer, TelemetryKafkaTimer,
|
||||
TelemetryWebSocketCount, TelemetryKafkaCount, TelemetryWebSocketPackets,
|
||||
TelemetryKafkaPackets);
|
||||
}
|
||||
|
||||
bool AP_WS_Server::SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->SendRadiusAccountingData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->SendRadiusAuthenticationData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->SendRadiusCoAData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} //namespace
|
||||
210
src/AP_WS_Server.h
Normal file
210
src/AP_WS_Server.h
Normal file
@@ -0,0 +1,210 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/ParallelSocketAcceptor.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include "Poco/Timer.h"
|
||||
#include "Poco/Net/HTTPRequestHandler.h"
|
||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
|
||||
#include "framework/utils.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit AP_WS_RequestHandler(Poco::Logger &L, uint64_t id)
|
||||
: Logger_(L),
|
||||
id_(id){
|
||||
};
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
uint64_t id_=0;
|
||||
};
|
||||
|
||||
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L)
|
||||
: Logger_(L) {
|
||||
}
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *
|
||||
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
|
||||
if (request.find("Upgrade") != request.end() &&
|
||||
Poco::icompare(request["Upgrade"], "websocket") == 0) {
|
||||
Utils::SetThreadName("ws:conn-init");
|
||||
return new AP_WS_RequestHandler(Logger_,id_++);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static uint64_t id_=1;
|
||||
};
|
||||
|
||||
class AP_WS_Server : public SubSystemServer {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new AP_WS_Server;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool IsCertOk() { return IssuerCert_!= nullptr; }
|
||||
bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
|
||||
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
|
||||
|
||||
inline bool IsSimSerialNumber(const std::string & SerialNumber) const {
|
||||
return IsSim(Poco::toLower(SerialNumber)) && Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
|
||||
}
|
||||
|
||||
inline static bool IsSim(const std::string & SerialNumber) {
|
||||
return SerialNumber.substr(0,6) == "53494d";
|
||||
}
|
||||
|
||||
inline bool IsSimEnabled() const {
|
||||
return SimulatorEnabled_;
|
||||
}
|
||||
|
||||
inline bool AllowSerialNumberMismatch() const {
|
||||
return AllowSerialNumberMismatch_;
|
||||
}
|
||||
|
||||
inline uint64_t MismatchDepth() const {
|
||||
return MismatchDepth_;
|
||||
}
|
||||
|
||||
inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
|
||||
[[nodiscard]] inline Poco::Net::SocketReactor & NextReactor() { return Reactor_pool_->NextReactor(); }
|
||||
[[nodiscard]] inline bool Running() const { return Running_; }
|
||||
|
||||
inline void AddConnection(uint64_t session_id, std::shared_ptr<AP_WS_Connection> Connection ) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
Sessions_[session_id] = std::move(Connection);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<AP_WS_Connection> FindConnection(uint64_t session_id) const {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Connection = Sessions_.find(session_id);
|
||||
if(Connection!=end(Sessions_))
|
||||
return Connection->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) const {
|
||||
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
|
||||
}
|
||||
bool GetStatistics(uint64_t SerialNumber, std::string & Statistics) const ;
|
||||
|
||||
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) const {
|
||||
return GetState(Utils::SerialNumberToInt(SerialNumber), State);
|
||||
}
|
||||
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const;
|
||||
|
||||
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) const {
|
||||
return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
|
||||
}
|
||||
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const ;
|
||||
|
||||
bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions & Restrictions) const ;
|
||||
bool Connected(uint64_t SerialNumber) const ;
|
||||
|
||||
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) const {
|
||||
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
|
||||
}
|
||||
|
||||
bool SendFrame(uint64_t SerialNumber, const std::string & Payload) const ;
|
||||
|
||||
bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
|
||||
void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
|
||||
bool EndSession(uint64_t connection_id, uint64_t serial_number);
|
||||
|
||||
void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
|
||||
void StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber);
|
||||
void SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
|
||||
void StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber);
|
||||
void GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
|
||||
uint64_t & TelemetryInterval,
|
||||
uint64_t & TelemetryWebSocketTimer,
|
||||
uint64_t & TelemetryKafkaTimer,
|
||||
uint64_t & TelemetryWebSocketCount,
|
||||
uint64_t & TelemetryKafkaCount,
|
||||
uint64_t & TelemetryWebSocketPackets,
|
||||
uint64_t & TelemetryKafkaPackets);
|
||||
|
||||
void onGarbageCollecting(Poco::Timer & timer);
|
||||
|
||||
inline void AverageDeviceStatistics( uint64_t & Connections, uint64_t & AverageConnectionTime, uint64_t & NumberOfConnectingDevices) const {
|
||||
Connections = NumberOfConnectedDevices_;
|
||||
AverageConnectionTime = AverageDeviceConnectionTime_;
|
||||
NumberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex WSServerMutex_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
std::string SimulatorId_;
|
||||
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 2, 64};
|
||||
bool LookAtProvisioning_ = false;
|
||||
bool UseDefaultConfig_ = true;
|
||||
bool SimulatorEnabled_=false;
|
||||
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
|
||||
std::atomic_bool Running_=false;
|
||||
// std::map<uint64_t, std::pair<std::shared_ptr<AP_WS_Connection>,bool>> Sessions_;
|
||||
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Sessions_;
|
||||
std::map<uint64_t, std::pair<uint64_t,std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
|
||||
std::atomic_bool AllowSerialNumberMismatch_=true;
|
||||
std::atomic_uint64_t MismatchDepth_=2;
|
||||
|
||||
std::atomic_uint64_t NumberOfConnectedDevices_=0;
|
||||
std::atomic_uint64_t AverageDeviceConnectionTime_=0;
|
||||
std::atomic_uint64_t NumberOfConnectingDevices_=0;
|
||||
|
||||
std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;
|
||||
|
||||
std::unique_ptr<Poco::TimerCallback<AP_WS_Server>> GarbageCollectorCallback_;
|
||||
Poco::Timer Timer_;
|
||||
Poco::Thread GarbageCollector_;
|
||||
|
||||
AP_WS_Server() noexcept:
|
||||
SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto AP_WS_Server() { return AP_WS_Server::instance(); }
|
||||
|
||||
} //namespace
|
||||
@@ -4,8 +4,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "CentralConfig.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
const std::string PlatformCacheFileName{"/plat_cache.json"};
|
||||
@@ -21,17 +28,17 @@ namespace OpenWifi {
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline void Add(const std::string & DeviceType, const std::string & Platform, const std::string & FullCapabilities) {
|
||||
if(DeviceType.empty() || Platform.empty())
|
||||
inline void Add(const Config::Capabilities &Caps) {
|
||||
if(Caps.Compatible().empty() || Caps.Platform().empty())
|
||||
return;
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
if(!PlatformsLoaded_)
|
||||
LoadPlatforms();
|
||||
auto P = Poco::toUpper(Platform);
|
||||
auto Hint = Platforms_.find(DeviceType);
|
||||
auto P = Poco::toUpper(Caps.Platform());
|
||||
auto Hint = Platforms_.find(Caps.Compatible());
|
||||
if(Hint==Platforms_.end()) {
|
||||
Platforms_.insert(std::make_pair(DeviceType,P));
|
||||
Platforms_.insert(std::make_pair(Caps.Compatible(),P));
|
||||
SavePlatforms();
|
||||
} else if(Hint->second != P) {
|
||||
Hint->second = P;
|
||||
@@ -41,12 +48,14 @@ namespace OpenWifi {
|
||||
if(!CapabilitiesLoaded_)
|
||||
LoadCapabilities();
|
||||
|
||||
auto CapHint = Capabilities_.find(DeviceType);
|
||||
auto CapHint = Capabilities_.find(Caps.Compatible());
|
||||
if(CapHint==Capabilities_.end()) {
|
||||
Capabilities_[DeviceType] = nlohmann::json::parse(FullCapabilities);
|
||||
auto C = nlohmann::json::parse(Caps.AsString());
|
||||
C.erase("restrictions");
|
||||
Capabilities_[Caps.Compatible()] = nlohmann::json::parse(Caps.AsString());
|
||||
SaveCapabilities();
|
||||
} else {
|
||||
CapHint->second = nlohmann::json::parse(FullCapabilities);
|
||||
CapHint->second = nlohmann::json::parse(Caps.AsString());
|
||||
SaveCapabilities();
|
||||
}
|
||||
}
|
||||
@@ -91,8 +100,8 @@ namespace OpenWifi {
|
||||
std::atomic_bool CapabilitiesLoaded_=false;
|
||||
std::map<std::string,std::string> Platforms_;
|
||||
CapabilitiesCache_t Capabilities_;
|
||||
std::string PlatformCacheFileName_{ MicroService::instance().DataDir()+PlatformCacheFileName };
|
||||
std::string CapabilitiesCacheFileName_{ MicroService::instance().DataDir()+CapabilitiesCacheFileName };
|
||||
std::string PlatformCacheFileName_{ MicroServiceDataDirectory()+PlatformCacheFileName };
|
||||
std::string CapabilitiesCacheFileName_{ MicroServiceDataDirectory()+CapabilitiesCacheFileName };
|
||||
|
||||
inline void LoadPlatforms() {
|
||||
try {
|
||||
@@ -144,4 +153,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline auto CapabilitiesCache() { return CapabilitiesCache::instance(); };
|
||||
|
||||
}
|
||||
@@ -12,110 +12,141 @@
|
||||
#include "Poco/File.h"
|
||||
|
||||
#include "CentralConfig.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace OpenWifi::Config {
|
||||
|
||||
const static std::string BasicConfig {
|
||||
R"lit({
|
||||
"uuid": 1,
|
||||
"radios": [
|
||||
{
|
||||
"band": "5G",
|
||||
"country": "CA",
|
||||
"channel-mode": "HE",
|
||||
"channel-width": 80,
|
||||
"channel": 32
|
||||
}
|
||||
],
|
||||
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "WAN",
|
||||
"role": "upstream",
|
||||
"services": [ "lldp" ],
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ssids": [
|
||||
{
|
||||
"name": "OpenWifi",
|
||||
"wifi-bands": [
|
||||
"5G"
|
||||
],
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"proto": "psk2",
|
||||
"key": "OpenWifi",
|
||||
"ieee80211w": "optional"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LAN",
|
||||
"role": "downstream",
|
||||
"services": [ "ssh", "lldp" ],
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "192.168.1.1/24",
|
||||
"dhcp": {
|
||||
"lease-first": 10,
|
||||
"lease-count": 100,
|
||||
"lease-time": "6h"
|
||||
}
|
||||
},
|
||||
"ssids": [
|
||||
{
|
||||
"name": "OpenWifi",
|
||||
"wifi-bands": [
|
||||
"5G"
|
||||
],
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"proto": "psk2",
|
||||
"key": "OpenWifi",
|
||||
"ieee80211w": "optional"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"statistics": {
|
||||
"interval": 120,
|
||||
"types": [ "ssids", "lldp", "clients" ]
|
||||
},
|
||||
"health": {
|
||||
"interval": 120
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"lldp": {
|
||||
"describe": "uCentral",
|
||||
"location": "universe"
|
||||
},
|
||||
"ssh": {
|
||||
"port": 22
|
||||
}
|
||||
}
|
||||
})lit"};
|
||||
R"lit(
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "WAN",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh",
|
||||
"lldp",
|
||||
"dhcp-snooping"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "optional",
|
||||
"key": "OpenWifi",
|
||||
"proto": "psk2"
|
||||
},
|
||||
"name": "OpenWifi",
|
||||
"services": [
|
||||
"wifi-frames"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G","5G"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 100,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"subnet": "192.168.1.1/24"
|
||||
},
|
||||
"name": "LAN",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"ssh",
|
||||
"lldp",
|
||||
"dhcp-snooping"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 120
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"country": "CA"
|
||||
},
|
||||
{
|
||||
"allow-dfs": true,
|
||||
"band": "5G",
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"country": "CA"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"lldp": {
|
||||
"describe": "TIP OpenWiFi",
|
||||
"location": "QA"
|
||||
},
|
||||
"ssh": {
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 2
|
||||
}
|
||||
)lit"};
|
||||
|
||||
void Config::SetBasicConfigFile() {
|
||||
try {
|
||||
@@ -197,7 +228,7 @@ namespace OpenWifi::Config {
|
||||
return DefaultConfiguration_;
|
||||
}
|
||||
|
||||
std::string Capabilities::Default() {
|
||||
/* std::string Capabilities::Default() {
|
||||
return std::string(R"lit({"model":{"id":"linksys,ea8300","name":"Linksys EA8300 (Dallas)"},
|
||||
"network":{"lan":{"ifname":"eth0","protocol":"static"},"wan":{"ifname":"eth1","protocol":"dhcp"}},
|
||||
"switch":{"switch0":{"enable":true,"reset":true,"ports":[{"num":0,"device":"eth0","need_tag":false,
|
||||
@@ -211,27 +242,23 @@ namespace OpenWifi::Config {
|
||||
"platform/soc/a800000.wifi":{"band":["5l"],"ht_capa":6639,"vht_capa":865687986,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],
|
||||
"tx_ant":3,"rx_ant":3,"channels":[36,40,44,48,52,56,60,64]}}})lit");
|
||||
}
|
||||
*/
|
||||
|
||||
void Capabilities::Parse() {
|
||||
if(Capabilities_.empty())
|
||||
Capabilities_=Default();
|
||||
|
||||
Capabilities::Capabilities(const Poco::JSON::Object::Ptr &Caps) {
|
||||
try {
|
||||
Poco::JSON::Parser parser;
|
||||
|
||||
auto Result = parser.parse(Capabilities_);
|
||||
auto Objects = Result.extract<Poco::JSON::Object::Ptr>();
|
||||
if(Caps->has("compatible"))
|
||||
Compatible_ = Caps->get("compatible").toString();
|
||||
|
||||
if(Objects->has("compatible"))
|
||||
Compatible_ = Objects->get("compatible").toString();
|
||||
if(Caps->has("model"))
|
||||
Model_ = Caps->get("model").toString();
|
||||
|
||||
if(Objects->has("model"))
|
||||
Model_ = Objects->get("model").toString();
|
||||
if(Caps->has("platform"))
|
||||
Platform_ = Caps->get("platform").toString();
|
||||
|
||||
if(Objects->has("platform"))
|
||||
Platform_ = Objects->get("platform").toString();
|
||||
|
||||
Parsed_ = true ;
|
||||
std::ostringstream OS;
|
||||
Caps->stringify(OS);
|
||||
AsString_ = OS.str();
|
||||
}
|
||||
catch ( const Poco::Exception & E )
|
||||
{
|
||||
@@ -239,22 +266,20 @@ namespace OpenWifi::Config {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string & Capabilities::Compatible() {
|
||||
if(!Parsed_)
|
||||
Parse();
|
||||
const std::string & Capabilities::Compatible() const {
|
||||
return Compatible_;
|
||||
}
|
||||
|
||||
const std::string & Capabilities::Model() {
|
||||
if(!Parsed_)
|
||||
Parse();
|
||||
const std::string & Capabilities::Model() const {
|
||||
return Model_;
|
||||
}
|
||||
|
||||
const std::string & Capabilities::Platform() {
|
||||
if(!Parsed_)
|
||||
Parse();
|
||||
const std::string & Capabilities::Platform() const {
|
||||
return Platform_;
|
||||
}
|
||||
|
||||
const std::string & Capabilities::AsString() const {
|
||||
return AsString_;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -35,29 +35,28 @@ namespace OpenWifi::Config {
|
||||
|
||||
class Capabilities {
|
||||
public:
|
||||
explicit Capabilities(std::string Caps)
|
||||
: Capabilities_(std::move(Caps))
|
||||
{
|
||||
explicit Capabilities(const Poco::JSON::Object::Ptr &Caps);
|
||||
|
||||
}
|
||||
|
||||
Capabilities()
|
||||
/* Capabilities()
|
||||
{
|
||||
Capabilities_ = Default();
|
||||
}
|
||||
|
||||
static std::string Default();
|
||||
|
||||
[[nodiscard]] const std::string & Get() const { return Capabilities_; };
|
||||
[[nodiscard]] const std::string & Compatible();
|
||||
[[nodiscard]] const std::string & Model();
|
||||
[[nodiscard]] const std::string & Platform();
|
||||
*/
|
||||
|
||||
[[nodiscard]] const std::string & Compatible() const;
|
||||
[[nodiscard]] const std::string & Model() const;
|
||||
[[nodiscard]] const std::string & Platform() const;
|
||||
[[nodiscard]] const std::string & AsString() const;
|
||||
|
||||
private:
|
||||
std::string Capabilities_;
|
||||
bool Parsed_=false;
|
||||
std::string Compatible_;
|
||||
std::string Model_;
|
||||
std::string Platform_;
|
||||
std::string AsString_;
|
||||
|
||||
void Parse();
|
||||
};
|
||||
|
||||
@@ -11,211 +11,328 @@
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void CommandManager::run() {
|
||||
Utils::SetThreadName("cmd-mgr");
|
||||
Utils::SetThreadName("cmd:mgr");
|
||||
Running_ = true;
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while(NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification*>(NextMsg.get());
|
||||
|
||||
if(Resp!= nullptr) {
|
||||
const Poco::JSON::Object & Payload = Resp->Payload_;
|
||||
const std::string & SerialNumber = Resp->SerialNumber_;
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while (NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification *>(NextMsg.get());
|
||||
|
||||
std::ostringstream SS;
|
||||
Payload.stringify(SS);
|
||||
try {
|
||||
if (Resp != nullptr) {
|
||||
Poco::JSON::Object::Ptr Payload = Resp->Payload_;
|
||||
std::string SerialNumberStr = Utils::IntToSerialNumber(Resp->SerialNumber_);
|
||||
|
||||
Logger().debug(fmt::format("({}): RPC Response received.", SerialNumber));
|
||||
if(!Payload.has(uCentralProtocol::ID)){
|
||||
Logger().error(fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
} else {
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
if (ID < 2) {
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
bool NoReply = false;
|
||||
|
||||
if (!Payload->has(uCentralProtocol::ID)) {
|
||||
poco_error(Logger(), fmt::format("({}): Invalid RPC response.", SerialNumberStr));
|
||||
} else {
|
||||
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
|
||||
std::lock_guard G(Mutex_);
|
||||
auto RPC = OutStandingRequests_.find(Idx);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
Logger().warning(
|
||||
fmt::format("({}): Outdated RPC {}", SerialNumber, ID));
|
||||
} else {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time =
|
||||
std::chrono::high_resolution_clock::now() - RPC->second->submitted;
|
||||
StorageService()->CommandCompleted(RPC->second->uuid, Payload,
|
||||
rpc_execution_time, true);
|
||||
if (RPC->second->rpc_entry) {
|
||||
RPC->second->rpc_entry->set_value(Payload);
|
||||
uint64_t ID = Payload->get(uCentralProtocol::ID);
|
||||
std::shared_ptr<promise_type_t> TmpRpcEntry;
|
||||
poco_debug(Logger(),fmt::format("({}): Processing {} response.", SerialNumberStr, ID));
|
||||
if (ID > 1) {
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
auto RPC = OutStandingRequests_.find(ID);
|
||||
if (RPC == OutStandingRequests_.end() ||
|
||||
RPC->second.SerialNumber != Resp->SerialNumber_) {
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): RPC {} completed.", SerialNumberStr, ID));
|
||||
} else {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time =
|
||||
std::chrono::high_resolution_clock::now() -
|
||||
RPC->second.submitted;
|
||||
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): Received RPC answer {}. Command={}",
|
||||
SerialNumberStr, ID, APCommands::to_string(RPC->second.Command)));
|
||||
if(RPC->second.Command==APCommands::Commands::script) {
|
||||
if(RPC->second.State==2) {
|
||||
// look at the payload to see if we should continue or not...
|
||||
if (RPC->second.rpc_entry) {
|
||||
TmpRpcEntry = RPC->second.rpc_entry;
|
||||
}
|
||||
|
||||
// Payload->stringify(std::cout);
|
||||
|
||||
if (Payload->has("result")) {
|
||||
auto Result = Payload->getObject("result");
|
||||
if (Result->has("status")) {
|
||||
auto Status = Result->getObject("status");
|
||||
// Status->stringify(std::cout);
|
||||
std::uint64_t Error = Status->get("error");
|
||||
if(Error==0) {
|
||||
StorageService()->CommandCompleted(RPC->second.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
RPC->second.State = 1 ;
|
||||
} else {
|
||||
StorageService()->CommandCompleted(RPC->second.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
std::string ErrorTxt = Status->get("result");
|
||||
StorageService()->CancelWaitFile(RPC->second.UUID, ErrorTxt);
|
||||
RPC->second.State = 0 ;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// std::cout << "Bad payload on command result" << std::endl;
|
||||
RPC->second.State=0;
|
||||
}
|
||||
} else {
|
||||
// std::cout << "Completing script 2 phase commit." << std::endl;
|
||||
StorageService()->CommandCompleted(RPC->second.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
NoReply = true;
|
||||
RPC->second.State=0;
|
||||
}
|
||||
} else {
|
||||
if(RPC->second.Command!=APCommands::Commands::telemetry) {
|
||||
StorageService()->CommandCompleted(
|
||||
RPC->second.UUID, Payload, rpc_execution_time, true);
|
||||
}
|
||||
if (RPC->second.rpc_entry) {
|
||||
TmpRpcEntry = RPC->second.rpc_entry;
|
||||
}
|
||||
RPC->second.State = 0 ;
|
||||
}
|
||||
|
||||
if(RPC->second.State==0) {
|
||||
OutStandingRequests_.erase(ID);
|
||||
}
|
||||
}
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(
|
||||
fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
if(!NoReply && TmpRpcEntry != nullptr)
|
||||
TmpRpcEntry->set_value(Payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),"Exception occurred during run.");
|
||||
}
|
||||
NextMsg = ResponseQueue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger(),"RPC Command processor stopping.");
|
||||
}
|
||||
|
||||
int CommandManager::Start() {
|
||||
Logger().notice("Starting...");
|
||||
ManagerThread.start(*this);
|
||||
poco_notice(Logger(),"Starting...");
|
||||
|
||||
ManagerThread.start(*this);
|
||||
|
||||
JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onJanitorTimer);
|
||||
JanitorTimer_.setStartInterval( 10000 );
|
||||
JanitorTimer_.setPeriodicInterval(10 * 60 * 1000); // 1 hours
|
||||
JanitorTimer_.start(*JanitorCallback_);
|
||||
JanitorTimer_.start(*JanitorCallback_, MicroServiceTimerPool());
|
||||
|
||||
CommandRunnerCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onCommandRunnerTimer);
|
||||
CommandRunnerTimer_.setStartInterval( 10000 );
|
||||
CommandRunnerTimer_.setPeriodicInterval(30 * 1000); // 1 hours
|
||||
CommandRunnerTimer_.start(*CommandRunnerCallback_);
|
||||
CommandRunnerTimer_.start(*CommandRunnerCallback_, MicroServiceTimerPool());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CommandManager::Stop() {
|
||||
Logger().notice("Stopping...");
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
JanitorTimer_.stop();
|
||||
CommandRunnerTimer_.stop();
|
||||
ResponseQueue_.wakeUpAll();
|
||||
ManagerThread.wakeUp();
|
||||
ManagerThread.join();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void CommandManager::WakeUp() {
|
||||
Logger().notice("Waking up...");
|
||||
poco_notice(Logger(),"Waking up...");
|
||||
ManagerThread.wakeUp();
|
||||
}
|
||||
|
||||
void CommandManager::onJanitorTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Utils::SetThreadName("cmd-janitor");
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
Utils::SetThreadName("cmd:janitor");
|
||||
Poco::Logger & MyLogger = Poco::Logger::get("CMD-MGR-JANITOR");
|
||||
MyLogger.information(
|
||||
fmt::format("Removing expired commands: start. {} outstanding-requests {} outstanding-uuids commands.",
|
||||
OutStandingRequests_.size(), OutstandingUUIDs_.size() ));
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
for(auto i=OutStandingRequests_.begin();i!=OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - i->second->submitted;
|
||||
if(delta > 6000000ms) {
|
||||
MyLogger.debug(fmt::format("{}: Timed out.", i->second->uuid));
|
||||
OutstandingUUIDs_.erase(i->second->uuid);
|
||||
i = OutStandingRequests_.erase(i);
|
||||
for(auto request=OutStandingRequests_.begin();request!=OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
|
||||
if(delta > 10min) {
|
||||
MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.",
|
||||
request->second.UUID,
|
||||
APCommands::to_string(request->second.Command),
|
||||
Utils::IntToSerialNumber(request->second.SerialNumber)));
|
||||
request = OutStandingRequests_.erase(request);
|
||||
} else {
|
||||
++i;
|
||||
++request;
|
||||
}
|
||||
}
|
||||
MyLogger.information("Removing expired commands: done.");
|
||||
poco_information(MyLogger,
|
||||
fmt::format("Outstanding-requests {}", OutStandingRequests_.size()));
|
||||
}
|
||||
|
||||
bool CommandManager::IsCommandRunning(const std::string &C) {
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
for (const auto &request : OutStandingRequests_) {
|
||||
if (request.second.UUID == C) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandManager::onCommandRunnerTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
Utils::SetThreadName("cmd-schdlr");
|
||||
Poco::Logger & MyLogger = Poco::Logger::get("CMD-MGR-SCHEDULER");
|
||||
Utils::SetThreadName("cmd:schdlr");
|
||||
Poco::Logger &MyLogger = Poco::Logger::get("CMD-MGR-SCHEDULER");
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if(StorageService()->GetReadyToExecuteCommands(0,200,Commands))
|
||||
{
|
||||
for(auto & Cmd: Commands)
|
||||
{
|
||||
if(!Running_)
|
||||
break;
|
||||
try {
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
if(OutstandingUUIDs_.find(Cmd.UUID)!=OutstandingUUIDs_.end())
|
||||
poco_trace(MyLogger,"Scheduler starting.");
|
||||
|
||||
try {
|
||||
|
||||
StorageService()->RemovedExpiredCommands();
|
||||
StorageService()->RemoveTimedOutCommands();
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
|
||||
poco_trace(MyLogger,fmt::format("Scheduler about to process {} commands.", Commands.size()));
|
||||
for (auto &Cmd : Commands) {
|
||||
if (!Running_) {
|
||||
poco_warning(MyLogger,"Scheduler quitting because service is stopping.");
|
||||
break;
|
||||
}
|
||||
poco_trace(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} Starting processing.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
try {
|
||||
|
||||
// Skip an already running command
|
||||
if(IsCommandRunning(Cmd.UUID))
|
||||
continue;
|
||||
}
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
MyLogger.information(fmt::format("{}: Preparing execution of {} for {}.", Cmd.UUID, Cmd.Command, Cmd.SerialNumber));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk( Cmd.SerialNumber,
|
||||
Cmd.Command,
|
||||
*Params,
|
||||
Cmd.UUID,
|
||||
Sent);
|
||||
if(Sent) {
|
||||
auto now = Utils::Now();
|
||||
// 2 hour timeout for commands
|
||||
if ((now - Cmd.Submitted) > (1 * 60 * 60)) {
|
||||
poco_information(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandTimedOut(Cmd.UUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!AP_WS_Server()->Connected(
|
||||
Utils::SerialNumberToInt(Cmd.SerialNumber))) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Device is not connected.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string ExecutingUUID;
|
||||
APCommands::Commands ExecutingCommand=APCommands::Commands::unknown;
|
||||
if (CommandRunningForDevice(Utils::SerialNumberToInt(Cmd.SerialNumber),
|
||||
ExecutingUUID, ExecutingCommand)) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Device is already busy with command {} (Command={})."
|
||||
, Cmd.UUID, Cmd.SerialNumber, Cmd.Command, ExecutingUUID, APCommands::to_string(ExecutingCommand)));
|
||||
continue;
|
||||
}
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
poco_information(MyLogger, fmt::format("{}: Serial={} Command={} Preparing execution.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk(Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()), Cmd.SerialNumber, Cmd.Command,
|
||||
*Params, Cmd.UUID, Sent);
|
||||
if (Sent) {
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Sent.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
} else {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Re-queued command.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Failed. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Hard failure. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
std::lock_guard M(Mutex_);
|
||||
OutstandingUUIDs_.insert(Cmd.UUID);
|
||||
MyLogger.information(fmt::format("{}: Queued command.", Cmd.UUID));
|
||||
} else {
|
||||
MyLogger.information(fmt::format("{}: Could queue command.", Cmd.UUID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
MyLogger.information(fmt::format("{}: Failed. Command marked as completed.", Cmd.UUID));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
MyLogger.information(fmt::format("{}: Hard failure.", Cmd.UUID));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
}
|
||||
}
|
||||
} catch (Poco::Exception &E) {
|
||||
MyLogger.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(MyLogger,"Exception during command processing.");
|
||||
}
|
||||
poco_trace(MyLogger,"Scheduler done.");
|
||||
}
|
||||
|
||||
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool oneway_rpc,
|
||||
bool disk_only,
|
||||
bool & Sent) {
|
||||
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(
|
||||
uint64_t RPC_ID,
|
||||
APCommands::Commands Command,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &CommandStr,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool oneway_rpc,
|
||||
bool disk_only,
|
||||
bool & Sent) {
|
||||
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(SerialNumber);
|
||||
Sent=false;
|
||||
if(!DeviceRegistry()->Connected(SerialNumber)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::stringstream ToSend;
|
||||
auto Object = std::make_shared<RpcObject>();
|
||||
|
||||
CommandTagIndex Idx;
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
if (oneway_rpc)
|
||||
Idx.Id = 1;
|
||||
else
|
||||
Idx.Id = ++Id_;
|
||||
Idx.SerialNumber = SerialNumber;
|
||||
CommandInfo Idx;
|
||||
Idx.Id = oneway_rpc ? 1 : RPC_ID;
|
||||
Idx.SerialNumber = SerialNumberInt;
|
||||
Idx.Command = Command;
|
||||
if(Command == APCommands::Commands::script)
|
||||
Idx.State=2;
|
||||
Idx.UUID = UUID;
|
||||
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, Idx.Id);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
Object->submitted = std::chrono::high_resolution_clock::now();
|
||||
Object->uuid = UUID;
|
||||
if(disk_only) {
|
||||
Object->rpc_entry = nullptr;
|
||||
} else {
|
||||
Object->rpc_entry = std::make_shared<CommandManager::promise_type_t>();
|
||||
}
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, RPC_ID);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, CommandStr);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
Idx.rpc_entry = disk_only ? nullptr : std::make_shared<CommandManager::promise_type_t>();
|
||||
|
||||
poco_debug(Logger(), fmt::format("{}: Sending command {} to {}. ID: {}", UUID, CommandStr, SerialNumber, RPC_ID));
|
||||
if(AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())) {
|
||||
if(!oneway_rpc) {
|
||||
OutStandingRequests_[Idx] = Object;
|
||||
OutstandingUUIDs_.insert(UUID);
|
||||
std::lock_guard M(Mutex_);
|
||||
OutStandingRequests_[RPC_ID] = Idx;
|
||||
}
|
||||
poco_debug(Logger(), fmt::format("{}: Sent command. ID: {}", UUID, RPC_ID));
|
||||
Sent=true;
|
||||
return Idx.rpc_entry;
|
||||
}
|
||||
|
||||
Logger().information(fmt::format("{}: Sending command. ID: {}", UUID, Idx.Id));
|
||||
if(DeviceRegistry()->SendFrame(SerialNumber, ToSend.str())) {
|
||||
Logger().information(fmt::format("{}: Sent command. ID: {}", UUID, Idx.Id));
|
||||
Sent=true;
|
||||
return Object->rpc_entry;
|
||||
}
|
||||
Logger().information(fmt::format("{}: Failed to send command. ID: {}", UUID, Idx.Id));
|
||||
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID));
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
@@ -13,87 +13,79 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/Timer.h"
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
struct CommandTagIndex {
|
||||
uint64_t Id=0;
|
||||
std::string SerialNumber;
|
||||
};
|
||||
|
||||
inline bool operator <(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id<rhs.Id)
|
||||
return true;
|
||||
if(lhs.Id>rhs.Id)
|
||||
return false;
|
||||
return lhs.SerialNumber<rhs.SerialNumber;
|
||||
}
|
||||
|
||||
inline bool operator ==(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id == rhs.Id && lhs.SerialNumber == rhs.SerialNumber)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
class RPCResponseNotification: public Poco::Notification {
|
||||
public:
|
||||
RPCResponseNotification(const std::string &ser,
|
||||
const Poco::JSON::Object &pl) :
|
||||
RPCResponseNotification(std::uint64_t ser,
|
||||
Poco::JSON::Object::Ptr pl) :
|
||||
SerialNumber_(ser),
|
||||
Payload_(pl)
|
||||
Payload_(std::move(pl))
|
||||
{
|
||||
|
||||
}
|
||||
std::string SerialNumber_;
|
||||
Poco::JSON::Object Payload_;
|
||||
std::uint64_t SerialNumber_;
|
||||
Poco::JSON::Object::Ptr Payload_;
|
||||
};
|
||||
|
||||
|
||||
class CommandManager : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
typedef Poco::JSON::Object objtype_t;
|
||||
typedef std::promise<objtype_t> promise_type_t;
|
||||
struct RpcObject {
|
||||
std::string uuid;
|
||||
using objtype_t = Poco::JSON::Object::Ptr;
|
||||
using promise_type_t = std::promise<objtype_t>;
|
||||
|
||||
struct CommandInfo {
|
||||
std::uint64_t Id=0;
|
||||
std::uint64_t SerialNumber=0;
|
||||
APCommands::Commands Command;
|
||||
std::string UUID;
|
||||
std::uint64_t State=1;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> submitted = std::chrono::high_resolution_clock::now();
|
||||
std::shared_ptr<promise_type_t> rpc_entry;
|
||||
};
|
||||
|
||||
struct RPCResponse {
|
||||
std::string serialNumber;
|
||||
Poco::JSON::Object payload;
|
||||
std::uint64_t serialNumber;
|
||||
Poco::JSON::Object::Ptr payload;
|
||||
|
||||
explicit RPCResponse(const std::string &ser, const Poco::JSON::Object &pl)
|
||||
explicit RPCResponse(std::uint64_t ser, Poco::JSON::Object::Ptr pl)
|
||||
:
|
||||
serialNumber(ser),
|
||||
payload(pl) {
|
||||
payload(std::move(pl)) {
|
||||
}
|
||||
};
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void WakeUp();
|
||||
inline void PostCommandResult(const std::string &SerialNumber, const Poco::JSON::Object &Obj) {
|
||||
std::lock_guard G(Mutex_);
|
||||
// RPCResponseQueue_->Write(RPCResponse{.serialNumber=SerialNumber, .payload = Obj});
|
||||
ResponseQueue_.enqueueNotification(new RPCResponseNotification(SerialNumber,Obj));
|
||||
inline void PostCommandResult(const std::string &SerialNumber, Poco::JSON::Object::Ptr Obj) {
|
||||
ResponseQueue_.enqueueNotification(new RPCResponseNotification(Utils::SerialNumberToInt(SerialNumber),std::move(Obj)));
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(uint64_t RPC_ID,
|
||||
APCommands::Commands Command,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPC_ID,
|
||||
Command,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -101,12 +93,16 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandDisk(
|
||||
uint64_t RPC_ID,
|
||||
APCommands::Commands Command,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPC_ID,
|
||||
Command,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -114,12 +110,16 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommand(
|
||||
uint64_t RPC_ID,
|
||||
APCommands::Commands Command,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPC_ID,
|
||||
Command,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -128,12 +128,16 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWay(
|
||||
uint64_t RPC_ID,
|
||||
APCommands::Commands Command,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPC_ID,
|
||||
Command,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -141,6 +145,8 @@ namespace OpenWifi {
|
||||
false, Sent );
|
||||
}
|
||||
|
||||
bool IsCommandRunning(const std::string &C);
|
||||
|
||||
void run() override;
|
||||
|
||||
static auto instance() {
|
||||
@@ -151,14 +157,42 @@ namespace OpenWifi {
|
||||
inline bool Running() const { return Running_; }
|
||||
void onJanitorTimer(Poco::Timer & timer);
|
||||
void onCommandRunnerTimer(Poco::Timer & timer);
|
||||
void onRPCAnswer(bool& b);
|
||||
inline uint64_t Next_RPC_ID() { return ++Id_; }
|
||||
|
||||
void RemovePendingCommand(std::uint64_t Id) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
OutStandingRequests_.erase(Id);
|
||||
}
|
||||
|
||||
inline bool CommandRunningForDevice(std::uint64_t SerialNumber, std::string & uuid, APCommands::Commands &command) {
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
|
||||
for(const auto &[Request,Command]:OutStandingRequests_) {
|
||||
if(Command.SerialNumber==SerialNumber) {
|
||||
uuid = Command.UUID;
|
||||
command = Command.Command;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void ClearQueue(std::uint64_t SerialNumber) {
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
for(auto Request = OutStandingRequests_.begin(); Request != OutStandingRequests_.end() ; ) {
|
||||
if(Request->second.SerialNumber==SerialNumber)
|
||||
Request = OutStandingRequests_.erase(Request);
|
||||
else
|
||||
++Request;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
volatile bool Running_ = false;
|
||||
mutable std::recursive_mutex LocalMutex_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
volatile uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
std::map<CommandTagIndex,std::shared_ptr<RpcObject>> OutStandingRequests_;
|
||||
std::set<std::string> OutstandingUUIDs_;
|
||||
std::atomic_uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
std::map<std::uint64_t , CommandInfo> OutStandingRequests_;
|
||||
Poco::Timer JanitorTimer_;
|
||||
std::unique_ptr<Poco::TimerCallback<CommandManager>> JanitorCallback_;
|
||||
Poco::Timer CommandRunnerTimer_;
|
||||
@@ -166,6 +200,8 @@ namespace OpenWifi {
|
||||
Poco::NotificationQueue ResponseQueue_;
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommand(
|
||||
uint64_t RPCID,
|
||||
APCommands::Commands Command,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ConfigurationCache {
|
||||
|
||||
@@ -9,23 +9,27 @@
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CommandManager.h"
|
||||
#include "Daemon.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "FileUploader.h"
|
||||
#include "FindCountry.h"
|
||||
#include "OUIServer.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "StorageArchiver.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "WS_Server.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "FindCountry.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "VenueBroadcaster.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
#include "framework/UI_WebSocketClientServer.h"
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
#include "ScriptManager.h"
|
||||
#include "SignatureMgr.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class Daemon *Daemon::instance() {
|
||||
@@ -38,18 +42,19 @@ namespace OpenWifi {
|
||||
StorageService(),
|
||||
SerialNumberCache(),
|
||||
ConfigurationValidator(),
|
||||
WebSocketClientServer(),
|
||||
UI_WebSocketClientServer(),
|
||||
OUIServer(),
|
||||
FindCountryFromIP(),
|
||||
DeviceRegistry(),
|
||||
CommandManager(),
|
||||
FileUploader(),
|
||||
StorageArchiver(),
|
||||
TelemetryStream(),
|
||||
RTTYS_server(),
|
||||
WebSocketServer(),
|
||||
RADIUS_proxy_server(),
|
||||
VenueBroadcaster()
|
||||
VenueBroadcaster(),
|
||||
ScriptManager(),
|
||||
SignatureManager(),
|
||||
AP_WS_Server()
|
||||
});
|
||||
return &instance;
|
||||
}
|
||||
@@ -102,19 +107,33 @@ namespace OpenWifi {
|
||||
}
|
||||
return "AP";
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
try {
|
||||
|
||||
auto App = OpenWifi::Daemon::instance();
|
||||
auto ExitCode = App->run(argc, argv);
|
||||
return ExitCode;
|
||||
|
||||
} catch (Poco::Exception &exc) {
|
||||
std::cerr << exc.displayText() << std::endl;
|
||||
return Poco::Util::Application::EXIT_SOFTWARE;
|
||||
void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||
Daemon()->PostInitialization(self);
|
||||
GWWebSocketNotifications::Register();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ExitCode;
|
||||
try {
|
||||
Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr);
|
||||
auto App = OpenWifi::Daemon::instance();
|
||||
ExitCode = App->run(argc, argv);
|
||||
Poco::Net::SSLManager::instance().shutdown();
|
||||
} catch (Poco::Exception &exc) {
|
||||
ExitCode = Poco::Util::Application::EXIT_SOFTWARE;
|
||||
std::cout << exc.displayText() << std::endl;
|
||||
} catch (std::exception &exc) {
|
||||
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
|
||||
std::cout << exc.what() << std::endl;
|
||||
} catch (...) {
|
||||
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
|
||||
std::cout << "Exception on closure" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Exitcode: " << ExitCode << std::endl;
|
||||
return ExitCode;
|
||||
}
|
||||
|
||||
// end of namespace
|
||||
16
src/Daemon.h
16
src/Daemon.h
@@ -14,18 +14,10 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/ServerApplication.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
#include "Poco/Util/OptionSet.h"
|
||||
#include "Poco/UUIDGenerator.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/Crypto/CipherFactory.h"
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
#include "framework/MicroServiceNames.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Dashboard.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "GwWebSocketClient.h"
|
||||
|
||||
@@ -61,8 +53,6 @@ namespace OpenWifi {
|
||||
};
|
||||
|
||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
||||
inline void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||
Daemon()->PostInitialization(self);
|
||||
}
|
||||
void DaemonPostInitialization(Poco::Util::Application &self);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,49 @@
|
||||
//
|
||||
|
||||
#include "Dashboard.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void DeviceDashboard::Create() {
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
|
||||
if(LastRun_==0 || (Now-LastRun_)>120) {
|
||||
DB_.reset();
|
||||
StorageService()->AnalyzeCommands(DB_.commands);
|
||||
StorageService()->AnalyzeDevices(DB_);
|
||||
LastRun_ = Now;
|
||||
bool DeviceDashboard::Get(GWObjects::Dashboard &D, Poco::Logger & Logger) {
|
||||
uint64_t Now = Utils::Now();
|
||||
if(!ValidDashboard_ || LastRun_==0 || (Now-LastRun_)>120) {
|
||||
Generate(D, Logger);
|
||||
} else {
|
||||
std::lock_guard G(DataMutex_);
|
||||
D = DB_;
|
||||
}
|
||||
return ValidDashboard_;
|
||||
};
|
||||
|
||||
void DeviceDashboard::Generate(GWObjects::Dashboard &D, Poco::Logger & Logger ) {
|
||||
if (GeneratingDashboard_.load()) {
|
||||
// std::cout << "Trying to generate dashboard but already being generated" << std::endl;
|
||||
while(GeneratingDashboard_.load()) {
|
||||
Poco::Thread::trySleep(100);
|
||||
}
|
||||
std::lock_guard G(DataMutex_);
|
||||
D = DB_;
|
||||
} else {
|
||||
GeneratingDashboard_ = true;
|
||||
ValidDashboard_ = false;
|
||||
try {
|
||||
// std::cout << "Generating dashboard." << std::endl;
|
||||
poco_information(Logger, "DASHBOARD: Generating a new dashboard.");
|
||||
GWObjects::Dashboard NewData;
|
||||
StorageService()->AnalyzeCommands(NewData.commands);
|
||||
StorageService()->AnalyzeDevices(NewData);
|
||||
LastRun_ = Utils::Now();
|
||||
NewData.snapshot = LastRun_;
|
||||
D = NewData;
|
||||
std::lock_guard G(DataMutex_);
|
||||
DB_ = NewData;
|
||||
ValidDashboard_=true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
GeneratingDashboard_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "Poco/Logger.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class DeviceDashboard {
|
||||
public:
|
||||
DeviceDashboard() { DB_.reset(); }
|
||||
void Create();
|
||||
[[nodiscard]] const GWObjects::Dashboard & Report() const { return DB_;}
|
||||
bool Get(GWObjects::Dashboard &D, Poco::Logger & Logger);
|
||||
private:
|
||||
GWObjects::Dashboard DB_;
|
||||
uint64_t LastRun_=0;
|
||||
inline void Reset() { DB_.reset(); }
|
||||
std::mutex DataMutex_;
|
||||
volatile std::atomic_bool GeneratingDashboard_=false;
|
||||
volatile bool ValidDashboard_=false;
|
||||
GWObjects::Dashboard DB_;
|
||||
uint64_t LastRun_=0;
|
||||
|
||||
void Generate(GWObjects::Dashboard &D, Poco::Logger & Logger);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "DeviceRegistry.h"
|
||||
#include "WS_Server.h"
|
||||
#include "OUIServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int DeviceRegistry::Start() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Starting ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeviceRegistry::Stop() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Stopping ");
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
Statistics = Device->second->LastStats;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetStatistics(uint64_t SerialNumber, const std::string &Statistics) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->Conn_.LastContact = time(nullptr);
|
||||
Device->second->LastStats = Statistics;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
|
||||
State = Device->second->Conn_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->Conn_.LastContact = time(nullptr);
|
||||
Device->second->Conn_ = State;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end()) {
|
||||
CheckData = Device->second->LastHealthcheck;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck & CheckData) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->LastHealthcheck = CheckData;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceRegistry::ConnectionEntry> DeviceRegistry::Register(uint64_t SerialNumber, WSConnection *Ptr, uint64_t & ConnectionId )
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
const auto & E = Devices_[SerialNumber] = std::make_shared<ConnectionEntry>();
|
||||
E->WSConn_ = Ptr;
|
||||
E->Conn_.LastContact = OpenWifi::Now();
|
||||
E->Conn_.Connected = true ;
|
||||
E->Conn_.UUID = 0 ;
|
||||
E->Conn_.MessageCount = 0 ;
|
||||
E->Conn_.Address = "";
|
||||
E->Conn_.TX = 0 ;
|
||||
E->Conn_.RX = 0;
|
||||
E->Conn_.VerifiedCertificate = GWObjects::CertificateValidation::NO_CERTIFICATE;
|
||||
ConnectionId = E->ConnectionId = ++Id_;
|
||||
return E;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::Connected(uint64_t SerialNumber) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
return Device->second->Conn_.Connected;
|
||||
}
|
||||
|
||||
void DeviceRegistry::UnRegister(uint64_t SerialNumber, uint64_t ConnectionId) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto It = Devices_.find(SerialNumber);
|
||||
if(It!=Devices_.end()) {
|
||||
if(It->second->ConnectionId == ConnectionId)
|
||||
Devices_.erase(SerialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->Send(Payload);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->SendRadiusAccountingData(buffer,size);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->SendRadiusAuthenticationData(buffer,size);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->SendRadiusCoAData(buffer,size);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end()) {
|
||||
Device->second->Conn_.PendingUUID = PendingUUID;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -1,122 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
// class uCentral::WebSocket::WSConnection;
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WSConnection;
|
||||
class DeviceRegistry : public SubSystemServer {
|
||||
public:
|
||||
struct ConnectionEntry {
|
||||
WSConnection * WSConn_ = nullptr;
|
||||
GWObjects::ConnectionState Conn_;
|
||||
std::string LastStats;
|
||||
GWObjects::HealthCheck LastHealthcheck;
|
||||
uint64_t ConnectionId=0;
|
||||
};
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new DeviceRegistry;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) {
|
||||
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
|
||||
}
|
||||
bool GetStatistics(uint64_t SerialNumber, std::string & Statistics);
|
||||
|
||||
inline void SetStatistics(const std::string &SerialNumber, const std::string &Statistics) {
|
||||
return SetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
|
||||
}
|
||||
void SetStatistics(uint64_t SerialNumber, const std::string &stats);
|
||||
|
||||
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) {
|
||||
return GetState(Utils::SerialNumberToInt(SerialNumber), State);
|
||||
}
|
||||
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State);
|
||||
|
||||
inline void SetState(const std::string & SerialNumber, const GWObjects::ConnectionState & State) {
|
||||
return SetState(Utils::SerialNumberToInt(SerialNumber), State);
|
||||
}
|
||||
void SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State);
|
||||
|
||||
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) {
|
||||
return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
|
||||
}
|
||||
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData);
|
||||
|
||||
inline void SetHealthcheck(const std::string &SerialNumber, const GWObjects::HealthCheck &H) {
|
||||
return SetHealthcheck(Utils::SerialNumberToInt(SerialNumber),H);
|
||||
}
|
||||
void SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck &H);
|
||||
|
||||
std::shared_ptr<ConnectionEntry> Register(uint64_t SerialNumber, WSConnection *Conn, uint64_t & ConnectionId);
|
||||
|
||||
inline void UnRegister(const std::string & SerialNumber, uint64_t ConnectionId) {
|
||||
return UnRegister(Utils::SerialNumberToInt(SerialNumber),ConnectionId);
|
||||
}
|
||||
void UnRegister(uint64_t SerialNumber, uint64_t ConnectionId);
|
||||
|
||||
inline bool Connected(const std::string & SerialNumber) {
|
||||
return Connected(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
|
||||
bool Connected(uint64_t SerialNumber);
|
||||
|
||||
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) {
|
||||
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
|
||||
}
|
||||
|
||||
bool SendFrame(uint64_t SerialNumber, const std::string & Payload);
|
||||
|
||||
inline void SetPendingUUID(const std::string & SerialNumber, uint64_t PendingUUID) {
|
||||
return SetPendingUUID(Utils::SerialNumberToInt(SerialNumber), PendingUUID);
|
||||
}
|
||||
void SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID);
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(const std::string & SerialNumber) {
|
||||
return GetDeviceConnection(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(uint64_t SerialNumber) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
return Device->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
|
||||
private:
|
||||
inline static std::atomic_uint64_t Id_=1;
|
||||
std::map<uint64_t ,std::shared_ptr<ConnectionEntry>> Devices_;
|
||||
|
||||
DeviceRegistry() noexcept:
|
||||
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto DeviceRegistry() { return DeviceRegistry::instance(); }
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include "Poco/Net/HTTPServerParams.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
@@ -19,19 +17,25 @@
|
||||
#include "Poco/CountingStream.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include "FileUploader.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string URI_BASE{"/v1/upload/"};
|
||||
|
||||
int FileUploader::Start() {
|
||||
Logger().notice("Starting.");
|
||||
poco_notice(Logger(),"Starting.");
|
||||
|
||||
Poco::File UploadsDir(MicroService::instance().ConfigPath("openwifi.fileuploader.path","/tmp"));
|
||||
Poco::File UploadsDir(MicroServiceConfigPath("openwifi.fileuploader.path","/tmp"));
|
||||
Path_ = UploadsDir.path();
|
||||
if(!UploadsDir.exists()) {
|
||||
try {
|
||||
@@ -43,35 +47,37 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Logger().information(fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
if(MicroServiceNoAPISecurity()) {
|
||||
poco_notice(Logger(), fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
|
||||
auto Sock{Svr.CreateSocket(Logger())};
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
MicroService::instance().ConfigGetString("openwifi.fileuploader.uri", "");
|
||||
MicroServiceConfigGetString("openwifi.fileuploader.uri", "");
|
||||
if (TmpName.empty()) {
|
||||
FullName_ =
|
||||
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
Logger().information(fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
poco_information(Logger(),fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
|
||||
Params->setName("file-upldr");
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
} else {
|
||||
std::string l{"Starting: " + Svr.Address() + ":" + std::to_string(Svr.Port()) +
|
||||
" key:" + Svr.KeyFile() + " cert:" + Svr.CertFile()};
|
||||
Logger().information(l);
|
||||
poco_information(Logger(),l);
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
|
||||
@@ -82,17 +88,18 @@ namespace OpenWifi {
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
MicroService::instance().ConfigGetString("openwifi.fileuploader.uri", "");
|
||||
MicroServiceConfigGetString("openwifi.fileuploader.uri", "");
|
||||
if (TmpName.empty()) {
|
||||
FullName_ =
|
||||
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
Logger().information(fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
poco_information(Logger(), fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
@@ -102,14 +109,14 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
MaxSize_ = 1000 * MicroService::instance().ConfigGetInt("openwifi.fileuploader.maxsize", 10000);
|
||||
MaxSize_ = 1000 * MicroServiceConfigGetInt("openwifi.fileuploader.maxsize", 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FileUploader::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
MicroService::instance().LoadConfigurationFile();
|
||||
Logger().information("Reinitializing.");
|
||||
MicroServiceLoadConfigurationFile();
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
@@ -119,34 +126,32 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
// if you pass in an empty UUID, it will just clean the list and not add it.
|
||||
bool FileUploader::AddUUID( const std::string & UUID) {
|
||||
bool FileUploader::AddUUID( const std::string & UUID, std::chrono::seconds WaitTimeInSeconds, const std::string &Type) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
uint64_t now = OpenWifi::Now();
|
||||
|
||||
// remove old stuff...
|
||||
for(auto i=OutStandingUploads_.begin();i!=OutStandingUploads_.end();) {
|
||||
if ((now-i->second) > (60 * 30))
|
||||
i = OutStandingUploads_.erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
if(!UUID.empty())
|
||||
OutStandingUploads_[UUID] = now;
|
||||
|
||||
uint64_t now = Utils::Now();
|
||||
auto Func=[now](const UploadId &I) -> bool {
|
||||
return (now > I.Expires);
|
||||
};
|
||||
OutStandingUploads_.erase(std::remove_if(OutStandingUploads_.begin(),OutStandingUploads_.end(),Func),OutStandingUploads_.end());
|
||||
OutStandingUploads_.emplace_back(UploadId{UUID, now + WaitTimeInSeconds.count(), Type});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileUploader::ValidRequest(const std::string &UUID) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
return OutStandingUploads_.find(UUID)!=OutStandingUploads_.end();
|
||||
auto Func = [UUID](const UploadId &P) -> bool {
|
||||
return (P.UUID==UUID);
|
||||
};
|
||||
return std::find_if(OutStandingUploads_.begin(), OutStandingUploads_.end(), Func) != end(OutStandingUploads_);
|
||||
}
|
||||
|
||||
void FileUploader::RemoveRequest(const std::string &UUID) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
OutStandingUploads_.erase(UUID);
|
||||
auto Func = [UUID](const UploadId &P) -> bool {
|
||||
return (P.UUID==UUID);
|
||||
};
|
||||
OutStandingUploads_.erase(std::remove_if(OutStandingUploads_.begin(),OutStandingUploads_.end(),Func),OutStandingUploads_.end());
|
||||
}
|
||||
|
||||
class FileUploaderPartHandler2 : public Poco::Net::PartHandler {
|
||||
@@ -186,9 +191,10 @@ namespace OpenWifi {
|
||||
class FormRequestHandler: public Poco::Net::HTTPRequestHandler
|
||||
{
|
||||
public:
|
||||
explicit FormRequestHandler(std::string UUID, Poco::Logger & L):
|
||||
explicit FormRequestHandler(std::string UUID, Poco::Logger & L, const std::string &Type):
|
||||
UUID_(std::move(UUID)),
|
||||
Logger_(L)
|
||||
Logger_(L),
|
||||
Type_(Type)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -198,7 +204,7 @@ namespace OpenWifi {
|
||||
const auto ContentType = Request.getContentType();
|
||||
const auto Tokens = Poco::StringTokenizer(ContentType,";",Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
Logger().debug(fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
try {
|
||||
@@ -223,8 +229,8 @@ namespace OpenWifi {
|
||||
Poco::StreamCopier::copyStream(Reader.stream(), FileContent);
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 0);
|
||||
Logger().debug(fmt::format("{}: Trace file uploaded.", UUID_));
|
||||
StorageService()->AttachFileDataToCommand(UUID_, FileContent);
|
||||
poco_debug(Logger(),fmt::format("{}: File uploaded.", UUID_));
|
||||
StorageService()->AttachFileDataToCommand(UUID_, FileContent, Type_);
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
return;
|
||||
@@ -241,10 +247,10 @@ namespace OpenWifi {
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
Logger().debug("Exception while receiving trace file.");
|
||||
poco_debug(Logger(),"Exception while receiving trace file.");
|
||||
}
|
||||
|
||||
Logger().debug(fmt::format("{}: Failed to upload trace file.",UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Failed to upload trace file.",UUID_));
|
||||
std::string Error{"Trace file rejected"};
|
||||
StorageService()->CancelWaitFile(UUID_, Error);
|
||||
Answer.set("filename", UUID_);
|
||||
@@ -260,11 +266,18 @@ namespace OpenWifi {
|
||||
private:
|
||||
std::string UUID_;
|
||||
Poco::Logger & Logger_;
|
||||
std::string Type_;
|
||||
};
|
||||
|
||||
Poco::Net::HTTPRequestHandler *FileUpLoaderRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest & Request) {
|
||||
|
||||
Logger().debug(fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
poco_debug(Logger(),fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
|
||||
if(Request.getMethod()!=Poco::Net::HTTPRequest::HTTP_POST ||
|
||||
Request.getURI().size()<(URI_BASE.size()+36)) {
|
||||
poco_warning(Logger(),fmt::format("ILLEGAL-REQUEST({}): {} {}. Dropped.", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The UUID should be after the /v1/upload/ part...
|
||||
auto UUIDLocation = Request.getURI().find_first_of(URI_BASE);
|
||||
@@ -272,25 +285,38 @@ namespace OpenWifi {
|
||||
if( UUIDLocation != std::string::npos )
|
||||
{
|
||||
auto UUID = Request.getURI().substr(UUIDLocation+URI_BASE.size());
|
||||
if(FileUploader()->ValidRequest(UUID))
|
||||
|
||||
FileUploader::UploadId E;
|
||||
if(FileUploader()->Find(UUID,E))
|
||||
{
|
||||
// make sure we do not allow anyone else to overwrite our file
|
||||
FileUploader()->RemoveRequest(UUID);
|
||||
return new FormRequestHandler(UUID,Logger());
|
||||
return new FormRequestHandler(UUID,Logger(),E.Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger().warning(fmt::format("Unknown UUID={}",UUID));
|
||||
poco_warning(Logger(),fmt::format("Unknown UUID={}",UUID));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FileUploader::Find(const std::string &UUID, UploadId &V) {
|
||||
std::lock_guard G(Mutex_);
|
||||
for(const auto &E:OutStandingUploads_) {
|
||||
if (E.UUID == UUID) {
|
||||
V = E;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileUploader::Stop() {
|
||||
Logger().notice("Stopping ");
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
for( const auto & svr : Servers_ )
|
||||
svr->stop();
|
||||
svr->stopAll(true);
|
||||
Servers_.clear();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
@@ -13,17 +13,24 @@
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class FileUploader : public SubSystemServer {
|
||||
public:
|
||||
|
||||
struct UploadId {
|
||||
std::string UUID;
|
||||
std::uint64_t Expires;
|
||||
std::string Type;
|
||||
};
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
const std::string & FullName();
|
||||
bool AddUUID( const std::string & UUID);
|
||||
bool AddUUID( const std::string & UUID, std::chrono::seconds WaitTimeInSecond, const std::string &Type);
|
||||
bool ValidRequest(const std::string & UUID);
|
||||
void RemoveRequest(const std::string &UUID);
|
||||
const std::string & Path() { return Path_; };
|
||||
@@ -35,12 +42,13 @@ namespace OpenWifi {
|
||||
|
||||
[[nodiscard]] inline uint64_t MaxSize() const { return MaxSize_; }
|
||||
|
||||
bool Find(const std::string &UUID, UploadId &V);
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
|
||||
std::string FullName_;
|
||||
std::map<std::string,uint64_t> OutStandingUploads_;
|
||||
std::string Path_;
|
||||
uint64_t MaxSize_=10000000;
|
||||
std::string FullName_;
|
||||
std::list<UploadId> OutStandingUploads_;
|
||||
std::string Path_;
|
||||
uint64_t MaxSize_=10000000;
|
||||
|
||||
explicit FileUploader() noexcept:
|
||||
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader")
|
||||
@@ -51,10 +59,13 @@ namespace OpenWifi {
|
||||
class FileUpLoaderRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
explicit FileUpLoaderRequestHandlerFactory(Poco::Logger &L) :
|
||||
Logger_(L){}
|
||||
Logger_(L) {
|
||||
}
|
||||
|
||||
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &request) override;
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
inline Poco::Logger & Logger() {
|
||||
return Logger_;
|
||||
}
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
};
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/Net/IPAddress.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -23,7 +26,7 @@ namespace OpenWifi {
|
||||
public:
|
||||
static std::string Name() { return "ipinfo"; }
|
||||
inline bool Init() override {
|
||||
Key_ = MicroService::instance().ConfigGetString("iptocountry.ipinfo.token", "");
|
||||
Key_ = MicroServiceConfigGetString("iptocountry.ipinfo.token", "");
|
||||
return !Key_.empty();
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ namespace OpenWifi {
|
||||
public:
|
||||
static std::string Name() { return "ipdata"; }
|
||||
inline bool Init() override {
|
||||
Key_ = MicroService::instance().ConfigGetString("iptocountry.ipdata.apikey", "");
|
||||
Key_ = MicroServiceConfigGetString("iptocountry.ipdata.apikey", "");
|
||||
return !Key_.empty();
|
||||
}
|
||||
|
||||
@@ -85,7 +88,7 @@ namespace OpenWifi {
|
||||
public:
|
||||
static std::string Name() { return "ip2location"; }
|
||||
inline bool Init() override {
|
||||
Key_ = MicroService::instance().ConfigGetString("iptocountry.ip2location.apikey", "");
|
||||
Key_ = MicroServiceConfigGetString("iptocountry.ip2location.apikey", "");
|
||||
return !Key_.empty();
|
||||
}
|
||||
|
||||
@@ -133,18 +136,22 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline int Start() final {
|
||||
ProviderName_ = MicroService::instance().ConfigGetString("iptocountry.provider","");
|
||||
poco_notice(Logger(),"Starting...");
|
||||
ProviderName_ = MicroServiceConfigGetString("iptocountry.provider","");
|
||||
if(!ProviderName_.empty()) {
|
||||
Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(ProviderName_);
|
||||
if(Provider_!= nullptr) {
|
||||
Enabled_ = Provider_->Init();
|
||||
}
|
||||
}
|
||||
Default_ = MicroService::instance().ConfigGetString("iptocountry.default", "US");
|
||||
Default_ = MicroServiceConfigGetString("iptocountry.default", "US");
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() final {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
// Nothing to do - just to provide the same look at the others.
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline std::string ReformatAddress(const std::string & I )
|
||||
|
||||
@@ -9,11 +9,11 @@ namespace OpenWifi {
|
||||
|
||||
GwWebSocketClient::GwWebSocketClient(Poco::Logger &Logger):
|
||||
Logger_(Logger){
|
||||
WebSocketClientServer()->SetProcessor(this);
|
||||
UI_WebSocketClientServer()->SetProcessor(this);
|
||||
}
|
||||
|
||||
GwWebSocketClient::~GwWebSocketClient() {
|
||||
WebSocketClientServer()->SetProcessor(nullptr);
|
||||
UI_WebSocketClientServer()->SetProcessor(nullptr);
|
||||
}
|
||||
|
||||
void GwWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ) {
|
||||
@@ -37,7 +37,6 @@ namespace OpenWifi {
|
||||
bool &Done, std::string &Answer) {
|
||||
Done = false;
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
Logger().information(Poco::format("serial_number_search: %s", Prefix));
|
||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||
std::vector<uint64_t> Numbers;
|
||||
SerialNumberCache()->FindNumbers(Prefix, 50, Numbers);
|
||||
@@ -61,7 +60,4 @@ namespace OpenWifi {
|
||||
Done = false;
|
||||
Answer = std::string{R"lit({ "error" : "invalid command" })lit"};
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/UI_WebSocketClientServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class GwWebSocketClient : public WebSocketClientProcessor {
|
||||
class GwWebSocketClient : public UI_WebSocketClientProcessor {
|
||||
public:
|
||||
explicit GwWebSocketClient(Poco::Logger &Logger);
|
||||
virtual ~GwWebSocketClient();
|
||||
|
||||
@@ -5,55 +5,76 @@
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "OUIServer.h"
|
||||
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/URIStreamOpener.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/File.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "OUIServer.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int OUIServer::Start() {
|
||||
Running_ = true;
|
||||
LatestOUIFileName_ = MicroService::instance().DataDir() + "/newOUIFile.txt";
|
||||
CurrentOUIFileName_ = MicroService::instance().DataDir() + "/current_oui.txt";
|
||||
LatestOUIFileName_ = MicroServiceDataDirectory() + "/newOUIFile.txt";
|
||||
CurrentOUIFileName_ = MicroServiceDataDirectory() + "/current_oui.txt";
|
||||
|
||||
bool Recovered = false;
|
||||
Poco::File OuiFile(CurrentOUIFileName_);
|
||||
if(OuiFile.exists()) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
Recovered = ProcessFile(CurrentOUIFileName_,OUIs_);
|
||||
if(Recovered) {
|
||||
poco_notice(Logger(),
|
||||
fmt::format("Recovered last OUI file - {}", CurrentOUIFileName_));
|
||||
}
|
||||
} else {
|
||||
poco_notice(Logger(),
|
||||
fmt::format("No existing OUIFile.", CurrentOUIFileName_));
|
||||
}
|
||||
|
||||
UpdaterCallBack_ = std::make_unique<Poco::TimerCallback<OUIServer>>(*this, &OUIServer::onTimer);
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
|
||||
if(Recovered) {
|
||||
Timer_.setStartInterval(60 * 60 * 1000); // first run in 1 hour
|
||||
} else {
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
|
||||
}
|
||||
Timer_.setPeriodicInterval(7 * 24 * 60 * 60 * 1000);
|
||||
Timer_.start(*UpdaterCallBack_);
|
||||
Timer_.start(*UpdaterCallBack_, MicroServiceTimerPool());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OUIServer::Stop() {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
Running_=false;
|
||||
Timer_.stop();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void OUIServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
MicroService::instance().LoadConfigurationFile();
|
||||
Logger().information("Reinitializing.");
|
||||
MicroServiceLoadConfigurationFile();
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
|
||||
bool OUIServer::GetFile(const std::string &FileName) {
|
||||
try {
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
Logger().information(fmt::format("Start: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
LastUpdate_ = Utils::Now();
|
||||
poco_information(Logger(), fmt::format("Start: Retrieving OUI file: {}",MicroServiceConfigGetString("oui.download.uri","")));
|
||||
std::unique_ptr<std::istream> pStr(
|
||||
Poco::URIStreamOpener::defaultOpener().open(MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
Poco::URIStreamOpener::defaultOpener().open(MicroServiceConfigGetString("oui.download.uri","")));
|
||||
std::ofstream OS;
|
||||
OS.open(FileName);
|
||||
Poco::StreamCopier::copyStream(*pStr, OS);
|
||||
OS.close();
|
||||
Logger().information(fmt::format("Done: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
poco_information(Logger(), fmt::format("Done: Retrieving OUI file: {}",MicroServiceConfigGetString("oui.download.uri","")));
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -103,15 +124,17 @@ namespace OpenWifi {
|
||||
return;
|
||||
Updating_ = true;
|
||||
|
||||
poco_information(Logger(),"Starting to process OUI file...");
|
||||
|
||||
// fetch data from server, if not available, just use the file we already have.
|
||||
Poco::File Current(CurrentOUIFileName_);
|
||||
if(Current.exists()) {
|
||||
if((OpenWifi::Now()-Current.getLastModified().epochTime()) < (7*24*60*60)) {
|
||||
if((Utils::Now()-Current.getLastModified().epochTime()) < (7*24*60*60)) {
|
||||
if(!Initialized_) {
|
||||
if(ProcessFile(CurrentOUIFileName_, OUIs_)) {
|
||||
Initialized_ = true;
|
||||
Updating_=false;
|
||||
Logger().information("Using cached file.");
|
||||
poco_information(Logger(), "Using cached file.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -123,28 +146,30 @@ namespace OpenWifi {
|
||||
|
||||
OUIMap TmpOUIs;
|
||||
if(GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
|
||||
std::lock_guard G(Mutex_);
|
||||
std::unique_lock G(LocalMutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
LastUpdate_ = Utils::Now();
|
||||
Poco::File F1(CurrentOUIFileName_);
|
||||
if(F1.exists())
|
||||
F1.remove();
|
||||
Poco::File F2(LatestOUIFileName_);
|
||||
F2.renameTo(CurrentOUIFileName_);
|
||||
Logger().information(fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
poco_information(Logger(), fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
} else if(OUIs_.empty()) {
|
||||
if(ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
std::lock_guard G(Mutex_);
|
||||
LastUpdate_ = Utils::Now();
|
||||
std::unique_lock G(LocalMutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
}
|
||||
}
|
||||
Initialized_=true;
|
||||
Updating_ = false;
|
||||
poco_information(Logger(),"Done processing OUI file...");
|
||||
}
|
||||
|
||||
std::string OUIServer::GetManufacturer(const std::string &MAC) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
|
||||
if(Manufacturer != OUIs_.end())
|
||||
return Manufacturer->second;
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -30,6 +33,7 @@ namespace OpenWifi {
|
||||
[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
|
||||
|
||||
private:
|
||||
std::shared_mutex LocalMutex_;
|
||||
uint64_t LastUpdate_ = 0 ;
|
||||
bool Initialized_ = false;
|
||||
OUIMap OUIs_;
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -1565,6 +1570,7 @@ namespace OpenWifi {
|
||||
ie["TLV Block"] = BufferToHex(&b[offset],l-offset);
|
||||
} break;
|
||||
default:
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1612,7 +1618,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_wfa(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Wi-Fi Alliance";
|
||||
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1620,6 +1626,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_aironet(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Cisco Wireless (Aironet)";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1627,6 +1634,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_marvell(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Marvell Semiconductor";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1634,6 +1642,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_atheros(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Atheros Communications";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1641,6 +1650,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_aruba(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Aruba Networks";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1648,6 +1658,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_nintendo(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Nintendo";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1705,7 +1716,7 @@ namespace OpenWifi {
|
||||
nlohmann::json new_ie;
|
||||
nlohmann::json content;
|
||||
|
||||
std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
// std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
uint offset=0;
|
||||
auto sub_ie = data[offset++];
|
||||
switch (sub_ie) {
|
||||
@@ -1737,91 +1748,112 @@ namespace OpenWifi {
|
||||
std::ostringstream ofs;
|
||||
Obj->stringify(ofs);
|
||||
|
||||
nlohmann::json D = nlohmann::json::parse(ofs.str());
|
||||
std::cout << "Start of parsing wifi" << std::endl;
|
||||
if (D.contains("status")) {
|
||||
auto Status = D["status"];
|
||||
if (Status.contains("scan") && Status["scan"].is_array()) {
|
||||
nlohmann::json ScanArray = Status["scan"];
|
||||
nlohmann::json ParsedScan = nlohmann::json::array();
|
||||
for (auto &scan_entry : ScanArray) {
|
||||
if (scan_entry.contains("ies") && scan_entry["ies"].is_array()) {
|
||||
auto ies = scan_entry["ies"];
|
||||
nlohmann::json new_ies=nlohmann::json::array();
|
||||
for (auto &ie : ies) {
|
||||
try {
|
||||
if (ie.contains("type") && ie.contains("data")) {
|
||||
uint64_t ie_type = ie["type"];
|
||||
std::string ie_data = ie["data"];
|
||||
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data << std::endl;
|
||||
auto data = Base64Decode2Vec(ie_data);
|
||||
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_FH_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_FH_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_DS_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_DS_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TIM) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TIM(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_QBSS_LOAD) {
|
||||
new_ies.push_back(WFS_WLAN_EID_QBSS_LOAD(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_PWR_CONSTRAINT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_PWR_CONSTRAINT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_ERP_INFO) {
|
||||
new_ies.push_back(WFS_WLAN_EID_ERP_INFO(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPPORTED_REGULATORY_CLASSES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPPORTED_REGULATORY_CLASSES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_HT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_HT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXT_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TX_POWER_ENVELOPE) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TX_POWER_ENVELOPE(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_VHT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VHT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RRM_ENABLED_CAPABILITIES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RRM_ENABLED_CAPABILITIES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TPC_REPORT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TPC_REPORT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RSN) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RSN(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_VENDOR_SPECIFIC) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VENDOR_SPECIFIC(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
|
||||
try {
|
||||
nlohmann::json D = nlohmann::json::parse(ofs.str());
|
||||
// std::cout << "Start of parsing wifi" << std::endl;
|
||||
if (D.contains("status")) {
|
||||
auto Status = D["status"];
|
||||
if (Status.contains("scan") && Status["scan"].is_array()) {
|
||||
nlohmann::json ScanArray = Status["scan"];
|
||||
nlohmann::json ParsedScan = nlohmann::json::array();
|
||||
for (auto &scan_entry : ScanArray) {
|
||||
if (scan_entry.contains("ies") && scan_entry["ies"].is_array()) {
|
||||
auto ies = scan_entry["ies"];
|
||||
nlohmann::json new_ies = nlohmann::json::array();
|
||||
for (auto &ie : ies) {
|
||||
try {
|
||||
if (ie.contains("type") && ie.contains("data")) {
|
||||
uint64_t ie_type = ie["type"];
|
||||
std::string ie_data = ie["data"];
|
||||
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data << std::endl;
|
||||
auto data = Base64Decode2Vec(ie_data);
|
||||
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_FH_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_FH_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_DS_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_DS_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TIM) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TIM(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_QBSS_LOAD) {
|
||||
new_ies.push_back(WFS_WLAN_EID_QBSS_LOAD(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_PWR_CONSTRAINT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_PWR_CONSTRAINT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_ERP_INFO) {
|
||||
new_ies.push_back(WFS_WLAN_EID_ERP_INFO(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES) {
|
||||
new_ies.push_back(
|
||||
WFS_WLAN_EID_SUPPORTED_REGULATORY_CLASSES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_HT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_HT_CAPABILITY(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_EXT_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_SUPP_RATES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_TX_POWER_ENVELOPE) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TX_POWER_ENVELOPE(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_VHT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VHT_CAPABILITY(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::
|
||||
WLAN_EID_RRM_ENABLED_CAPABILITIES) {
|
||||
new_ies.push_back(
|
||||
WFS_WLAN_EID_RRM_ENABLED_CAPABILITIES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_EXT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TPC_REPORT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TPC_REPORT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RSN) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RSN(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_VENDOR_SPECIFIC) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VENDOR_SPECIFIC(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
|
||||
} else {
|
||||
// std::cout
|
||||
// << "Skipping IE: no parsing available: " << ie_type
|
||||
// << std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} else {
|
||||
std::cout
|
||||
<< "Skipping IE: no parsing available: " << ie_type
|
||||
<< std::endl;
|
||||
// std::cout << "Skipping IE: no data and type" << std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} else {
|
||||
std::cout << "Skipping IE: no data and type" << std::endl;
|
||||
} catch (...) {
|
||||
// std::cout << "Skipping IE: exception" << std::endl;
|
||||
Logger.information(fmt::format("Error parsing IEs"));
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} catch (...) {
|
||||
std::cout << "Skipping IE: exception" << std::endl;
|
||||
Logger.information(fmt::format("Error parsing IEs"));
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
// std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
Status["scan"] = ParsedScan;
|
||||
D["status"] = Status;
|
||||
}
|
||||
Status["scan"] = ParsedScan;
|
||||
D["status"] = Status;
|
||||
}
|
||||
Result << to_string(D);
|
||||
// std::cout << "End of parsing wifi" << std::endl;
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger.log(E);
|
||||
Logger.error(fmt::format("Failure to parse WifiScan."));
|
||||
} catch (...) {
|
||||
Logger.error(fmt::format("Failure to parse WifiScan."));
|
||||
}
|
||||
Result << to_string(D);
|
||||
std::cout << "End of parsing wifi" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,256 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "Poco/HMACEngine.h"
|
||||
#include "Poco/MD5Engine.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
namespace OpenWifi::RADIUS {
|
||||
|
||||
#define RADCMD_ACCESS_REQ 1 /* Access-Request */
|
||||
#define RADCMD_ACCESS_ACC 2 /* Access-Accept */
|
||||
#define RADCMD_ACCESS_REJ 3 /* Access-Reject */
|
||||
#define RADCMD_ACCOUN_REQ 4 /* Accounting-Request */
|
||||
#define RADCMD_ACCOUN_RES 5 /* Accounting-Response */
|
||||
#define RADCMD_ACCOUN_STATUS 6 /* Accounting-Status */
|
||||
#define RADCMD_PASSWORD_REQUEST 7 /* Password-Request [RFC3575] */
|
||||
#define RADCMD_PASSWORD_ACK 8 /* Password-Ack [RFC3575] */
|
||||
#define RADCMD_PASSWORD_REJECT 9 /* Password-Reject [RFC3575] */
|
||||
#define RADCMD_ACCOUN_MESSAGE 10 /* Accounting-Message [RFC3575] */
|
||||
|
||||
#define RADCMD_RES_FREE_REQ 21 /* Resource-Free-Request [RFC3575] */
|
||||
#define RADCMD_RES_FREE_RES 22 /* Resource-Free-Response [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_REQ 23 /* Resource-Query-Request [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_RES 24 /* Resource-Query-Response [RFC3575] */
|
||||
#define RADCMD_RES_ALT_RECLAIM_REQ 25 /* Alternate-Resource-Reclaim-Request [RFC3575] */
|
||||
|
||||
#define RADCMD_ACCESS_CHA 11 /* Access-Challenge */
|
||||
#define RADCMD_STATUS_SER 12 /* Status-Server */
|
||||
#define RADCMD_STATUS_CLI 13 /* Status-Client */
|
||||
#define RADCMD_DISCON_REQ 40 /* Disconnect-Request */
|
||||
#define RADCMD_DISCON_ACK 41 /* Disconnect-ACK */
|
||||
#define RADCMD_DISCON_NAK 42 /* Disconnect-NAK */
|
||||
#define RADCMD_COA_REQ 43 /* CoA-Request */
|
||||
#define RADCMD_COA_ACK 44 /* CoA-ACK */
|
||||
#define RADCMD_COA_NAK 45 /* CoA-NAK */
|
||||
#define RADCMD_RESERVED 255 /* Reserved */
|
||||
|
||||
/*
|
||||
21 Resource-Free-Request [RFC3575]
|
||||
22 Resource-Free-Response [RFC3575]
|
||||
23 Resource-Query-Request [RFC3575]
|
||||
24 Resource-Query-Response [RFC3575]
|
||||
25 Alternate-Resource-Reclaim-Request [RFC3575]
|
||||
|
||||
26 NAS-Reboot-Request [RFC3575]
|
||||
27 NAS-Reboot-Response [RFC3575]
|
||||
28 Reserved
|
||||
29 Next-Passcode [RFC3575]
|
||||
30 New-Pin [RFC3575]
|
||||
31 Terminate-Session [RFC3575]
|
||||
32 Password-Expired [RFC3575]
|
||||
33 Event-Request [RFC3575]
|
||||
34 Event-Response [RFC3575]
|
||||
35-39 Unassigned
|
||||
40 Disconnect-Request [RFC3575][RFC5176]
|
||||
41 Disconnect-ACK [RFC3575][RFC5176]
|
||||
42 Disconnect-NAK [RFC3575][RFC5176]
|
||||
43 CoA-Request [RFC3575][RFC5176]
|
||||
44 CoA-ACK [RFC3575][RFC5176]
|
||||
45 CoA-NAK [RFC3575][RFC5176]
|
||||
46-49 Unassigned
|
||||
50 IP-Address-Allocate [RFC3575]
|
||||
51 IP-Address-Release [RFC3575]
|
||||
52 Protocol-Error [RFC7930]
|
||||
53-249 Unassigned
|
||||
250-253 Experimental Use [RFC3575]
|
||||
254 Reserved [RFC3575]
|
||||
255 Reserved [RFC3575]
|
||||
*/
|
||||
|
||||
struct tok {
|
||||
uint cmd;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Radius commands
|
||||
|
||||
char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
|
||||
"", //!< 0
|
||||
"Access-Request",
|
||||
"Access-Accept",
|
||||
"Access-Reject",
|
||||
"Accounting-Request",
|
||||
"Accounting-Response",
|
||||
"Accounting-Status",
|
||||
"Password-Request",
|
||||
"Password-Accept",
|
||||
"Password-Reject",
|
||||
"Accounting-Message", //!< 10
|
||||
"Access-Challenge",
|
||||
"Status-Server",
|
||||
"Status-Client",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
"18",
|
||||
"19",
|
||||
"20", //!< 20
|
||||
"Resource-Free-Request",
|
||||
"Resource-Free-Response",
|
||||
"Resource-Query-Request",
|
||||
"Resource-Query-Response",
|
||||
"Alternate-Resource-Reclaim-Request",
|
||||
"NAS-Reboot-Request",
|
||||
"NAS-Reboot-Response",
|
||||
"28",
|
||||
"Next-Passcode",
|
||||
"New-Pin", //!< 30
|
||||
"Terminate-Session",
|
||||
"Password-Expired",
|
||||
"Event-Request",
|
||||
"Event-Response",
|
||||
"35",
|
||||
"36",
|
||||
"37",
|
||||
"38",
|
||||
"39",
|
||||
"Disconnect-Request", //!< 40
|
||||
"Disconnect-ACK",
|
||||
"Disconnect-NAK",
|
||||
"CoA-Request",
|
||||
"CoA-ACK",
|
||||
"CoA-NAK",
|
||||
"46",
|
||||
"47",
|
||||
"48",
|
||||
"49",
|
||||
"IP-Address-Allocate",
|
||||
"IP-Address-Release", //!< 50
|
||||
};
|
||||
|
||||
|
||||
*/
|
||||
|
||||
static const struct tok radius_command_values[] = {
|
||||
{ RADCMD_ACCESS_REQ, "Access-Request" },
|
||||
{ RADCMD_ACCESS_ACC, "Access-Accept" },
|
||||
{ RADCMD_ACCESS_REJ, "Access-Reject" },
|
||||
{ RADCMD_ACCOUN_REQ, "Accounting-Request" },
|
||||
{ RADCMD_ACCOUN_RES, "Accounting-Response" },
|
||||
{ RADCMD_ACCESS_CHA, "Access-Challenge" },
|
||||
{ RADCMD_STATUS_SER, "Status-Server" },
|
||||
{ RADCMD_STATUS_CLI, "Status-Client" },
|
||||
{ RADCMD_DISCON_REQ, "Disconnect-Request" },
|
||||
{ RADCMD_DISCON_ACK, "Disconnect-ACK" },
|
||||
{ RADCMD_DISCON_NAK, "Disconnect-NAK" },
|
||||
{ RADCMD_COA_REQ, "CoA-Request" },
|
||||
{ RADCMD_COA_ACK, "CoA-ACK" },
|
||||
{ RADCMD_COA_NAK, "CoA-NAK" },
|
||||
{ RADCMD_RESERVED, "Reserved" },
|
||||
{ RADCMD_ACCOUN_STATUS, "Accounting-Status"},
|
||||
{ RADCMD_PASSWORD_REQUEST, "Password-Request"},
|
||||
{ RADCMD_PASSWORD_ACK, "Password-Ack"},
|
||||
{ RADCMD_PASSWORD_REJECT, "Password-Reject"},
|
||||
{ RADCMD_ACCOUN_MESSAGE, "Accounting-Message"},
|
||||
{ RADCMD_RES_FREE_REQ, "Resource-Free-Request"},
|
||||
{ RADCMD_RES_FREE_RES, "Resource-Free-Response"},
|
||||
{ RADCMD_RES_QUERY_REQ, "Resource-Query-Request"},
|
||||
{ RADCMD_RES_QUERY_RES, "Resource-Query-Response"},
|
||||
{ RADCMD_RES_ALT_RECLAIM_REQ, "Alternate-Resource-Reclaim-Request"},
|
||||
{ 0, nullptr}
|
||||
};
|
||||
|
||||
static const struct tok radius_attribute_names[] = {
|
||||
{1,"User-Name"},
|
||||
{2,"User-Password"},
|
||||
{3,"CHAP-Password"},
|
||||
{4,"NAS-IP Address"},
|
||||
{5,"NAS-Port"},
|
||||
{6,"Service-Type"},
|
||||
{7,"Framed-Protocol"},
|
||||
{8,"Framed-IP-Address"},
|
||||
{9,"Framed-IP-Netmask"},
|
||||
{10,"Framed-Routing"},
|
||||
{11,"Filter-Id"},
|
||||
{12,"Framed-MTU"},
|
||||
{13,"Framed-Compression"},
|
||||
{14,"Login-IP-Host"},
|
||||
{15,"Login-Service"},
|
||||
{16,"Login-TCP-Port"},
|
||||
{18,"Reply-Message"},
|
||||
{19,"Callback-Number"},
|
||||
{20,"Callback-ID"},
|
||||
{22,"Framed-Route"},
|
||||
{23,"Framed-IPX-Network"},
|
||||
{24,"State"},
|
||||
{25,"Class"},
|
||||
{26,"Vendor-Specific"},
|
||||
{27,"Session-Timeout"},
|
||||
{28,"Idle-Timeout"},
|
||||
{29,"Termination-Action"},
|
||||
{30,"Called-Station-Id"},
|
||||
{31,"Calling-Station-Id"},
|
||||
{32,"NAS-Identifier"},
|
||||
{33,"Proxy-State"},
|
||||
{34,"Login-LAT-Service"},
|
||||
{35,"Login-LAT-Node"},
|
||||
{36,"Login-LAT-Group"},
|
||||
{37,"Framed-AppleTalk-Link"},
|
||||
{38,"Framed-AppleTalk-Network"},
|
||||
{39,"Framed-AppleTalk-Zone"},
|
||||
{40,"Acct-Status-Type"},
|
||||
{41,"Acct-Delay-Time"},
|
||||
{42,"Acct-Input-Octets"},
|
||||
{43,"Acct-Output-Octets"},
|
||||
{44,"Acct-Session-Id"},
|
||||
{45,"Acct-Authentic"},
|
||||
{46,"Acct-Session-Time"},
|
||||
{47,"Acct-Input-Packets"},
|
||||
{48,"Acct-Output-Packets"},
|
||||
{49,"Acct-Terminate-Cause"},
|
||||
{50,"Acct-Multi-Session-Id"},
|
||||
{51,"Acct-Link-Count"},
|
||||
{52,"Acct-Input-Gigawords"},
|
||||
{53,"Acct-Output-Gigawords"},
|
||||
{55,"Event-Timestamp"},
|
||||
{60,"CHAP-Challenge"},
|
||||
{61,"NAS-Port-Type"},
|
||||
{62,"Port-Limit"},
|
||||
{63,"Login-LAT-Port"},
|
||||
{64,"Tunnel-Type3"},
|
||||
{65,"Tunnel-Medium-Type1"},
|
||||
{66,"Tunnel-Client-Endpoint"},
|
||||
{67,"Tunnel-Server-Endpoint1"},
|
||||
{68,"Acct-Tunnel-Connection-ID"},
|
||||
{69,"Tunnel-Password1"},
|
||||
{70,"ARAP-Password"},
|
||||
{71,"ARAP-Features"},
|
||||
{72,"ARAP-Zone-Access"},
|
||||
{73,"ARAP-Security"},
|
||||
{74,"ARAP-Security-Data"},
|
||||
{75,"Password-Retry"},
|
||||
{76,"Prompt"},
|
||||
{77,"Connect-Info"},
|
||||
{78,"Configuration-Token"},
|
||||
{79,"EAP-Message"},
|
||||
{80,"Message-Authenticator"},
|
||||
{81,"Tunnel-Private-Group-ID"},
|
||||
{82,"Tunnel-Assignment-ID1"},
|
||||
{83,"Tunnel-Preference"},
|
||||
{84,"ARAP-Challenge-Response"},
|
||||
{85,"Acct-Interim-Interval"},
|
||||
{86,"Acct-Tunnel-Packets-Lost"},
|
||||
{87,"NAS-Port-ID"},
|
||||
{88,"Framed-Pool"},
|
||||
{90,"Tunnel-Client-Auth-ID"},
|
||||
{91,"Tunnel-Server-Auth-ID"},
|
||||
{0, nullptr}
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct RadiusAttribute {
|
||||
unsigned char type{0};
|
||||
@@ -20,12 +268,75 @@ namespace OpenWifi::RADIUS {
|
||||
struct RawRadiusPacket {
|
||||
unsigned char code{1};
|
||||
unsigned char identifier{0};
|
||||
uint16_t len{0};
|
||||
uint16_t rawlen{0};
|
||||
unsigned char authenticator[16]{0};
|
||||
unsigned char attributes[4096]{0};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr unsigned char Access_Request = 1;
|
||||
constexpr unsigned char Access_Accept = 2;
|
||||
constexpr unsigned char Access_Reject = 3;
|
||||
constexpr unsigned char Access_Challenge = 11;
|
||||
|
||||
constexpr unsigned char Accounting_Request = 4;
|
||||
constexpr unsigned char Accounting_Response = 5;
|
||||
constexpr unsigned char Accounting_Status = 6;
|
||||
constexpr unsigned char Accounting_Message = 10;
|
||||
|
||||
constexpr unsigned char Disconnect_Request = 40;
|
||||
constexpr unsigned char Disconnect_ACK = 41;
|
||||
constexpr unsigned char Disconnect_NAK = 42;
|
||||
constexpr unsigned char CoA_Request = 43;
|
||||
constexpr unsigned char CoA_ACK = 44;
|
||||
constexpr unsigned char CoA_NAK = 45;
|
||||
|
||||
constexpr unsigned char ATTR_MessageAuthenticator = 80;
|
||||
|
||||
inline bool IsAuthentication(unsigned char t) {
|
||||
return (t == RADIUS::Access_Request ||
|
||||
t == RADIUS::Access_Accept ||
|
||||
t == RADIUS::Access_Challenge ||
|
||||
t == RADIUS::Access_Reject);
|
||||
}
|
||||
|
||||
inline bool IsAccounting(unsigned char t) {
|
||||
return (t == RADIUS::Accounting_Request ||
|
||||
t == RADIUS::Accounting_Response ||
|
||||
t == RADIUS::Accounting_Status ||
|
||||
t == RADIUS::Accounting_Message);
|
||||
}
|
||||
|
||||
inline bool IsAuthority(unsigned char t) {
|
||||
return (t == RADIUS::Disconnect_Request ||
|
||||
t == RADIUS::Disconnect_ACK ||
|
||||
t == RADIUS::Disconnect_NAK ||
|
||||
t == RADIUS::CoA_Request ||
|
||||
t == RADIUS::CoA_ACK ||
|
||||
t == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
inline const char * CommandName(uint cmd) {
|
||||
auto cmds = radius_command_values;
|
||||
while(cmds->cmd && (cmds->cmd!=cmd))
|
||||
cmds++;
|
||||
if(cmds->cmd==cmd) return cmds->name;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char * AttributeName(uint cmd) {
|
||||
auto cmds = radius_attribute_names;
|
||||
while(cmds->cmd && (cmds->cmd!=cmd))
|
||||
cmds++;
|
||||
if(cmds->cmd==cmd) return cmds->name;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline void MakeRadiusAuthenticator(unsigned char *authenticator) {
|
||||
for(int i=0;i<16;i++)
|
||||
authenticator[i]=std::rand() & 0xff;
|
||||
}
|
||||
|
||||
//
|
||||
// From: https://github.com/Telecominfraproject/wlan-dictionary/blob/main/dictionary.tip
|
||||
//
|
||||
@@ -34,23 +345,21 @@ namespace OpenWifi::RADIUS {
|
||||
static const unsigned char TIP_AAAipaddr = 2;
|
||||
static const unsigned char TIP_AAAipv6addr = 3;
|
||||
|
||||
|
||||
using AttributeList = std::list<RadiusAttribute>;
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, AttributeList const &P) {
|
||||
inline std::ostream &operator<<(std::ostream &os, AttributeList const &P) {
|
||||
for(const auto &attr:P) {
|
||||
os << "\tAttr: " << (uint16_t) attr.type << " Size: " << (uint16_t) attr.len << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
bool ParseRadius(uint32_t offset, const unsigned char *Buffer, uint16_t Size, AttributeList &Attrs) {
|
||||
inline bool ParseRadius(uint32_t offset, const unsigned char *Buffer, uint16_t Size, AttributeList &Attrs) {
|
||||
Attrs.clear();
|
||||
uint16_t pos=0;
|
||||
auto x=25;
|
||||
while(pos<Size && x) {
|
||||
RadiusAttribute Attr{ .type=Buffer[pos], .pos=(uint16_t )(pos+2+offset), .len=Buffer[pos+1]};
|
||||
// std::cout << "POS: " << pos << " P:" << (uint32_t) Attr.pos << " T:" << (uint32_t) Attr.type << " L:" << (uint32_t) Attr.len << " S:" << (uint32_t) Size << std::endl;
|
||||
RadiusAttribute Attr{ .type=Buffer[pos], .pos=(uint16_t)(pos+2+offset), .len=(unsigned int)(Buffer[pos+1]-2)};
|
||||
if(pos+Attr.len<=Size) {
|
||||
Attrs.emplace_back(Attr);
|
||||
} else {
|
||||
@@ -64,25 +373,55 @@ namespace OpenWifi::RADIUS {
|
||||
pos+=Buffer[pos+1];
|
||||
x--;
|
||||
}
|
||||
// std::cout << "Good parse" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
class RadiusPacket {
|
||||
public:
|
||||
explicit RadiusPacket(const Poco::Buffer<char> & Buf) {
|
||||
if(Buf.size() >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,Buf.begin(), Buf.size());
|
||||
Size_=Buf.size();
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const unsigned char *buffer, uint16_t size) {
|
||||
if(size >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,buffer, size);
|
||||
Size_=size;
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const std::string &p) {
|
||||
if(p.size() >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,(const unsigned char*) p.c_str(), p.size());
|
||||
Size_=p.size();
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
RadiusPacket() = default;
|
||||
explicit RadiusPacket(const RadiusPacket &P) {
|
||||
Valid_ = P.Valid_;
|
||||
Size_ = P.Size_;
|
||||
P_ = P.P_;
|
||||
Attrs_ = P.Attrs_;
|
||||
}
|
||||
|
||||
explicit RadiusPacket() = default;
|
||||
|
||||
unsigned char * Buffer() { return (unsigned char *)&P_; }
|
||||
[[nodiscard]] uint16_t BufferLen() const { return sizeof(P_);}
|
||||
@@ -92,11 +431,39 @@ namespace OpenWifi::RADIUS {
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.len); }
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.rawlen); }
|
||||
[[nodiscard]] uint16_t Size() const { return Size_; }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
|
||||
|
||||
inline bool IsAuthentication() {
|
||||
return (P_.code == RADIUS::Access_Request ||
|
||||
P_.code == RADIUS::Access_Accept ||
|
||||
P_.code == RADIUS::Access_Challenge ||
|
||||
P_.code == RADIUS::Access_Reject ||
|
||||
P_.code == RADCMD_RES_FREE_REQ ||
|
||||
P_.code == RADCMD_RES_FREE_RES ||
|
||||
P_.code == RADCMD_RES_QUERY_REQ ||
|
||||
P_.code == RADCMD_RES_QUERY_RES ||
|
||||
P_.code == RADCMD_RES_ALT_RECLAIM_REQ);
|
||||
}
|
||||
|
||||
inline bool IsAccounting() {
|
||||
return (P_.code == RADIUS::Accounting_Request ||
|
||||
P_.code == RADIUS::Accounting_Response ||
|
||||
P_.code == RADIUS::Accounting_Status ||
|
||||
P_.code == RADIUS::Accounting_Message);
|
||||
}
|
||||
|
||||
inline bool IsAuthority() {
|
||||
return (P_.code == RADIUS::Disconnect_Request ||
|
||||
P_.code == RADIUS::Disconnect_ACK ||
|
||||
P_.code == RADIUS::Disconnect_NAK ||
|
||||
P_.code == RADIUS::CoA_Request ||
|
||||
P_.code == RADIUS::CoA_ACK ||
|
||||
P_.code == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
void Log(std::ostream &os) {
|
||||
uint16_t p = 0;
|
||||
|
||||
@@ -110,9 +477,102 @@ namespace OpenWifi::RADIUS {
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec << std::endl;
|
||||
os << std::dec << std::endl << std::endl;
|
||||
Print(os);
|
||||
}
|
||||
|
||||
inline const char * PacketType() {
|
||||
return CommandName(P_.code);
|
||||
}
|
||||
|
||||
inline int PacketTypeInt() {
|
||||
return (int)(P_.code);
|
||||
}
|
||||
|
||||
void ComputeMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
|
||||
if(P_.code==1) {
|
||||
unsigned char OldAuthenticator[16]{0};
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
|
||||
memset(&P.attributes[attr.pos], 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char NewAuthenticator[16]{0};
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(secret);
|
||||
H.update((const unsigned char *)&P, Size_);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
NewAuthenticator[p++] = i;
|
||||
|
||||
if (memcmp(OldAuthenticator, NewAuthenticator, 16) == 0) {
|
||||
std::cout << "Authenticator match..." << std::endl;
|
||||
} else {
|
||||
std::cout << "Authenticator MIS-match..." << std::endl;
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(&P_.attributes[attr.pos], NewAuthenticator, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VerifyMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
if(P_.code==1) {
|
||||
unsigned char OldAuthenticator[16]{0};
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
|
||||
memset(&P.attributes[attr.pos], 0, 16);
|
||||
}
|
||||
}
|
||||
unsigned char NewAuthenticator[16]{0};
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(secret);
|
||||
H.update((const unsigned char *)&P, Size_);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
NewAuthenticator[p++] = i;
|
||||
return memcmp(OldAuthenticator, NewAuthenticator, 16) == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void BufLog(std::ostream & os, const char * pre, const unsigned char *b, uint s) {
|
||||
uint16_t p = 0;
|
||||
while(p<s) {
|
||||
os << pre << std::setfill('0') << std::setw(4) << p << ": ";
|
||||
uint16_t v=0;
|
||||
while(v<16 && p+v<s) {
|
||||
os << std::setfill('0') << std::setw(2) << std::right << std::hex << (uint16_t )b[p+v] << " ";
|
||||
v++;
|
||||
}
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec ;
|
||||
}
|
||||
|
||||
inline void Print(std::ostream &os) {
|
||||
os << "Packet type: (" << (uint) P_.code << ") " << CommandName(P_.code) << std::endl;
|
||||
os << " Identifier: " << (uint) P_.identifier << std::endl;
|
||||
os << " Length: " << Size_ << std::endl;
|
||||
os << " Authenticator: " ;
|
||||
BufLog(os, "", P_.authenticator, sizeof(P_.authenticator));
|
||||
os << " Attributes: " << std::endl;
|
||||
for(const auto &attr:Attrs_) {
|
||||
os << " " << std::setfill(' ') << "(" << std::setw(4) << (uint) attr.type << ") " << AttributeName(attr.type) << " Len:" << attr.len << std::endl;
|
||||
BufLog(os, " " , &P_.attributes[attr.pos], attr.len);
|
||||
}
|
||||
os << std::dec << std::endl << std::endl;
|
||||
}
|
||||
|
||||
std::string ExtractSerialNumberTIP() {
|
||||
std::string R;
|
||||
|
||||
@@ -121,7 +581,7 @@ namespace OpenWifi::RADIUS {
|
||||
AttributeList VendorAttributes;
|
||||
uint32_t VendorId = htonl( *(const uint32_t *)&(P_.attributes[attribute.pos]));
|
||||
// std::cout << VendorId << std::endl;
|
||||
if(VendorId==TIP_vendor_id) {
|
||||
if(VendorId==TIP_vendor_id && attribute.len>(4+2)) {
|
||||
if (ParseRadius(attribute.pos + 4, &P_.attributes[attribute.pos + 4], attribute.len - 4 - 2,
|
||||
VendorAttributes)) {
|
||||
// std::cout << VendorAttributes << std::endl;
|
||||
@@ -139,7 +599,6 @@ namespace OpenWifi::RADIUS {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
@@ -197,6 +656,16 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string UserName() const {
|
||||
for(const auto &attr:Attrs_) {
|
||||
if(attr.type==1) {
|
||||
std::string user_name{(const char *)&P_.attributes[attr.pos],attr.len};
|
||||
return user_name;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
RawRadiusPacket P_;
|
||||
uint16_t Size_{0};
|
||||
@@ -204,7 +673,45 @@ namespace OpenWifi::RADIUS {
|
||||
bool Valid_=false;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
class RadiusOutputPacket {
|
||||
public:
|
||||
explicit RadiusOutputPacket(const std::string &Secret)
|
||||
: Secret_(Secret) {
|
||||
}
|
||||
|
||||
inline void MakeStatusMessage() {
|
||||
P_.code = RADCMD_STATUS_SER;
|
||||
P_.identifier = std::rand() & 0x00ff;
|
||||
MakeRadiusAuthenticator(P_.authenticator);
|
||||
unsigned char MessageAuthenticator[16]{0};
|
||||
AddAttribute(ATTR_MessageAuthenticator,sizeof(MessageAuthenticator),MessageAuthenticator);
|
||||
P_.rawlen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
|
||||
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(Secret_);
|
||||
H.update((const unsigned char *)&P_, P_.rawlen);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
P_.attributes[1 + 1 + p++] = i;
|
||||
}
|
||||
|
||||
inline void AddAttribute(unsigned char attr, uint8_t len, const unsigned char * data) {
|
||||
P_.attributes[AttributesLen_++] = attr;
|
||||
P_.attributes[AttributesLen_++] = len;
|
||||
memcpy(&P_.attributes[AttributesLen_],data,len);
|
||||
AttributesLen_+=len;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const unsigned char * Data() const { return (const unsigned char *) &P_;}
|
||||
[[nodiscard]] inline std::uint16_t Len() const { return P_.rawlen; }
|
||||
|
||||
private:
|
||||
RawRadiusPacket P_;
|
||||
uint16_t AttributesLen_=0;
|
||||
std::string Secret_;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
os << P.Attrs_ ;
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
// Created by stephane bourque on 2022-05-18.
|
||||
//
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RADIUS_helpers.h"
|
||||
#include "AP_WS_Server.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -15,125 +19,155 @@ namespace OpenWifi {
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
enabled_ = MicroService::instance().ConfigGetBool("radius.proxy.enable",false);
|
||||
if(!enabled_)
|
||||
ConfigFilename_ = MicroServiceDataDirectory()+"/radius_pool_config.json";
|
||||
Poco::File Config(ConfigFilename_);
|
||||
|
||||
Enabled_ = MicroServiceConfigGetBool("radius.proxy.enable",false);
|
||||
if(!Enabled_ && !Config.exists()) {
|
||||
StopRADSECServers();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConfigFilename_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
|
||||
|
||||
poco_notice(Logger(),"Starting...");
|
||||
|
||||
Enabled_ = true;
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4,true);
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4,true,true);
|
||||
Poco::Net::SocketAddress AuthSockAddrV6(Poco::Net::AddressFamily::IPv6,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6,true);
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6,true,true);
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.accounting.port",DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4,true);
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4,true,true);
|
||||
Poco::Net::SocketAddress AcctSockAddrV6(Poco::Net::AddressFamily::IPv6,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.accounting.port",DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6,true);
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6,true,true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4,true);
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4,true,true);
|
||||
Poco::Net::SocketAddress CoASockAddrV6(Poco::Net::AddressFamily::IPv6,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6,true);
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6,true,true);
|
||||
|
||||
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.reset();
|
||||
RadiusReactor_ = std::make_unique<Poco::Net::SocketReactor>();
|
||||
RadiusReactor_->addEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_->addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_->addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
AccountingReactor_.addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_->addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
|
||||
CoAReactor_.addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_->addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
CoAReactor_.addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_->addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
ParseConfig();
|
||||
|
||||
AuthenticationReactorThread_.start(AuthenticationReactor_);
|
||||
AccountingReactorThread_.start(AccountingReactor_);
|
||||
CoAReactorThread_.start(CoAReactor_);
|
||||
|
||||
Utils::SetThreadName(AuthenticationReactorThread_,"radproxy-auth");
|
||||
Utils::SetThreadName(AccountingReactorThread_,"radproxy-acct");
|
||||
Utils::SetThreadName(CoAReactorThread_,"radproxy-coa");
|
||||
StartRADSECServers();
|
||||
RadiusReactorThread_.start(*RadiusReactor_);
|
||||
Utils::SetThreadName(RadiusReactorThread_,"rad:reactor");
|
||||
Running_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::Stop() {
|
||||
if(enabled_) {
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
if(Enabled_ && Running_) {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.removeEventHandler(
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
AccountingReactor_.removeEventHandler(
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
CoAReactor_.removeEventHandler(
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
CoAReactor_.removeEventHandler(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
AuthenticationReactor_.stop();
|
||||
AuthenticationReactorThread_.join();
|
||||
AuthenticationSocketV4_->close();
|
||||
AuthenticationSocketV6_->close();
|
||||
AccountingSocketV4_->close();
|
||||
AccountingSocketV6_->close();
|
||||
CoASocketV4_->close();
|
||||
CoASocketV6_->close();
|
||||
|
||||
AccountingReactor_.stop();
|
||||
AccountingReactorThread_.join();
|
||||
AuthenticationSocketV4_.reset();
|
||||
AuthenticationSocketV6_.reset();
|
||||
AccountingSocketV4_.reset();
|
||||
AccountingSocketV6_.reset();
|
||||
CoASocketV4_.reset();
|
||||
CoASocketV6_.reset();
|
||||
|
||||
CoAReactor_.stop();
|
||||
CoAReactorThread_.join();
|
||||
enabled_=false;
|
||||
StopRADSECServers();
|
||||
RadiusReactor_->stop();
|
||||
RadiusReactorThread_.join();
|
||||
Running_=false;
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StartRADSECServers() {
|
||||
std::lock_guard G(Mutex_);
|
||||
for(const auto &pool:PoolList_.pools) {
|
||||
for(const auto &entry:pool.authConfig.servers) {
|
||||
if(entry.radsec) {
|
||||
RADSECservers_[ Poco::Net::SocketAddress(entry.ip,0) ] = std::make_unique<RADSEC_server>(*RadiusReactor_,entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StopRADSECServers() {
|
||||
std::lock_guard G(Mutex_);
|
||||
RADSECservers_.clear();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("Accounting: bad packet received.");
|
||||
poco_warning(Logger(),"Accounting: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("Accounting: missing serial number.");
|
||||
poco_warning(Logger(),"Accounting: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAccountingData(SerialNumber,P.Buffer(),P.Size());
|
||||
poco_debug(Logger(), fmt::format("Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
@@ -142,20 +176,20 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("Authentication: bad packet received.");
|
||||
poco_warning(Logger(),"Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("Authentication: missing serial number.");
|
||||
poco_warning(Logger(),"Authentication: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAuthenticationData(SerialNumber,P.Buffer(),P.Size());
|
||||
poco_debug(Logger(), fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
@@ -164,36 +198,74 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("CoA/DM: bad packet received.");
|
||||
poco_warning(Logger(),"CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("CoA/DM: missing serial number.");
|
||||
poco_warning(Logger(),"CoA/DM: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusCoAData(SerialNumber,P.Buffer(),P.Size());
|
||||
poco_debug(Logger(), fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size) {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
auto FinalDestination = Route(radius_type::auth, Dst);
|
||||
auto AllSent = SendData(Dst.family()==Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_ : *AccountingSocketV6_, (const unsigned char *)buffer, size, FinalDestination);
|
||||
if(!AllSent)
|
||||
Logger().error(fmt::format("{}: Could not send Accounting packet packet to {}.", serialNumber, Destination));
|
||||
else
|
||||
Logger().information(fmt::format("{}: Sending Accounting Packet to {}, CalledStationID: {}, CallingStationID:{}", serialNumber, FinalDestination.toString(), CalledStationID, CallingStationID));
|
||||
if(!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC);
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if (DestinationServer != end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
|
||||
size);
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
|
||||
AccountingSocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
|
||||
AccountingSocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"ACCT: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
}
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
|
||||
: *AccountingSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),
|
||||
fmt::format("{}: Could not send Accounting packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_debug(Logger(), fmt::format("{}: Sending Accounting Packet to {}, CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(),
|
||||
CalledStationID, CallingStationID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),fmt::format("Bad RADIUS ACCT Packet from {}. Dropped.",serialNumber));
|
||||
}
|
||||
}
|
||||
|
||||
bool RADIUS_proxy_server::SendData( Poco::Net::DatagramSocket & Sock, const unsigned char *buf , std::size_t size, const Poco::Net::SocketAddress &S) {
|
||||
@@ -201,39 +273,102 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber, const char *buffer, std::size_t size) {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
auto FinalDestination = Route(radius_type::auth, Dst);
|
||||
auto AllSent = SendData(Dst.family()==Poco::Net::SocketAddress::IPv4 ? *AuthenticationSocketV4_ : *AuthenticationSocketV6_, (const unsigned char *)buffer, size, FinalDestination);
|
||||
if(!AllSent)
|
||||
Logger().error(fmt::format("{}: Could not send Authentication packet packet to {}.", serialNumber, Destination));
|
||||
else
|
||||
Logger().information(fmt::format("{}: Sending Authentication Packet to {}, CalledStationID: {}, CallingStationID:{}", serialNumber, FinalDestination.toString(), CalledStationID, CallingStationID));
|
||||
if(!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
|
||||
AuthenticationSocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
|
||||
AuthenticationSocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format("AUTH: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
}
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AuthenticationSocketV4_
|
||||
: *AuthenticationSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),
|
||||
fmt::format("{}: Could not send Authentication packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_debug(Logger(), fmt::format("{}: Sending Authentication Packet to {}, CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(),
|
||||
CalledStationID, CallingStationID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),fmt::format("Bad RADIUS AUTH Packet from {}. Dropped.",serialNumber));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size) {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
// auto CallingStationID = P.ExtractCallingStationID();
|
||||
// auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
if(Destination.empty()) {
|
||||
Destination = "0.0.0.0:0";
|
||||
if(!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
|
||||
if(Destination.empty()) {
|
||||
Destination = "0.0.0.0:0";
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
if( (Dst.family() == Poco::Net::SocketAddress::IPv4 && CoASocketV4_== nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 && CoASocketV6_== nullptr)) {
|
||||
poco_debug(Logger(),fmt::format("CoA: Trying to use RADIUS GW PROXY but not configured. Device={}",serialNumber));
|
||||
return;
|
||||
}
|
||||
auto AllSent = SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_
|
||||
: *CoASocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),fmt::format("{}: Could not send CoA packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_debug(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
|
||||
FinalDestination.toString()));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),fmt::format("Bad RADIUS CoA/DM Packet from {}. Dropped.",serialNumber));
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
std::lock_guard G(Mutex_);
|
||||
auto FinalDestination = Route(radius_type::auth, Dst);
|
||||
auto AllSent = SendData(Dst.family()==Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_ : *CoASocketV6_, (const unsigned char *)buffer, size, FinalDestination);
|
||||
if(!AllSent)
|
||||
Logger().error(fmt::format("{}: Could not send CoA packet packet to {}.", serialNumber, Destination));
|
||||
else
|
||||
Logger().information(fmt::format("{}: Sending CoA Packet to {}", serialNumber, FinalDestination.toString()));
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault) {
|
||||
@@ -242,7 +377,7 @@ namespace OpenWifi {
|
||||
for(const auto &server:Config.servers) {
|
||||
Poco::Net::IPAddress a;
|
||||
if(!Poco::Net::IPAddress::tryParse(server.ip,a)) {
|
||||
Logger().error(fmt::format("RADIUS-PARSE Config: server address {} is nto a valid address in v4 or v6. Entry skipped.",server.ip));
|
||||
poco_error(Logger(),fmt::format("RADIUS-PARSE Config: server address {} is nto a valid address in v4 or v6. Entry skipped.",server.ip));
|
||||
continue;
|
||||
}
|
||||
auto S = Poco::Net::SocketAddress(fmt::format("{}:{}",server.ip,server.port));
|
||||
@@ -256,9 +391,14 @@ namespace OpenWifi {
|
||||
.monitor = Config. monitor,
|
||||
.monitorMethod = Config.monitorMethod,
|
||||
.methodParameters = Config.methodParameters,
|
||||
.useAsDefault = setAsDefault
|
||||
.useAsDefault = setAsDefault,
|
||||
.useRADSEC = server.radsec,
|
||||
.realms = server.radsecRealms
|
||||
};
|
||||
|
||||
if(setAsDefault && D.useRADSEC)
|
||||
DefaultIsRADSEC_ = true;
|
||||
|
||||
if(S.family()==Poco::Net::IPAddress::IPv4) {
|
||||
TotalV4 += server.weight;
|
||||
V4.push_back(D);
|
||||
@@ -308,82 +448,121 @@ namespace OpenWifi {
|
||||
Pools_.push_back(NewPool);
|
||||
}
|
||||
} else {
|
||||
Logger().warning(fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
poco_warning(Logger(),fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
}
|
||||
} else {
|
||||
Logger().warning(fmt::format("No configuration file '{}' exists.",ConfigFilename_));
|
||||
poco_warning(Logger(),fmt::format("No configuration file '{}' exists.",ConfigFilename_));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
Logger().error(fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
|
||||
poco_error(Logger(),fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
static bool RealmMatch(const std::string &user_realm, const std::string & realm) {
|
||||
if(realm.find_first_of('*') == std::string::npos)
|
||||
return user_realm == realm;
|
||||
return realm.find(user_realm) != std::string::npos;
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::DefaultRoute(radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
|
||||
// find the realm...
|
||||
auto UserName = P.UserName();
|
||||
if(!UserName.empty()) {
|
||||
auto UserTokens = Poco::StringTokenizer(UserName, "@");
|
||||
auto UserRealm = ((UserTokens.count() > 1) ? UserTokens[1] : UserName);
|
||||
Poco::toLowerInPlace(UserRealm);
|
||||
|
||||
for(const auto &pool:Pools_) {
|
||||
for(const auto &server:pool.AuthV4) {
|
||||
if(!server.realms.empty()) {
|
||||
for(const auto &realm:server.realms) {
|
||||
if (RealmMatch(UserRealm,realm)) {
|
||||
std::cout << "Realm match..." << std::endl;
|
||||
UseRADSEC = true;
|
||||
return server.Addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(DefaultIsRADSEC_) {
|
||||
UseRADSEC = true;
|
||||
return (IsV4 ? Pools_[DefaultPoolIndex_].AuthV4[0].Addr : Pools_[DefaultPoolIndex_].AuthV6[0].Addr );
|
||||
}
|
||||
|
||||
switch(rtype) {
|
||||
case radius_type::coa: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].CoaV4
|
||||
: Pools_[defaultPoolIndex_].CoaV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::auth: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AuthV4
|
||||
: Pools_[defaultPoolIndex_].AuthV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::acct:
|
||||
default: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AcctV4
|
||||
: Pools_[defaultPoolIndex_].AcctV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
}
|
||||
case radius_type::auth: {
|
||||
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AuthV4
|
||||
: Pools_[DefaultPoolIndex_].AuthV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::acct:
|
||||
default: {
|
||||
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AcctV4
|
||||
: Pools_[DefaultPoolIndex_].AcctV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::coa: {
|
||||
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
|
||||
: Pools_[DefaultPoolIndex_].CoaV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if(Pools_.empty()) {
|
||||
UseRADSEC = false;
|
||||
return RequestedAddress;
|
||||
}
|
||||
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
bool useDefault = false;
|
||||
bool useDefault;
|
||||
useDefault = IsV4 ? RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4) : RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6) ;
|
||||
|
||||
if(useDefault) {
|
||||
return DefaultRoute(rtype, RequestedAddress);
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
|
||||
}
|
||||
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D) -> bool {
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D, bool &UseRADSEC) -> bool {
|
||||
for(const auto &entry:D)
|
||||
if(entry.Addr.host()==RequestedAddress.host())
|
||||
if(entry.Addr.host()==RequestedAddress.host()) {
|
||||
UseRADSEC = entry.useRADSEC;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for(auto &i:Pools_) {
|
||||
switch(rtype) {
|
||||
case radius_type::coa: {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::auth: {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::acct: {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return DefaultRoute(rtype, RequestedAddress);
|
||||
|
||||
UseRADSEC = false;
|
||||
return RequestedAddress;
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress) {
|
||||
@@ -450,7 +629,6 @@ namespace OpenWifi {
|
||||
|
||||
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
|
||||
std::lock_guard G(Mutex_);
|
||||
PoolList_ = C;
|
||||
|
||||
Poco::JSON::Object Disk;
|
||||
C.to_json(Disk);
|
||||
@@ -459,13 +637,17 @@ namespace OpenWifi {
|
||||
Disk.stringify(ofs);
|
||||
ofs.close();
|
||||
|
||||
ParseConfig();
|
||||
Stop();
|
||||
ResetConfig();
|
||||
PoolList_ = C;
|
||||
Start();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ResetConfig() {
|
||||
PoolList_.pools.clear();
|
||||
Pools_.clear();
|
||||
defaultPoolIndex_=0;
|
||||
DefaultPoolIndex_=0;
|
||||
DefaultIsRADSEC_=false;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::DeleteConfig() {
|
||||
@@ -478,6 +660,7 @@ namespace OpenWifi {
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
Stop();
|
||||
ResetConfig();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Net/DatagramSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "RADSEC_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -15,6 +19,7 @@ namespace OpenWifi {
|
||||
auth, acct, coa
|
||||
};
|
||||
|
||||
|
||||
class RADIUS_proxy_server : public SubSystemServer {
|
||||
public:
|
||||
inline static auto instance() {
|
||||
@@ -24,7 +29,7 @@ namespace OpenWifi {
|
||||
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
inline bool Enabled() const { return enabled_; }
|
||||
inline bool Enabled() const { return Enabled_; }
|
||||
|
||||
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
@@ -38,6 +43,9 @@ namespace OpenWifi {
|
||||
void DeleteConfig();
|
||||
void GetConfig(GWObjects::RadiusProxyPoolList &C);
|
||||
|
||||
void StartRADSECServers();
|
||||
void StopRADSECServers();
|
||||
|
||||
struct Destination {
|
||||
Poco::Net::SocketAddress Addr;
|
||||
uint64_t state = 0;
|
||||
@@ -49,8 +57,14 @@ namespace OpenWifi {
|
||||
std::string monitorMethod;
|
||||
std::vector<std::string> methodParameters;
|
||||
bool useAsDefault=false;
|
||||
bool useRADSEC=false;
|
||||
std::vector<std::string> realms;
|
||||
};
|
||||
|
||||
inline bool Continue() const {
|
||||
return Running_ && Enabled_ && !Pools_.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
|
||||
@@ -58,16 +72,14 @@ namespace OpenWifi {
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
|
||||
Poco::Net::SocketReactor AccountingReactor_;
|
||||
Poco::Net::SocketReactor AuthenticationReactor_;
|
||||
Poco::Net::SocketReactor CoAReactor_;
|
||||
Poco::Thread AuthenticationReactorThread_;
|
||||
Poco::Thread AccountingReactorThread_;
|
||||
Poco::Thread CoAReactorThread_;
|
||||
std::unique_ptr<Poco::Net::SocketReactor> RadiusReactor_;
|
||||
Poco::Thread RadiusReactorThread_;
|
||||
|
||||
GWObjects::RadiusProxyPoolList PoolList_;
|
||||
std::string ConfigFilename_;
|
||||
|
||||
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSEC_server>> RADSECservers_;
|
||||
|
||||
struct RadiusPool {
|
||||
std::vector<Destination> AuthV4;
|
||||
std::vector<Destination> AuthV6;
|
||||
@@ -78,8 +90,10 @@ namespace OpenWifi {
|
||||
};
|
||||
|
||||
std::vector<RadiusPool> Pools_;
|
||||
uint defaultPoolIndex_=0;
|
||||
bool enabled_=false;
|
||||
uint DefaultPoolIndex_=0;
|
||||
bool Enabled_=false;
|
||||
bool DefaultIsRADSEC_=false;
|
||||
std::atomic_bool Running_=false;
|
||||
|
||||
RADIUS_proxy_server() noexcept:
|
||||
SubSystemServer("RADIUS-PROXY", "RADIUS-PROXY", "radius.proxy")
|
||||
@@ -90,10 +104,10 @@ namespace OpenWifi {
|
||||
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A);
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
void ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault);
|
||||
static Poco::Net::SocketAddress ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
};
|
||||
|
||||
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
|
||||
|
||||
303
src/RADSEC_server.h
Normal file
303
src/RADSEC_server.h
Normal file
@@ -0,0 +1,303 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-08-15.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "RADIUS_helpers.h"
|
||||
#include "AP_WS_Server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RADSEC_server : public Poco::Runnable {
|
||||
public:
|
||||
RADSEC_server(Poco::Net::SocketReactor & R, GWObjects::RadiusProxyServerEntry E) :
|
||||
Reactor_(R),
|
||||
Server_(std::move(E)),
|
||||
Logger_(Poco::Logger::get(fmt::format("RADSEC: {}@{}:{}",
|
||||
Server_.name ,
|
||||
Server_.ip,
|
||||
Server_.port))) {
|
||||
Start();
|
||||
}
|
||||
|
||||
~RADSEC_server() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
inline int Start() {
|
||||
ReconnectThread_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() {
|
||||
TryAgain_ = false;
|
||||
Disconnect();
|
||||
ReconnectThread_.wakeUp();
|
||||
ReconnectThread_.join();
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
Poco::Thread::trySleep(3000);
|
||||
std::uint64_t LastStatus=0 ;
|
||||
auto RadSecKeepAlive = MicroServiceConfigGetInt("radsec.keepalive",120);
|
||||
while(TryAgain_) {
|
||||
if(!Connected_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
LastStatus = Utils::Now() ;
|
||||
Connect();
|
||||
} else if( (Utils::Now() - LastStatus) > RadSecKeepAlive) {
|
||||
RADIUS::RadiusOutputPacket P(Server_.radsecSecret);
|
||||
P.MakeStatusMessage();
|
||||
poco_information(Logger_,"Keep-Alive message.");
|
||||
Socket_->sendBytes(P.Data(), P.Len());
|
||||
LastStatus = Utils::Now();
|
||||
}
|
||||
Poco::Thread::trySleep(!Connected_ ? 3000 : 10000);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SendData(const std::string &serial_number, const unsigned char *buffer, int length) {
|
||||
try {
|
||||
if (Connected_) {
|
||||
RADIUS::RadiusPacket P(buffer, length);
|
||||
int sent_bytes;
|
||||
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
|
||||
poco_debug(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
sent_bytes = Socket_->sendBytes(buffer, length);
|
||||
} else {
|
||||
poco_debug(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
P.ComputeMessageAuthenticator(Server_.radsecSecret);
|
||||
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
|
||||
}
|
||||
return (sent_bytes == length);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_,"Exception occurred: while sending data.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
unsigned char Buffer[4096];
|
||||
|
||||
try {
|
||||
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer,sizeof(Buffer));
|
||||
if(NumberOfReceivedBytes>=20) {
|
||||
RADIUS::RadiusPacket P(Buffer,NumberOfReceivedBytes);
|
||||
if (P.IsAuthentication()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_debug(Logger_, "AUTH packet dropped.");
|
||||
}
|
||||
} else if (P.IsAccounting()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_debug(Logger_, "ACCT packet dropped.");
|
||||
}
|
||||
} else if (P.IsAuthority()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if(!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_debug(Logger_, "CoA/DM packet dropped.");
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,fmt::format("Unknown packet: Type: {} (type={}) Length={}", P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,"Invalid packet received. Resetting the connection.");
|
||||
Disconnect();
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Disconnect();
|
||||
} catch (...) {
|
||||
Disconnect();
|
||||
poco_warning(Logger_,"Exception occurred. Resetting the connection.");
|
||||
}
|
||||
}
|
||||
|
||||
inline void onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
|
||||
poco_warning(Logger_,"Socker error. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
poco_warning(Logger_,"Socker socket shutdown. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline bool Connect() {
|
||||
if(TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
|
||||
|
||||
DecodeFile(CertFile_.path(), Server_.radsecCert);
|
||||
DecodeFile(KeyFile_.path(), Server_.radsecKey);
|
||||
|
||||
for(auto &cert:Server_.radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
|
||||
DecodeFile(CaCertFiles_[CaCertFiles_.size()-1]->path(), cert);
|
||||
}
|
||||
|
||||
Poco::Net::Context::Ptr SecureContext = Poco::AutoPtr<Poco::Net::Context>(
|
||||
new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE,
|
||||
KeyFile_.path(),
|
||||
CertFile_.path(),""));
|
||||
if(Server_.allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
for(const auto &ca:CaCertFiles_) {
|
||||
Poco::Crypto::X509Certificate cert(ca->path());
|
||||
SecureContext->addCertificateAuthority(cert);
|
||||
}
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
|
||||
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
|
||||
|
||||
try {
|
||||
poco_information(Logger_, "Attempting to connect");
|
||||
Socket_->connect(Destination, Poco::Timespan(100, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if(!Server_.allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if(Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60,0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_,fmt::format("Connected. CN={}",CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Disconnect() {
|
||||
if(Connected_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
Socket_->close();
|
||||
Connected_ = false;
|
||||
}
|
||||
poco_information(Logger_,"Disconnecting.");
|
||||
}
|
||||
|
||||
static void DecodeFile(const std::string &filename, const std::string &s) {
|
||||
std::ofstream sec_file(filename,std::ios_base::out|std::ios_base::trunc|std::ios_base::binary);
|
||||
std::stringstream is(s);
|
||||
Poco::Base64Decoder ds(is);
|
||||
Poco::StreamCopier::copyStream(ds,sec_file);
|
||||
sec_file.close();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string CommonName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->commonName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string IssuerName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->issuerName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string SubjectName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->subjectName();
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex LocalMutex_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
GWObjects::RadiusProxyServerEntry Server_;
|
||||
Poco::Logger &Logger_;
|
||||
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
|
||||
Poco::Thread ReconnectThread_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
|
||||
volatile bool Connected_=false;
|
||||
volatile bool TryAgain_=true;
|
||||
};
|
||||
}
|
||||
@@ -8,10 +8,12 @@
|
||||
#include "RESTAPI_RPC.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
#include "ParseWifiScan.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
void SetCommandStatus(GWObjects::CommandDetails &Cmd,
|
||||
@@ -31,7 +33,10 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
void WaitForCommand(GWObjects::CommandDetails &Cmd,
|
||||
void WaitForCommand(uint64_t RPCID,
|
||||
APCommands::Commands Command,
|
||||
bool RetryLater,
|
||||
GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
@@ -40,53 +45,59 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger) {
|
||||
|
||||
Logger.information(fmt::format("{}: New {} command. User={} Serial={}. ", Cmd.UUID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
|
||||
Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID, RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
|
||||
|
||||
// if the command should be executed in the future, or if the device is not connected,
|
||||
// then we should just add the command to
|
||||
// the DB and let it figure out when to deliver the command.
|
||||
if (Cmd.RunAt || !DeviceRegistry()->Connected(Cmd.SerialNumber)) {
|
||||
Logger.information(fmt::format("{}: Command will be run in the future or when device is connected again.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
|
||||
if (Cmd.RunAt || (!AP_WS_Server()->Connected(SerialNumberInt) && RetryLater)) {
|
||||
Logger.information(fmt::format("{},{}: Command will be run in the future or when device is connected again.", Cmd.UUID, RPCID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
return;
|
||||
} else if ((!AP_WS_Server()->Connected(SerialNumberInt) && !RetryLater)){
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
|
||||
Cmd.Executed = OpenWifi::Now();
|
||||
Cmd.Executed = Utils::Now();
|
||||
|
||||
bool Sent;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> rpc_submitted = std::chrono::high_resolution_clock::now();
|
||||
std::shared_ptr<CommandManager::promise_type_t> rpc_endpoint =
|
||||
CommandManager()->PostCommand(Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
CommandManager()->PostCommand(RPCID, Command, Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
|
||||
if(!Sent || rpc_endpoint== nullptr) {
|
||||
Logger.information(fmt::format("{}: Pending completion. Device is not connected.", Cmd.UUID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
if(RetryLater && (!Sent || rpc_endpoint== nullptr)) {
|
||||
Logger.information(fmt::format("{},{}: Pending completion. Device is not connected.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
}
|
||||
|
||||
Logger.information(fmt::format("{}: Command sent.", Cmd.UUID));
|
||||
|
||||
Poco::JSON::Object L;
|
||||
if(!RetryLater && !Sent) {
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
|
||||
Logger.information(fmt::format("{},{}: Command sent.", Cmd.UUID, RPCID));
|
||||
std::future<CommandManager::objtype_t> rpc_future(rpc_endpoint->get_future());
|
||||
auto rpc_result = rpc_future.wait_for(WaitTimeInMs);
|
||||
if (rpc_result == std::future_status::ready) {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - rpc_submitted;
|
||||
auto rpc_answer = rpc_future.get();
|
||||
if (!rpc_answer.has(uCentralProtocol::RESULT) || !rpc_answer.isObject(uCentralProtocol::RESULT)) {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response. Missing result.", Cmd.UUID));
|
||||
if (!rpc_answer->has(uCentralProtocol::RESULT) || !rpc_answer->isObject(uCentralProtocol::RESULT)) {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response. Missing result.", Cmd.UUID, RPCID));
|
||||
return;
|
||||
}
|
||||
|
||||
auto ResultFields = rpc_answer.get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
auto ResultFields = rpc_answer->get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
if (!ResultFields->has(uCentralProtocol::STATUS) || !ResultFields->isObject(uCentralProtocol::STATUS)) {
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
if(Cmd.Command=="ping") {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_COMPLETED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response from device (ping: fix override). Missing status.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_COMPLETED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response from device (ping: fix override). Missing status.", Cmd.UUID, RPCID));
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response from device. Missing status.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response from device. Missing status.", Cmd.UUID,RPCID));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -97,36 +108,36 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if (StatusInnerObj->has(uCentralProtocol::TEXT))
|
||||
Cmd.ErrorText = StatusInnerObj->get(uCentralProtocol::TEXT).toString();
|
||||
std::stringstream ResultText;
|
||||
if(rpc_answer.has(uCentralProtocol::RESULT)) {
|
||||
if(rpc_answer->has(uCentralProtocol::RESULT)) {
|
||||
if(Cmd.Command==uCentralProtocol::WIFISCAN) {
|
||||
auto ScanObj = rpc_answer.get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
auto ScanObj = rpc_answer->get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
ParseWifiScan(ScanObj, ResultText, Logger);
|
||||
} else {
|
||||
Poco::JSON::Stringifier::stringify(
|
||||
rpc_answer.get(uCentralProtocol::RESULT), ResultText);
|
||||
rpc_answer->get(uCentralProtocol::RESULT), ResultText);
|
||||
}
|
||||
} if (rpc_answer.has(uCentralProtocol::RESULT_64)) {
|
||||
} if (rpc_answer->has(uCentralProtocol::RESULT_64)) {
|
||||
uint64_t sz=0;
|
||||
if(rpc_answer.has(uCentralProtocol::RESULT_SZ))
|
||||
sz=rpc_answer.get(uCentralProtocol::RESULT_SZ);
|
||||
if(rpc_answer->has(uCentralProtocol::RESULT_SZ))
|
||||
sz=rpc_answer->get(uCentralProtocol::RESULT_SZ);
|
||||
std::string UnCompressedData;
|
||||
Utils::ExtractBase64CompressedData(rpc_answer.get(uCentralProtocol::RESULT_64).toString(),
|
||||
Utils::ExtractBase64CompressedData(rpc_answer->get(uCentralProtocol::RESULT_64).toString(),
|
||||
UnCompressedData,sz);
|
||||
Poco::JSON::Stringifier::stringify(UnCompressedData, ResultText);
|
||||
}
|
||||
Cmd.Results = ResultText.str();
|
||||
Cmd.Status = "completed";
|
||||
Cmd.Completed = OpenWifi::Now();
|
||||
Cmd.Completed = Utils::Now();
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
|
||||
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
|
||||
if (Cmd.ErrorCode && (Cmd.Command == uCentralProtocol::TRACE || Cmd.Command == uCentralProtocol::SCRIPT)) {
|
||||
Cmd.WaitingForFile = 0;
|
||||
Cmd.AttachDate = Cmd.AttachSize = 0;
|
||||
Cmd.AttachType = "";
|
||||
}
|
||||
|
||||
// Add the completed command to the database...
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::COMMAND_COMPLETED);
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
|
||||
if (ObjectToReturn && Handler) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
@@ -136,10 +147,16 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if(Handler)
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
Logger.information( fmt::format("{}: Completed in {:.3f}ms.", Cmd.UUID, Cmd.executionTime));
|
||||
Logger.information( fmt::format("{},{}: Completed in {:.3f}ms.", Cmd.UUID, RPCID, Cmd.executionTime));
|
||||
return;
|
||||
}
|
||||
Logger.information(fmt::format( "{}: Pending completion.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
CommandManager()->RemovePendingCommand(RPCID);
|
||||
if(RetryLater) {
|
||||
Logger.information(fmt::format("{},{}: Pending completion.", Cmd.UUID, RPCID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
} else {
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,24 @@
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
|
||||
void WaitForCommand( GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger);
|
||||
void WaitForCommand(
|
||||
uint64_t RPCID,
|
||||
APCommands::Commands Command,
|
||||
bool RetryLater,
|
||||
GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger);
|
||||
|
||||
void SetCommandStatus( GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/JSON/Stringifier.h"
|
||||
#include "RESTAPI_blacklist.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_blacklist::DoDelete() {
|
||||
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
poco_debug(Logger(),fmt::format("BLACKLIST-DELETE: {}", SerialNumber));
|
||||
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!StorageService()->GetBlackListDevice(SerialNumber, D)) {
|
||||
return NotFound();
|
||||
@@ -36,54 +36,51 @@ namespace OpenWifi {
|
||||
void RESTAPI_blacklist::DoGet() {
|
||||
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
poco_debug(Logger(),fmt::format("BLACKLIST-GET: {}", SerialNumber));
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!StorageService()->GetBlackListDevice(SerialNumber, D)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
D.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
return Object(D);
|
||||
}
|
||||
|
||||
void RESTAPI_blacklist::DoPost() {
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!D.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(D.serialNumber.empty()) {
|
||||
if(D.serialNumber.empty() || !Utils::NormalizeMac(D.serialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
poco_debug(Logger(),fmt::format("BLACKLIST-POST: {}", D.serialNumber));
|
||||
|
||||
Poco::toLowerInPlace(D.serialNumber);
|
||||
if(StorageService()->IsBlackListed(D.serialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberExists);
|
||||
}
|
||||
|
||||
D.author = UserInfo_.userinfo.email;
|
||||
D.created = OpenWifi::Now();
|
||||
D.created = Utils::Now();
|
||||
|
||||
if(StorageService()->AddBlackListDevice(D)) {
|
||||
GWObjects::BlackListedDevice CreatedDevice;
|
||||
|
||||
StorageService()->GetBlackListDevice(D.serialNumber,CreatedDevice);
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
CreatedDevice.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
return Object(CreatedDevice);
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
void RESTAPI_blacklist::DoPut() {
|
||||
auto SerialNumber = Poco::toLower(GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""));
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -93,6 +90,8 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
poco_debug(Logger(),fmt::format("BLACKLIST-PUT: {}", SerialNumber));
|
||||
|
||||
GWObjects::BlackListedDevice NewDevice;
|
||||
if(!NewDevice.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
@@ -105,10 +104,7 @@ namespace OpenWifi {
|
||||
GWObjects::BlackListedDevice CreatedDevice;
|
||||
|
||||
StorageService()->GetBlackListDevice(SerialNumber,CreatedDevice);
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
CreatedDevice.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
return Object(CreatedDevice);
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_blacklist : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_blacklist(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server , uint64_t TransactionId , bool Internal)
|
||||
RESTAPI_blacklist(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server , uint64_t TransactionId , bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_POST,
|
||||
|
||||
@@ -10,22 +10,16 @@
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_blacklist_list::DoGet() {
|
||||
|
||||
std::vector<GWObjects::BlackListedDevice> Devices;
|
||||
poco_debug(Logger(),fmt::format("BLACKLIST-GET: Device serial number list"));
|
||||
|
||||
Poco::JSON::Array Arr;
|
||||
Poco::JSON::Object Answer;
|
||||
std::vector<GWObjects::BlackListedDevice> Devices;
|
||||
|
||||
if(QB_.CountOnly) {
|
||||
auto Count = StorageService()->GetBlackListDeviceCount();
|
||||
return ReturnCountOnly(Count);
|
||||
} else if(StorageService()->GetBlackListDevices(QB_.Offset, QB_.Limit, Devices)) {
|
||||
for(const auto &i:Devices) {
|
||||
Poco::JSON::Object O;
|
||||
i.to_json(O);
|
||||
Arr.add(O);
|
||||
}
|
||||
return Object("devices",Devices);
|
||||
}
|
||||
Answer.set("devices", Arr);
|
||||
return ReturnObject(Answer);
|
||||
NotFound();
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_blacklist_list : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_blacklist_list(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_blacklist_list(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_capabilities_handler::DoGet() {
|
||||
CapabilitiesCache_t Caps = CapabilitiesCache().AllCapabilities();
|
||||
CapabilitiesCache_t Caps = CapabilitiesCache()->AllCapabilities();
|
||||
|
||||
Poco::JSON::Array ObjArr;
|
||||
for(const auto &[deviceType,capabilities]:Caps) {
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_capabilities_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_capabilities_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_capabilities_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace OpenWifi {
|
||||
|
||||
GWObjects::CommandDetails Command;
|
||||
if (StorageService()->GetCommand(CommandUUID, Command)) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Command.to_json(RetObj);
|
||||
return ReturnObject(RetObj);
|
||||
return Object(Command);
|
||||
}
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_command : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_commands::DoGet() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (QB_.Newest) {
|
||||
StorageService()->GetNewestCommands(SerialNumber, QB_.Limit, Commands);
|
||||
@@ -20,23 +24,15 @@ namespace OpenWifi {
|
||||
StorageService()->GetCommands(SerialNumber, QB_.StartDate, QB_.EndDate, QB_.Offset, QB_.Limit,
|
||||
Commands);
|
||||
}
|
||||
Poco::JSON::Array ArrayObj;
|
||||
for (const auto &i : Commands) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
ArrayObj.add(Obj);
|
||||
}
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(RESTAPI::Protocol::COMMANDS, ArrayObj);
|
||||
ReturnObject(RetObj);
|
||||
return Object(RESTAPI::Protocol::COMMANDS, Commands);
|
||||
}
|
||||
|
||||
void RESTAPI_commands::DoDelete() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
if (StorageService()->DeleteCommands(SerialNumber, QB_.StartDate, QB_.EndDate)) {
|
||||
return OK();
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_commands : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_commands(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_commands(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
|
||||
@@ -14,21 +14,21 @@
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "framework/orm.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_default_configuration::DoGet() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (StorageService()->GetDefaultConfiguration(Name, DefConfig)) {
|
||||
Poco::JSON::Object Obj;
|
||||
DefConfig.to_json(Obj);
|
||||
return ReturnObject(Obj);
|
||||
return Object(DefConfig);
|
||||
}
|
||||
NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_default_configuration::DoDelete() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
|
||||
if(Name.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
|
||||
DefConfig.Created = DefConfig.LastModified = OpenWifi::Now();
|
||||
DefConfig.Created = DefConfig.LastModified = Utils::Now();
|
||||
if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) {
|
||||
return OK();
|
||||
}
|
||||
@@ -95,7 +95,7 @@ namespace OpenWifi {
|
||||
Existing.Configuration = NewConfig.Configuration;
|
||||
}
|
||||
|
||||
Existing.LastModified = OpenWifi::Now();
|
||||
Existing.LastModified = Utils::Now();
|
||||
AssignIfPresent(Obj,"description",Existing.Description);
|
||||
if(Obj->has("modelIds"))
|
||||
Existing.Models = NewConfig.Models;
|
||||
@@ -104,12 +104,9 @@ namespace OpenWifi {
|
||||
GWObjects::DefaultConfiguration ModifiedConfig;
|
||||
|
||||
StorageService()->GetDefaultConfiguration(Name,ModifiedConfig);
|
||||
Poco::JSON::Object Answer;
|
||||
ModifiedConfig.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
return Object(ModifiedConfig);
|
||||
}
|
||||
|
||||
BadRequest(RESTAPI::Errors::RecordNotUpdated);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_default_configuration : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_default_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_default_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{
|
||||
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST,
|
||||
|
||||
@@ -23,16 +23,6 @@ namespace OpenWifi {
|
||||
|
||||
std::vector<GWObjects::DefaultConfiguration> DefConfigs;
|
||||
StorageService()->GetDefaultConfigurations(QB_.Offset, QB_.Limit, DefConfigs);
|
||||
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : DefConfigs) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
}
|
||||
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(RESTAPI::Protocol::CONFIGURATIONS, Objects);
|
||||
ReturnObject(RetObj);
|
||||
return Object(RESTAPI::Protocol::CONFIGURATIONS, DefConfigs);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user