mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-12-24 14:27:00 +00:00
Compare commits
736 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
351633f215 | ||
|
|
5ec9d6a2c8 | ||
|
|
3abb24919f | ||
|
|
089446c3b4 | ||
|
|
345195dd1e | ||
|
|
21db12bcc6 | ||
|
|
be01cfb142 | ||
|
|
55645c5da4 | ||
|
|
aa0316462f | ||
|
|
ebb3c8fed0 | ||
|
|
4fb788def4 | ||
|
|
5b1e048be3 | ||
|
|
03ebc88672 | ||
|
|
80bb7ffa07 | ||
|
|
1776a70a0e | ||
|
|
3a0de1fee9 | ||
|
|
8414ed719b | ||
|
|
eebb18fccf | ||
|
|
1e59b8e160 | ||
|
|
6da673e754 | ||
|
|
ee4cb53517 | ||
|
|
61da6aa317 | ||
|
|
bbbadd3a23 | ||
|
|
855eb0dc13 | ||
|
|
0601aaf340 | ||
|
|
100d0302be | ||
|
|
1fe4dbf49f | ||
|
|
720222137c | ||
|
|
d464b8a6f4 | ||
|
|
019a995bdd | ||
|
|
f70a8f1732 | ||
|
|
0c79d2a632 | ||
|
|
1d16bd352a | ||
|
|
88564f2a77 | ||
|
|
1907ab9623 | ||
|
|
60e50b2af4 | ||
|
|
cd24a45c87 | ||
|
|
cab25f6fd7 | ||
|
|
23c5879a4b | ||
|
|
4e90422e7c | ||
|
|
e75983019a | ||
|
|
a6afef5f8e | ||
|
|
15e45f32a1 | ||
|
|
4c7e1807a2 | ||
|
|
301b24415c | ||
|
|
da0698ab9b | ||
|
|
f8454e6b83 | ||
|
|
cfaab404e9 | ||
|
|
e5f98cda04 | ||
|
|
bd8fece423 | ||
|
|
68a707fe57 | ||
|
|
e02a5595a1 | ||
|
|
744c1143fb | ||
|
|
41423a6d5f | ||
|
|
060c8673e7 | ||
|
|
1210ae821b | ||
|
|
1a2e4cc184 | ||
|
|
e32ace120b | ||
|
|
3f2c046a96 | ||
|
|
9459bb022c | ||
|
|
9526a2639a | ||
|
|
2051467c0b | ||
|
|
bacaa9959c | ||
|
|
875ee6bfd1 | ||
|
|
8f966fa80c | ||
|
|
d9ac843134 | ||
|
|
4abedcddf0 | ||
|
|
c14abf8aa0 | ||
|
|
d779fca535 | ||
|
|
7e1d545f26 | ||
|
|
9c2d60ed3a | ||
|
|
b8516cad84 | ||
|
|
eba979d9da | ||
|
|
d163f7522d | ||
|
|
132fdafd32 | ||
|
|
3d6527f30b | ||
|
|
dc114de8fa | ||
|
|
0592537b71 | ||
|
|
eddaaa0cd6 | ||
|
|
46e72369ae | ||
|
|
3fc3af68ee | ||
|
|
58648d7dc5 | ||
|
|
b2bd6aab9e | ||
|
|
3781f5283f | ||
|
|
7b990a7d2f | ||
|
|
eca43e1d57 | ||
|
|
c1347fc3b8 | ||
|
|
888fcbbcd3 | ||
|
|
4e4156c420 | ||
|
|
ee98a7b8a5 | ||
|
|
0b5518d265 | ||
|
|
7bc0656f25 | ||
|
|
177a8b40ee | ||
|
|
85ee78f35e | ||
|
|
9043b3a558 | ||
|
|
4d2d488812 | ||
|
|
adf226f2e8 | ||
|
|
749d425d80 | ||
|
|
a6f9deb315 | ||
|
|
f4236408fc | ||
|
|
377c7bfc0b | ||
|
|
2e3efd97e4 | ||
|
|
58abf04e42 | ||
|
|
5e002899b5 | ||
|
|
d43c8f63ab | ||
|
|
07a64877bb | ||
|
|
a00ba50920 | ||
|
|
c2fa87d6bd | ||
|
|
ab0b36a96f | ||
|
|
89f8047e2f | ||
|
|
1515c9bb6a | ||
|
|
b53e6f44fa | ||
|
|
769c9c90f6 | ||
|
|
dc0eb35376 | ||
|
|
e6b497f0b4 | ||
|
|
bab9d869b1 | ||
|
|
a9127d4fcf | ||
|
|
fea78abe9b | ||
|
|
bd72993fa5 | ||
|
|
7d74694bf9 | ||
|
|
8e84a0f1f3 | ||
|
|
98c8f29555 | ||
|
|
42a4ee0864 | ||
|
|
fcce86acf4 | ||
|
|
31aad8b41b | ||
|
|
a828039445 | ||
|
|
6905aeaeec | ||
|
|
3293b7b71d | ||
|
|
2d6df5ea29 | ||
|
|
e466f76b75 | ||
|
|
170b97514b | ||
|
|
a463bb60dd | ||
|
|
9bbb12b674 | ||
|
|
46cc41e065 | ||
|
|
1776643579 | ||
|
|
c0d9aca88a | ||
|
|
88018335da | ||
|
|
7ce7927c95 | ||
|
|
5b797cf937 | ||
|
|
cd615e8f2b | ||
|
|
cf3f0fe67f | ||
|
|
b80e92f3dc | ||
|
|
11034bd4fd | ||
|
|
01980892b1 | ||
|
|
f4d4405663 | ||
|
|
a8370dc8dd | ||
|
|
861c4d0dee | ||
|
|
8c70e833ea | ||
|
|
f8928bbec2 | ||
|
|
0b7e474e01 | ||
|
|
14f0bb75d1 | ||
|
|
32d37a3b9c | ||
|
|
24391c5ac4 | ||
|
|
7ac47dfaa0 | ||
|
|
fd77d6ef37 | ||
|
|
04c9deffd3 | ||
|
|
f8bc00cb55 | ||
|
|
f2ae0b6bd4 | ||
|
|
1904b34c84 | ||
|
|
23ea21d2b4 | ||
|
|
276572a8a5 | ||
|
|
b9bd5ca6a5 | ||
|
|
201a4dd6e7 | ||
|
|
769eb83744 | ||
|
|
66a30c4f37 | ||
|
|
2a744e2fde | ||
|
|
f212aa2e8c | ||
|
|
fc478bd304 | ||
|
|
6e8a2478c4 | ||
|
|
eceb5a9034 | ||
|
|
782acea8c7 | ||
|
|
524d392e83 | ||
|
|
885f1affeb | ||
|
|
50abf75a0a | ||
|
|
4af6427814 | ||
|
|
2a6ec50ce1 | ||
|
|
4497dc655b | ||
|
|
1e2d04ad07 | ||
|
|
5874d3f1fd | ||
|
|
a4abbe6ef3 | ||
|
|
41e3cbb2b2 | ||
|
|
1f77083973 | ||
|
|
b08f993a20 | ||
|
|
113baa625e | ||
|
|
3765d22815 | ||
|
|
24d492903b | ||
|
|
3b4fd70522 | ||
|
|
19cf9101fe | ||
|
|
004319e7ad | ||
|
|
94893d1185 | ||
|
|
13dce2f3e8 | ||
|
|
ea7bc3c52f | ||
|
|
0235a13841 | ||
|
|
be33c88337 | ||
|
|
0456f638c9 | ||
|
|
83ada79ca3 | ||
|
|
913d1e571d | ||
|
|
8f98e510db | ||
|
|
fb0da90b63 | ||
|
|
1e1dec51ab | ||
|
|
c35602e30e | ||
|
|
4c90a777e0 | ||
|
|
9abfa4bad5 | ||
|
|
7ecd0c9891 | ||
|
|
6e25ccdd87 | ||
|
|
a8f970eaf2 | ||
|
|
9f4d362a6d | ||
|
|
5f3f9e93d2 | ||
|
|
c84f05cd22 | ||
|
|
a532520044 | ||
|
|
6d82ee355e | ||
|
|
02c3b2fe2e | ||
|
|
cce4a7ec93 | ||
|
|
9aef183dc2 | ||
|
|
60a3365a9e | ||
|
|
6c052d7afe | ||
|
|
88eae31b7f | ||
|
|
d59f6e3dfc | ||
|
|
c97566f625 | ||
|
|
1fb41a9460 | ||
|
|
cfec8a1cbc | ||
|
|
7a84640c71 | ||
|
|
0d2276ff5a | ||
|
|
d227f83384 | ||
|
|
acb4d91a3d | ||
|
|
72b2913cc5 | ||
|
|
746ef603e2 | ||
|
|
ab792f7239 | ||
|
|
c4bb577763 | ||
|
|
3caf67102e | ||
|
|
8a3ade14ae | ||
|
|
4199b859ad | ||
|
|
be1b571f7f | ||
|
|
3002e17fd2 | ||
|
|
0d1a794e10 | ||
|
|
2aa7d97c80 | ||
|
|
0d3a0cbf03 | ||
|
|
1d8cb5447b | ||
|
|
3526a7abd9 | ||
|
|
d7ec9a3552 | ||
|
|
9f567e0e69 | ||
|
|
b16a410f1d | ||
|
|
0955f23dfc | ||
|
|
bd10ebc19c | ||
|
|
f74c5b496f | ||
|
|
6e961be74e | ||
|
|
c92d22f3cb | ||
|
|
e1770dc6a2 | ||
|
|
eace417fd3 | ||
|
|
ec3b5ededc | ||
|
|
4c6a0ab9e2 | ||
|
|
78a6b011f8 | ||
|
|
a5450418b3 | ||
|
|
c74aa0d89f | ||
|
|
5f5e887f91 | ||
|
|
54a9290589 | ||
|
|
24be35c974 | ||
|
|
937d2818c0 | ||
|
|
f014960b3a | ||
|
|
cc5b319141 | ||
|
|
d5e7a6661f | ||
|
|
3368782471 | ||
|
|
2f013557a9 | ||
|
|
09595abc8c | ||
|
|
5104ab1dc3 | ||
|
|
8f3b2f795f | ||
|
|
9779ee669b | ||
|
|
f7187749a1 | ||
|
|
ddec407856 | ||
|
|
4650ac592a | ||
|
|
bc5c9e30cf | ||
|
|
1b53398e1e | ||
|
|
7b59a981dd | ||
|
|
ec3cb6586f | ||
|
|
c40be95aa8 | ||
|
|
ba8edb7f74 | ||
|
|
ea14936a1d | ||
|
|
676f131ca9 | ||
|
|
2e1fc663c8 | ||
|
|
cd9ef2ed2a | ||
|
|
4a1a903656 | ||
|
|
f6409fc063 | ||
|
|
6af855f6ca | ||
|
|
bec81bc380 | ||
|
|
0e4e4156a1 | ||
|
|
2aa60a5676 | ||
|
|
8b396e51ff | ||
|
|
01f53d7b78 | ||
|
|
b3c188701f | ||
|
|
7eb4c9e38b | ||
|
|
c93c34c042 | ||
|
|
418f8d31ae | ||
|
|
77c0c191f7 | ||
|
|
f0f4cf54bb | ||
|
|
917abf1d7f | ||
|
|
b4e7e4e26b | ||
|
|
9d0a146859 | ||
|
|
2efed5e626 | ||
|
|
7420b72b23 | ||
|
|
5fc675484c | ||
|
|
38ad11542b | ||
|
|
63f2a4085a | ||
|
|
fea70efb2d | ||
|
|
da42c9845f | ||
|
|
ed46778bd4 | ||
|
|
1f7c0b7fdf | ||
|
|
15ec31fc89 | ||
|
|
d2a0d6da8a | ||
|
|
77cae31031 | ||
|
|
6cab1caf6c | ||
|
|
faf7881c87 | ||
|
|
eea8203869 | ||
|
|
040397aa8e | ||
|
|
bba92aa9b8 | ||
|
|
c332a3946d | ||
|
|
02e677f849 | ||
|
|
a26f7c03c1 | ||
|
|
9181ae01cc | ||
|
|
7825b00d2e | ||
|
|
8b895c2088 | ||
|
|
49d39d37a1 | ||
|
|
406d59d5d7 | ||
|
|
186d12c78a | ||
|
|
421c24c961 | ||
|
|
e00c835680 | ||
|
|
3f972ebb4a | ||
|
|
cf8d29e66f | ||
|
|
d5e11d246a | ||
|
|
6ac29199e0 | ||
|
|
2f9452d6ef | ||
|
|
caed454e1a | ||
|
|
30916cbed1 | ||
|
|
81899788a9 | ||
|
|
e1590cbe90 | ||
|
|
bcbc212436 | ||
|
|
520671684b | ||
|
|
eacf9c0450 | ||
|
|
bef4c3ed5c | ||
|
|
4fe6254bf2 | ||
|
|
63ba3d633d | ||
|
|
1255cf0a56 | ||
|
|
7a6f2a517c | ||
|
|
6c15908ed6 | ||
|
|
d0a7670fff | ||
|
|
17d6253cfe | ||
|
|
ab592305ce | ||
|
|
0da527e1d7 | ||
|
|
d3848a6f8b | ||
|
|
c522c22d31 | ||
|
|
783886662f | ||
|
|
56ab9b1409 | ||
|
|
67e86a0edf | ||
|
|
70c12a5b77 | ||
|
|
03f2e2d457 | ||
|
|
ed12331d20 | ||
|
|
ec0c295c7c | ||
|
|
2438bd7ca7 | ||
|
|
18d18f68c5 | ||
|
|
120f94a95a | ||
|
|
7b9cda8c3d | ||
|
|
0d116119ed | ||
|
|
b9a7f53a92 | ||
|
|
ee3aa66b11 | ||
|
|
459029d5d7 | ||
|
|
bfe0ff4481 | ||
|
|
b70a95d12b | ||
|
|
8280ff46db | ||
|
|
59da808bcd | ||
|
|
dbc785aca6 | ||
|
|
5207579645 | ||
|
|
840c22e0d1 | ||
|
|
996e410fde | ||
|
|
521dcc2eed | ||
|
|
4d73467b8a | ||
|
|
515444d223 | ||
|
|
dccda306d4 | ||
|
|
3fd5c59994 | ||
|
|
87fee4ecd2 | ||
|
|
b37e7d4c5d | ||
|
|
f8c21f0c68 | ||
|
|
f74c098b99 | ||
|
|
1619cec197 | ||
|
|
62211b6e8b | ||
|
|
1bebe0729a | ||
|
|
6a8a6aa851 | ||
|
|
4b6880a306 | ||
|
|
3d252116dd | ||
|
|
2fc5e69145 | ||
|
|
8d2e85d0ee | ||
|
|
d1efdc93a4 | ||
|
|
c27627302f | ||
|
|
ae18fead11 | ||
|
|
75a6300ffb | ||
|
|
f84a4c83d0 | ||
|
|
b882f07eef | ||
|
|
d5c8cb5837 | ||
|
|
a09f2ec7bd | ||
|
|
7af9be5845 | ||
|
|
bc6e7d538b | ||
|
|
59ed9df3c9 | ||
|
|
0f46a6ded0 | ||
|
|
ef09214187 | ||
|
|
aa4631b55d | ||
|
|
08b59e04ee | ||
|
|
3455297cd6 | ||
|
|
8f4e585c88 | ||
|
|
350ccd5371 | ||
|
|
b89c0773c5 | ||
|
|
d03cd6a6df | ||
|
|
142a04ffc3 | ||
|
|
bb519eb84b | ||
|
|
2b8e496bbc | ||
|
|
776a781a87 | ||
|
|
f5d66365b8 | ||
|
|
fd8b021225 | ||
|
|
1d2b54b6cf | ||
|
|
07ed169c08 | ||
|
|
f33b6c94be | ||
|
|
b073246293 | ||
|
|
8205cb7336 | ||
|
|
9339ae893a | ||
|
|
ce483ba51c | ||
|
|
85a7de67fb | ||
|
|
abdabe7da3 | ||
|
|
669af7640c | ||
|
|
83c46c44aa | ||
|
|
7b2ba4fed4 | ||
|
|
ef5aa26991 | ||
|
|
92b25846d2 | ||
|
|
77663f9184 | ||
|
|
61c7ab3267 | ||
|
|
8ae0006343 | ||
|
|
64a1fa1c85 | ||
|
|
2b9c90d5e6 | ||
|
|
565cee2373 | ||
|
|
36c5c9c5b6 | ||
|
|
837c3d5570 | ||
|
|
2a71721548 | ||
|
|
055bdcf937 | ||
|
|
221ee05298 | ||
|
|
afb8252dc2 | ||
|
|
77f86d139f | ||
|
|
b2353b6a0e | ||
|
|
bf4b9b0d63 | ||
|
|
e51236f0ca | ||
|
|
5be8ad75ed | ||
|
|
054e3e1591 | ||
|
|
06366f875c | ||
|
|
64d3f8c3ee | ||
|
|
8878445e03 | ||
|
|
ea30684f0c | ||
|
|
ebf08a63f1 | ||
|
|
e9e7db9ac0 | ||
|
|
7f9d03ed34 | ||
|
|
084483b028 | ||
|
|
285dbacd12 | ||
|
|
8f79d70753 | ||
|
|
6d20481d64 | ||
|
|
7da4bbba61 | ||
|
|
ff955d8b2f | ||
|
|
29d615393f | ||
|
|
2a716e6c66 | ||
|
|
b662dcf88c | ||
|
|
253ffbf111 | ||
|
|
dfd689512b | ||
|
|
cee2705bf8 | ||
|
|
af1e293bde | ||
|
|
58266eb239 | ||
|
|
87dc357c9f | ||
|
|
02798de88a | ||
|
|
d7bd812f97 | ||
|
|
b692a7868e | ||
|
|
f57dfc62c0 | ||
|
|
21794d669e | ||
|
|
2139093a73 | ||
|
|
bc1f0670fb | ||
|
|
a0b0a169fa | ||
|
|
7feb9f3655 | ||
|
|
3878d8abe6 | ||
|
|
770b5969f8 | ||
|
|
00bca216fc | ||
|
|
64eb7748d1 | ||
|
|
8ed351ad17 | ||
|
|
4a71be0558 | ||
|
|
d6434666b4 | ||
|
|
747c84de4a | ||
|
|
538bdb25b1 | ||
|
|
07229e7e1f | ||
|
|
a63a1785e2 | ||
|
|
14820bd9c8 | ||
|
|
aeeb333c62 | ||
|
|
caa8f8c5a5 | ||
|
|
02aada469b | ||
|
|
020f9aea16 | ||
|
|
a8d5717fd5 | ||
|
|
51dd030419 | ||
|
|
6a83895efc | ||
|
|
c5e2574ab1 | ||
|
|
5a1828eaea | ||
|
|
c62f5a16f5 | ||
|
|
b6e778ada3 | ||
|
|
1b34ec8a78 | ||
|
|
57eb7312c8 | ||
|
|
368cdb72d4 | ||
|
|
712d326560 | ||
|
|
11df029ec0 | ||
|
|
020542b751 | ||
|
|
4b19163091 | ||
|
|
852ae3fde7 | ||
|
|
1ab9729ec1 | ||
|
|
9b1711fff6 | ||
|
|
929bc79136 | ||
|
|
e8fec5075f | ||
|
|
0bae840106 | ||
|
|
bf519637aa | ||
|
|
b15dc2b517 | ||
|
|
44f2843a7f | ||
|
|
e2eda25764 | ||
|
|
b2411d97d6 | ||
|
|
4a61f57912 | ||
|
|
1cafe0b6fc | ||
|
|
20763dedf6 | ||
|
|
80c0a3c07e | ||
|
|
0138cfdede | ||
|
|
066bad7953 | ||
|
|
2ca1508be1 | ||
|
|
737e49a376 | ||
|
|
251a4c2310 | ||
|
|
4e4ad418b6 | ||
|
|
b07c381bf7 | ||
|
|
e3375a4510 | ||
|
|
6134c37d2b | ||
|
|
5e42202264 | ||
|
|
2f389599f8 | ||
|
|
36b633fcb7 | ||
|
|
5a1d56399c | ||
|
|
8ebb92b95a | ||
|
|
69716f50c0 | ||
|
|
580e4ce052 | ||
|
|
ab663be084 | ||
|
|
d5350b4283 | ||
|
|
873d77adf0 | ||
|
|
530555ff26 | ||
|
|
3db8892e58 | ||
|
|
c1ba58be6e | ||
|
|
0750be2d81 | ||
|
|
adec21906f | ||
|
|
80b5c6f3b5 | ||
|
|
e29a7589f2 | ||
|
|
8255ff3218 | ||
|
|
5b70cdfe53 | ||
|
|
2e94733c8d | ||
|
|
3d62625cf6 | ||
|
|
eb0eae90b6 | ||
|
|
d7dc43f0de | ||
|
|
3c6ec00695 | ||
|
|
eb705dfeb1 | ||
|
|
46bd78ba15 | ||
|
|
e730c60ebc | ||
|
|
3329781bc2 | ||
|
|
dfcc59a7b8 | ||
|
|
b72fb379cd | ||
|
|
74db8cd36d | ||
|
|
1219a70da2 | ||
|
|
dc95a8632a | ||
|
|
8b0ecb464b | ||
|
|
9f863c1cc2 | ||
|
|
fda6f8b2d9 | ||
|
|
9703ed035a | ||
|
|
4117ed927a | ||
|
|
8980eaa5ba | ||
|
|
d3d1ccee81 | ||
|
|
4a0aaa8f6b | ||
|
|
85e84e0672 | ||
|
|
7d63852d94 | ||
|
|
698a2b2fcb | ||
|
|
62e1c6eb0f | ||
|
|
1a8fa724d6 | ||
|
|
b4088519cf | ||
|
|
58ce304e53 | ||
|
|
9fbc77a85a | ||
|
|
623c4c43d4 | ||
|
|
63ea97b435 | ||
|
|
d9f3d92736 | ||
|
|
7fc2239e59 | ||
|
|
badfe61d6a | ||
|
|
ab57221040 | ||
|
|
5ae62b8892 | ||
|
|
c5425fc9cf | ||
|
|
dbdc14891c | ||
|
|
f4b4627c78 | ||
|
|
35dbe47571 | ||
|
|
a97337234e | ||
|
|
a87b8de6e3 | ||
|
|
949d7a54ad | ||
|
|
5a3c97a529 | ||
|
|
0772898160 | ||
|
|
638ed3f5c8 | ||
|
|
d996e9e05e | ||
|
|
58fd622980 | ||
|
|
29113ac39c | ||
|
|
f947f472b9 | ||
|
|
393763fb9e | ||
|
|
eced94910d | ||
|
|
df000f35ee | ||
|
|
24d2de568f | ||
|
|
8508396ae6 | ||
|
|
9f6d38e6b7 | ||
|
|
b8f3b9b37a | ||
|
|
71cdcb5909 | ||
|
|
e92e852dcb | ||
|
|
0ac5b3a39d | ||
|
|
3fbf460f81 | ||
|
|
9b7db5c095 | ||
|
|
eb9e88b54a | ||
|
|
952b1c4562 | ||
|
|
cec50beecf | ||
|
|
2048107866 | ||
|
|
2d72a15ec0 | ||
|
|
d5c36aa2e9 | ||
|
|
41079d9f0b | ||
|
|
a47977b029 | ||
|
|
e20b71181f | ||
|
|
4f29e5a650 | ||
|
|
e168c7b2c7 | ||
|
|
1f6de95f16 | ||
|
|
96995730c6 | ||
|
|
9d000ca84d | ||
|
|
9af6deaec3 | ||
|
|
aaa13e1e2f | ||
|
|
bd0419fb0c | ||
|
|
656efd0d57 | ||
|
|
863ff017b0 | ||
|
|
8c26cc37d7 | ||
|
|
4e9c26cd04 | ||
|
|
d098bca86f | ||
|
|
9980c2b175 | ||
|
|
a52daae4a5 | ||
|
|
1d8af05302 | ||
|
|
2efccedfba | ||
|
|
243b615814 | ||
|
|
dc37bcb5ff | ||
|
|
edac1d6ceb | ||
|
|
64848d8fdd | ||
|
|
c874b7633d | ||
|
|
2ca85970e4 | ||
|
|
0184aa8879 | ||
|
|
ac05fe833e | ||
|
|
998a686179 | ||
|
|
288b5e207f | ||
|
|
2ec0c923c3 | ||
|
|
4c9dd0cef7 | ||
|
|
8f16abd4ff | ||
|
|
c706ea4118 | ||
|
|
9c2fef1ee4 | ||
|
|
1648acca32 | ||
|
|
c11c0281ce | ||
|
|
58ee7344bf | ||
|
|
6c9dac79d5 | ||
|
|
7aa284e92c | ||
|
|
933b41e7c1 | ||
|
|
a39e586bc1 | ||
|
|
4e81683bcd | ||
|
|
6a74297cb3 | ||
|
|
67764ec5c1 | ||
|
|
ebbcd99453 | ||
|
|
3719df39fe | ||
|
|
70670117a7 | ||
|
|
31f77b84d6 | ||
|
|
924e2f0775 | ||
|
|
cb61ce3f9e | ||
|
|
d97033d6cf | ||
|
|
c2f547da0c | ||
|
|
7cc60e6063 | ||
|
|
4f117199f0 | ||
|
|
0d444c4bc9 | ||
|
|
87646944dd | ||
|
|
13c9633964 | ||
|
|
ab77f1371d | ||
|
|
4ac71c4af2 | ||
|
|
1ca1fffa26 | ||
|
|
4e623ab182 | ||
|
|
fb27ea8528 | ||
|
|
bc20d66694 | ||
|
|
beadcd50e7 | ||
|
|
5d1c9b10da | ||
|
|
7e877b74a7 | ||
|
|
47b569aa59 | ||
|
|
2afa4b64e8 | ||
|
|
315bad5451 | ||
|
|
c8fa1d5405 | ||
|
|
40a28015bd | ||
|
|
4a25b0ba99 | ||
|
|
9ea7ab14df | ||
|
|
aa692d9f30 | ||
|
|
044d978c46 | ||
|
|
b767dd3aa4 | ||
|
|
9acbd6cef6 | ||
|
|
a20ec0587e | ||
|
|
28b72a6303 | ||
|
|
9540fc9a5f | ||
|
|
18eac29b1a | ||
|
|
76b2255716 | ||
|
|
17377aa8bc | ||
|
|
d1a50fcf22 | ||
|
|
cccd8f8fbd | ||
|
|
9c37d0760d | ||
|
|
90d56197e6 | ||
|
|
6b91065468 | ||
|
|
f851957523 | ||
|
|
ec0574bfdf | ||
|
|
6bc279ac32 | ||
|
|
1cdb5ef2e3 | ||
|
|
d85854a1f2 | ||
|
|
e0d6fb0bcc | ||
|
|
6e864c14a1 | ||
|
|
8e49ffa904 | ||
|
|
4db50c0ed2 | ||
|
|
191611bc24 | ||
|
|
d10541afb7 | ||
|
|
1887878088 | ||
|
|
de3985191a | ||
|
|
629a615f7c | ||
|
|
ec947df8a0 | ||
|
|
203095a6f7 | ||
|
|
f71ce62c5b | ||
|
|
89680d6be7 | ||
|
|
e411f4f6ac | ||
|
|
bbcb23b821 | ||
|
|
75dfd49067 | ||
|
|
39d4423a5e | ||
|
|
6238fee522 | ||
|
|
e301ea7cee | ||
|
|
42aff04610 | ||
|
|
345053bdba | ||
|
|
285fd26f99 |
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@@ -13,6 +13,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- 'release/*'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
||||
8
.github/workflows/cleanup.yml
vendored
8
.github/workflows/cleanup.yml
vendored
@@ -17,4 +17,10 @@ jobs:
|
||||
- name: Cleanup Docker image with PR branch tag
|
||||
run: |
|
||||
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
|
||||
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"
|
||||
|
||||
if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then
|
||||
echo "PR branch is $PR_BRANCH_TAG, deleting Docker image"
|
||||
curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"
|
||||
else
|
||||
echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image"
|
||||
fi
|
||||
|
||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
path: wlan-cloud-ucentralgw
|
||||
|
||||
- name: Build package
|
||||
working-directory: wlan-cloud-ucentralgw/chart
|
||||
working-directory: wlan-cloud-ucentralgw/helm
|
||||
run: |
|
||||
helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
helm package . -d dist
|
||||
|
||||
- name: Generate GitHub release body
|
||||
working-directory: wlan-cloud-ucentralgw/chart
|
||||
working-directory: wlan-cloud-ucentralgw/helm
|
||||
run: |
|
||||
pip3 install yq -q
|
||||
echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owgw:$GITHUB_REF_NAME" > release.txt
|
||||
@@ -42,5 +42,5 @@ jobs:
|
||||
- name: Create GitHub release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body_path: wlan-cloud-ucentralgw/chart/release.txt
|
||||
files: wlan-cloud-ucentralgw/chart/dist/*
|
||||
body_path: wlan-cloud-ucentralgw/helm/release.txt
|
||||
files: wlan-cloud-ucentralgw/helm/dist/*
|
||||
|
||||
@@ -67,6 +67,8 @@ 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
|
||||
@@ -97,7 +99,6 @@ add_executable( owgw
|
||||
src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h
|
||||
src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
|
||||
src/RESTAPI/RESTAPI_telemetryWebSocket.cpp src/RESTAPI/RESTAPI_telemetryWebSocket.h
|
||||
src/RESTAPI/RESTAPI_webSocketServer.cpp src/RESTAPI/RESTAPI_webSocketServer.h
|
||||
src/storage/storage_blacklist.cpp src/storage/storage_tables.cpp src/storage/storage_logs.cpp
|
||||
src/storage/storage_command.cpp src/storage/storage_healthcheck.cpp src/storage/storage_statistics.cpp
|
||||
src/storage/storage_device.cpp src/storage/storage_capabilities.cpp src/storage/storage_defconfig.cpp
|
||||
@@ -117,7 +118,7 @@ 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/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)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
|
||||
|
||||
182
MICRO_SERVICE_PROTOCOL.md
Normal file
182
MICRO_SERVICE_PROTOCOL.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# Micro-service backbone responsibilities
|
||||
|
||||
## Bus management
|
||||
Each microservice must get onto kafka and consume/produce messages on the kafka bus. The topic to subscribe to is `service_events`.
|
||||
|
||||
## System messages
|
||||
System messages are what maintains the collection of micro-services working on the system. Each message has the format
|
||||
|
||||
```json
|
||||
{
|
||||
"event": <event-type>,
|
||||
"id": 1234567890,
|
||||
"type": "owrrm",
|
||||
"publicEndPoint": "https://myhostname.com:16020",
|
||||
"privateEndPoint": "https://localhost:17020",
|
||||
"key" : "289479847948794870749",
|
||||
"version" : "1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### `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.
|
||||
|
||||
### `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++
|
||||
static const std::string uSERVICE_SECURITY{"owsec"};
|
||||
static const std::string uSERVICE_GATEWAY{"owgw"};
|
||||
static const std::string uSERVICE_FIRMWARE{ "owfms"};
|
||||
static const std::string uSERVICE_TOPOLOGY{ "owtopo"};
|
||||
static const std::string uSERVICE_PROVISIONING{ "owprov"};
|
||||
static const std::string uSERVICE_OWLS{ "owls"};
|
||||
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
|
||||
static const std::string uSERVICE_INSTALLER{ "owinst"};
|
||||
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
|
||||
static const std::string uSERVICE_OWRRM{ "owrrm"};
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
```text
|
||||
1. Look into my list of current Micro-services for the type=owgw.
|
||||
2. Use the priovateEndPoint associated with that entry
|
||||
```
|
||||
|
||||
## REST API calls on the private interface
|
||||
For inter-service REST calls, you should never use the `Authorization: Bearer token` method. Instead, the following headers should be included in all API calls
|
||||
```json
|
||||
{
|
||||
"X-API-KEY" : "289479847948794870749",
|
||||
"X-INTERNAL-NAME" : "https://myhostname.com:16020"
|
||||
}
|
||||
```
|
||||
|
||||
### `X-API-KEY`
|
||||
This is the `key` you included in your `system-messages`.
|
||||
|
||||
### `X-INTERNAL-NAME`
|
||||
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.
|
||||
|
||||
Here is a brief description of what the micro-service should answer:
|
||||
```yaml
|
||||
/system:
|
||||
get:
|
||||
tags:
|
||||
- System Commands
|
||||
summary: Retrieve different values from the running service.
|
||||
operationId: getSystemCommand
|
||||
parameters:
|
||||
- in: query
|
||||
description: Get a value
|
||||
name: command
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- info
|
||||
required: true
|
||||
|
||||
responses:
|
||||
200:
|
||||
description: Successful command execution
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemInfoResults'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
```
|
||||
The relevant data structures are:
|
||||
```yaml
|
||||
SystemInfoResults:
|
||||
type: object
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
uptime:
|
||||
type: integer
|
||||
format: integer64
|
||||
start:
|
||||
type: integer
|
||||
format: integer64
|
||||
os:
|
||||
type: string
|
||||
processors:
|
||||
type: integer
|
||||
hostname:
|
||||
type: string
|
||||
certificates:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
filename:
|
||||
type: string
|
||||
expires:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
```
|
||||
and
|
||||
```yaml
|
||||
responses:
|
||||
NotFound:
|
||||
description: The specified resource was not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
Unauthorized:
|
||||
description: The requested does not have sufficient rights to perform the operation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
enum:
|
||||
- 0 # Success
|
||||
- 1 # PASSWORD_CHANGE_REQUIRED,
|
||||
- 2 # INVALID_CREDENTIALS,
|
||||
- 3 # PASSWORD_ALREADY_USED,
|
||||
- 4 # USERNAME_PENDING_VERIFICATION,
|
||||
- 5 # PASSWORD_INVALID,
|
||||
- 6 # INTERNAL_ERROR,
|
||||
- 7 # ACCESS_DENIED,
|
||||
- 8 # INVALID_TOKEN
|
||||
- 9 # EXPIRED_TOKEN
|
||||
- 10 # RATE_LIMIT_EXCEEDED
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
```
|
||||
192
PROTOCOL.md
192
PROTOCOL.md
@@ -30,7 +30,7 @@ In this RPC, here are some common interpretations:
|
||||
#### Connection event
|
||||
Device Sends connection notification to the controller after establishing a connection. The controller
|
||||
my decide to send the AP a newer configuration. The controller will record the device capabilities provided.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "connect" ,
|
||||
"params" : {
|
||||
@@ -47,7 +47,7 @@ my decide to send the AP a newer configuration. The controller will record the d
|
||||
#### State event
|
||||
The device sends device state information periodically. If the controller detects that it has a newer configuration, it
|
||||
may decide to send this new configuration to the AP.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "state" ,
|
||||
"params" : {
|
||||
@@ -62,7 +62,7 @@ may decide to send this new configuration to the AP.
|
||||
#### Healthcheck event
|
||||
Device sends a `healthcheck` periodically. This message contains information about how vital subsystems are operating and
|
||||
if they need attention.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "healthcheck" ,
|
||||
"params" : {
|
||||
@@ -77,7 +77,7 @@ if they need attention.
|
||||
|
||||
#### Log event
|
||||
Device sends a log message whenever necessary. The controller will log this message to the log system for the device.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "log" ,
|
||||
"params" : {
|
||||
@@ -102,7 +102,7 @@ The `severity` matches the `syslog` levels. Here are the details:
|
||||
|
||||
#### Crash Log event
|
||||
Device may send a crash log event after rebooting after a crash. The event cannot be sent until a connection event has been sent.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "crashlog" ,
|
||||
"params" : {
|
||||
@@ -117,7 +117,7 @@ Device may send a crash log event after rebooting after a crash. The event canno
|
||||
Device sends this message to tell the controller that the device
|
||||
has received a configuration but is still running an older configuration. The controller will not
|
||||
reply to this message.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "cfgpending" ,
|
||||
"params" : {
|
||||
@@ -131,7 +131,7 @@ reply to this message.
|
||||
#### DeviceUpdate event
|
||||
Device sends this message to tell the controller it is changing something is its configuration because
|
||||
of some requirement or some changes.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "deviceupdate" ,
|
||||
"params" : {
|
||||
@@ -145,7 +145,7 @@ of some requirement or some changes.
|
||||
#### Send a keepalive to the controller event
|
||||
Device sends a keepalive whenever necessary. The device will send this message to tell the controller
|
||||
which version it is running. The Controller may decide to send the device a newer configuration.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "ping" ,
|
||||
"params" : {
|
||||
@@ -157,7 +157,7 @@ which version it is running. The Controller may decide to send the device a newe
|
||||
|
||||
#### Recovery Event
|
||||
Device may decide it has to do into recovery mode. This event should be used.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "recovery" ,
|
||||
"params" : {
|
||||
@@ -170,6 +170,19 @@ Device may decide it has to do into recovery mode. This event should be used.
|
||||
}
|
||||
```
|
||||
|
||||
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>
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
### Controller commands
|
||||
Most controller commands include a `when` member. This is a UTC clock time asking the AP
|
||||
@@ -180,7 +193,7 @@ always a numeric parameter.
|
||||
#### Controller wants the device to apply a given configuration
|
||||
Controller sends this command when it believes the device should load a new configuration. The device
|
||||
should send message with `pending change` events until this version has been applied and running.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "configure" ,
|
||||
"params" : {
|
||||
@@ -194,7 +207,7 @@ should send message with `pending change` events until this version has been app
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -233,7 +246,7 @@ The rejected section is an array containing the following:
|
||||
|
||||
#### Controller wants the device to reboot
|
||||
Controller sends this command when it believes the device should reboot.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "reboot" ,
|
||||
"params" : {
|
||||
@@ -245,7 +258,7 @@ Controller sends this command when it believes the device should reboot.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -264,7 +277,7 @@ The device should answer:
|
||||
|
||||
#### Controller wants the device to upgrade its firmware
|
||||
Controller sends this command when it believes the device should upgrade its firmware.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "upgrade" ,
|
||||
"params" : {
|
||||
@@ -277,7 +290,7 @@ Controller sends this command when it believes the device should upgrade its fir
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -293,7 +306,7 @@ The device should answer:
|
||||
|
||||
#### Controller wants the device to perform a factory reset
|
||||
Controller sends this command when it believes the device should upgrade its firmware.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "factory" ,
|
||||
"params" : {
|
||||
@@ -306,7 +319,7 @@ Controller sends this command when it believes the device should upgrade its fir
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -320,9 +333,50 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller issuing RRM commands to the AP
|
||||
Controller sends this command to perform several RRM commands.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "rrm" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"actions": [
|
||||
{
|
||||
"type": "roam",
|
||||
"bss": [ "00:11:22:33:44:55", ... ],
|
||||
"params" : { action specific data }
|
||||
}, {
|
||||
"type": "tx-power",
|
||||
"bss": [ "00:11:22:33:44:55", ... ],
|
||||
“params”: { action specific data }
|
||||
}, {
|
||||
"type": "beacon-request",
|
||||
"bss": [ "00:11:22:33:44:55", ... ],
|
||||
"params": { action specific data }
|
||||
}
|
||||
]
|
||||
},
|
||||
"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>,
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to flash its LEDs
|
||||
Controller sends this command when it wants the device to flash its LEDs.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "leds" ,
|
||||
"params" : {
|
||||
@@ -336,14 +390,13 @@ Controller sends this command when it wants the device to flash its LEDs.
|
||||
```
|
||||
|
||||
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" : <time when this will be performed as UTC seconds>,
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
@@ -358,7 +411,7 @@ The device should answer:
|
||||
#### 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" : {
|
||||
@@ -372,7 +425,7 @@ and the controller.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -395,7 +448,7 @@ The device should answer with teh above message. The `error` value should be int
|
||||
|
||||
#### 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
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "trace" ,
|
||||
"params" : {
|
||||
@@ -412,7 +465,7 @@ Controller sends this command when it needs the device to perform a trace (i.e.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -438,7 +491,7 @@ uploaded or the timeout occurs, the upload will be rejected.
|
||||
|
||||
#### Controller wants the device to perform a WiFi Scan
|
||||
Controller sends this command when it needs the device to perform a WiFi Scan.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "wifiscan" ,
|
||||
"params" : {
|
||||
@@ -446,15 +499,16 @@ Controller sends this command when it needs the device to perform a WiFi Scan.
|
||||
"bands" : [ "2","5","5l","5u",6" ], <optional this is a list of bands to scan: on or more bands >
|
||||
"channels" : [ 1,2,3...] , <optional list of discreet channels to scan >
|
||||
"verbose" : <optional boolean: true or false> (by default false),
|
||||
"bandwidth" : <optional int: 20,40,80 in MHz>
|
||||
"active" : 0 or 1 (to select passive or active scan)
|
||||
"bandwidth" : <optional int: 20,40,80 in MHz>,
|
||||
"active" : 0 or 1 (to select passive or active scan),
|
||||
"ies": <optional: array of unsigned int 8 bits: i.e. [1,4,34,58,91]>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -477,7 +531,7 @@ Controller sends this command when it needs the device to provide a message back
|
||||
supported messages are "state" and "healthcheck". More messages maybe added later. The messages will
|
||||
be returned the usual way. The RPC response to this message just says that the request has been accepted and the
|
||||
message will be returned "soon".
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "request" ,
|
||||
"params" : {
|
||||
@@ -491,7 +545,7 @@ message will be returned "soon".
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -507,7 +561,7 @@ The device should answer:
|
||||
|
||||
#### Controller requesting eventqueue buffers
|
||||
Controller sends this command when it needs the device to provide the content of ist ring buffers.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "event" ,
|
||||
"params" : {
|
||||
@@ -521,7 +575,7 @@ Controller sends this command when it needs the device to provide the content of
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -537,7 +591,7 @@ The device should answer:
|
||||
|
||||
#### Controller requesting telemetry stream information
|
||||
Controller sends this command when it needs the device to telemetry streaming.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "telemetry" ,
|
||||
"params" : {
|
||||
@@ -550,7 +604,7 @@ Controller sends this command when it needs the device to telemetry streaming.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -564,7 +618,7 @@ The device should answer:
|
||||
```
|
||||
|
||||
When the interval is greater than 0, the gateway will start to receive messages
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "telemetry" ,
|
||||
"params" : {
|
||||
@@ -579,7 +633,7 @@ The device will stop sending data after 30 minutes or if it receives a `telemetr
|
||||
|
||||
#### Controller requesting an `rtty` session
|
||||
Controller sends this command an administrator requests to start an `rtty` session with the AP.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "remote_access" ,
|
||||
"params" : {
|
||||
@@ -597,7 +651,7 @@ Controller sends this command an administrator requests to start an `rtty` sessi
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -613,7 +667,7 @@ The device should answer:
|
||||
|
||||
#### Controller wants to ping the device
|
||||
Controller sends this command when it tries to establish latency to the device.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "ping" ,
|
||||
"params" : {
|
||||
@@ -624,7 +678,7 @@ Controller sends this command when it tries to establish latency to the device.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -635,8 +689,41 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to perform a script
|
||||
Controller sends this command to run a predefined script. Extreme care must be taken.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"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>,
|
||||
"when" : <time when this will be performed as UTC seconds>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
#### `rtty server`
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
one of either
|
||||
"result_64" : <gzipped base64 result of running the command>,
|
||||
"result_sz" : <size of unzipped content>
|
||||
or
|
||||
"result" : <a single text blob of the result>
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
### `rtty server`
|
||||
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.
|
||||
|
||||
### Message compression
|
||||
@@ -653,7 +740,7 @@ params will be dropped. Additional compression schemes may be developed later.
|
||||
The original `params` element should be run through `zlib:compress` and then encoded using base64, and passed as a string. Here is an example
|
||||
of the completed message. The following should how the `state` event could be compressed:
|
||||
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "state" ,
|
||||
"params" : {
|
||||
@@ -662,6 +749,29 @@ of the completed message. The following should how the `state` event could be co
|
||||
}
|
||||
```
|
||||
|
||||
### 'Radius Proxying'
|
||||
The gateway can receive RADIUS messages from the device and forward them. It can also receive messages
|
||||
on its behalf and send them to the device.
|
||||
|
||||
```json
|
||||
{
|
||||
"radius" : <type, can be auth, acct, coa> ,
|
||||
"data" : <base 64 encoded raw RADIUS payload>
|
||||
}
|
||||
```
|
||||
|
||||
The GW will include a TLV to mark the sender MAC. The RADIUS server must use the same TLV to
|
||||
identify the destination for its messages.
|
||||
|
||||
#### Incoming RADIUS messages configuration
|
||||
The GW must be configured with the following:
|
||||
|
||||
```asm
|
||||
radius.proxy.enable = true
|
||||
radius.proxy.accounting.port = 1813
|
||||
radius.proxy.authentication.port = 1812
|
||||
radius.proxy.coa.port = 3799
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ 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 ..
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
||||
update-ca-certificates
|
||||
fi
|
||||
|
||||
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWGW_CONFIG"/owgw.properties ]]; then
|
||||
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
|
||||
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
|
||||
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 10.9.2
|
||||
- name: mysql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 8.8.3
|
||||
- name: mariadb
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 9.4.2
|
||||
digest: sha256:1fdae7cbea906e41dccd8618ff9e2c68d0c684724ae27c79a12bb6089968df5c
|
||||
generated: "2021-08-17T12:18:40.341427893+03:00"
|
||||
digest: sha256:e9df5a5d8a0a193bfda33ea06060203aace01f0f7df9eda662a84185322c7ab5
|
||||
generated: "2022-06-03T15:38:31.063022252+03:00"
|
||||
|
||||
@@ -5,14 +5,14 @@ name: owgw
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 10.9.2
|
||||
condition: postgresql.enabled
|
||||
- name: mysql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 8.8.3
|
||||
condition: mysql.enabled
|
||||
- name: mariadb
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 9.4.2
|
||||
condition: mariadb.enabled
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owgw:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
|
||||
tag: master
|
||||
tag: v2.6.0
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
@@ -215,8 +215,9 @@ configProperties:
|
||||
openwifi.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2: IOT:esp32
|
||||
oui.download.uri: https://linuxnet.ca/ieee/oui.txt
|
||||
oui.download.uri: https://standards-oui.ieee.org/oui/oui.txt
|
||||
firmware.autoupdate.policy.default: auto
|
||||
iptocountry.provider: ipinfo
|
||||
# Callback
|
||||
openwifi.callback.enable: "false"
|
||||
openwifi.callback.0.local: localhost:16001
|
||||
|
||||
@@ -31,58 +31,13 @@ components:
|
||||
|
||||
responses:
|
||||
NotFound:
|
||||
description: The specified resource was not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||
Unauthorized:
|
||||
description: The requested does not have sufficient rights to perform the operation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
enum:
|
||||
- 0 # Success
|
||||
- 1 # PASSWORD_CHANGE_REQUIRED,
|
||||
- 2 # INVALID_CREDENTIALS,
|
||||
- 3 # PASSWORD_ALREADY_USED,
|
||||
- 4 # USERNAME_PENDING_VERIFICATION,
|
||||
- 5 # PASSWORD_INVALID,
|
||||
- 6 # INTERNAL_ERROR,
|
||||
- 7 # ACCESS_DENIED,
|
||||
- 8 # INVALID_TOKEN
|
||||
- 9 # EXPIRED_TOKEN
|
||||
- 10 # RATE_LIMIT_EXCEEDED
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||
Success:
|
||||
description: The requested operation was performed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
Operation:
|
||||
type: string
|
||||
Details:
|
||||
type: string
|
||||
Code:
|
||||
type: integer
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
|
||||
BadRequest:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
|
||||
|
||||
schemas:
|
||||
DeviceType:
|
||||
@@ -510,6 +465,31 @@ components:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
ScriptRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
timeout:
|
||||
type: integer
|
||||
format: int64
|
||||
default: 30
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- uci
|
||||
- ucode
|
||||
- shell
|
||||
script:
|
||||
type: string
|
||||
scriptId:
|
||||
type: string
|
||||
format: uuid
|
||||
when:
|
||||
type: integer
|
||||
format: int64
|
||||
default: 0
|
||||
|
||||
FactoryRequest:
|
||||
type: object
|
||||
properties:
|
||||
@@ -976,6 +956,12 @@ components:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/WifiBands'
|
||||
- $ref: '#/components/schemas/WifiChannels'
|
||||
ies:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 255
|
||||
required:
|
||||
- serialNumber
|
||||
|
||||
@@ -1047,6 +1033,72 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/CapabilitiesModel'
|
||||
|
||||
RadiusProxyServerEntry:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
ip:
|
||||
type: string
|
||||
format: ip-addr
|
||||
port:
|
||||
type: integer
|
||||
weight:
|
||||
type: integer
|
||||
secret:
|
||||
type: string
|
||||
certificate:
|
||||
type: string
|
||||
|
||||
RadiusProxyServerConfig:
|
||||
type: object
|
||||
properties:
|
||||
strategy:
|
||||
type: string
|
||||
enum:
|
||||
- random
|
||||
- round_robin
|
||||
- weighted
|
||||
monitor:
|
||||
type: boolean
|
||||
default: false
|
||||
monitorMethod:
|
||||
type: string
|
||||
enum:
|
||||
- none
|
||||
- https
|
||||
- radius
|
||||
methodParameters:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
servers:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RadiusProxyServerEntry'
|
||||
|
||||
RadiusProxyPool:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
authConfig:
|
||||
$ref: '#/components/schemas/RadiusProxyServerConfig'
|
||||
acctConfig:
|
||||
$ref: '#/components/schemas/RadiusProxyServerConfig'
|
||||
coaConfig:
|
||||
$ref: '#/components/schemas/RadiusProxyServerConfig'
|
||||
|
||||
RadiusProxyPoolList:
|
||||
type: object
|
||||
properties:
|
||||
pools:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RadiusProxyPool'
|
||||
|
||||
paths:
|
||||
/devices:
|
||||
get:
|
||||
@@ -1096,6 +1148,20 @@ paths:
|
||||
name: deviceWithStatus
|
||||
schema:
|
||||
type: boolean
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: orderBy
|
||||
schema:
|
||||
type: string
|
||||
example: serialNumber:a,created:d
|
||||
required: false
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: orderSpec
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List devices
|
||||
@@ -1992,6 +2058,32 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/script:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Debug a device.
|
||||
operationId: debugDevice
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Command details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScriptRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/CommandInfo'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/factory:
|
||||
post:
|
||||
tags:
|
||||
@@ -2433,6 +2525,45 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/radiusProxyConfig:
|
||||
get:
|
||||
tags:
|
||||
- RADIUSProxy
|
||||
summary: Retrieve RADIUS Proxy configuration.
|
||||
operationId: getRadiusProxyConfig
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/RadiusProxyPoolList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
put:
|
||||
tags:
|
||||
- RADIUSProxy
|
||||
summary: Modify RADIUS Proxy configuration.
|
||||
operationId: modifyRadiusProxyConfig
|
||||
requestBody:
|
||||
description: Change RADIUS configuration pool config
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RadiusProxyPoolList'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/RadiusProxyPoolList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- RADIUSProxy
|
||||
summary: Delete RADIUS Proxy configuration.
|
||||
operationId: deleteRadiusProxyConfig
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/deviceDashboard:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -96,6 +96,12 @@ rtty.timeout = 60
|
||||
rtty.viewport = 5913
|
||||
rtty.assets = $OWGW_ROOT/rtty_ui
|
||||
|
||||
### RADIUS proxy config
|
||||
radius.proxy.enable = false
|
||||
radius.proxy.accounting.port = 1813
|
||||
radius.proxy.authentication.port = 1812
|
||||
radius.proxy.coa.port = 3799
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
#############################
|
||||
|
||||
41
pcap/radius
Normal file
41
pcap/radius
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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
pcap/radius.blob.bin
Normal file
1
pcap/radius.blob.bin
Normal file
@@ -0,0 +1 @@
|
||||
192.168.178.1
|
||||
BIN
pcap/radius.pcapng
Normal file
BIN
pcap/radius.pcapng
Normal file
Binary file not shown.
72
radius_config_sample.json
Normal file
72
radius_config_sample.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"pools" : [
|
||||
{
|
||||
"name" : "master" ,
|
||||
"description" : "master pool",
|
||||
"useByDefault" : true,
|
||||
"authConfig" : {
|
||||
"strategy" : "weighted",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "10.100.0.1",
|
||||
"port" : 1812,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
},
|
||||
{
|
||||
"name" : "svr2",
|
||||
"ip" : "10.100.10.1",
|
||||
"port" : 1812,
|
||||
"weight" : 20,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
},
|
||||
"acctConfig" : {
|
||||
"strategy" : "random",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "10.100.0.1",
|
||||
"port" : 1813,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
},
|
||||
{
|
||||
"name" : "svr2",
|
||||
"ip" : "10.100.10.1",
|
||||
"port" : 1813,
|
||||
"weight" : 20,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
},
|
||||
"coaConfig" : {
|
||||
"strategy" : "round_robin",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "10.100.0.1",
|
||||
"port" : 3799,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
},
|
||||
{
|
||||
"name" : "svr2",
|
||||
"ip" : "10.100.10.1",
|
||||
"port" : 3799,
|
||||
"weight" : 20,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include "CommandManager.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
@@ -20,38 +19,48 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
void CommandManager::run() {
|
||||
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_;
|
||||
|
||||
std::ostringstream SS;
|
||||
Payload.stringify(SS);
|
||||
|
||||
Logger().debug(fmt::format("({}): RPC Response received.", SerialNumber));
|
||||
if(!Payload.has(uCentralProtocol::ID)){
|
||||
Logger().error(fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
return;
|
||||
} else {
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
if (ID < 2) {
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
} 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);
|
||||
}
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(
|
||||
fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
if(ID<2) {
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
return;
|
||||
}
|
||||
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
|
||||
auto RPC = OutStandingRequests_.find(Idx);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
Logger().warning(fmt::format("({}): Outdated RPC {}", SerialNumber, ID));
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
}
|
||||
NextMsg = ResponseQueue_.waitDequeueNotification();
|
||||
}
|
||||
@@ -70,15 +79,11 @@ namespace OpenWifi {
|
||||
CommandRunnerTimer_.setPeriodicInterval(30 * 1000); // 1 hours
|
||||
CommandRunnerTimer_.start(*CommandRunnerCallback_);
|
||||
|
||||
// RPCResponseQueue_->Readable_ += Poco::delegate(this,&CommandManager::onRPCAnswer);
|
||||
// RPCResponseQueue_->Writable_ += Poco::delegate(this,&CommandManager::onRPCAnswer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CommandManager::Stop() {
|
||||
Logger().notice("Stopping...");
|
||||
// RPCResponseQueue_->Readable_ -= Poco::delegate(this,&CommandManager::onRPCAnswer);
|
||||
// RPCResponseQueue_->Writable_ -= Poco::delegate(this,&CommandManager::onRPCAnswer);
|
||||
Running_ = false;
|
||||
JanitorTimer_.stop();
|
||||
CommandRunnerTimer_.stop();
|
||||
@@ -94,24 +99,29 @@ namespace OpenWifi {
|
||||
|
||||
void CommandManager::onJanitorTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Logger().information(
|
||||
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 > 120000ms) {
|
||||
Logger().debug(fmt::format("Timing out {}", i->second->uuid));
|
||||
if(delta > 6000000ms) {
|
||||
MyLogger.debug(fmt::format("{}: Timed out.", i->second->uuid));
|
||||
OutstandingUUIDs_.erase(i->second->uuid);
|
||||
i = OutStandingRequests_.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
Logger().information("Removing expired commands: done");
|
||||
MyLogger.information("Removing expired commands: done.");
|
||||
}
|
||||
|
||||
void CommandManager::onCommandRunnerTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
Utils::SetThreadName("cmd-schdlr");
|
||||
Poco::Logger & MyLogger = Poco::Logger::get("CMD-MGR-SCHEDULER");
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if(StorageService()->GetReadyToExecuteCommands(0,200,Commands))
|
||||
{
|
||||
@@ -128,9 +138,8 @@ namespace OpenWifi {
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
Logger().information(fmt::format("Parsing: {}", Cmd.UUID));
|
||||
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>();
|
||||
Logger().information(fmt::format("Parsed: {}", Cmd.UUID));
|
||||
auto Result = PostCommandDisk( Cmd.SerialNumber,
|
||||
Cmd.Command,
|
||||
*Params,
|
||||
@@ -138,24 +147,25 @@ namespace OpenWifi {
|
||||
Sent);
|
||||
if(Sent) {
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
std::lock_guard M(Mutex_);
|
||||
OutstandingUUIDs_.insert(Cmd.UUID);
|
||||
Logger().information(fmt::format("{}: Sent command '{}-{}'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
|
||||
MyLogger.information(fmt::format("{}: Queued command.", Cmd.UUID));
|
||||
} else {
|
||||
Logger().information(fmt::format("{}: Could not send command '{}-{}'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
|
||||
MyLogger.information(fmt::format("{}: Could queue command.", Cmd.UUID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().information(fmt::format("{}: Failed command '{}-{}'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
|
||||
Logger().log(E);
|
||||
MyLogger.information(fmt::format("{}: Failed. Command marked as completed.", Cmd.UUID));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
Logger().information(fmt::format("{}: Exception - hard fail - Failed command '{}-{}'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
|
||||
MyLogger.information(fmt::format("{}: Hard failure.", Cmd.UUID));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand( const std::string &SerialNumber,
|
||||
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,
|
||||
@@ -186,9 +196,6 @@ namespace OpenWifi {
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
Logger().information(
|
||||
fmt::format("({}): Sending command '{}', ID: {}", SerialNumber, Method, Idx.Id));
|
||||
|
||||
Object->submitted = std::chrono::high_resolution_clock::now();
|
||||
Object->uuid = UUID;
|
||||
if(disk_only) {
|
||||
@@ -202,46 +209,13 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* void CommandManager::onRPCAnswer(bool &b) {
|
||||
if(b) {
|
||||
RPCResponse Resp;
|
||||
auto S = RPCResponseQueue_->Read(Resp);
|
||||
const std::string & SerialNumber = Resp.serialNumber;
|
||||
std::lock_guard M(Mutex_);
|
||||
if(S) {
|
||||
if(!Resp.payload.has(uCentralProtocol::ID)){
|
||||
Logger().error(fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t ID = Resp.payload.get(uCentralProtocol::ID);
|
||||
if(ID<2) {
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
return;
|
||||
}
|
||||
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
|
||||
auto RPC = OutStandingRequests_.find(Idx);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
Logger().warning(fmt::format("({}): Outdated RPC {}", SerialNumber, ID));
|
||||
return;
|
||||
}
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - RPC->second->submitted;
|
||||
StorageService()->CommandCompleted(RPC->second->uuid, Resp.payload, rpc_execution_time, true);
|
||||
if(RPC->second->rpc_entry) {
|
||||
RPC->second->rpc_entry->set_value(Resp.payload);
|
||||
}
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
} // namespace
|
||||
@@ -154,16 +154,15 @@ namespace OpenWifi {
|
||||
void onRPCAnswer(bool& b);
|
||||
|
||||
private:
|
||||
std::atomic_bool Running_ = false;
|
||||
volatile bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
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_;
|
||||
Poco::Timer JanitorTimer_;
|
||||
std::unique_ptr<Poco::TimerCallback<CommandManager>> JanitorCallback_;
|
||||
Poco::Timer CommandRunnerTimer_;
|
||||
std::unique_ptr<Poco::TimerCallback<CommandManager>> CommandRunnerCallback_;
|
||||
// std::unique_ptr<FIFO<RPCResponse>> RPCResponseQueue_=std::make_unique<FIFO<RPCResponse>>(100);
|
||||
Poco::NotificationQueue ResponseQueue_;
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommand(
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "framework/MicroService.h"
|
||||
#include "FindCountry.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class Daemon *Daemon::instance() {
|
||||
@@ -36,6 +37,7 @@ namespace OpenWifi {
|
||||
StorageService(),
|
||||
SerialNumberCache(),
|
||||
ConfigurationValidator(),
|
||||
WebSocketClientServer(),
|
||||
OUIServer(),
|
||||
FindCountryFromIP(),
|
||||
DeviceRegistry(),
|
||||
@@ -44,7 +46,8 @@ namespace OpenWifi {
|
||||
StorageArchiver(),
|
||||
TelemetryStream(),
|
||||
RTTYS_server(),
|
||||
WebSocketServer()
|
||||
WebSocketServer(),
|
||||
RADIUS_proxy_server()
|
||||
});
|
||||
return &instance;
|
||||
}
|
||||
@@ -85,6 +88,8 @@ namespace OpenWifi {
|
||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning",false);
|
||||
DeviceTypes_ = DefaultDeviceTypes;
|
||||
|
||||
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string & Id ) const {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "Dashboard.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "GwWebSocketClient.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -56,7 +57,7 @@ namespace OpenWifi {
|
||||
bool AutoProvisioning_ = false;
|
||||
std::vector<std::pair<std::string,std::string>> DeviceTypes_;
|
||||
DeviceDashboard DB_;
|
||||
|
||||
std::unique_ptr<GwWebSocketClient> WebSocketProcessor_;
|
||||
};
|
||||
|
||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
void DeviceDashboard::Create() {
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
|
||||
if(LastRun_==0 || (Now-LastRun_)>120) {
|
||||
DB_.reset();
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace OpenWifi {
|
||||
|
||||
const auto & E = Devices_[SerialNumber] = std::make_shared<ConnectionEntry>();
|
||||
E->WSConn_ = Ptr;
|
||||
E->Conn_.LastContact = std::time(nullptr);
|
||||
E->Conn_.LastContact = OpenWifi::Now();
|
||||
E->Conn_.Connected = true ;
|
||||
E->Conn_.UUID = 0 ;
|
||||
E->Conn_.MessageCount = 0 ;
|
||||
@@ -139,6 +139,57 @@ namespace OpenWifi {
|
||||
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);
|
||||
|
||||
@@ -103,6 +103,10 @@ namespace OpenWifi {
|
||||
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_;
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#include "Poco/Net/HTTPServerParams.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/DynamicAny.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "Poco/Net/PartHandler.h"
|
||||
#include "Poco/Net/MessageHeader.h"
|
||||
#include "Poco/Net/MultipartReader.h"
|
||||
#include "Poco/CountingStream.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/Exception.h"
|
||||
@@ -41,37 +41,65 @@ namespace OpenWifi {
|
||||
Path_ = "/tmp";
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
std::string l{"Starting: " +
|
||||
Svr.Address() + ":" + std::to_string(Svr.Port()) +
|
||||
" key:" + Svr.KeyFile() +
|
||||
" cert:" + Svr.CertFile()};
|
||||
Logger().information(l);
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Logger().information(fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
auto Sock{Svr.CreateSocket(Logger())};
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if(!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
MicroService::instance().ConfigGetString("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_));
|
||||
}
|
||||
|
||||
if(FullName_.empty()) {
|
||||
std::string TmpName = MicroService::instance().ConfigGetString("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_));
|
||||
}
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
|
||||
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);
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new FileUpLoaderRequestHandlerFactory(Logger()), Pool_, Sock, Params);
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if (!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
MicroService::instance().ConfigGetString("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_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
}
|
||||
}
|
||||
|
||||
MaxSize_ = 1000 * MicroService::instance().ConfigGetInt("openwifi.fileuploader.maxsize", 10000);
|
||||
@@ -94,18 +122,18 @@ namespace OpenWifi {
|
||||
bool FileUploader::AddUUID( const std::string & UUID) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
uint64_t Now = time(nullptr) ;
|
||||
uint64_t now = OpenWifi::Now();
|
||||
|
||||
// remove old stuff...
|
||||
for(auto i=OutStandingUploads_.cbegin();i!=OutStandingUploads_.end();) {
|
||||
if ((Now-i->second) > (60 * 30))
|
||||
OutStandingUploads_.erase(i++);
|
||||
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;
|
||||
OutStandingUploads_[UUID] = now;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -121,64 +149,39 @@ namespace OpenWifi {
|
||||
OutStandingUploads_.erase(UUID);
|
||||
}
|
||||
|
||||
class FileUploaderPartHandler: public Poco::Net::PartHandler
|
||||
{
|
||||
public:
|
||||
FileUploaderPartHandler(std::string UUID, Poco::Logger & Logger):
|
||||
UUID_(std::move(UUID)),
|
||||
Logger_(Logger)
|
||||
{
|
||||
}
|
||||
|
||||
void handlePart(const Poco::Net::MessageHeader& Header, std::istream& Stream) override
|
||||
{
|
||||
try {
|
||||
Name_ = "(unnamed)";
|
||||
if (Header.has("Content-Disposition")) {
|
||||
std::string Disposition;
|
||||
Poco::Net::NameValueCollection Parameters;
|
||||
Poco::Net::MessageHeader::splitParameters(Header["Content-Disposition"],
|
||||
Disposition, Parameters);
|
||||
Name_ = Parameters.get("filename", "(unnamed)");
|
||||
}
|
||||
|
||||
std::string FinalFileName = FileUploader()->Path() + "/" + UUID_;
|
||||
|
||||
Logger().information(fmt::format("FILE-UPLOADER: uploading trace for {}", FinalFileName));
|
||||
Poco::CountingInputStream InputStream(Stream);
|
||||
std::ofstream OutputStream(FinalFileName, std::ofstream::out);
|
||||
Poco::StreamCopier::copyStream(InputStream, OutputStream);
|
||||
|
||||
Poco::File TmpFile(FinalFileName);
|
||||
Length_ = TmpFile.getSize();
|
||||
if (Length_ < FileUploader()->MaxSize()) {
|
||||
Good_=true;
|
||||
} else {
|
||||
TmpFile.remove();
|
||||
Error_ = "File is too large.";
|
||||
}
|
||||
return;
|
||||
} catch (const Poco::Exception &E ) {
|
||||
Logger().log(E);
|
||||
Error_ = std::string("Upload caused an internal error: ") + E.what() ;
|
||||
}
|
||||
class FileUploaderPartHandler2 : public Poco::Net::PartHandler {
|
||||
public:
|
||||
FileUploaderPartHandler2(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
|
||||
Id_(std::move(Id)),
|
||||
Logger_(Logger),
|
||||
OutputStream_(ofs){
|
||||
}
|
||||
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
|
||||
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
|
||||
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
|
||||
std::string Disposition;
|
||||
Poco::Net::NameValueCollection Parameters;
|
||||
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
|
||||
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
|
||||
}
|
||||
Poco::CountingInputStream InputStream(Stream);
|
||||
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
|
||||
Length_ = OutputStream_.str().size();
|
||||
}
|
||||
[[nodiscard]] uint64_t Length() const { return Length_; }
|
||||
[[nodiscard]] std::string &Name() { return Name_; }
|
||||
[[nodiscard]] std::string &ContentType() { return FileType_; }
|
||||
|
||||
[[nodiscard]] uint64_t Length() const { return Length_; }
|
||||
[[nodiscard]] const std::string& Name() const { return Name_; }
|
||||
[[nodiscard]] bool Good() const { return Good_; }
|
||||
std::string & Error() { return Error_; }
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
private:
|
||||
uint64_t Length_=0;
|
||||
bool Good_=false;
|
||||
std::string Name_;
|
||||
std::string UUID_;
|
||||
std::string Error_;
|
||||
Poco::Logger & Logger_;
|
||||
};
|
||||
private:
|
||||
uint64_t Length_ = 0;
|
||||
std::string FileType_;
|
||||
std::string Name_;
|
||||
std::string Id_;
|
||||
Poco::Logger &Logger_;
|
||||
std::stringstream &OutputStream_;
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; };
|
||||
};
|
||||
|
||||
class FormRequestHandler: public Poco::Net::HTTPRequestHandler
|
||||
{
|
||||
@@ -189,40 +192,71 @@ namespace OpenWifi {
|
||||
{
|
||||
}
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override
|
||||
{
|
||||
try {
|
||||
FileUploaderPartHandler partHandler(UUID_,Logger());
|
||||
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) final {
|
||||
|
||||
Poco::Net::HTMLForm form(Request, Request.stream(), partHandler);
|
||||
Utils::SetThreadName("FileUploader");
|
||||
const auto ContentType = Request.getContentType();
|
||||
const auto Tokens = Poco::StringTokenizer(ContentType,";",Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
Response.setContentType("application/json");
|
||||
Logger().debug(fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
if (partHandler.Good()) {
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 0);
|
||||
StorageService()->AttachFileToCommand(UUID_);
|
||||
} else {
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 13);
|
||||
Answer.set("errorText", partHandler.Error() );
|
||||
StorageService()->CancelWaitFile(UUID_, partHandler.Error() );
|
||||
try {
|
||||
if (Poco::icompare(Tokens[0], "multipart/form-data") == 0 ||
|
||||
Poco::icompare(Tokens[0], "multipart/mixed") == 0) {
|
||||
|
||||
const auto &BoundaryTokens =
|
||||
Poco::StringTokenizer(Tokens[1], "=", Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
if (BoundaryTokens[0] == "boundary") {
|
||||
const std::string &Boundary = BoundaryTokens[1];
|
||||
Poco::Net::MultipartReader Reader(Request.stream(), Boundary);
|
||||
bool Done = false;
|
||||
|
||||
while (!Done) {
|
||||
Poco::Net::MessageHeader Hdr;
|
||||
Reader.nextPart(Hdr);
|
||||
|
||||
const auto PartContentType = Hdr.get("Content-Type", "");
|
||||
if (PartContentType == "application/octet-stream") {
|
||||
std::stringstream FileContent;
|
||||
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);
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
return;
|
||||
} else {
|
||||
std::stringstream OO;
|
||||
Poco::StreamCopier::copyStream(Reader.stream(), OO);
|
||||
}
|
||||
|
||||
if (!Reader.hasNextPart())
|
||||
Done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
return;
|
||||
}
|
||||
catch( const Poco::Exception & E )
|
||||
{
|
||||
Logger().warning(fmt::format("Error occurred while performing upload. Error='{}'",E.displayText()));
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
Logger().debug("Exception while receiving trace file.");
|
||||
}
|
||||
|
||||
Logger().debug(fmt::format("{}: Failed to upload trace file.",UUID_));
|
||||
std::string Error{"Trace file rejected"};
|
||||
StorageService()->CancelWaitFile(UUID_, Error);
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 13);
|
||||
Answer.set("errorText", "Attached file is too large");
|
||||
StorageService()->CancelWaitFile(UUID_, Error);
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
}
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
private:
|
||||
std::string UUID_;
|
||||
Poco::Logger & Logger_;
|
||||
|
||||
@@ -37,15 +37,13 @@ namespace OpenWifi {
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
|
||||
Poco::ThreadPool Pool_;
|
||||
std::string FullName_;
|
||||
std::map<std::string,uint64_t> OutStandingUploads_;
|
||||
std::string Path_;
|
||||
uint64_t MaxSize_=10000000;
|
||||
|
||||
explicit FileUploader() noexcept:
|
||||
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader"),
|
||||
Pool_("FileUpLoaderPool")
|
||||
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
67
src/GwWebSocketClient.cpp
Normal file
67
src/GwWebSocketClient.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-04-28.
|
||||
//
|
||||
|
||||
#include "GwWebSocketClient.h"
|
||||
#include "SerialNumberCache.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
GwWebSocketClient::GwWebSocketClient(Poco::Logger &Logger):
|
||||
Logger_(Logger){
|
||||
WebSocketClientServer()->SetProcessor(this);
|
||||
}
|
||||
|
||||
GwWebSocketClient::~GwWebSocketClient() {
|
||||
WebSocketClientServer()->SetProcessor(nullptr);
|
||||
}
|
||||
|
||||
void GwWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ) {
|
||||
try {
|
||||
if (O->has("command")) {
|
||||
auto Command = O->get("command").toString();
|
||||
if (Command == "serial_number_search" && O->has("serial_prefix")) {
|
||||
ws_command_serial_number_search(O,Done,Answer);
|
||||
} else if (Command=="exit") {
|
||||
ws_command_exit(O,Done,Answer);
|
||||
} else {
|
||||
ws_command_invalid(O, Done, Answer);
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
|
||||
void GwWebSocketClient::ws_command_serial_number_search(const Poco::JSON::Object::Ptr &O,
|
||||
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);
|
||||
Poco::JSON::Array Arr;
|
||||
for (const auto &i : Numbers)
|
||||
Arr.add(Utils::int_to_hex(i));
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set("serialNumbers", Arr);
|
||||
std::ostringstream SS;
|
||||
Poco::JSON::Stringifier::stringify(RetObj, SS);
|
||||
Answer = SS.str();
|
||||
}
|
||||
}
|
||||
|
||||
void GwWebSocketClient::ws_command_exit([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
|
||||
Done = true;
|
||||
Answer = R"lit({ "closing" : "Goodbye! Aurevoir! Hasta la vista!" })lit";
|
||||
}
|
||||
|
||||
void GwWebSocketClient::ws_command_invalid([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
|
||||
Done = false;
|
||||
Answer = std::string{R"lit({ "error" : "invalid command" })lit"};
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
23
src/GwWebSocketClient.h
Normal file
23
src/GwWebSocketClient.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-04-28.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class GwWebSocketClient : public WebSocketClientProcessor {
|
||||
public:
|
||||
explicit GwWebSocketClient(Poco::Logger &Logger);
|
||||
virtual ~GwWebSocketClient();
|
||||
virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done );
|
||||
void ws_command_serial_number_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
|
||||
void ws_command_exit( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
|
||||
void ws_command_invalid( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
|
||||
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
};
|
||||
}
|
||||
@@ -21,6 +21,9 @@ namespace OpenWifi {
|
||||
|
||||
int OUIServer::Start() {
|
||||
Running_ = true;
|
||||
LatestOUIFileName_ = MicroService::instance().DataDir() + "/newOUIFile.txt";
|
||||
CurrentOUIFileName_ = MicroService::instance().DataDir() + "/current_oui.txt";
|
||||
|
||||
UpdaterCallBack_ = std::make_unique<Poco::TimerCallback<OUIServer>>(*this, &OUIServer::onTimer);
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
|
||||
Timer_.setPeriodicInterval(7 * 24 * 60 * 60 * 1000);
|
||||
@@ -42,18 +45,11 @@ namespace OpenWifi {
|
||||
|
||||
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")));
|
||||
std::unique_ptr<std::istream> pStr(
|
||||
Poco::URIStreamOpener::defaultOpener().open(MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
std::ofstream OS;
|
||||
Poco::File F(FileName);
|
||||
if(F.exists()) {
|
||||
auto LastModified = F.getLastModified();
|
||||
auto Delta = OpenWifi::Now() - LastModified.epochTime();
|
||||
if((Delta / (24*60*60)) < 1)
|
||||
return true;
|
||||
F.remove();
|
||||
}
|
||||
OS.open(FileName);
|
||||
Poco::StreamCopier::copyStream(*pStr, OS);
|
||||
OS.close();
|
||||
@@ -102,32 +98,48 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void OUIServer::onTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
Utils::SetThreadName("ouisvr-timer");
|
||||
if(Updating_)
|
||||
return;
|
||||
Updating_ = true;
|
||||
|
||||
// fetch data from server, if not available, just use the file we already have.
|
||||
std::string LatestOUIFileName{ MicroService::instance().DataDir() + "/newOUIFile.txt"};
|
||||
std::string CurrentOUIFileName{ MicroService::instance().DataDir() + "/current_oui.txt"};
|
||||
Poco::File Current(CurrentOUIFileName_);
|
||||
if(Current.exists()) {
|
||||
if((OpenWifi::Now()-Current.getLastModified().epochTime()) < (7*24*60*60)) {
|
||||
if(!Initialized_) {
|
||||
if(ProcessFile(CurrentOUIFileName_, OUIs_)) {
|
||||
Initialized_ = true;
|
||||
Updating_=false;
|
||||
Logger().information("Using cached file.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Updating_=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OUIMap TmpOUIs;
|
||||
if(GetFile(LatestOUIFileName) && ProcessFile(LatestOUIFileName, TmpOUIs)) {
|
||||
if(GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
|
||||
std::lock_guard G(Mutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
LastUpdate_ = std::time(nullptr);
|
||||
Poco::File F1(CurrentOUIFileName);
|
||||
LastUpdate_ = OpenWifi::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::File F2(LatestOUIFileName_);
|
||||
F2.renameTo(CurrentOUIFileName_);
|
||||
Logger().information(fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
} else if(OUIs_.empty()) {
|
||||
if(ProcessFile(CurrentOUIFileName, TmpOUIs)) {
|
||||
LastUpdate_ = std::time(nullptr);
|
||||
if(ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
std::lock_guard G(Mutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
}
|
||||
}
|
||||
Initialized_=true;
|
||||
Updating_ = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,12 +31,13 @@ namespace OpenWifi {
|
||||
|
||||
private:
|
||||
uint64_t LastUpdate_ = 0 ;
|
||||
// bool ValidFile_=false;
|
||||
bool Initialized_ = false;
|
||||
OUIMap OUIs_;
|
||||
std::atomic_bool Updating_=false;
|
||||
std::atomic_bool Running_=false;
|
||||
volatile std::atomic_bool Updating_=false;
|
||||
volatile std::atomic_bool Running_=false;
|
||||
Poco::Timer Timer_;
|
||||
std::unique_ptr<Poco::TimerCallback<OUIServer>> UpdaterCallBack_;
|
||||
std::string LatestOUIFileName_,CurrentOUIFileName_;
|
||||
|
||||
OUIServer() noexcept:
|
||||
SubSystemServer("OUIServer", "OUI-SVR", "ouiserver")
|
||||
|
||||
1830
src/ParseWifiScan.h
Normal file
1830
src/ParseWifiScan.h
Normal file
File diff suppressed because it is too large
Load Diff
211
src/RADIUS_helpers.h
Normal file
211
src/RADIUS_helpers.h
Normal file
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-06-20.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace OpenWifi::RADIUS {
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct RadiusAttribute {
|
||||
unsigned char type{0};
|
||||
uint16_t pos{0};
|
||||
unsigned len{0};
|
||||
};
|
||||
struct RawRadiusPacket {
|
||||
unsigned char code{1};
|
||||
unsigned char identifier{0};
|
||||
uint16_t len{0};
|
||||
unsigned char authenticator[16]{0};
|
||||
unsigned char attributes[4096]{0};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
//
|
||||
// From: https://github.com/Telecominfraproject/wlan-dictionary/blob/main/dictionary.tip
|
||||
//
|
||||
static const uint32_t TIP_vendor_id = 58888;
|
||||
static const unsigned char TIP_serial = 1;
|
||||
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) {
|
||||
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) {
|
||||
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;
|
||||
if(pos+Attr.len<=Size) {
|
||||
Attrs.emplace_back(Attr);
|
||||
} else {
|
||||
std::cout << "Bad parse1: " << (uint32_t) (pos+Attr.len) << " S:" << Size << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(Buffer[pos+1]==0) {
|
||||
std::cout << "Bad parse2: " << (uint32_t) (pos+Attr.len) << " S:" << Size << std::endl;
|
||||
return false;
|
||||
}
|
||||
pos+=Buffer[pos+1];
|
||||
x--;
|
||||
}
|
||||
// std::cout << "Good parse" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
class RadiusPacket {
|
||||
public:
|
||||
explicit RadiusPacket(const unsigned char *buffer, uint16_t size) {
|
||||
memcpy((void *)&P_,buffer, size);
|
||||
Size_=size;
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const std::string &p) {
|
||||
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_);
|
||||
}
|
||||
|
||||
RadiusPacket() = default;
|
||||
|
||||
unsigned char * Buffer() { return (unsigned char *)&P_; }
|
||||
[[nodiscard]] uint16_t BufferLen() const { return sizeof(P_);}
|
||||
|
||||
void Evaluate(uint16_t size) {
|
||||
Size_ = size;
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.len); }
|
||||
[[nodiscard]] uint16_t Size() const { return Size_; }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
|
||||
|
||||
void Log(std::ostream &os) {
|
||||
uint16_t p = 0;
|
||||
|
||||
while(p<Size_) {
|
||||
os << std::setfill('0') << std::setw(4) << p << ": ";
|
||||
uint16_t v=0;
|
||||
while(v<16 && p+v<Size_) {
|
||||
os << std::setfill('0') << std::setw(2) << std::right << std::hex << (uint16_t )((const unsigned char *)&P_)[p+v] << " ";
|
||||
v++;
|
||||
}
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec << std::endl;
|
||||
}
|
||||
|
||||
std::string ExtractSerialNumberTIP() {
|
||||
std::string R;
|
||||
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==26) {
|
||||
AttributeList VendorAttributes;
|
||||
uint32_t VendorId = htonl( *(const uint32_t *)&(P_.attributes[attribute.pos]));
|
||||
// std::cout << VendorId << std::endl;
|
||||
if(VendorId==TIP_vendor_id) {
|
||||
if (ParseRadius(attribute.pos + 4, &P_.attributes[attribute.pos + 4], attribute.len - 4 - 2,
|
||||
VendorAttributes)) {
|
||||
// std::cout << VendorAttributes << std::endl;
|
||||
for (const auto &vendorAttr: VendorAttributes) {
|
||||
if (vendorAttr.type == TIP_serial) {
|
||||
for (uint16_t i = 0; i < vendorAttr.len; i++) {
|
||||
if (P_.attributes[vendorAttr.pos + i] == '-')
|
||||
continue;
|
||||
R += (char) P_.attributes[vendorAttr.pos + i];
|
||||
}
|
||||
return R;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
std::string ExtractSerialNumberFromProxyState() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==33) {
|
||||
const char * SN = (const char *)&P_.attributes[attribute.pos];
|
||||
auto i=0;
|
||||
while(*SN!=':' && i<12) {
|
||||
Result+=*SN++;
|
||||
i++;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractProxyStateDestination() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==33 && attribute.len>2) {
|
||||
std::string Attr33;
|
||||
// format is serial:IP:port:interface
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
|
||||
auto Parts = Poco::StringTokenizer(Attr33,":");
|
||||
if(Parts.count()==4)
|
||||
return Parts[1]+":"+Parts[2];
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractCallingStationID() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==31 && attribute.len>2) {
|
||||
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractCalledStationID() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==30 && attribute.len>2) {
|
||||
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
private:
|
||||
RawRadiusPacket P_;
|
||||
uint16_t Size_{0};
|
||||
AttributeList Attrs_;
|
||||
bool Valid_=false;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
os << P.Attrs_ ;
|
||||
return os;
|
||||
}
|
||||
}
|
||||
489
src/RADIUS_proxy_server.cpp
Normal file
489
src/RADIUS_proxy_server.cpp
Normal file
@@ -0,0 +1,489 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-18.
|
||||
//
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RADIUS_helpers.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
const int SMALLEST_RADIUS_PACKET = 20+19+4;
|
||||
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
|
||||
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
|
||||
const int DEFAULT_RADIUS_CoA_PORT = 3799;
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
enabled_ = MicroService::instance().ConfigGetBool("radius.proxy.enable",false);
|
||||
if(!enabled_)
|
||||
return 0;
|
||||
|
||||
ConfigFilename_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
|
||||
|
||||
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
AuthenticationReactor_.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>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.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>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
|
||||
CoAReactor_.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>(
|
||||
*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");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::Stop() {
|
||||
if(enabled_) {
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
AccountingReactor_.removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
CoAReactor_.removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
CoAReactor_.removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
AuthenticationReactor_.stop();
|
||||
AuthenticationReactorThread_.join();
|
||||
|
||||
AccountingReactor_.stop();
|
||||
AccountingReactorThread_.join();
|
||||
|
||||
CoAReactor_.stop();
|
||||
CoAReactorThread_.join();
|
||||
enabled_=false;
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("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());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAuthenticationSocketReadable(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("Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("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());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("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());
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
bool RADIUS_proxy_server::SendData( Poco::Net::DatagramSocket & Sock, const unsigned char *buf , std::size_t size, const Poco::Net::SocketAddress &S) {
|
||||
return Sock.sendTo(buf, size, S)==(int)size;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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) {
|
||||
uint64_t TotalV4=0, TotalV6=0;
|
||||
|
||||
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));
|
||||
continue;
|
||||
}
|
||||
auto S = Poco::Net::SocketAddress(fmt::format("{}:{}",server.ip,server.port));
|
||||
Destination D{
|
||||
.Addr = S,
|
||||
.state = 0,
|
||||
.step = 0,
|
||||
.weight = server.weight,
|
||||
.available = true,
|
||||
.strategy = Config.strategy,
|
||||
.monitor = Config. monitor,
|
||||
.monitorMethod = Config.monitorMethod,
|
||||
.methodParameters = Config.methodParameters,
|
||||
.useAsDefault = setAsDefault
|
||||
};
|
||||
|
||||
if(S.family()==Poco::Net::IPAddress::IPv4) {
|
||||
TotalV4 += server.weight;
|
||||
V4.push_back(D);
|
||||
} else {
|
||||
TotalV6 += server.weight;
|
||||
V6.push_back(D);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &i:V4) {
|
||||
if(TotalV4==0) {
|
||||
i.step = 1000;
|
||||
} else {
|
||||
i.step = 1000 - ((1000 * i.weight) / TotalV4);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &i:V6) {
|
||||
if(TotalV6==0) {
|
||||
i.step = 1000;
|
||||
} else {
|
||||
i.step = 1000 - ((1000 * i.weight) / TotalV6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ParseConfig() {
|
||||
|
||||
try {
|
||||
Poco::File F(ConfigFilename_);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if(F.exists()) {
|
||||
std::ifstream ifs(ConfigFilename_,std::ios_base::binary);
|
||||
Poco::JSON::Parser P;
|
||||
auto RawConfig = P.parse(ifs).extract<Poco::JSON::Object::Ptr>();
|
||||
GWObjects::RadiusProxyPoolList RPC;
|
||||
if(RPC.from_json(RawConfig)) {
|
||||
ResetConfig();
|
||||
PoolList_ = RPC;
|
||||
for(const auto &pool:RPC.pools) {
|
||||
RadiusPool NewPool;
|
||||
ParseServerList(pool.authConfig, NewPool.AuthV4, NewPool.AuthV6, pool.useByDefault);
|
||||
ParseServerList(pool.acctConfig, NewPool.AcctV4, NewPool.AcctV6, pool.useByDefault);
|
||||
ParseServerList(pool.coaConfig, NewPool.CoaV4, NewPool.CoaV6, pool.useByDefault);
|
||||
Pools_.push_back(NewPool);
|
||||
}
|
||||
} else {
|
||||
Logger().warning(fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
}
|
||||
} else {
|
||||
Logger().warning(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::Net::SocketAddress RADIUS_proxy_server::DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if(Pools_.empty()) {
|
||||
return RequestedAddress;
|
||||
}
|
||||
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
bool useDefault = false;
|
||||
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);
|
||||
}
|
||||
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D) -> bool {
|
||||
for(const auto &entry:D)
|
||||
if(entry.Addr.host()==RequestedAddress.host())
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
for(auto &i:Pools_) {
|
||||
switch(rtype) {
|
||||
case radius_type::coa: {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6))) {
|
||||
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::auth: {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6))) {
|
||||
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::acct: {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6))) {
|
||||
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return DefaultRoute(rtype, RequestedAddress);
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress) {
|
||||
|
||||
if(Pool.size()==1) {
|
||||
return Pool[0].Addr;
|
||||
}
|
||||
|
||||
if (Pool[0].strategy == "weighted") {
|
||||
bool found = false;
|
||||
uint64_t cur_state = std::numeric_limits<uint64_t>::max();
|
||||
std::size_t pos = 0, index = 0;
|
||||
for (auto &i : Pool) {
|
||||
if (!i.available) {
|
||||
i.state += i.step;
|
||||
continue;
|
||||
}
|
||||
if (i.state < cur_state) {
|
||||
index = pos;
|
||||
cur_state = i.state;
|
||||
found = true;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
Pool[index].state += Pool[index].step;
|
||||
return Pool[index].Addr;
|
||||
} else if (Pool[0].strategy == "round_robin") {
|
||||
bool found = false;
|
||||
uint64_t cur_state = std::numeric_limits<uint64_t>::max();
|
||||
std::size_t pos = 0, index = 0;
|
||||
for (auto &i : Pool) {
|
||||
if (!i.available) {
|
||||
i.state += 1;
|
||||
continue;
|
||||
}
|
||||
if (i.state < cur_state) {
|
||||
index = pos;
|
||||
cur_state = i.state;
|
||||
found = true;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
Pool[index].state += 1;
|
||||
return Pool[index].Addr;
|
||||
} else if (Pool[0].strategy == "random") {
|
||||
if (Pool.size() > 1) {
|
||||
return Pool[std::rand() % Pool.size()].Addr;
|
||||
} else {
|
||||
return OriginalAddress;
|
||||
}
|
||||
}
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
|
||||
std::lock_guard G(Mutex_);
|
||||
PoolList_ = C;
|
||||
|
||||
Poco::JSON::Object Disk;
|
||||
C.to_json(Disk);
|
||||
|
||||
std::ofstream ofs(ConfigFilename_, std::ios_base::trunc | std::ios_base::binary );
|
||||
Disk.stringify(ofs);
|
||||
ofs.close();
|
||||
|
||||
ParseConfig();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ResetConfig() {
|
||||
PoolList_.pools.clear();
|
||||
Pools_.clear();
|
||||
defaultPoolIndex_=0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::DeleteConfig() {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
try {
|
||||
Poco::File F(ConfigFilename_);
|
||||
if (F.exists())
|
||||
F.remove();
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
ResetConfig();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::GetConfig(GWObjects::RadiusProxyPoolList &C) {
|
||||
std::lock_guard G(Mutex_);
|
||||
C = PoolList_;
|
||||
}
|
||||
|
||||
}
|
||||
102
src/RADIUS_proxy_server.h
Normal file
102
src/RADIUS_proxy_server.h
Normal file
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-18.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/Net/DatagramSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
enum class radius_type {
|
||||
auth, acct, coa
|
||||
};
|
||||
|
||||
class RADIUS_proxy_server : public SubSystemServer {
|
||||
public:
|
||||
inline static auto instance() {
|
||||
static auto instance_= new RADIUS_proxy_server;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
inline bool Enabled() const { return enabled_; }
|
||||
|
||||
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
|
||||
void SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
void SendAuthenticationData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
|
||||
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
|
||||
void DeleteConfig();
|
||||
void GetConfig(GWObjects::RadiusProxyPoolList &C);
|
||||
|
||||
struct Destination {
|
||||
Poco::Net::SocketAddress Addr;
|
||||
uint64_t state = 0;
|
||||
uint64_t step = 0;
|
||||
uint64_t weight=0;
|
||||
bool available = true;
|
||||
std::string strategy;
|
||||
bool monitor=false;
|
||||
std::string monitorMethod;
|
||||
std::vector<std::string> methodParameters;
|
||||
bool useAsDefault=false;
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
|
||||
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_;
|
||||
|
||||
GWObjects::RadiusProxyPoolList PoolList_;
|
||||
std::string ConfigFilename_;
|
||||
|
||||
struct RadiusPool {
|
||||
std::vector<Destination> AuthV4;
|
||||
std::vector<Destination> AuthV6;
|
||||
std::vector<Destination> AcctV4;
|
||||
std::vector<Destination> AcctV6;
|
||||
std::vector<Destination> CoaV4;
|
||||
std::vector<Destination> CoaV6;
|
||||
};
|
||||
|
||||
std::vector<RadiusPool> Pools_;
|
||||
uint defaultPoolIndex_=0;
|
||||
bool enabled_=false;
|
||||
|
||||
RADIUS_proxy_server() noexcept:
|
||||
SubSystemServer("RADIUS-PROXY", "RADIUS-PROXY", "radius.proxy")
|
||||
{
|
||||
}
|
||||
|
||||
static bool SendData( Poco::Net::DatagramSocket & Sock, const unsigned char *buf , std::size_t size, const Poco::Net::SocketAddress &S);
|
||||
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A);
|
||||
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);
|
||||
};
|
||||
|
||||
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "DeviceRegistry.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "ParseWifiScan.h"
|
||||
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
void SetCommandStatus(GWObjects::CommandDetails &Cmd,
|
||||
@@ -22,9 +23,12 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if (StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Status)) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Cmd.to_json(RetObj);
|
||||
return Handler->ReturnObject(RetObj);
|
||||
if(Handler!= nullptr)
|
||||
return Handler->ReturnObject(RetObj);
|
||||
return;
|
||||
}
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
if(Handler!= nullptr)
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
void WaitForCommand(GWObjects::CommandDetails &Cmd,
|
||||
@@ -36,10 +40,13 @@ 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));
|
||||
|
||||
// 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);
|
||||
return;
|
||||
}
|
||||
@@ -51,81 +58,88 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
std::shared_ptr<CommandManager::promise_type_t> rpc_endpoint =
|
||||
CommandManager()->PostCommand(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);
|
||||
}
|
||||
|
||||
Logger.information(fmt::format("{}: Command sent.", Cmd.UUID));
|
||||
|
||||
Poco::JSON::Object L;
|
||||
|
||||
if (Sent && rpc_endpoint!= nullptr) {
|
||||
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)) {
|
||||
auto ResultFields =
|
||||
rpc_answer.get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
if (ResultFields->has(uCentralProtocol::STATUS) && ResultFields->isObject(uCentralProtocol::STATUS)) {
|
||||
auto StatusInnerObj =
|
||||
ResultFields->get(uCentralProtocol::STATUS).extract<Poco::JSON::Object::Ptr>();
|
||||
if (StatusInnerObj->has(uCentralProtocol::ERROR))
|
||||
Cmd.ErrorCode = StatusInnerObj->get(uCentralProtocol::ERROR);
|
||||
if (StatusInnerObj->has(uCentralProtocol::TEXT))
|
||||
Cmd.ErrorText = StatusInnerObj->get(uCentralProtocol::TEXT).toString();
|
||||
std::stringstream ResultText;
|
||||
Poco::JSON::Stringifier::stringify(rpc_answer.get(uCentralProtocol::RESULT),
|
||||
ResultText);
|
||||
Cmd.Results = ResultText.str();
|
||||
Cmd.Status = "completed";
|
||||
Cmd.Completed = std::time(nullptr);
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
|
||||
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
|
||||
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);
|
||||
|
||||
if (ObjectToReturn) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
} else {
|
||||
Poco::JSON::Object O;
|
||||
Cmd.to_json(O);
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
Logger.information( fmt::format("Command({}): completed in {:.3f}ms.", Cmd.UUID, Cmd.executionTime));
|
||||
return;
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler,
|
||||
Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format(
|
||||
"Invalid response for command '{}'. Missing status.", Cmd.UUID));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED,
|
||||
Logger);
|
||||
Logger.information(fmt::format(
|
||||
"Invalid response for command '{}'. Missing status.", Cmd.UUID));
|
||||
return;
|
||||
}
|
||||
} else if (rpc_result == std::future_status::timeout) {
|
||||
Logger.information(fmt::format(
|
||||
"Timeout2 for command '{}'.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_TIMEDOUT,
|
||||
Logger);
|
||||
return;
|
||||
} else {
|
||||
Logger.information(fmt::format(
|
||||
"Pending completion for command '{}'.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
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));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Logger.information(fmt::format(
|
||||
"Pending completion for command '{}'.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
|
||||
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));
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response from device. Missing status.", Cmd.UUID));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto StatusInnerObj = ResultFields->get(uCentralProtocol::STATUS).extract<Poco::JSON::Object::Ptr>();
|
||||
if (StatusInnerObj->has(uCentralProtocol::ERROR))
|
||||
Cmd.ErrorCode = StatusInnerObj->get(uCentralProtocol::ERROR);
|
||||
if (StatusInnerObj->has(uCentralProtocol::TEXT))
|
||||
Cmd.ErrorText = StatusInnerObj->get(uCentralProtocol::TEXT).toString();
|
||||
std::stringstream ResultText;
|
||||
if(rpc_answer.has(uCentralProtocol::RESULT)) {
|
||||
if(Cmd.Command==uCentralProtocol::WIFISCAN) {
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
std::string UnCompressedData;
|
||||
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.executionTime = rpc_execution_time.count();
|
||||
|
||||
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
|
||||
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);
|
||||
|
||||
if (ObjectToReturn && Handler) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
} else {
|
||||
Poco::JSON::Object O;
|
||||
Cmd.to_json(O);
|
||||
if(Handler)
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
Logger.information( fmt::format("{}: Completed in {:.3f}ms.", Cmd.UUID, Cmd.executionTime));
|
||||
return;
|
||||
}
|
||||
Logger.information(fmt::format( "{}: Pending completion.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RESTAPI_blacklist::DoPost() {
|
||||
auto Obj = ParseStream();
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!D.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
@@ -68,7 +67,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
D.author = UserInfo_.userinfo.email;
|
||||
D.created = std::time(nullptr);
|
||||
D.created = OpenWifi::Now();
|
||||
|
||||
if(StorageService()->AddBlackListDevice(D)) {
|
||||
GWObjects::BlackListedDevice CreatedDevice;
|
||||
@@ -88,8 +87,7 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::BlackListedDevice Existing;
|
||||
if(!StorageService()->GetBlackListDevice(SerialNumber, Existing)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
|
||||
@@ -45,6 +45,6 @@ namespace OpenWifi {
|
||||
if (StorageService()->DeleteCommand(CommandUUID)) {
|
||||
return OK();
|
||||
}
|
||||
return InternalError();
|
||||
return InternalError(RESTAPI::Errors::NoRecordsDeleted);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,6 @@ namespace OpenWifi {
|
||||
if (StorageService()->DeleteCommands(SerialNumber, QB_.StartDate, QB_.EndDate)) {
|
||||
return OK();
|
||||
}
|
||||
InternalError();
|
||||
InternalError(RESTAPI::Errors::NoRecordsDeleted);
|
||||
}
|
||||
}
|
||||
@@ -47,17 +47,17 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if(StorageService()->DefaultConfigurationAlreadyExists(Name)) {
|
||||
return BadRequest("Configuration name already exists.");
|
||||
return BadRequest(RESTAPI::Errors::DefConfigNameExists);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (!DefConfig.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(DefConfig.Models.empty()) {
|
||||
return BadRequest("modelIds cannot be empty");
|
||||
return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty);
|
||||
}
|
||||
|
||||
std::string Error;
|
||||
@@ -65,7 +65,7 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
|
||||
DefConfig.Created = DefConfig.LastModified = std::time(nullptr);
|
||||
DefConfig.Created = DefConfig.LastModified = OpenWifi::Now();
|
||||
if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) {
|
||||
return OK();
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_default_configuration::DoPut() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
|
||||
auto Obj = ParseStream();
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::DefaultConfiguration NewConfig;
|
||||
if (!NewConfig.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
@@ -95,7 +95,7 @@ namespace OpenWifi {
|
||||
Existing.Configuration = NewConfig.Configuration;
|
||||
}
|
||||
|
||||
Existing.LastModified = std::time(nullptr);
|
||||
Existing.LastModified = OpenWifi::Now();
|
||||
AssignIfPresent(Obj,"description",Existing.Description);
|
||||
if(Obj->has("modelIds"))
|
||||
Existing.Models = NewConfig.Models;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,7 @@ namespace OpenWifi {
|
||||
void Rtty();
|
||||
void Telemetry();
|
||||
void Ping();
|
||||
void Script();
|
||||
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"}; };
|
||||
void DoGet() final;
|
||||
|
||||
@@ -90,13 +90,13 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
std::string Arg;
|
||||
if(HasParameter("validateOnly",Arg) && Arg=="true") {
|
||||
auto Body = ParseStream();
|
||||
if(!Body->has("configuration")) {
|
||||
return BadRequest("Must have 'configuration' element.");
|
||||
if(!Obj->has("configuration")) {
|
||||
return BadRequest(RESTAPI::Errors::MustHaveConfigElement);
|
||||
}
|
||||
auto Config=Body->get("configuration").toString();
|
||||
auto Config=Obj->get("configuration").toString();
|
||||
Poco::JSON::Object Answer;
|
||||
std::string Error;
|
||||
auto Res = ValidateUCentralConfiguration(Config, Error);
|
||||
@@ -111,7 +111,6 @@ namespace OpenWifi {
|
||||
return BadRequest( RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
GWObjects::Device Device;
|
||||
if (!Device.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
@@ -126,11 +125,13 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
|
||||
for(auto &i:Device.Notes)
|
||||
for(auto &i:Device.Notes) {
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
i.created = OpenWifi::Now();
|
||||
}
|
||||
|
||||
Config::Config NewConfig(Device.Configuration);
|
||||
Device.UUID = std::time(nullptr);
|
||||
Device.UUID = OpenWifi::Now();
|
||||
NewConfig.SetUUID(Device.UUID);
|
||||
Device.Configuration = NewConfig.get();
|
||||
|
||||
@@ -152,7 +153,7 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::Device NewDevice;
|
||||
if (!NewDevice.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
@@ -169,7 +170,7 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
Config::Config NewConfig(NewDevice.Configuration);
|
||||
uint64_t NewConfigUUID = std::time(nullptr);
|
||||
uint64_t NewConfigUUID = OpenWifi::Now();
|
||||
NewConfig.SetUUID(NewConfigUUID);
|
||||
Existing.Configuration = NewConfig.get();
|
||||
Existing.UUID = NewConfigUUID;
|
||||
@@ -183,10 +184,11 @@ namespace OpenWifi {
|
||||
|
||||
for(auto &i:NewDevice.Notes) {
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
i.created = OpenWifi::Now();
|
||||
Existing.Notes.push_back(i);
|
||||
}
|
||||
|
||||
Existing.LastConfigurationChange = std::time(nullptr);
|
||||
Existing.LastConfigurationChange = OpenWifi::Now();
|
||||
if (StorageService()->UpdateDevice(Existing)) {
|
||||
SetCurrentConfigurationID(SerialNumber, Existing.UUID);
|
||||
Poco::JSON::Object DevObj;
|
||||
|
||||
@@ -17,8 +17,60 @@
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
bool PrepareOrderBy(const std::string &OrderByList, std::string &OrderByString) {
|
||||
auto items = Poco::StringTokenizer(OrderByList,",");
|
||||
std::string ItemList;
|
||||
|
||||
Types::StringVec Fields;
|
||||
StorageService()->GetDeviceDbFieldList(Fields);
|
||||
|
||||
std::set<std::string> FieldNames;
|
||||
for(const auto &field:Fields)
|
||||
FieldNames.insert(Poco::toLower(field));
|
||||
|
||||
for(const auto &i:items) {
|
||||
auto T = Poco::StringTokenizer(i,":");
|
||||
if(T.count()!=2) {
|
||||
return false;
|
||||
}
|
||||
if(T[1]!="a" && T[1]!="d") {
|
||||
return false;
|
||||
}
|
||||
if(!ItemList.empty())
|
||||
ItemList += " , ";
|
||||
auto hint = FieldNames.find(Poco::toLower(T[0]));
|
||||
if(hint==FieldNames.end()) {
|
||||
return false;
|
||||
}
|
||||
ItemList += T[0] + (T[1]=="a" ? " ASC" : " DESC");
|
||||
}
|
||||
|
||||
if(!ItemList.empty()) {
|
||||
OrderByString = " ORDER BY " + ItemList;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RESTAPI_devices_handler::DoGet() {
|
||||
|
||||
if(GetBoolParameter("orderSpec")) {
|
||||
Types::StringVec Fields;
|
||||
StorageService()->GetDeviceDbFieldList(Fields);
|
||||
std::sort(Fields.begin(),Fields.end());
|
||||
Poco::JSON::Object Answer;
|
||||
RESTAPI_utils::field_to_json(Answer,"list",Fields);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
std::string OrderBy{" ORDER BY serialNumber ASC "}, Arg;
|
||||
if(HasParameter("orderBy",Arg)) {
|
||||
if(!PrepareOrderBy(Arg,OrderBy)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidLOrderBy);
|
||||
}
|
||||
}
|
||||
|
||||
auto serialOnly = GetBoolParameter(RESTAPI::Protocol::SERIALONLY, false);
|
||||
auto deviceWithStatus = GetBoolParameter(RESTAPI::Protocol::DEVICEWITHSTATUS, false);
|
||||
auto completeInfo = GetBoolParameter("completeInfo",false);
|
||||
@@ -59,7 +111,7 @@ namespace OpenWifi {
|
||||
}
|
||||
} else if (serialOnly) {
|
||||
std::vector<std::string> SerialNumbers;
|
||||
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers);
|
||||
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers, OrderBy);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : SerialNumbers) {
|
||||
Objects.add(i);
|
||||
@@ -67,7 +119,7 @@ namespace OpenWifi {
|
||||
RetObj.set(RESTAPI::Protocol::SERIALNUMBERS, Objects);
|
||||
} else {
|
||||
std::vector<GWObjects::Device> Devices;
|
||||
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices);
|
||||
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices, OrderBy);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : Devices) {
|
||||
Poco::JSON::Object Obj;
|
||||
|
||||
@@ -20,15 +20,12 @@ namespace OpenWifi {
|
||||
auto UUID = GetBinding(RESTAPI::Protocol::FILEUUID, "");
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
// does the file exist
|
||||
Poco::File DownloadFile(FileUploader()->Path() + "/" + UUID);
|
||||
|
||||
std::string FileType;
|
||||
if (!StorageService()->GetAttachedFile(UUID, SerialNumber, DownloadFile.path(), FileType)) {
|
||||
std::string FileContent;
|
||||
if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType)) {
|
||||
return NotFound();
|
||||
}
|
||||
SendFile(DownloadFile, UUID);
|
||||
DownloadFile.remove();
|
||||
SendFileContent(FileContent,"pcap",UUID+".pcap");
|
||||
}
|
||||
|
||||
void RESTAPI_file::DoDelete() {
|
||||
|
||||
70
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp
Normal file
70
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-20.
|
||||
//
|
||||
|
||||
#include "RESTAPI_radiusProxyConfig_handler.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_radiusProxyConfig_handler::DoGet() {
|
||||
GWObjects::RadiusProxyPoolList C;
|
||||
RADIUS_proxy_server()->GetConfig(C);
|
||||
Poco::JSON::Object Answer;
|
||||
C.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
void RESTAPI_radiusProxyConfig_handler::DoDelete() {
|
||||
if(!Internal_ && (UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
RADIUS_proxy_server()->DeleteConfig();
|
||||
return OK();
|
||||
}
|
||||
|
||||
void RESTAPI_radiusProxyConfig_handler::DoPut() {
|
||||
|
||||
if(!Internal_ && (UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
GWObjects::RadiusProxyPoolList C;
|
||||
if(!C.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
// Logically validate the config.
|
||||
for(const auto &pool:C.pools) {
|
||||
if(pool.name.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::PoolNameInvalid);
|
||||
}
|
||||
for(const auto &config:{pool.acctConfig,pool.authConfig,pool.coaConfig}) {
|
||||
if(config.strategy!="random" && config.strategy!="round_robin" && config.strategy!="weighted") {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusProxyStrategy);
|
||||
}
|
||||
if(config.monitorMethod!="none" && config.monitorMethod!="https" && config.monitorMethod!="radius") {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusProxyMonitorMethod);
|
||||
}
|
||||
if(config.servers.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MustHaveAtLeastOneRadiusServer);
|
||||
}
|
||||
|
||||
for(auto &server:config.servers) {
|
||||
Poco::Net::IPAddress Addr;
|
||||
if(!Poco::Net::IPAddress::tryParse(server.ip,Addr) || server.port==0) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusServerEntry);
|
||||
}
|
||||
if(config.strategy=="weighted" && server.weight==0) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusServerWeigth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RADIUS_proxy_server()->SetConfig(C);
|
||||
return ReturnObject(*ParsedBody_);
|
||||
}
|
||||
|
||||
}
|
||||
27
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h
Normal file
27
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-20.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_radiusProxyConfig_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_radiusProxyConfig_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServer &Server, uint64_t TransactionId,
|
||||
bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/radiusProxyConfig"}; }
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final{};
|
||||
void DoPut() final;
|
||||
};
|
||||
}
|
||||
@@ -16,11 +16,10 @@
|
||||
#include "RESTAPI/RESTAPI_devices_handler.h"
|
||||
#include "RESTAPI/RESTAPI_file.h"
|
||||
#include "RESTAPI/RESTAPI_ouis.h"
|
||||
|
||||
#include "RESTAPI/RESTAPI_capabilities_handler.h"
|
||||
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
|
||||
#include "RESTAPI/RESTAPI_webSocketServer.h"
|
||||
#include "RESTAPI/RESTAPI_iptocountry_handler.h"
|
||||
#include "RESTAPI/RESTAPI_radiusProxyConfig_handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -44,6 +43,7 @@ namespace OpenWifi {
|
||||
RESTAPI_blacklist,
|
||||
RESTAPI_blacklist_list,
|
||||
RESTAPI_iptocountry_handler,
|
||||
RESTAPI_radiusProxyConfig_handler,
|
||||
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket>(Path,Bindings,L, S, TransactionId);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace OpenWifi {
|
||||
RESTAPI_file,
|
||||
RESTAPI_blacklist,
|
||||
RESTAPI_iptocountry_handler,
|
||||
RESTAPI_radiusProxyConfig_handler,
|
||||
RESTAPI_blacklist_list>(Path,Bindings,L, S, TransactionId);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
// try and upgrade this session to websocket...
|
||||
Poco::Thread::current()->setName(fmt::format("TELEMETRY-WS({})",UserInfo_.userinfo.email));
|
||||
if (Request->find("Upgrade") != Request->end() &&
|
||||
Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
|
||||
try {
|
||||
@@ -29,10 +30,15 @@ void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
|
||||
if(!TelemetryStream()->IsValidEndPoint(SerialNumber,UUID)) {
|
||||
Logger_.warning(fmt::format("Illegal telemetry request for S: {}, UUID: {}", SerialNumber, UUID));
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
return;
|
||||
}
|
||||
auto WS = Poco::SharedPtr<Poco::Net::WebSocket>( new Poco::Net::WebSocket(*Request, *Response));
|
||||
new TelemetryClient(UUID, SerialNumber, WS, TelemetryStream()->NextReactor(), Logger_);
|
||||
|
||||
auto WS = std::make_unique<Poco::Net::WebSocket>(*Request, *Response);
|
||||
new TelemetryClient(UUID, SerialNumber, std::move(WS), TelemetryStream()->NextReactor(), Logger_);
|
||||
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
Logger_.log(E);
|
||||
switch (E.code()) {
|
||||
@@ -49,7 +55,21 @@ void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
return;
|
||||
} catch (...) {
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SetCommonHeaders(true);
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTP_METHOD_NOT_ALLOWED);
|
||||
Response->send();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-08-12.
|
||||
//
|
||||
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/JSON/Stringifier.h"
|
||||
#include "RESTAPI_webSocketServer.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_webSocketServer::DoGet() {
|
||||
|
||||
// try and upgrade this session to websocket...
|
||||
if(Request->find("Upgrade") != Request->end() && Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
|
||||
try
|
||||
{
|
||||
Poco::Net::WebSocket WS(*Request, *Response);
|
||||
int flags;
|
||||
int n;
|
||||
bool Authenticated=false;
|
||||
bool Done=false;
|
||||
do
|
||||
{
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
n = WS.receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
switch(Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS.sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
IncomingFrame.append(0);
|
||||
if(!Authenticated) {
|
||||
std::string Frame{IncomingFrame.begin()};
|
||||
auto Tokens = Utils::Split(Frame,':');
|
||||
bool Expired=false, Contacted = false;
|
||||
if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||
Authenticated=true;
|
||||
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||
WS.sendFrame(S.c_str(),S.size());
|
||||
} else {
|
||||
std::string S{"Invalid token. Closing connection."};
|
||||
WS.sendFrame(S.c_str(),S.size());
|
||||
Done=true;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Obj = P.parse(IncomingFrame.begin())
|
||||
.extract<Poco::JSON::Object::Ptr>();
|
||||
std::string Answer;
|
||||
if(Process(Obj, Answer)) {
|
||||
if (!Answer.empty())
|
||||
WS.sendFrame(Answer.c_str(), Answer.size());
|
||||
else {
|
||||
WS.sendFrame("{}", 2);
|
||||
}
|
||||
} else {
|
||||
Done=true;
|
||||
}
|
||||
} catch (const Poco::JSON::JSONException & E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Done=true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!Done && (n > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE));
|
||||
}
|
||||
catch (const Poco::Net::WebSocketException & E)
|
||||
{
|
||||
Logger_.log(E);
|
||||
switch (E.code())
|
||||
{
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION:
|
||||
Response->set("Sec-WebSocket-Version", Poco::Net::WebSocket::WEBSOCKET_VERSION);
|
||||
// fallthrough
|
||||
case Poco::Net::WebSocket::WS_ERR_NO_HANDSHAKE:
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_VERSION:
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_KEY:
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
catch (...) {
|
||||
|
||||
}
|
||||
} else {
|
||||
return BadRequest("Client does not support a websocket connection.");
|
||||
}
|
||||
}
|
||||
|
||||
bool RESTAPI_webSocketServer::Process(const Poco::JSON::Object::Ptr &O, std::string &Answer ) {
|
||||
try {
|
||||
if (O->has("command")) {
|
||||
auto Command = O->get("command").toString();
|
||||
if (Command == "serial_number_search" && O->has("serial_prefix")) {
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
uint64_t HowMany = 50;
|
||||
if (O->has("howMany"))
|
||||
HowMany = O->get("howMany");
|
||||
Logger_.information(fmt::format("serial_number_search: {}", Prefix));
|
||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||
std::vector<uint64_t> Numbers;
|
||||
SerialNumberCache()->FindNumbers(Prefix, HowMany, Numbers);
|
||||
Poco::JSON::Array A;
|
||||
for (const auto &i : Numbers)
|
||||
A.add(Utils::IntToSerialNumber(i));
|
||||
Poco::JSON::Object AO;
|
||||
AO.set("serialNumbers", A);
|
||||
AO.set("command","serial_number_search");
|
||||
std::ostringstream SS;
|
||||
Poco::JSON::Stringifier::stringify(AO, SS);
|
||||
Answer = SS.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-08-12.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_webSocketServer : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_webSocketServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{ Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal,false) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/ws"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final {};
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
private:
|
||||
bool Process(const Poco::JSON::Object::Ptr &O, std::string &Answer);
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
void Report::reset() {
|
||||
}
|
||||
|
||||
void Report::to_json(Poco::JSON::Object &Obj) const {
|
||||
void Report::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
|
||||
}
|
||||
|
||||
void VenueInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
@@ -167,6 +167,23 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"inactive",inactive);
|
||||
field_to_json(Obj,"tx_rate",tx_rate);
|
||||
field_to_json(Obj,"rx_rate",rx_rate);
|
||||
// field_to_json(Obj, "tidstats", tidstats);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_to_json(Obj,"tx_failed_delta",tx_failed_delta);
|
||||
field_to_json(Obj,"tx_retries_delta",tx_retries_delta);
|
||||
field_to_json(Obj,"tx_duration_delta",tx_duration_delta);
|
||||
}
|
||||
|
||||
bool UETimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -184,6 +201,21 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"inactive",inactive);
|
||||
field_from_json(Obj,"tx_rate",tx_rate);
|
||||
field_from_json(Obj,"rx_rate",rx_rate);
|
||||
// field_from_json(Obj,"tidstats",tidstats);
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_from_json(Obj,"tx_failed_delta",tx_failed_delta);
|
||||
field_from_json(Obj,"tx_retries_delta",tx_retries_delta);
|
||||
field_from_json(Obj,"tx_duration_delta",tx_duration_delta);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -203,6 +235,24 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"tx_dropped",tx_dropped);
|
||||
field_to_json(Obj,"tx_errors",tx_errors);
|
||||
field_to_json(Obj,"tx_packets",tx_packets);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_to_json(Obj,"rx_dropped_delta",rx_dropped_delta);
|
||||
field_to_json(Obj,"tx_dropped_delta",tx_dropped_delta);
|
||||
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_to_json(Obj,"rx_errors_delta",rx_errors_delta);
|
||||
field_to_json(Obj,"tx_errors_delta",tx_errors_delta);
|
||||
}
|
||||
|
||||
bool APTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -218,6 +268,25 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"tx_dropped",tx_dropped);
|
||||
field_from_json(Obj,"tx_errors",tx_errors);
|
||||
field_from_json(Obj,"tx_packets",tx_packets);
|
||||
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
|
||||
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_from_json(Obj,"rx_dropped_delta",rx_dropped_delta);
|
||||
field_from_json(Obj,"tx_dropped_delta",tx_dropped_delta);
|
||||
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_from_json(Obj,"rx_errors_delta",rx_errors_delta);
|
||||
field_from_json(Obj,"tx_errors_delta",tx_errors_delta);
|
||||
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -247,7 +316,7 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
|
||||
void RadioTimePoint::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"band",band);
|
||||
field_to_json(Obj,"radio_channel",radio_channel);
|
||||
field_to_json(Obj,"channel_width",channel_width);
|
||||
field_to_json(Obj,"active_ms",active_ms);
|
||||
field_to_json(Obj,"busy_ms",busy_ms);
|
||||
field_to_json(Obj,"receive_ms",receive_ms);
|
||||
@@ -256,12 +325,16 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"channel",channel);
|
||||
field_to_json(Obj,"temperature",temperature);
|
||||
field_to_json(Obj,"noise",noise);
|
||||
field_to_json(Obj,"active_pct",active_pct);
|
||||
field_to_json(Obj,"busy_pct",busy_pct);
|
||||
field_to_json(Obj,"receive_pct",receive_pct);
|
||||
field_to_json(Obj,"transmit_pct",transmit_pct);
|
||||
}
|
||||
|
||||
bool RadioTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"band",band);
|
||||
field_from_json(Obj,"radio_channel",radio_channel);
|
||||
field_from_json(Obj,"channel_width",channel_width);
|
||||
field_from_json(Obj,"active_ms",active_ms);
|
||||
field_from_json(Obj,"busy_ms",busy_ms);
|
||||
field_from_json(Obj,"receive_ms",receive_ms);
|
||||
@@ -270,6 +343,28 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"channel",channel);
|
||||
field_from_json(Obj,"temperature",temperature);
|
||||
field_from_json(Obj,"noise",noise);
|
||||
field_from_json(Obj,"active_pct",active_pct);
|
||||
field_from_json(Obj,"busy_pct",busy_pct);
|
||||
field_from_json(Obj,"receive_pct",receive_pct);
|
||||
field_from_json(Obj,"transmit_pct",transmit_pct);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AveragePoint::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"min",min);
|
||||
field_to_json(Obj,"max",max);
|
||||
field_to_json(Obj,"avg",avg);
|
||||
}
|
||||
|
||||
bool AveragePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"min",min);
|
||||
field_from_json(Obj,"max",max);
|
||||
field_from_json(Obj,"avg",avg);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -282,7 +377,15 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"mode",mode);
|
||||
field_to_json(Obj,"ssid",ssid);
|
||||
field_to_json(Obj,"band",band);
|
||||
field_to_json(Obj,"channel",channel);
|
||||
field_to_json(Obj,"associations",associations);
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
}
|
||||
|
||||
bool SSIDTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -291,7 +394,15 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"mode",mode);
|
||||
field_from_json(Obj,"ssid",ssid);
|
||||
field_from_json(Obj,"band",band);
|
||||
field_from_json(Obj,"channel",channel);
|
||||
field_from_json(Obj,"associations",associations);
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -307,6 +418,7 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"ssid_data",ssid_data);
|
||||
field_to_json(Obj,"radio_data",radio_data);
|
||||
field_to_json(Obj,"device_info",device_info);
|
||||
field_to_json(Obj,"serialNumber",serialNumber);
|
||||
}
|
||||
|
||||
bool DeviceTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -318,6 +430,49 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"ssid_data",ssid_data);
|
||||
field_from_json(Obj,"radio_data",radio_data);
|
||||
field_from_json(Obj,"device_info",device_info);
|
||||
field_from_json(Obj,"serialNumber",serialNumber);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceTimePointAnalysis::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"noise",noise);
|
||||
field_to_json(Obj,"temperature",temperature);
|
||||
field_to_json(Obj,"active_pct",active_pct);
|
||||
field_to_json(Obj,"busy_pct",busy_pct);
|
||||
field_to_json(Obj,"receive_pct",receive_pct);
|
||||
field_to_json(Obj,"transmit_pct",transmit_pct);
|
||||
field_to_json(Obj,"tx_power",tx_power);
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
}
|
||||
|
||||
bool DeviceTimePointAnalysis::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"noise",noise);
|
||||
field_from_json(Obj,"temperature",temperature);
|
||||
field_from_json(Obj,"active_pct",active_pct);
|
||||
field_from_json(Obj,"busy_pct",busy_pct);
|
||||
field_from_json(Obj,"receive_pct",receive_pct);
|
||||
field_from_json(Obj,"transmit_pct",transmit_pct);
|
||||
field_from_json(Obj,"tx_power",tx_power);
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -327,11 +482,13 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
|
||||
void DeviceTimePointList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"points",points);
|
||||
field_to_json(Obj,"stats",stats);
|
||||
}
|
||||
|
||||
bool DeviceTimePointList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"points",points);
|
||||
field_from_json(Obj,"stats",stats);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -357,4 +514,111 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WifiClientRate::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"bitrate",bitrate);
|
||||
field_to_json(Obj,"chwidth",chwidth);
|
||||
field_to_json(Obj,"mcs",mcs);
|
||||
field_to_json(Obj,"nss",nss);
|
||||
field_to_json(Obj,"vht",vht);
|
||||
}
|
||||
|
||||
bool WifiClientRate::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"bitrate",bitrate);
|
||||
field_from_json(Obj,"chwidth",chwidth);
|
||||
field_from_json(Obj,"mcs",mcs);
|
||||
field_from_json(Obj,"nss",nss);
|
||||
field_from_json(Obj,"vht",vht);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"timestamp",timestamp);
|
||||
field_to_json(Obj,"station_id",station_id);
|
||||
field_to_json(Obj,"bssid",bssid);
|
||||
field_to_json(Obj,"ssid",ssid);
|
||||
field_to_json(Obj,"rssi",rssi);
|
||||
field_to_json(Obj,"rx_bitrate",rx_bitrate);
|
||||
field_to_json(Obj,"rx_chwidth",rx_chwidth);
|
||||
field_to_json(Obj,"rx_mcs",rx_mcs);
|
||||
field_to_json(Obj,"rx_nss",rx_nss);
|
||||
field_to_json(Obj,"rx_vht",rx_vht);
|
||||
field_to_json(Obj,"tx_bitrate",tx_bitrate);
|
||||
field_to_json(Obj,"tx_chwidth",tx_chwidth);
|
||||
field_to_json(Obj,"tx_mcs",tx_mcs);
|
||||
field_to_json(Obj,"tx_nss",tx_nss);
|
||||
field_to_json(Obj,"tx_vht",tx_vht);
|
||||
field_to_json(Obj,"rx_bytes",rx_bytes);
|
||||
field_to_json(Obj,"tx_bytes",tx_bytes);
|
||||
field_to_json(Obj,"rx_duration",rx_duration);
|
||||
field_to_json(Obj,"tx_duration",tx_duration);
|
||||
field_to_json(Obj,"rx_packets",rx_packets);
|
||||
field_to_json(Obj,"tx_packets",tx_packets);
|
||||
field_to_json(Obj,"ipv4",ipv4);
|
||||
field_to_json(Obj,"ipv6",ipv6);
|
||||
field_to_json(Obj,"channel_width",channel_width);
|
||||
field_to_json(Obj,"noise",noise);
|
||||
field_to_json(Obj,"tx_power",tx_power);
|
||||
field_to_json(Obj,"channel",channel);
|
||||
field_to_json(Obj,"active_ms",active_ms);
|
||||
field_to_json(Obj,"busy_ms",busy_ms);
|
||||
field_to_json(Obj,"receive_ms",receive_ms);
|
||||
field_to_json(Obj,"mode",mode);
|
||||
field_to_json(Obj,"ack_signal",ack_signal);
|
||||
field_to_json(Obj,"ack_signal_avg",ack_signal_avg);
|
||||
field_to_json(Obj,"connected",connected);
|
||||
field_to_json(Obj,"inactive",inactive);
|
||||
field_to_json(Obj,"tx_retries",tx_retries);
|
||||
field_to_json(Obj,"venue_id",venue_id);
|
||||
}
|
||||
|
||||
bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"timestamp",timestamp);
|
||||
field_from_json(Obj,"station_id",station_id);
|
||||
field_from_json(Obj,"bssid",bssid);
|
||||
field_from_json(Obj,"ssid",ssid);
|
||||
field_from_json(Obj,"rssi",rssi);
|
||||
field_from_json(Obj,"rx_bitrate",rx_bitrate);
|
||||
field_from_json(Obj,"rx_chwidth",rx_chwidth);
|
||||
field_from_json(Obj,"rx_mcs",rx_mcs);
|
||||
field_from_json(Obj,"rx_nss",rx_nss);
|
||||
field_from_json(Obj,"rx_vht",rx_vht);
|
||||
field_from_json(Obj,"tx_bitrate",tx_bitrate);
|
||||
field_from_json(Obj,"tx_chwidth",tx_chwidth);
|
||||
field_from_json(Obj,"tx_mcs",tx_mcs);
|
||||
field_from_json(Obj,"tx_nss",tx_nss);
|
||||
field_from_json(Obj,"tx_vht",tx_vht);
|
||||
field_from_json(Obj,"rx_bytes",rx_bytes);
|
||||
field_from_json(Obj,"tx_bytes",tx_bytes);
|
||||
field_from_json(Obj,"rx_duration",rx_duration);
|
||||
field_from_json(Obj,"tx_duration",tx_duration);
|
||||
field_from_json(Obj,"rx_packets",rx_packets);
|
||||
field_from_json(Obj,"tx_packets",tx_packets);
|
||||
field_from_json(Obj,"ipv4",ipv4);
|
||||
field_from_json(Obj,"ipv6",ipv6);
|
||||
field_from_json(Obj,"channel_width",channel_width);
|
||||
field_from_json(Obj,"noise",noise);
|
||||
field_from_json(Obj,"tx_power",tx_power);
|
||||
field_from_json(Obj,"channel",channel);
|
||||
field_from_json(Obj,"active_ms",active_ms);
|
||||
field_from_json(Obj,"busy_ms",busy_ms);
|
||||
field_from_json(Obj,"receive_ms",receive_ms);
|
||||
field_from_json(Obj,"mode",mode);
|
||||
field_from_json(Obj,"ack_signal",ack_signal);
|
||||
field_from_json(Obj,"ack_signal_avg",ack_signal_avg);
|
||||
field_from_json(Obj,"connected",connected);
|
||||
field_from_json(Obj,"inactive",inactive);
|
||||
field_from_json(Obj,"tx_retries",tx_retries);
|
||||
field_from_json(Obj,"venue_id",venue_id);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,14 @@ namespace OpenWifi {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct AveragePoint {
|
||||
double min = 0.0,
|
||||
max = 0.0,
|
||||
avg = 0.0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct UETimePoint {
|
||||
std::string station;
|
||||
int64_t rssi = 0;
|
||||
@@ -121,9 +129,26 @@ namespace OpenWifi {
|
||||
tx_failed = 0,
|
||||
connected = 0,
|
||||
inactive = 0;
|
||||
|
||||
double tx_bytes_bw = 0.0 ,
|
||||
rx_bytes_bw = 0.0 ,
|
||||
tx_packets_bw = 0.0 ,
|
||||
rx_packets_bw = 0.0 ,
|
||||
tx_failed_pct = 0.0 ,
|
||||
tx_retries_pct = 0.0 ,
|
||||
tx_duration_pct = 0.0;
|
||||
|
||||
uint64_t tx_bytes_delta = 0,
|
||||
rx_bytes_delta = 0,
|
||||
tx_duration_delta = 0,
|
||||
rx_packets_delta = 0,
|
||||
tx_packets_delta = 0,
|
||||
tx_retries_delta = 0,
|
||||
tx_failed_delta = 0;
|
||||
|
||||
UE_rate tx_rate,
|
||||
rx_rate;
|
||||
std::vector<TIDstat_entry> tidstat;
|
||||
std::vector<TIDstat_entry> tidstats;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -159,9 +184,18 @@ namespace OpenWifi {
|
||||
std::string bssid,
|
||||
mode,
|
||||
ssid;
|
||||
uint64_t band=0;
|
||||
uint64_t band=0,
|
||||
channel=0;
|
||||
std::vector<UETimePoint> associations;
|
||||
|
||||
AveragePoint tx_bytes_bw,
|
||||
rx_bytes_bw,
|
||||
tx_packets_bw,
|
||||
rx_packets_bw,
|
||||
tx_failed_pct,
|
||||
tx_retries_pct,
|
||||
tx_duration_pct;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
@@ -184,7 +218,18 @@ namespace OpenWifi {
|
||||
rx_dropped_pct = 0.0,
|
||||
tx_dropped_pct = 0.0,
|
||||
rx_packets_bw = 0.0,
|
||||
tx_packets_bw = 0.0;
|
||||
tx_packets_bw = 0.0,
|
||||
rx_errors_pct = 0.0 ,
|
||||
tx_errors_pct = 0.0;
|
||||
|
||||
uint64_t tx_bytes_delta = 0,
|
||||
rx_bytes_delta = 0 ,
|
||||
rx_dropped_delta = 0,
|
||||
tx_dropped_delta = 0,
|
||||
rx_packets_delta = 0,
|
||||
tx_packets_delta = 0,
|
||||
rx_errors_delta = 0,
|
||||
tx_errors_delta = 0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -192,15 +237,20 @@ namespace OpenWifi {
|
||||
|
||||
struct RadioTimePoint {
|
||||
uint64_t band = 0,
|
||||
radio_channel = 0;
|
||||
uint64_t active_ms = 0,
|
||||
busy_ms = 0,
|
||||
receive_ms = 0,
|
||||
transmit_ms = 0,
|
||||
tx_power = 0,
|
||||
channel = 0;
|
||||
int64_t temperature = 0,
|
||||
noise = 0;
|
||||
channel_width = 0;
|
||||
uint64_t active_ms = 0,
|
||||
busy_ms = 0,
|
||||
receive_ms = 0,
|
||||
transmit_ms = 0,
|
||||
tx_power = 0,
|
||||
channel = 0;
|
||||
int64_t temperature = 0,
|
||||
noise = 0;
|
||||
|
||||
double active_pct = 0.0 ,
|
||||
busy_pct = 0.0,
|
||||
receive_pct = 0.0,
|
||||
transmit_pct = 0.0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -208,13 +258,14 @@ namespace OpenWifi {
|
||||
|
||||
|
||||
struct DeviceTimePoint {
|
||||
std::string id;
|
||||
std::string boardId;
|
||||
uint64_t timestamp = 0;
|
||||
APTimePoint ap_data;
|
||||
std::vector<SSIDTimePoint> ssid_data;
|
||||
std::vector<RadioTimePoint> radio_data;
|
||||
AnalyticsObjects::DeviceInfo device_info;
|
||||
std::string id;
|
||||
std::string boardId;
|
||||
uint64_t timestamp = 0;
|
||||
APTimePoint ap_data;
|
||||
std::vector<SSIDTimePoint> ssid_data;
|
||||
std::vector<RadioTimePoint> radio_data;
|
||||
AnalyticsObjects::DeviceInfo device_info;
|
||||
std::string serialNumber;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -245,9 +296,34 @@ namespace OpenWifi {
|
||||
|
||||
};
|
||||
|
||||
struct DeviceTimePointList {
|
||||
std::vector<DeviceTimePoint> points;
|
||||
struct DeviceTimePointAnalysis {
|
||||
uint64_t timestamp;
|
||||
|
||||
AveragePoint noise;
|
||||
AveragePoint temperature;
|
||||
AveragePoint active_pct;
|
||||
AveragePoint busy_pct;
|
||||
AveragePoint receive_pct;
|
||||
AveragePoint transmit_pct;
|
||||
AveragePoint tx_power;
|
||||
|
||||
AveragePoint tx_bytes_bw;
|
||||
AveragePoint rx_bytes_bw;
|
||||
AveragePoint rx_dropped_pct;
|
||||
AveragePoint tx_dropped_pct;
|
||||
AveragePoint rx_packets_bw;
|
||||
AveragePoint tx_packets_bw;
|
||||
AveragePoint rx_errors_pct;
|
||||
AveragePoint tx_errors_pct;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
|
||||
};
|
||||
|
||||
struct DeviceTimePointList {
|
||||
std::vector<DeviceTimePoint> points;
|
||||
std::vector<DeviceTimePointAnalysis> stats;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
@@ -286,5 +362,61 @@ namespace OpenWifi {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WifiClientRate {
|
||||
uint32_t bitrate=0;
|
||||
uint32_t chwidth=0;
|
||||
uint16_t mcs=0;
|
||||
uint16_t nss=0;
|
||||
bool vht=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WifiClientHistory {
|
||||
uint64_t timestamp=OpenWifi::Now();
|
||||
std::string station_id;
|
||||
std::string bssid;
|
||||
std::string ssid;
|
||||
int64_t rssi=0;
|
||||
uint32_t rx_bitrate=0;
|
||||
uint32_t rx_chwidth=0;
|
||||
uint16_t rx_mcs=0;
|
||||
uint16_t rx_nss=0;
|
||||
bool rx_vht=false;
|
||||
uint32_t tx_bitrate=0;
|
||||
uint32_t tx_chwidth=0;
|
||||
uint16_t tx_mcs=0;
|
||||
uint16_t tx_nss=0;
|
||||
bool tx_vht=false;
|
||||
uint64_t rx_bytes=0;
|
||||
uint64_t tx_bytes=0;
|
||||
uint64_t rx_duration=0;
|
||||
uint64_t tx_duration=0;
|
||||
uint64_t rx_packets=0;
|
||||
uint64_t tx_packets=0;
|
||||
std::string ipv4;
|
||||
std::string ipv6;
|
||||
uint64_t channel_width=0;
|
||||
int64_t noise=0;
|
||||
uint64_t tx_power=0;
|
||||
uint64_t channel=0;
|
||||
uint64_t active_ms=0;
|
||||
uint64_t busy_ms=0;
|
||||
uint64_t receive_ms=0;
|
||||
std::string mode;
|
||||
int64_t ack_signal=0;
|
||||
int64_t ack_signal_avg=0;
|
||||
uint64_t connected=0;
|
||||
uint64_t inactive=0;
|
||||
uint64_t tx_retries=0;
|
||||
std::string venue_id;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,176 +3,206 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_CertObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
|
||||
namespace OpenWifi {
|
||||
namespace CertObjects {
|
||||
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"type", type);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"certificate", certificate);
|
||||
field_to_json(Obj,"key", key);
|
||||
field_to_json(Obj,"devid", devid);
|
||||
field_to_json(Obj,"cas", cas);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonName", commonName);
|
||||
field_to_json(Obj,"certificateId", certificateId);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"revoked", revoked);
|
||||
field_to_json(Obj,"revokeCount", revokeCount);
|
||||
}
|
||||
namespace OpenWifi::CertObjects {
|
||||
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"type", type);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"certificate", certificate);
|
||||
field_to_json(Obj,"key", key);
|
||||
field_to_json(Obj,"devid", devid);
|
||||
field_to_json(Obj,"cas", cas);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonName", commonName);
|
||||
field_to_json(Obj,"certificateId", certificateId);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"revoked", revoked);
|
||||
field_to_json(Obj,"revokeCount", revokeCount);
|
||||
field_to_json(Obj,"synched", synched);
|
||||
}
|
||||
|
||||
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"type", type);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"certificate", certificate);
|
||||
field_from_json(Obj,"key", key);
|
||||
field_from_json(Obj,"devid", devid);
|
||||
field_from_json(Obj,"cas", cas);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonName", commonName);
|
||||
field_from_json(Obj,"certificateId", certificateId);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"revoked", revoked);
|
||||
field_from_json(Obj,"revokeCount", revokeCount);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"type", type);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"certificate", certificate);
|
||||
field_from_json(Obj,"key", key);
|
||||
field_from_json(Obj,"devid", devid);
|
||||
field_from_json(Obj,"cas", cas);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonName", commonName);
|
||||
field_from_json(Obj,"certificateId", certificateId);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"revoked", revoked);
|
||||
field_from_json(Obj,"revokeCount", revokeCount);
|
||||
field_from_json(Obj,"synched", synched);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_to_json(Obj,"apiKey", apiKey);
|
||||
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_to_json(Obj,"organization", organization);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"suspended", suspended);
|
||||
field_to_json(Obj,"deleted", deleted);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
}
|
||||
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_to_json(Obj,"apiKey", apiKey);
|
||||
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_to_json(Obj,"organization", organization);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"suspended", suspended);
|
||||
field_to_json(Obj,"deleted", deleted);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
}
|
||||
|
||||
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_from_json(Obj,"apiKey", apiKey);
|
||||
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_from_json(Obj,"organization", organization);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"suspended", suspended);
|
||||
field_from_json(Obj,"deleted", deleted);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_from_json(Obj,"apiKey", apiKey);
|
||||
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_from_json(Obj,"organization", organization);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"suspended", suspended);
|
||||
field_from_json(Obj,"deleted", deleted);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"jobHistory", jobHistory);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
}
|
||||
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"jobHistory", jobHistory);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
}
|
||||
|
||||
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"jobHistory", jobHistory);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"jobHistory", jobHistory);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"completedNames", completedNames);
|
||||
field_to_json(Obj,"errorNames", errorNames);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"command", command);
|
||||
field_to_json(Obj,"parameters", parameters);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
}
|
||||
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"completedNames", completedNames);
|
||||
field_to_json(Obj,"errorNames", errorNames);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"command", command);
|
||||
field_to_json(Obj,"parameters", parameters);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
}
|
||||
|
||||
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"completedNames", completedNames);
|
||||
field_from_json(Obj,"errorNames", errorNames);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"command", command);
|
||||
field_from_json(Obj,"parameters", parameters);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"completedNames", completedNames);
|
||||
field_from_json(Obj,"errorNames", errorNames);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"command", command);
|
||||
field_from_json(Obj,"parameters", parameters);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "year", year);
|
||||
field_to_json(Obj, "activeCerts", activeCerts);
|
||||
field_to_json(Obj, "revokedCerts", revokedCerts);
|
||||
}
|
||||
|
||||
void Dashboard::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"snapshot", snapshot);
|
||||
field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts);
|
||||
field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts);
|
||||
field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization);
|
||||
field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization);
|
||||
field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors);
|
||||
field_to_json(Obj,"deviceTypes", deviceTypes);
|
||||
field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts);
|
||||
field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear);
|
||||
}
|
||||
|
||||
void Dashboard::reset() {
|
||||
snapshot=0;
|
||||
numberOfRevokedCerts = numberOfIssuedCerts = 0;
|
||||
activeCertsPerOrganization.clear();
|
||||
revokedCertsPerOrganization.clear();
|
||||
numberOfRedirectors.clear();
|
||||
deviceTypes.clear();
|
||||
monthlyNumberOfCerts.clear();
|
||||
monthlyNumberOfCertsPerOrgPerYear.clear();
|
||||
}
|
||||
}
|
||||
@@ -5,97 +5,118 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
namespace OpenWifi::CertObjects {
|
||||
|
||||
namespace CertObjects {
|
||||
struct CertificateEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string type;
|
||||
std::string status;
|
||||
std::string certificate;
|
||||
std::string key;
|
||||
std::string devid;
|
||||
std::string cas;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::string commonName;
|
||||
std::string certificateId;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
uint64_t created = 0;
|
||||
uint64_t modified = 0;
|
||||
uint64_t revoked = 0;
|
||||
uint64_t revokeCount = 0;
|
||||
uint64_t synched = 0;
|
||||
|
||||
struct CertificateEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string type;
|
||||
std::string status;
|
||||
std::string certificate;
|
||||
std::string key;
|
||||
std::string devid;
|
||||
std::string cas;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::string commonName;
|
||||
std::string certificateId;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
uint64_t created = 0;
|
||||
uint64_t modified = 0;
|
||||
uint64_t revoked = 0;
|
||||
uint64_t revokeCount = 0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct EntityEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string defaultRedirector;
|
||||
std::string apiKey;
|
||||
std::string serverEnrollmentProfile;
|
||||
std::string clientEnrollmentProfile;
|
||||
std::string organization;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
bool suspended=false;
|
||||
bool deleted=false;
|
||||
uint64_t created = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
|
||||
struct EntityEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string defaultRedirector;
|
||||
std::string apiKey;
|
||||
std::string serverEnrollmentProfile;
|
||||
std::string clientEnrollmentProfile;
|
||||
std::string organization;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
bool suspended=false;
|
||||
bool deleted=false;
|
||||
uint64_t created = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct BatchEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::vector<std::string> commonNames;
|
||||
std::vector<std::string> jobHistory;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t submitted = 0 ;
|
||||
uint64_t started = 0 ;
|
||||
uint64_t completed = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
|
||||
struct BatchEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::vector<std::string> commonNames;
|
||||
std::vector<std::string> jobHistory;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t submitted = 0 ;
|
||||
uint64_t started = 0 ;
|
||||
uint64_t completed = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct JobEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
std::string command;
|
||||
OpenWifi::Types::StringVec commonNames;
|
||||
OpenWifi::Types::StringVec completedNames;
|
||||
OpenWifi::Types::StringVec errorNames;
|
||||
Types::StringPairVec parameters;
|
||||
std::string status;
|
||||
uint64_t submitted=0;
|
||||
uint64_t started=0;
|
||||
uint64_t completed=0;
|
||||
|
||||
struct JobEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
std::string command;
|
||||
OpenWifi::Types::StringVec commonNames;
|
||||
OpenWifi::Types::StringVec completedNames;
|
||||
OpenWifi::Types::StringVec errorNames;
|
||||
Types::StringPairVec parameters;
|
||||
std::string status;
|
||||
uint64_t submitted=0;
|
||||
uint64_t started=0;
|
||||
uint64_t completed=0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DashBoardYearlyStats {
|
||||
uint64_t year=0;
|
||||
OpenWifi::Types::Counted3DMapSII activeCerts;
|
||||
OpenWifi::Types::Counted3DMapSII revokedCerts;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct Dashboard {
|
||||
uint64_t snapshot=0;
|
||||
uint64_t numberOfIssuedCerts=0;
|
||||
uint64_t numberOfRevokedCerts=0;
|
||||
OpenWifi::Types::CountedMap activeCertsPerOrganization;
|
||||
OpenWifi::Types::CountedMap revokedCertsPerOrganization;
|
||||
OpenWifi::Types::CountedMap numberOfRedirectors;
|
||||
OpenWifi::Types::CountedMap deviceTypes;
|
||||
OpenWifi::Types::CountedMap monthlyNumberOfCerts;
|
||||
std::vector<DashBoardYearlyStats> monthlyNumberOfCertsPerOrgPerYear;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void reset();
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,7 @@ namespace OpenWifi::FMSObjects {
|
||||
UnknownFirmwares_.clear();
|
||||
totalSecondsOld_.clear();
|
||||
numberOfDevices = 0 ;
|
||||
snapshot = std::time(nullptr);
|
||||
snapshot = OpenWifi::Now();
|
||||
}
|
||||
|
||||
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -273,4 +273,37 @@ namespace OpenWifi::FMSObjects {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "serialNumber",serialNumber);
|
||||
field_to_json(Obj, "revision", revision);
|
||||
field_to_json(Obj, "upgraded", upgraded);
|
||||
}
|
||||
|
||||
bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serialNumber",serialNumber);
|
||||
field_from_json(Obj, "revision", revision);
|
||||
field_from_json(Obj, "upgraded", upgraded);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "devices",devices);
|
||||
}
|
||||
|
||||
bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "devices",devices);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
#define UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
@@ -29,7 +27,7 @@ namespace OpenWifi::FMSObjects {
|
||||
std::string location;
|
||||
std::string uploader;
|
||||
std::string digest;
|
||||
bool latest=0;
|
||||
bool latest=false;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t created=0;
|
||||
|
||||
@@ -141,7 +139,21 @@ namespace OpenWifi::FMSObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceCurrentInfo {
|
||||
std::string serialNumber;
|
||||
std::string revision;
|
||||
uint64_t upgraded=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceCurrentInfoList {
|
||||
std::vector<DeviceCurrentInfo> devices;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
|
||||
@@ -264,7 +264,7 @@ namespace OpenWifi::GWObjects {
|
||||
lastContact.clear();
|
||||
associations.clear();
|
||||
numberOfDevices = 0 ;
|
||||
snapshot = std::time(nullptr);
|
||||
snapshot = OpenWifi::Now();
|
||||
}
|
||||
|
||||
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
|
||||
@@ -272,5 +272,120 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"capabilities", capabilities);
|
||||
};
|
||||
|
||||
void ScriptRequest::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber",serialNumber);
|
||||
field_to_json(Obj,"timeout",timeout);
|
||||
field_to_json(Obj,"type",type);
|
||||
field_to_json(Obj,"script",script);
|
||||
field_to_json(Obj,"scriptId",scriptId);
|
||||
field_to_json(Obj,"when",when);
|
||||
}
|
||||
|
||||
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"serialNumber",serialNumber);
|
||||
field_from_json(Obj,"timeout",timeout);
|
||||
field_from_json(Obj,"type",type);
|
||||
field_from_json(Obj,"script",script);
|
||||
field_from_json(Obj,"scriptId",scriptId);
|
||||
field_from_json(Obj,"when",when);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"pools",pools);
|
||||
}
|
||||
|
||||
bool RadiusProxyPoolList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"pools",pools);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadiusProxyPool::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"name",name);
|
||||
field_to_json(Obj,"description",description);
|
||||
field_to_json(Obj,"authConfig",authConfig);
|
||||
field_to_json(Obj,"acctConfig",acctConfig);
|
||||
field_to_json(Obj,"coaConfig",coaConfig);
|
||||
field_to_json(Obj,"useByDefault",useByDefault);
|
||||
}
|
||||
|
||||
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"name",name);
|
||||
field_from_json(Obj,"description",description);
|
||||
field_from_json(Obj,"authConfig",authConfig);
|
||||
field_from_json(Obj,"acctConfig",acctConfig);
|
||||
field_from_json(Obj,"coaConfig",coaConfig);
|
||||
field_from_json(Obj,"useByDefault",useByDefault);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"strategy",strategy);
|
||||
field_to_json(Obj,"monitor",monitor);
|
||||
field_to_json(Obj,"monitorMethod",monitorMethod);
|
||||
field_to_json(Obj,"methodParameters",methodParameters);
|
||||
field_to_json(Obj,"servers",servers);
|
||||
}
|
||||
|
||||
bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"strategy",strategy);
|
||||
field_from_json(Obj,"monitor",monitor);
|
||||
field_from_json(Obj,"monitorMethod",monitorMethod);
|
||||
field_from_json(Obj,"methodParameters",methodParameters);
|
||||
field_from_json(Obj,"servers",servers);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadiusProxyServerEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"name",name);
|
||||
field_to_json(Obj,"ip",ip);
|
||||
field_to_json(Obj,"port",port);
|
||||
field_to_json(Obj,"weight",weight);
|
||||
field_to_json(Obj,"secret",secret);
|
||||
field_to_json(Obj,"certificate",certificate);
|
||||
field_to_json(Obj,"radsec",radsec);
|
||||
field_to_json(Obj,"radsec_secret",radsec_secret);
|
||||
field_to_json(Obj,"radsec_port",radsec_port);
|
||||
field_to_json(Obj,"radsec_cacerts",radsec_cacerts);
|
||||
field_to_json(Obj,"radsec_cert",radsec_cert);
|
||||
field_to_json(Obj,"radsec_key",radsec_key);
|
||||
}
|
||||
|
||||
bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"name",name);
|
||||
field_from_json(Obj,"ip",ip);
|
||||
field_from_json(Obj,"port",port);
|
||||
field_from_json(Obj,"weight",weight);
|
||||
field_from_json(Obj,"secret",secret);
|
||||
field_from_json(Obj,"certificate",certificate);
|
||||
field_from_json(Obj,"radsec",radsec);
|
||||
field_from_json(Obj,"radsec_port",radsec_port);
|
||||
field_from_json(Obj,"radsec_secret",radsec_secret);
|
||||
field_from_json(Obj,"radsec_cacerts",radsec_cacerts);
|
||||
field_from_json(Obj,"radsec_cert",radsec_cert);
|
||||
field_from_json(Obj,"radsec_key",radsec_key);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -199,4 +199,63 @@ namespace OpenWifi::GWObjects {
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct ScriptRequest {
|
||||
uint64_t timeout=30;
|
||||
std::string serialNumber;
|
||||
std::string type;
|
||||
std::string script;
|
||||
std::string scriptId;
|
||||
uint64_t when=0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RadiusProxyServerEntry {
|
||||
std::string name;
|
||||
std::string ip;
|
||||
uint16_t port=0;
|
||||
uint64_t weight=0;
|
||||
std::string secret;
|
||||
std::string certificate;
|
||||
bool radsec=false;
|
||||
uint16_t radsec_port=2084;
|
||||
std::string radsec_secret;
|
||||
std::string radsec_key;
|
||||
std::string radsec_cert;
|
||||
std::string radsec_cacerts;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RadiusProxyServerConfig {
|
||||
std::string strategy;
|
||||
bool monitor=false;
|
||||
std::string monitorMethod;
|
||||
std::vector<std::string> methodParameters;
|
||||
std::vector<RadiusProxyServerEntry> servers;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RadiusProxyPool {
|
||||
std::string name;
|
||||
std::string description;
|
||||
RadiusProxyServerConfig authConfig;
|
||||
RadiusProxyServerConfig acctConfig;
|
||||
RadiusProxyServerConfig coaConfig;
|
||||
bool useByDefault=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RadiusProxyPoolList {
|
||||
std::vector<RadiusProxyPool> pools;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_to_json( Obj,"devices",devices);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"sourceIP",sourceIP);
|
||||
field_to_json( Obj,"variables", variables);
|
||||
field_to_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -111,7 +111,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_from_json( Obj,"devices",devices);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"sourceIP",sourceIP);
|
||||
field_from_json( Obj,"variables", variables);
|
||||
field_from_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -154,7 +154,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_to_json( Obj,"contacts",contacts);
|
||||
field_to_json( Obj,"location",location);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"sourceIP",sourceIP);
|
||||
field_to_json( Obj,"variables", variables);
|
||||
field_to_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -178,7 +178,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_from_json( Obj,"contacts",contacts);
|
||||
field_from_json( Obj,"location",location);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"sourceIP",sourceIP);
|
||||
field_from_json( Obj,"variables", variables);
|
||||
field_from_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -197,9 +197,7 @@ namespace OpenWifi::ProvObjects {
|
||||
info.to_json(Obj);
|
||||
field_to_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_to_json( Obj,"managementRoles",managementRoles);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"variables",variables);
|
||||
field_to_json( Obj,"defaultOperator",defaultOperator);
|
||||
field_to_json( Obj,"sourceIP",sourceIP);
|
||||
@@ -211,9 +209,7 @@ namespace OpenWifi::ProvObjects {
|
||||
info.from_json(Obj);
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"managementRoles",managementRoles);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"variables",variables);
|
||||
field_from_json( Obj,"defaultOperator",defaultOperator);
|
||||
field_from_json( Obj,"sourceIP",sourceIP);
|
||||
@@ -598,7 +594,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj, "location", location);
|
||||
field_to_json( Obj, "contact", contact);
|
||||
field_to_json( Obj, "deviceConfiguration",deviceConfiguration);
|
||||
field_to_json( Obj, "rrm",rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj, "managementPolicy",managementPolicy);
|
||||
field_to_json( Obj, "state",state);
|
||||
field_to_json( Obj, "devClass",devClass);
|
||||
@@ -619,7 +615,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"location",location);
|
||||
field_from_json( Obj,"contact",contact);
|
||||
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"state",state);
|
||||
field_from_json( Obj,"devClass",devClass);
|
||||
@@ -690,16 +686,14 @@ namespace OpenWifi::ProvObjects {
|
||||
info.to_json(Obj);
|
||||
field_to_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_to_json( Obj,"deviceTypes",deviceTypes);
|
||||
field_to_json( Obj,"configuration",configuration);
|
||||
field_to_json( Obj,"inUse",inUse);
|
||||
field_to_json( Obj,"variables",variables);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_to_json( Obj,"subscriberOnly",subscriberOnly);
|
||||
field_to_json( Obj,"entity", entity);
|
||||
field_to_json( Obj,"venue", venue);
|
||||
field_to_json( Obj,"subscriber", subscriber);
|
||||
field_to_json( Obj,"configuration",configuration);
|
||||
field_to_json( Obj,"inUse",inUse);
|
||||
field_to_json( Obj,"variables",variables);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
}
|
||||
|
||||
bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -707,16 +701,14 @@ namespace OpenWifi::ProvObjects {
|
||||
info.from_json(Obj);
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"deviceTypes",deviceTypes);
|
||||
field_from_json( Obj,"configuration",configuration);
|
||||
field_from_json( Obj,"inUse",inUse);
|
||||
field_from_json( Obj,"variables",variables);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_from_json( Obj,"subscriberOnly",subscriberOnly);
|
||||
field_from_json( Obj,"entity", entity);
|
||||
field_from_json( Obj,"venue", venue);
|
||||
field_from_json( Obj,"subscriber", subscriber);
|
||||
field_from_json( Obj,"configuration",configuration);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -896,6 +888,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"statusCode", statusCode);
|
||||
field_to_json( Obj,"deviceID", deviceID);
|
||||
field_to_json( Obj,"registrationId",registrationId);
|
||||
field_to_json( Obj,"operatorId",operatorId);
|
||||
}
|
||||
|
||||
bool SignupEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -912,6 +905,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"statusCode", statusCode);
|
||||
field_from_json( Obj,"deviceID", deviceID);
|
||||
field_from_json( Obj,"registrationId",registrationId);
|
||||
field_from_json( Obj,"operatorId",operatorId);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -994,6 +988,26 @@ namespace OpenWifi::ProvObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConfigurationDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json( Obj,"configuration", configuration);
|
||||
field_to_json( Obj,"rrm", rrm);
|
||||
field_to_json( Obj,"firmwareRCOnly", firmwareRCOnly);
|
||||
field_to_json( Obj,"firmwareUpgrade", firmwareUpgrade);
|
||||
}
|
||||
|
||||
bool ConfigurationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json( Obj,"configuration", configuration);
|
||||
field_from_json( Obj,"rrm", rrm);
|
||||
field_from_json( Obj,"firmwareRCOnly", firmwareRCOnly);
|
||||
field_from_json( Obj,"firmwareUpgrade", firmwareUpgrade);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json( Obj,"serialNumber", serialNumber);
|
||||
@@ -1006,7 +1020,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"serviceClass", serviceClass);
|
||||
field_to_json( Obj,"qrCode", qrCode);
|
||||
field_to_json( Obj,"geoCode", geoCode);
|
||||
field_to_json( Obj,"rrm", rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"state", state);
|
||||
field_to_json( Obj,"locale", locale);
|
||||
field_to_json( Obj,"billingCode", billingCode);
|
||||
@@ -1028,7 +1042,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"serviceClass", serviceClass);
|
||||
field_from_json( Obj,"qrCode", qrCode);
|
||||
field_from_json( Obj,"geoCode", geoCode);
|
||||
field_from_json( Obj,"rrm", rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"state", state);
|
||||
field_from_json( Obj,"locale", locale);
|
||||
field_from_json( Obj,"billingCode", billingCode);
|
||||
@@ -1077,7 +1091,7 @@ namespace OpenWifi::ProvObjects {
|
||||
}
|
||||
|
||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
if(O->has("name"))
|
||||
I.name = O->get("name").toString();
|
||||
|
||||
@@ -1127,41 +1141,17 @@ namespace OpenWifi::ProvObjects {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketNotificationContent::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"title",title);
|
||||
field_to_json(Obj,"type",type);
|
||||
field_to_json(Obj,"success",success);
|
||||
field_to_json(Obj,"errors",errors);
|
||||
field_to_json(Obj,"warnings",warnings);
|
||||
field_to_json(Obj,"timeStamp",timeStamp);
|
||||
field_to_json(Obj,"details",details);
|
||||
void DeviceRules::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"rcOnly",rcOnly);
|
||||
field_to_json(Obj,"rrm",rrm);
|
||||
field_to_json(Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
}
|
||||
|
||||
bool WebSocketNotificationContent::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
bool DeviceRules::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"title",title);
|
||||
field_from_json(Obj,"type",type);
|
||||
field_from_json(Obj,"success",success);
|
||||
field_from_json(Obj,"errors",errors);
|
||||
field_from_json(Obj,"warnings",warnings);
|
||||
field_from_json(Obj,"timeStamp",timeStamp);
|
||||
field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebSocketNotification::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"notification_id",notification_id);
|
||||
field_to_json(Obj,"content",content);
|
||||
}
|
||||
|
||||
bool WebSocketNotification::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"notification_id",notification_id);
|
||||
field_from_json(Obj,"content",content);
|
||||
field_from_json(Obj,"rcOnly",rcOnly);
|
||||
field_from_json(Obj,"rrm",rrm);
|
||||
field_from_json(Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
|
||||
@@ -62,6 +62,15 @@ namespace OpenWifi::ProvObjects {
|
||||
};
|
||||
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
|
||||
|
||||
struct DeviceRules {
|
||||
std::string rcOnly{"inherit"};
|
||||
std::string rrm{"inherit"};
|
||||
std::string firmwareUpgrade{"inherit"};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Entity {
|
||||
ObjectInfo info;
|
||||
Types::UUID_t parent;
|
||||
@@ -72,7 +81,7 @@ namespace OpenWifi::ProvObjects {
|
||||
Types::UUID_t managementPolicy;
|
||||
Types::UUIDvec_t deviceConfiguration;
|
||||
Types::UUIDvec_t devices;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
Types::StringVec sourceIP;
|
||||
Types::UUIDvec_t variables;
|
||||
Types::UUIDvec_t managementPolicies;
|
||||
@@ -107,7 +116,7 @@ namespace OpenWifi::ProvObjects {
|
||||
Types::UUIDvec_t deviceConfiguration;
|
||||
Types::UUIDvec_t contacts;
|
||||
std::string location;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
Types::StringVec sourceIP;
|
||||
Types::UUIDvec_t variables;
|
||||
Types::UUIDvec_t configurations;
|
||||
@@ -375,9 +384,7 @@ namespace OpenWifi::ProvObjects {
|
||||
DeviceConfigurationElementVec configuration;
|
||||
Types::StringVec inUse;
|
||||
Types::UUIDvec_t variables;
|
||||
std::string rrm;
|
||||
std::string firmwareUpgrade;
|
||||
bool firmwareRCOnly=false;
|
||||
DeviceRules deviceRules;
|
||||
bool subscriberOnly=false;
|
||||
std::string venue;
|
||||
std::string entity;
|
||||
@@ -401,7 +408,7 @@ namespace OpenWifi::ProvObjects {
|
||||
std::string location;
|
||||
std::string contact;
|
||||
std::string deviceConfiguration;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
Types::UUID_t managementPolicy;
|
||||
std::string state;
|
||||
std::string devClass;
|
||||
@@ -534,6 +541,7 @@ namespace OpenWifi::ProvObjects {
|
||||
uint64_t statusCode=0;
|
||||
std::string deviceID;
|
||||
std::string registrationId;
|
||||
std::string operatorId;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -581,9 +589,7 @@ namespace OpenWifi::ProvObjects {
|
||||
ObjectInfo info;
|
||||
Types::UUID_t managementPolicy;
|
||||
Types::UUIDvec_t managementRoles;
|
||||
std::string rrm;
|
||||
std::string firmwareUpgrade;
|
||||
bool firmwareRCOnly=true;
|
||||
DeviceRules deviceRules;
|
||||
std::vector<Variable> variables;
|
||||
bool defaultOperator=false;
|
||||
Types::StringVec sourceIP;
|
||||
@@ -632,6 +638,16 @@ namespace OpenWifi::ProvObjects {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ConfigurationDetails {
|
||||
DeviceConfigurationElementVec configuration;
|
||||
std::string rrm{"inherit"};
|
||||
std::string firmwareUpgrade{"inherit"};
|
||||
std::string firmwareRCOnly{"inherit"};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SubscriberDevice {
|
||||
ObjectInfo info;
|
||||
std::string serialNumber;
|
||||
@@ -644,7 +660,7 @@ namespace OpenWifi::ProvObjects {
|
||||
Types::UUID_t serviceClass;
|
||||
std::string qrCode;
|
||||
std::string geoCode;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
std::string state;
|
||||
std::string locale;
|
||||
std::string billingCode;
|
||||
@@ -663,28 +679,6 @@ namespace OpenWifi::ProvObjects {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WebSocketNotificationContent {
|
||||
std::string title,
|
||||
type,
|
||||
details;
|
||||
std::vector<std::string> success,
|
||||
errors,
|
||||
warnings;
|
||||
uint64_t timeStamp=std::time(nullptr);
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WebSocketNotification {
|
||||
inline static uint64_t xid=1;
|
||||
uint64_t notification_id=++xid;
|
||||
WebSocketNotificationContent content;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
|
||||
@@ -113,6 +113,8 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"userMustChangePassword",userMustChangePassword);
|
||||
field_to_json(Obj,"errorCode", errorCode);
|
||||
Obj.set("aclTemplate",AclTemplateObj);
|
||||
field_to_json(Obj,"errorCode", errorCode);
|
||||
field_to_json(Obj,"lastRefresh", lastRefresh_);
|
||||
}
|
||||
|
||||
bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -129,6 +131,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_from_json(Obj, "created", created_);
|
||||
field_from_json(Obj, "username", username_);
|
||||
field_from_json(Obj, "userMustChangePassword",userMustChangePassword);
|
||||
field_from_json(Obj,"lastRefresh", lastRefresh_);
|
||||
return true;
|
||||
} catch (...) {
|
||||
std::cout << "Cannot parse: WebToken" << std::endl;
|
||||
@@ -430,7 +433,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
SecurityObjects::NoteInfoVec NIV;
|
||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
|
||||
for(auto const &i:NIV) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note};
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
Notes.push_back(ii);
|
||||
}
|
||||
}
|
||||
@@ -443,7 +446,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
|
||||
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
|
||||
for(auto const &i:NewNotes) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note};
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
ExistingNotes.push_back(ii);
|
||||
}
|
||||
return true;
|
||||
@@ -588,6 +591,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"expires",expires);
|
||||
field_to_json(Obj,"idleTimeout",idleTimeout);
|
||||
field_to_json(Obj,"revocationDate",revocationDate);
|
||||
field_to_json(Obj,"lastRefresh", lastRefresh);
|
||||
}
|
||||
|
||||
bool Token::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -600,6 +604,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_from_json(Obj,"expires",expires);
|
||||
field_from_json(Obj,"idleTimeout",idleTimeout);
|
||||
field_from_json(Obj,"revocationDate",revocationDate);
|
||||
field_from_json(Obj,"lastRefresh", lastRefresh);
|
||||
return true;
|
||||
} catch(...) {
|
||||
std::cout << "Cannot parse: Token" << std::endl;
|
||||
|
||||
@@ -9,14 +9,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Data/LOB.h"
|
||||
#include "Poco/Data/LOBStream.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
uint64_t Now();
|
||||
namespace SecurityObjects {
|
||||
|
||||
|
||||
typedef std::string USER_ID_TYPE;
|
||||
|
||||
struct AclTemplate {
|
||||
@@ -26,8 +28,13 @@ namespace OpenWifi {
|
||||
bool Delete_ = true;
|
||||
bool PortalLogin_ = true;
|
||||
|
||||
AclTemplate() noexcept = default;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj); };
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
static_assert( std::is_nothrow_move_constructible_v<AclTemplate> );
|
||||
|
||||
struct WebToken {
|
||||
std::string access_token_;
|
||||
@@ -41,6 +48,7 @@ namespace OpenWifi {
|
||||
uint64_t idle_timeout_=0;
|
||||
AclTemplate acl_template_;
|
||||
uint64_t created_=0;
|
||||
uint64_t lastRefresh_=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -54,7 +62,7 @@ namespace OpenWifi {
|
||||
std::string UserTypeToString(USER_ROLE U);
|
||||
|
||||
struct NoteInfo {
|
||||
uint64_t created=0; // = std::time(nullptr);
|
||||
uint64_t created=0; // = OpenWifi::Now();
|
||||
std::string createdBy;
|
||||
std::string note;
|
||||
|
||||
@@ -93,7 +101,7 @@ namespace OpenWifi {
|
||||
std::string uuid;
|
||||
std::string question;
|
||||
std::string method;
|
||||
uint64_t created = std::time(nullptr);
|
||||
uint64_t created = OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -255,7 +263,7 @@ namespace OpenWifi {
|
||||
std::string locale;
|
||||
std::string message;
|
||||
uint64_t sent=0;
|
||||
uint64_t created=std::time(nullptr);
|
||||
uint64_t created=OpenWifi::Now();
|
||||
uint64_t expires=0;
|
||||
uint64_t completed=0;
|
||||
uint64_t canceled=0;
|
||||
@@ -292,6 +300,7 @@ namespace OpenWifi {
|
||||
uint64_t expires=0;
|
||||
uint64_t idleTimeout=0;
|
||||
uint64_t revocationDate=0;
|
||||
uint64_t lastRefresh=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -302,7 +311,6 @@ namespace OpenWifi {
|
||||
std::string type;
|
||||
uint64_t created=0;
|
||||
std::string name;
|
||||
// Poco::Data::LOB<char> avatar;
|
||||
Poco::Data::BLOB avatar;
|
||||
};
|
||||
|
||||
|
||||
@@ -280,6 +280,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_to_json(Obj, "ipv6", ipv6);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "manufacturer", manufacturer);
|
||||
}
|
||||
|
||||
bool Association::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -293,6 +294,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_from_json(Obj, "ipv6", ipv6);
|
||||
field_from_json(Obj, "tx", tx);
|
||||
field_from_json(Obj, "rx", rx);
|
||||
field_from_json(Obj, "manufacturer", manufacturer);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
@@ -324,6 +326,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_to_json(Obj, "ipv6", ipv6);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "manufacturer", manufacturer);
|
||||
}
|
||||
|
||||
bool Client::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -335,6 +338,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_from_json(Obj, "ipv6", ipv6);
|
||||
field_from_json(Obj, "tx", tx);
|
||||
field_from_json(Obj, "rx", rx);
|
||||
field_from_json(Obj, "manufacturer", manufacturer);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
@@ -562,4 +566,38 @@ namespace OpenWifi::SubObjects {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StatsEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "timestamp", timestamp);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
}
|
||||
|
||||
bool StatsEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "timestamp", timestamp);
|
||||
field_from_json(Obj, "tx", tx);
|
||||
field_from_json(Obj, "rx", rx);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StatsBlock::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "modified", modified);
|
||||
field_to_json(Obj, "external", external);
|
||||
field_to_json(Obj, "internal", internal);
|
||||
}
|
||||
|
||||
bool StatsBlock::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "modified", modified);
|
||||
field_from_json(Obj, "external", external);
|
||||
field_from_json(Obj, "internal", internal);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,7 @@ namespace OpenWifi::SubObjects {
|
||||
std::string ipv6;
|
||||
uint64_t tx=0;
|
||||
uint64_t rx=0;
|
||||
std::string manufacturer;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -179,6 +180,7 @@ namespace OpenWifi::SubObjects {
|
||||
std::string ipv6;
|
||||
uint64_t tx=0;
|
||||
uint64_t rx=0;
|
||||
std::string manufacturer;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -298,6 +300,23 @@ namespace OpenWifi::SubObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct StatsEntry {
|
||||
uint64_t timestamp=0;
|
||||
uint64_t tx=0;
|
||||
uint64_t rx=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct StatsBlock {
|
||||
uint64_t modified=0;
|
||||
std::vector<StatsEntry> external, internal;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OWSUB_RESTAPI_SUBOBJECTS_H
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer){
|
||||
Utils::SetThreadName("strg-archiver");
|
||||
auto now = OpenWifi::Now();
|
||||
for(const auto &i:DBs_) {
|
||||
if (!Poco::icompare(i.DBName, "healthchecks")) {
|
||||
|
||||
@@ -85,17 +85,18 @@ namespace OpenWifi {
|
||||
bool CreateDefaultDevice(std::string & SerialNumber, std::string & Capabilities, std::string & Firmware, std::string &Compatible,const Poco::Net::IPAddress & IPAddress);
|
||||
|
||||
bool GetDevice(std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select, std::vector<GWObjects::Device> &Devices);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices, const std::string & orderBy="");
|
||||
// bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select, std::vector<GWObjects::Device> &Devices, const std::string & orderBy="");
|
||||
bool DeleteDevice(std::string &SerialNumber);
|
||||
bool UpdateDevice(GWObjects::Device &);
|
||||
bool DeviceExists(std::string & SerialNumber);
|
||||
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
|
||||
bool GetDeviceCount(uint64_t & Count);
|
||||
bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany, std::vector<std::string> & SerialNumbers);
|
||||
bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany, std::vector<std::string> & SerialNumbers, const std::string & orderBy="");
|
||||
bool GetDeviceFWUpdatePolicy(std::string & SerialNumber, std::string & Policy);
|
||||
bool SetDevicePassword(std::string & SerialNumber, std::string & Password);
|
||||
bool UpdateSerialNumberCache();
|
||||
void GetDeviceDbFieldList( Types::StringVec & Fields);
|
||||
|
||||
bool ExistingConfiguration(std::string &SerialNumber, uint64_t CurrentConfig, std::string &NewConfig, uint64_t &);
|
||||
|
||||
@@ -129,9 +130,11 @@ namespace OpenWifi {
|
||||
bool GetReadyToExecuteCommands( uint64_t Offset, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands );
|
||||
bool CommandExecuted(std::string & UUID);
|
||||
bool CommandCompleted(std::string & UUID, const Poco::JSON::Object & ReturnVars, const std::chrono::duration<double, std::milli> & execution_time, bool FullCommand);
|
||||
bool AttachFileToCommand(std::string & UUID);
|
||||
// bool AttachFileToCommand(std::string & UUID);
|
||||
bool AttachFileDataToCommand(std::string & UUID, const std::stringstream &s);
|
||||
bool CancelWaitFile( std::string & UUID, std::string & ErrorText );
|
||||
bool GetAttachedFile(std::string & UUID, const std::string & SerialNumber, const std::string & FileName, std::string &Type);
|
||||
// bool GetAttachedFile(std::string & UUID, const std::string & SerialNumber, const std::string & FileName, std::string &Type);
|
||||
bool GetAttachedFileContent(std::string & UUID, const std::string & SerialNumber, std::string & FileContent, std::string &Type);
|
||||
bool RemoveAttachedFile(std::string & UUID);
|
||||
bool SetCommandResult(std::string & UUID, std::string & Result);
|
||||
bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace OpenWifi {
|
||||
TelemetryClient::TelemetryClient(
|
||||
std::string UUID,
|
||||
uint64_t SerialNumber,
|
||||
Poco::SharedPtr<Poco::Net::WebSocket> WSock,
|
||||
std::unique_ptr<Poco::Net::WebSocket> WSock,
|
||||
Poco::Net::SocketReactor& Reactor,
|
||||
Poco::Logger &Logger):
|
||||
UUID_(std::move(UUID)),
|
||||
@@ -24,7 +24,6 @@ namespace OpenWifi {
|
||||
Reactor_(Reactor),
|
||||
Logger_(Logger),
|
||||
WS_(std::move(WSock)) {
|
||||
std::cout << "Telemetry client creation" << std::endl;
|
||||
try {
|
||||
std::thread T([this]() { this->CompleteStartup(); });
|
||||
T.detach();
|
||||
@@ -35,14 +34,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void TelemetryClient::CompleteStartup() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
try {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Socket_ = *WS_;
|
||||
CId_ = Utils::FormatIPv6(Socket_.peerAddress().toString());
|
||||
|
||||
// auto SS = static_cast<Poco::Net::SecureStreamSocketImpl*>((WS_->impl()));
|
||||
// SS->havePeerCertificate();
|
||||
|
||||
if (TelemetryStream()->RegisterClient(UUID_, this)) {
|
||||
auto TS = Poco::Timespan(240, 0);
|
||||
|
||||
@@ -60,7 +56,7 @@ namespace OpenWifi {
|
||||
*WS_, Poco::NObserver<TelemetryClient, Poco::Net::ErrorNotification>(
|
||||
*this, &TelemetryClient::OnSocketError));
|
||||
Registered_ = true;
|
||||
Logger().information(fmt::format("CONNECTION({}): completed.", CId_));
|
||||
Logger().information(fmt::format("CONNECTION({}): Connection completed.", CId_));
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
@@ -73,7 +69,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
TelemetryClient::~TelemetryClient() {
|
||||
Logger().information("Closing telemetry session.");
|
||||
Logger().information(fmt::format("CONNECTION({}): Closing connection.", CId_));
|
||||
if(Registered_ && WS_)
|
||||
{
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
@@ -85,13 +81,8 @@ namespace OpenWifi {
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
Poco::NObserver<TelemetryClient,
|
||||
Poco::Net::ErrorNotification>(*this,&TelemetryClient::OnSocketError));
|
||||
(*WS_).close();
|
||||
Socket_.shutdown();
|
||||
} else {
|
||||
if(WS_)
|
||||
(*WS_).close();
|
||||
Socket_.shutdown();
|
||||
}
|
||||
WS_->close();
|
||||
}
|
||||
|
||||
bool TelemetryClient::Send(const std::string &Payload) {
|
||||
@@ -112,21 +103,19 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().information(fmt::format("SOCKET-SHUTDOWN({}): Orderly shutdown.", CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().information(fmt::format("SOCKET-ERROR({}): Closing.",CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
try
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
ProcessIncomingFrame();
|
||||
}
|
||||
catch (const Poco::Exception & E)
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenWifi {
|
||||
TelemetryClient(
|
||||
std::string UUID,
|
||||
uint64_t SerialNumber,
|
||||
Poco::SharedPtr<Poco::Net::WebSocket> WSock,
|
||||
std::unique_ptr<Poco::Net::WebSocket> WSock,
|
||||
Poco::Net::SocketReactor& Reactor,
|
||||
Poco::Logger &Logger);
|
||||
~TelemetryClient();
|
||||
@@ -40,7 +40,7 @@ namespace OpenWifi {
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::StreamSocket Socket_;
|
||||
std::string CId_;
|
||||
Poco::SharedPtr<Poco::Net::WebSocket> WS_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
bool Registered_=false;
|
||||
void SendTelemetryShutdown();
|
||||
void CompleteStartup();
|
||||
|
||||
@@ -16,13 +16,17 @@ namespace OpenWifi {
|
||||
int TelemetryStream::Start() {
|
||||
Running_ = true;
|
||||
Messages_->Readable_ += Poco::delegate(this,&TelemetryStream::onMessage);
|
||||
ReactorPool_.Start("TelemetryWebSocketPool_");
|
||||
// ReactorPool_.Start("TelemetryWebSocketPool_");
|
||||
Thr_.start(Reactor_);
|
||||
Utils::SetThreadName(Thr_,"telemetry-svr");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TelemetryStream::Stop() {
|
||||
Logger().notice("Stopping reactors...");
|
||||
ReactorPool_.Stop();
|
||||
// ReactorPool_.Stop();
|
||||
Reactor_.stop();
|
||||
Thr_.join();
|
||||
if(Running_) {
|
||||
Running_ = false;
|
||||
Messages_->Readable_ -= Poco::delegate( this, &TelemetryStream::onMessage);
|
||||
@@ -129,7 +133,4 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -47,16 +47,17 @@ namespace OpenWifi {
|
||||
void UpdateEndPoint(uint64_t SerialNumber, const std::string &PayLoad);
|
||||
bool RegisterClient(const std::string &UUID, TelemetryClient *Client);
|
||||
void DeRegisterClient(const std::string &UUID);
|
||||
Poco::Net::SocketReactor & NextReactor() { return ReactorPool_.NextReactor(); }
|
||||
Poco::Net::SocketReactor & NextReactor() { return Reactor_; }
|
||||
|
||||
void onMessage(bool& b);
|
||||
|
||||
private:
|
||||
std::atomic_bool Running_=false;
|
||||
volatile std::atomic_bool Running_=false;
|
||||
std::map<std::string, TelemetryClient *> Clients_; // uuid -> client
|
||||
std::map<uint64_t, std::set<std::string>> SerialNumbers_; // serialNumber -> uuid
|
||||
ReactorPool ReactorPool_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
std::unique_ptr<FIFO<QueueUpdate>> Messages_=std::make_unique<FIFO<QueueUpdate>>(100);
|
||||
Poco::Thread Thr_;
|
||||
|
||||
TelemetryStream() noexcept:
|
||||
SubSystemServer("TelemetryServer", "TELEMETRY-SVR", "openwifi.telemetry") {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/Base64Encoder.h"
|
||||
|
||||
#include "Poco/zlib.h"
|
||||
|
||||
#include "WS_Server.h"
|
||||
@@ -18,13 +20,16 @@
|
||||
#include "CommandManager.h"
|
||||
#include "StateUtils.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "Daemon.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "FindCountry.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void WSConnection::LogException(const Poco::Exception &E) {
|
||||
Logger().information(fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
|
||||
}
|
||||
@@ -41,9 +46,9 @@ namespace OpenWifi {
|
||||
PeerAddress_ = SS->peerAddress().host();
|
||||
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
|
||||
if (!SS->secure()) {
|
||||
Logger().error(fmt::format("{}: Connection is NOT secure.", CId_));
|
||||
poco_error(Logger(),fmt::format("{}: Connection is NOT secure.", CId_));
|
||||
} else {
|
||||
Logger().debug(fmt::format("{}: Connection is secure.", CId_));
|
||||
poco_trace(Logger(),fmt::format("{}: Connection is secure.", CId_));
|
||||
}
|
||||
|
||||
if (SS->havePeerCertificate()) {
|
||||
@@ -55,15 +60,15 @@ namespace OpenWifi {
|
||||
if (WebSocketServer()->ValidateCertificate(CId_, PeerCert)) {
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
CertValidation_ = GWObjects::MISMATCH_SERIAL;
|
||||
Logger().debug(fmt::format("{}: Valid certificate: CN={}", CId_, CN_));
|
||||
poco_trace(Logger(),fmt::format("{}: Valid certificate: CN={}", CId_, CN_));
|
||||
} else {
|
||||
Logger().debug(fmt::format("{}: Certificate is not valid", CId_));
|
||||
poco_error(Logger(),fmt::format("{}: Certificate is not valid", CId_));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
LogException(E);
|
||||
}
|
||||
} else {
|
||||
Logger().error(fmt::format("{}: No certificates available..", CId_));
|
||||
poco_error(Logger(),fmt::format("{}: No certificates available..", CId_));
|
||||
}
|
||||
|
||||
if (WebSocketServer::IsSim(CN_) && !WebSocketServer()->IsSimEnabled()) {
|
||||
@@ -108,7 +113,7 @@ namespace OpenWifi {
|
||||
Reactor_.addEventHandler(*WS_, Poco::NObserver<WSConnection, Poco::Net::ErrorNotification>(
|
||||
*this, &WSConnection::OnSocketError));
|
||||
Registered_ = true;
|
||||
Logger().information(fmt::format("CONNECTION({}): completed.", CId_));
|
||||
poco_debug(Logger(),fmt::format("CONNECTION({}): completed.", CId_));
|
||||
return;
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
Logger().error(fmt::format("CONNECTION({}): Poco::Exception Certificate Validation failed during connection. Device will have to retry.",
|
||||
@@ -149,11 +154,10 @@ namespace OpenWifi {
|
||||
WSConnection::WSConnection(Poco::Net::StreamSocket &socket, [[maybe_unused]] Poco::Net::SocketReactor &reactor)
|
||||
: Logger_(WebSocketServer()->Logger()) ,
|
||||
Socket_(socket),
|
||||
Reactor_(WebSocketServer()->GetNextReactor())
|
||||
Reactor_(ReactorThreadPool()->NextReactor())
|
||||
{
|
||||
std::thread T([=]() { CompleteStartup(); });
|
||||
T.detach();
|
||||
// CompleteStartup();
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string & SerialNumber) {
|
||||
@@ -161,7 +165,7 @@ namespace OpenWifi {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, std::time(nullptr));
|
||||
Details.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
@@ -173,6 +177,7 @@ namespace OpenWifi {
|
||||
|
||||
WSConnection::~WSConnection() {
|
||||
|
||||
poco_debug(Logger(),fmt::format("{}: Removing connection for {}.", CId_, SerialNumber_));
|
||||
if (ConnectionId_)
|
||||
DeviceRegistry()->UnRegister(SerialNumberInt_, ConnectionId_);
|
||||
|
||||
@@ -198,23 +203,28 @@ namespace OpenWifi {
|
||||
std::thread t([s]() { NotifyKafkaDisconnect(s); });
|
||||
t.detach();
|
||||
}
|
||||
|
||||
WebSocketClientNotificationDeviceDisconnected(SerialNumber_);
|
||||
}
|
||||
|
||||
bool WSConnection::LookForUpgrade(uint64_t UUID) {
|
||||
bool WSConnection::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 == Conn_->Conn_.PendingUUID))
|
||||
if (GoodConfig && (GoodConfig == UUID || GoodConfig == Conn_->Conn_.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;
|
||||
}
|
||||
@@ -224,11 +234,13 @@ namespace OpenWifi {
|
||||
// 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;
|
||||
Conn_->Conn_.PendingUUID = D.UUID;
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
@@ -254,44 +266,13 @@ namespace OpenWifi {
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::COMMAND_EXECUTED);
|
||||
CommandManager()->PostCommand(SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
|
||||
WebSocketClientNotificationDeviceConfigurationChange(D.SerialNumber, UUID, UpgradedUUID);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WSConnection::ExtractBase64CompressedData(const std::string &CompressedData,
|
||||
std::string &UnCompressedData, uint64_t compress_sz ) {
|
||||
std::istringstream ifs(CompressedData);
|
||||
Poco::Base64Decoder b64in(ifs);
|
||||
std::ostringstream ofs;
|
||||
Poco::StreamCopier::copyStream(b64in, ofs);
|
||||
|
||||
int factor = 20;
|
||||
unsigned long MaxSize = compress_sz ? (unsigned long) (compress_sz + 5000) : (unsigned long) (ofs.str().size() * factor);
|
||||
while(true) {
|
||||
std::vector<uint8_t> UncompressedBuffer(MaxSize);
|
||||
unsigned long FinalSize = MaxSize;
|
||||
auto status = uncompress((uint8_t *)&UncompressedBuffer[0], &FinalSize,
|
||||
(uint8_t *)ofs.str().c_str(), ofs.str().size());
|
||||
if(status==Z_OK) {
|
||||
UncompressedBuffer[FinalSize] = 0;
|
||||
UnCompressedData = (char *)&UncompressedBuffer[0];
|
||||
return true;
|
||||
}
|
||||
if(status==Z_BUF_ERROR) {
|
||||
if(factor<300) {
|
||||
factor+=10;
|
||||
MaxSize = ofs.str().size() * factor;
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WSConnection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
|
||||
CommandManager()->PostCommandResult(SerialNumber_, *Doc);
|
||||
}
|
||||
@@ -323,7 +304,7 @@ namespace OpenWifi {
|
||||
compress_sz = ParamsObj->get("compress_sz");
|
||||
}
|
||||
|
||||
if (ExtractBase64CompressedData(CompressedData, UncompressedData, 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;
|
||||
@@ -366,7 +347,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if (Conn_ != nullptr)
|
||||
Conn_->Conn_.LastContact = std::time(nullptr);
|
||||
Conn_->Conn_.LastContact = OpenWifi::Now();
|
||||
|
||||
switch (EventType) {
|
||||
case uCentralProtocol::Events::ET_CONNECT: {
|
||||
@@ -383,14 +364,14 @@ namespace OpenWifi {
|
||||
Conn_->Conn_.UUID = UUID;
|
||||
Conn_->Conn_.Firmware = Firmware;
|
||||
Conn_->Conn_.PendingUUID = 0;
|
||||
Conn_->Conn_.LastContact = std::time(nullptr);
|
||||
Conn_->Conn_.LastContact = OpenWifi::Now();
|
||||
Conn_->Conn_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
|
||||
CId_ = SerialNumber_ + "@" + CId_;
|
||||
// We need to verify the certificate if we have one
|
||||
if ((!CN_.empty() && Utils::SerialNumberMatch(CN_, SerialNumber_)) ||
|
||||
WebSocketServer()->IsSimSerialNumber(CN_)) {
|
||||
CertValidation_ = GWObjects::VERIFIED;
|
||||
poco_information(Logger(), fmt::format("CONNECT({}): Fully validated and authenticated device..", CId_));
|
||||
poco_information(Logger(), fmt::format("CONNECT({}): Fully validated and authenticated device.", CId_));
|
||||
} else {
|
||||
if (CN_.empty())
|
||||
poco_information(Logger(), fmt::format("CONNECT({}): Not authenticated or validated.", CId_));
|
||||
@@ -418,28 +399,35 @@ namespace OpenWifi {
|
||||
if(!Firmware.empty() && Firmware!=DeviceInfo.Firmware) {
|
||||
DeviceInfo.Firmware = Firmware;
|
||||
Updated = true;
|
||||
WebSocketClientNotificationDeviceFirmwareUpdated(SerialNumber_, Firmware);
|
||||
}
|
||||
|
||||
if(DeviceInfo.locale != Conn_->Conn_.locale) {
|
||||
DeviceInfo.locale = Conn_->Conn_.locale;
|
||||
Updated = true;
|
||||
}
|
||||
|
||||
if(Compatible_ != DeviceInfo.DeviceType) {
|
||||
DeviceInfo.DeviceType = Compatible_;
|
||||
Updated = true;
|
||||
}
|
||||
|
||||
if(Updated) {
|
||||
StorageService()->UpdateDevice(DeviceInfo);
|
||||
}
|
||||
LookForUpgrade(UUID);
|
||||
uint64_t UpgradedUUID=0;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
Conn_->Conn_.UUID = UpgradedUUID;
|
||||
}
|
||||
|
||||
Conn_->Conn_.Compatible = Compatible_;
|
||||
|
||||
WebSocketClientNotificationDeviceConnected(SerialNumber_);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
ParamsObj->set("locale", Conn_->Conn_.locale );
|
||||
ParamsObj->set(uCentralProtocol::TIMESTAMP, std::time(nullptr));
|
||||
ParamsObj->set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
@@ -475,13 +463,14 @@ namespace OpenWifi {
|
||||
CId_, UUID, request_uuid));
|
||||
}
|
||||
|
||||
Conn_->Conn_.UUID = UUID;
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
Conn_->Conn_.UUID = UpgradedUUID;
|
||||
Conn_->LastStats = StateStr;
|
||||
|
||||
LookForUpgrade(UUID);
|
||||
GWObjects::Statistics Stats{
|
||||
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
|
||||
Stats.Recorded = std::time(nullptr);
|
||||
Stats.Recorded = OpenWifi::Now();
|
||||
StorageService()->AddStatisticsData(Stats);
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, StateStr);
|
||||
@@ -496,6 +485,12 @@ namespace OpenWifi {
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
|
||||
}
|
||||
|
||||
WebSocketNotification<WebNotificationSingleDevice> N;
|
||||
N.content.serialNumber = SerialNumber_;
|
||||
N.type = "device_statistics";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
|
||||
} else {
|
||||
poco_warning(Logger(), fmt::format("STATE({}): Invalid request. Missing serial, uuid, or state", CId_));
|
||||
}
|
||||
@@ -529,13 +524,14 @@ namespace OpenWifi {
|
||||
UUID, request_uuid));
|
||||
}
|
||||
|
||||
Conn_->Conn_.UUID = UUID;
|
||||
LookForUpgrade(UUID);
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
Conn_->Conn_.UUID = UpgradedUUID;
|
||||
|
||||
GWObjects::HealthCheck Check;
|
||||
|
||||
Check.SerialNumber = SerialNumber_;
|
||||
Check.Recorded = std::time(nullptr);
|
||||
Check.Recorded = OpenWifi::Now();
|
||||
Check.UUID = UUID;
|
||||
Check.Data = CheckData;
|
||||
Check.Sanity = Sanity;
|
||||
@@ -550,7 +546,7 @@ namespace OpenWifi {
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
ParamsObj->set("timestamp", std::time(nullptr));
|
||||
ParamsObj->set("timestamp", OpenWifi::Now());
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
|
||||
}
|
||||
@@ -722,27 +718,38 @@ namespace OpenWifi {
|
||||
if (TelemetryReporting_) {
|
||||
if (ParamsObj->has("data")) {
|
||||
auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
|
||||
Payload->set("timestamp", std::time(nullptr));
|
||||
Payload->set("timestamp", OpenWifi::Now());
|
||||
std::ostringstream SS;
|
||||
Payload->stringify(SS);
|
||||
auto now=OpenWifi::Now();
|
||||
if (TelemetryWebSocketRefCount_) {
|
||||
std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
|
||||
TelemetryWebSocketPackets_++;
|
||||
Conn_->Conn_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->UpdateEndPoint(SerialNumberInt_, SS.str());
|
||||
if(now<TelemetryWebSocketTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
|
||||
TelemetryWebSocketPackets_++;
|
||||
Conn_->Conn_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->UpdateEndPoint(SerialNumberInt_, SS.str());
|
||||
} else {
|
||||
StopWebSocketTelemetry();
|
||||
}
|
||||
}
|
||||
if (TelemetryKafkaRefCount_ && KafkaManager()->Enabled()) {
|
||||
std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl;
|
||||
TelemetryKafkaPackets_++;
|
||||
Conn_->Conn_.kafkaPackets = TelemetryKafkaPackets_;
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
|
||||
SS.str());
|
||||
if (TelemetryKafkaRefCount_) {
|
||||
if(KafkaManager()->Enabled() && now<TelemetryKafkaTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl;
|
||||
TelemetryKafkaPackets_++;
|
||||
Conn_->Conn_.kafkaPackets = TelemetryKafkaPackets_;
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
|
||||
SS.str());
|
||||
} else {
|
||||
StopKafkaTelemetry();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cout << SerialNumber_ << ": Invalid telemetry" << std::endl;
|
||||
poco_debug(Logger(),fmt::format("TELEMETRY({}): Invalid telemetry packet.",SerialNumber_));
|
||||
}
|
||||
} else {
|
||||
std::cout << SerialNumber_ << ":Ignoring telemetry" << std::endl;
|
||||
// if we are ignoring telemetry, then close it down on the device.
|
||||
poco_debug(Logger(),fmt::format("TELEMETRY({}): Stopping runaway telemetry.",SerialNumber_));
|
||||
StopTelemetry();
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -756,7 +763,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool WSConnection::StartTelemetry() {
|
||||
std::cout << "Start telemetry for " << SerialNumber_ << std::endl;
|
||||
// std::cout << "Start telemetry for " << SerialNumber_ << std::endl;
|
||||
poco_information(Logger(), fmt::format("TELEMETRY({}): Starting.", CId_));
|
||||
Poco::JSON::Object StartMessage;
|
||||
StartMessage.set("jsonrpc", "2.0");
|
||||
@@ -779,7 +786,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool WSConnection::StopTelemetry() {
|
||||
std::cout << "Stop telemetry for " << SerialNumber_ << std::endl;
|
||||
// std::cout << "Stop telemetry for " << SerialNumber_ << std::endl;
|
||||
poco_information(Logger(), fmt::format("TELEMETRY({}): Stopping.", CId_));
|
||||
Poco::JSON::Object StopMessage;
|
||||
StopMessage.set("jsonrpc", "2.0");
|
||||
@@ -806,10 +813,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool WSConnection::SetWebSocketTelemetryReporting(uint64_t Interval,
|
||||
uint64_t TelemetryWebSocketTimer) {
|
||||
uint64_t LifeTime) {
|
||||
std::lock_guard G(Mutex_);
|
||||
TelemetryWebSocketRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
|
||||
auto TelemetryWebSocketTimer = LifeTime + OpenWifi::Now();
|
||||
TelemetryWebSocketTimer_ = std::max(TelemetryWebSocketTimer, TelemetryWebSocketTimer_);
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
@@ -819,10 +827,11 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WSConnection::SetKafkaTelemetryReporting(uint64_t Interval, uint64_t TelemetryKafkaTimer) {
|
||||
bool WSConnection::SetKafkaTelemetryReporting(uint64_t Interval, uint64_t LifeTime) {
|
||||
std::lock_guard G(Mutex_);
|
||||
TelemetryKafkaRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
|
||||
auto TelemetryKafkaTimer = LifeTime + OpenWifi::Now();
|
||||
TelemetryKafkaTimer_ = std::max(TelemetryKafkaTimer, TelemetryKafkaTimer_);
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
@@ -939,7 +948,7 @@ namespace OpenWifi {
|
||||
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
|
||||
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
PingDetails.set(uCentralProtocol::TIMESTAMP, std::time(nullptr));
|
||||
PingDetails.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
PingDetails.set("locale", Conn_->Conn_.locale );
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
@@ -976,10 +985,15 @@ namespace OpenWifi {
|
||||
fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
|
||||
CId_, IncomingMessageStr));
|
||||
}
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
|
||||
ProcessIncomingRadiusData(IncomingJSON);
|
||||
} else {
|
||||
poco_warning(Logger(), fmt::format(
|
||||
"FRAME({}): illegal transaction header, missing 'jsonrpc'", CId_));
|
||||
Errors_++;
|
||||
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;
|
||||
@@ -1044,6 +1058,8 @@ namespace OpenWifi {
|
||||
CId_, std::string{E.what()}, IncomingMessageStr));
|
||||
return delete this;
|
||||
} catch (...) {
|
||||
poco_error(Logger(),fmt::format("Device {} must be disconnected. Unknown exception.", CId_));
|
||||
std::cout << "Device " << CId_ << " must be disconnected due to exception..." << std::endl;
|
||||
return delete this;
|
||||
}
|
||||
|
||||
@@ -1063,4 +1079,64 @@ namespace OpenWifi {
|
||||
return BytesSent == Payload.size();
|
||||
}
|
||||
|
||||
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 WSConnection::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 WSConnection::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 WSConnection::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 WSConnection::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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,18 @@ namespace OpenWifi {
|
||||
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);
|
||||
bool LookForUpgrade(const 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_; }
|
||||
@@ -64,22 +71,22 @@ namespace OpenWifi {
|
||||
uint64_t SerialNumberInt_=0;
|
||||
std::string Compatible_;
|
||||
std::shared_ptr<DeviceRegistry::ConnectionEntry> Conn_;
|
||||
bool Registered_ = false ;
|
||||
volatile bool Registered_ = false ;
|
||||
std::string CId_;
|
||||
std::string CN_;
|
||||
GWObjects::CertificateValidation CertValidation_ = GWObjects::CertificateValidation::NO_CERTIFICATE;
|
||||
uint64_t Errors_=0;
|
||||
bool Connected_=false;
|
||||
volatile bool Connected_=false;
|
||||
uint64_t ConnectionId_=0;
|
||||
Poco::Net::IPAddress PeerAddress_;
|
||||
mutable std::atomic_bool TelemetryReporting_ = false;
|
||||
mutable uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
mutable uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
mutable uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
mutable uint64_t TelemetryKafkaTimer_ = 0 ;
|
||||
mutable uint64_t TelemetryInterval_ = 0;
|
||||
mutable uint64_t TelemetryWebSocketPackets_=0;
|
||||
mutable uint64_t TelemetryKafkaPackets_=0;
|
||||
volatile std::atomic_bool TelemetryReporting_ = false;
|
||||
volatile uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
volatile uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
uint64_t TelemetryKafkaTimer_ = 0 ;
|
||||
uint64_t TelemetryInterval_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketPackets_=0;
|
||||
volatile uint64_t TelemetryKafkaPackets_=0;
|
||||
|
||||
void CompleteStartup();
|
||||
bool StartTelemetry();
|
||||
|
||||
@@ -9,22 +9,38 @@
|
||||
#include "Poco/Environment.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ReactorPool {
|
||||
class ReactorThreadPool {
|
||||
public:
|
||||
explicit ReactorPool(unsigned int NumberOfThreads = Poco::Environment::processorCount())
|
||||
: NumberOfThreads_(NumberOfThreads) {}
|
||||
explicit ReactorThreadPool() {
|
||||
if(Poco::Environment::processorCount()>8)
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()/2;
|
||||
else
|
||||
NumberOfThreads_ = 2;
|
||||
Start("ReactorThreadPool");
|
||||
}
|
||||
|
||||
~ ReactorThreadPool() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Start(const std::string & ThreadNamePrefix) {
|
||||
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);
|
||||
NewThread->setName(ThreadNamePrefix + std::to_string(i));
|
||||
std::string ThreadName{ThreadNamePrefix + "#" + 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();
|
||||
@@ -34,15 +50,18 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor &NextReactor() {
|
||||
std::lock_guard G(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
std::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(); }
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
int WebSocketServer::Start() {
|
||||
ReactorPool_.Start("DeviceReactorPool_");
|
||||
// ReactorPool_.Start("DeviceReactorPool_");
|
||||
for(const auto & Svr : ConfigServersList_ ) {
|
||||
Logger().notice( fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}",
|
||||
Svr.Address(),
|
||||
@@ -45,7 +45,7 @@ namespace OpenWifi {
|
||||
IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
|
||||
Logger().information( fmt::format("Certificate Issuer Name:{}",IssuerCert_->issuerName()));
|
||||
}
|
||||
auto NewSocketAcceptor = std::make_unique<Poco::Net::ParallelSocketAcceptor<WSConnection, Poco::Net::SocketReactor>>(Sock, Reactor_, Poco::Environment::processorCount()*2);
|
||||
auto NewSocketAcceptor = std::make_unique<ws_server_reactor_type_t>(Sock, Reactor_); // , 2 /*Poco::Environment::processorCount()*2) */ );
|
||||
Acceptors_.push_back(std::move(NewSocketAcceptor));
|
||||
}
|
||||
|
||||
@@ -65,14 +65,16 @@ namespace OpenWifi {
|
||||
SimulatorId_ = MicroService::instance().ConfigGetString("simulatorid","");
|
||||
SimulatorEnabled_ = !SimulatorId_.empty();
|
||||
|
||||
ReactorThread_.setStackSize(3000000);
|
||||
ReactorThread_.start(Reactor_);
|
||||
Utils::SetThreadName(ReactorThread_,"device-reactor");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebSocketServer::Stop() {
|
||||
Logger().notice("Stopping reactors...");
|
||||
ReactorPool_.Stop();
|
||||
// ReactorPool_.Stop();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/ParallelSocketAcceptor.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
|
||||
#include "WS_Connection.h"
|
||||
#include "WS_ReactorPool.h"
|
||||
@@ -35,7 +36,7 @@ namespace OpenWifi {
|
||||
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(); }
|
||||
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
|
||||
|
||||
inline bool IsSimSerialNumber(const std::string & SerialNumber) const {
|
||||
return IsSim(SerialNumber) && SerialNumber == SimulatorId_;
|
||||
@@ -54,10 +55,11 @@ namespace OpenWifi {
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
std::vector<std::unique_ptr<Poco::Net::ParallelSocketAcceptor<WSConnection, Poco::Net::SocketReactor>>> Acceptors_;
|
||||
// typedef std::unique_ptr<Poco::Net::ParallelSocketAcceptor<WSConnection, Poco::Net::SocketReactor>> ws_server_reactor_type_t;
|
||||
typedef Poco::Net::SocketAcceptor<WSConnection> ws_server_reactor_type_t;
|
||||
std::vector<std::unique_ptr<ws_server_reactor_type_t>> Acceptors_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
ReactorPool ReactorPool_;
|
||||
std::string SimulatorId_;
|
||||
bool LookAtProvisioning_ = false;
|
||||
bool UseDefaultConfig_ = true;
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string GitUCentralJSONSchemaFile{"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"};
|
||||
static const std::string GitUCentralJSONSchemaFile{
|
||||
"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"};
|
||||
|
||||
static json DefaultUCentralSchema = R"(
|
||||
static json DefaultUCentralSchema = R"(
|
||||
|
||||
{
|
||||
"$id": "https://openwrt.org/ucentral.schema.json",
|
||||
@@ -518,7 +519,7 @@ namespace OpenWifi {
|
||||
"maximum": 4050
|
||||
},
|
||||
"proto": {
|
||||
"decription": "The L2 vlan tag that shall be added (1q,1ad) ",
|
||||
"decription": "The L2 vlan tag that shall be added (1q,1ad ) ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"802.1ad",
|
||||
@@ -669,6 +670,47 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
},
|
||||
"interface.ipv4.port-forward": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tcp",
|
||||
"udp",
|
||||
"any"
|
||||
],
|
||||
"default": "any"
|
||||
},
|
||||
"external-port": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
],
|
||||
"minimum": 0,
|
||||
"maximum": 65535,
|
||||
"format": "uc-portrange"
|
||||
},
|
||||
"internal-address": {
|
||||
"type": "string",
|
||||
"format": "ipv4",
|
||||
"example": "0.0.0.120"
|
||||
},
|
||||
"internal-port": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
],
|
||||
"minimum": 0,
|
||||
"maximum": 65535,
|
||||
"format": "uc-portrange"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"external-port",
|
||||
"internal-address"
|
||||
]
|
||||
},
|
||||
"interface.ipv4": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -722,6 +764,12 @@ namespace OpenWifi {
|
||||
"items": {
|
||||
"$ref": "#/$defs/interface.ipv4.dhcp-lease"
|
||||
}
|
||||
},
|
||||
"port-forward": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/interface.ipv4.port-forward"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -751,6 +799,96 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
},
|
||||
"interface.ipv6.port-forward": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tcp",
|
||||
"udp",
|
||||
"any"
|
||||
],
|
||||
"default": "any"
|
||||
},
|
||||
"external-port": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
],
|
||||
"minimum": 0,
|
||||
"maximum": 65535,
|
||||
"format": "uc-portrange"
|
||||
},
|
||||
"internal-address": {
|
||||
"type": "string",
|
||||
"format": "ipv6",
|
||||
"example": "::1234:abcd"
|
||||
},
|
||||
"internal-port": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
],
|
||||
"minimum": 0,
|
||||
"maximum": 65535,
|
||||
"format": "uc-portrange"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"external-port",
|
||||
"internal-address"
|
||||
]
|
||||
},
|
||||
"interface.ipv6.traffic-allow": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"default": "any"
|
||||
},
|
||||
"source-address": {
|
||||
"type": "string",
|
||||
"format": "uc-cidr6",
|
||||
"example": "2001:db8:1234:abcd::/64",
|
||||
"default": "::/0"
|
||||
},
|
||||
"source-ports": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
],
|
||||
"minimum": 0,
|
||||
"maximum": 65535,
|
||||
"format": "uc-portrange"
|
||||
}
|
||||
},
|
||||
"destination-address": {
|
||||
"type": "string",
|
||||
"format": "ipv6",
|
||||
"example": "::1000"
|
||||
},
|
||||
"destination-ports": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
],
|
||||
"minimum": 0,
|
||||
"maximum": 65535,
|
||||
"format": "uc-portrange"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"destination-address"
|
||||
]
|
||||
},
|
||||
"interface.ipv6": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -782,6 +920,18 @@ namespace OpenWifi {
|
||||
},
|
||||
"dhcpv6": {
|
||||
"$ref": "#/$defs/interface.ipv6.dhcpv6"
|
||||
},
|
||||
"port-forward": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/interface.ipv6.port-forward"
|
||||
}
|
||||
},
|
||||
"traffic-allow": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/interface.ipv6.traffic-allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -866,7 +1016,7 @@ namespace OpenWifi {
|
||||
},
|
||||
"gateway-fqdn": {
|
||||
"type": "string",
|
||||
"format": "fqdn",
|
||||
"format": "uc-fqdn",
|
||||
"default": "ucentral.splash"
|
||||
},
|
||||
"max-clients": {
|
||||
@@ -901,6 +1051,7 @@ namespace OpenWifi {
|
||||
"psk",
|
||||
"psk2",
|
||||
"psk-mixed",
|
||||
"psk2-radius",
|
||||
"wpa",
|
||||
"wpa2",
|
||||
"wpa-mixed",
|
||||
@@ -961,6 +1112,10 @@ namespace OpenWifi {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"reduced-neighbor-reporting": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"lci": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -1527,6 +1682,11 @@ namespace OpenWifi {
|
||||
"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.",
|
||||
"type": "string"
|
||||
},
|
||||
"fils-discovery-interval": {
|
||||
"type": "integer",
|
||||
"default": 20,
|
||||
"maximum": 10000
|
||||
},
|
||||
"encryption": {
|
||||
"$ref": "#/$defs/interface.ssid.encryption"
|
||||
},
|
||||
@@ -2087,6 +2247,10 @@ namespace OpenWifi {
|
||||
"auto-channel": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"ipv6": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2193,7 +2357,7 @@ namespace OpenWifi {
|
||||
"properties": {
|
||||
"fqdn": {
|
||||
"type": "string",
|
||||
"format": "fqdn"
|
||||
"format": "uc-fqdn"
|
||||
},
|
||||
"suffix-matching": {
|
||||
"type": "boolean",
|
||||
@@ -2444,8 +2608,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
)"_json;
|
||||
)"_json;
|
||||
|
||||
class custom_error_handler : public nlohmann::json_schema::basic_error_handler
|
||||
{
|
||||
@@ -2460,9 +2623,18 @@ namespace OpenWifi {
|
||||
void ConfigurationValidator::Init() {
|
||||
if(Initialized_)
|
||||
return;
|
||||
|
||||
std::string GitSchema;
|
||||
if(MicroService::instance().ConfigGetBool("ucentral.datamodel.internal",true)) {
|
||||
RootSchema_ = DefaultUCentralSchema;
|
||||
Logger().information("Using uCentral validation from built-in default.");
|
||||
Initialized_ = Working_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) {
|
||||
auto GitURI = MicroService::instance().ConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile);
|
||||
if(Utils::wgets(GitURI, GitSchema)) {
|
||||
RootSchema_ = json::parse(GitSchema);
|
||||
Logger().information("Using uCentral validation schema from GIT.");
|
||||
} else {
|
||||
@@ -2528,6 +2700,17 @@ namespace OpenWifi {
|
||||
return IsCIDRv4(value) || IsCIDRv6(value);
|
||||
}
|
||||
|
||||
static inline bool IsPortRangeIsValid(const std::string &r) {
|
||||
const auto ports = Poco::StringTokenizer("-",r,Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
for(const auto &port:ports) {
|
||||
uint32_t port_num = std::stoul(port);
|
||||
if(port_num==0 || port_num>65535)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value)
|
||||
{
|
||||
static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"};
|
||||
@@ -2578,6 +2761,14 @@ namespace OpenWifi {
|
||||
} catch (...) {
|
||||
}
|
||||
throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com.");
|
||||
} else if(format == "uc-portrange") {
|
||||
try {
|
||||
if(IsPortRangeIsValid(value))
|
||||
return;
|
||||
throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port.");
|
||||
} catch (...) {
|
||||
}
|
||||
throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port.");
|
||||
} else if(format == "ip") {
|
||||
if (IsIP(value))
|
||||
return;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
193
src/framework/WebSocketClientNotifications.h
Normal file
193
src/framework/WebSocketClientNotifications.h
Normal file
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-05.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
struct WebNotificationSingleDevice {
|
||||
std::string serialNumber;
|
||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber);
|
||||
}
|
||||
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct WebNotificationSingleDeviceConfigurationChange {
|
||||
std::string serialNumber;
|
||||
uint64_t oldUUID;
|
||||
uint64_t newUUID;
|
||||
|
||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber);
|
||||
RESTAPI_utils::field_to_json(Obj,"oldUUID", oldUUID);
|
||||
RESTAPI_utils::field_to_json(Obj,"newUUID", newUUID);
|
||||
}
|
||||
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber);
|
||||
RESTAPI_utils::field_from_json(Obj,"oldUUID", oldUUID);
|
||||
RESTAPI_utils::field_from_json(Obj,"newUUID", newUUID);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct WebNotificationSingleDeviceFirmwareChange {
|
||||
std::string serialNumber;
|
||||
std::string newFirmware;
|
||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber);
|
||||
RESTAPI_utils::field_to_json(Obj,"newFirmware", newFirmware);
|
||||
}
|
||||
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber);
|
||||
RESTAPI_utils::field_from_json(Obj,"newFirmware", newFirmware);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
inline void WebSocketClientNotificationDeviceConfigurationChange(const std::string &SerialNumber, uint64_t oldUUID, uint64_t newUUID) {
|
||||
WebSocketNotification<WebNotificationSingleDeviceConfigurationChange> N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
N.content.oldUUID = oldUUID;
|
||||
N.content.newUUID = newUUID;
|
||||
N.type = "device_configuration_upgrade";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationDeviceFirmwareUpdated(const std::string &SerialNumber, const std::string &Firmware) {
|
||||
WebSocketNotification<WebNotificationSingleDeviceFirmwareChange> N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
N.content.newFirmware = Firmware;
|
||||
N.type = "device_firmware_upgrade";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationDeviceConnected(const std::string &SerialNumber) {
|
||||
WebSocketNotification<WebNotificationSingleDevice> N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
N.type = "device_connection";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationDeviceDisconnected(const std::string & SerialNumber) {
|
||||
WebSocketNotification<WebNotificationSingleDevice> N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
N.type = "device_disconnection";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
}
|
||||
|
||||
struct WebSocketNotificationJobContent {
|
||||
std::string title,
|
||||
details,
|
||||
jobId;
|
||||
std::vector<std::string> success,
|
||||
error,
|
||||
warning;
|
||||
uint64_t timeStamp=OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
inline void WebSocketNotificationJobContent::to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_to_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_to_json(Obj,"error",error);
|
||||
RESTAPI_utils::field_to_json(Obj,"warning",warning);
|
||||
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||
}
|
||||
|
||||
inline bool WebSocketNotificationJobContent::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_from_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_from_json(Obj,"error",error);
|
||||
RESTAPI_utils::field_from_json(Obj,"warning",warning);
|
||||
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef WebSocketNotification<WebSocketNotificationJobContent> WebSocketClientNotificationVenueUpdateJob_t;
|
||||
|
||||
inline void WebSocketClientNotificationVenueUpdateJobCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpdateJob_t &N) {
|
||||
N.type = "venue_configuration_update";
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
struct WebSocketNotificationRebootList {
|
||||
std::string title,
|
||||
details,
|
||||
jobId;
|
||||
std::vector<std::string> success,
|
||||
warning;
|
||||
uint64_t timeStamp=OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
typedef WebSocketNotification<WebSocketNotificationRebootList> WebSocketClientNotificationVenueRebootList_t;
|
||||
|
||||
inline void WebSocketNotificationRebootList::to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_to_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_to_json(Obj,"warning",warning);
|
||||
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||
}
|
||||
|
||||
inline bool WebSocketNotificationRebootList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_from_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_from_json(Obj,"warning",warning);
|
||||
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationVenueRebootCompletionToUser( const std::string & User, WebSocketClientNotificationVenueRebootList_t &N) {
|
||||
N.type = "venue_rebooter";
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -133,6 +133,37 @@ namespace ORM {
|
||||
return R;
|
||||
}
|
||||
|
||||
inline std::string WHERE_AND_(std::string Result) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args> std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) {
|
||||
if constexpr(std::is_same_v<T,std::string>)
|
||||
{
|
||||
if(!Value.empty()) {
|
||||
if(!Result.empty())
|
||||
Result += " and ";
|
||||
Result += fieldName;
|
||||
Result += '=';
|
||||
Result += "'";
|
||||
Result += Escape(Value);
|
||||
Result += "'";
|
||||
}
|
||||
} else {
|
||||
if(!Result.empty())
|
||||
Result += " and ";
|
||||
Result += fieldName ;
|
||||
Result += '=';
|
||||
Result += std::to_string(Value);
|
||||
}
|
||||
return WHERE_AND_(Result,args...);
|
||||
}
|
||||
|
||||
template <typename... Args> std::string WHERE_AND(Args... args) {
|
||||
std::string Result;
|
||||
return WHERE_AND_(Result, args...);
|
||||
}
|
||||
|
||||
enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE };
|
||||
enum SqlBinaryOp { AND = 0 , OR };
|
||||
|
||||
@@ -156,12 +187,8 @@ namespace ORM {
|
||||
}
|
||||
|
||||
inline std::string to_string(const Poco::Data::BLOB &blob) {
|
||||
auto Content = blob.content();
|
||||
std::string result;
|
||||
result.reserve(Content.size());
|
||||
for(const auto &c:Content) {
|
||||
result += (char) c;
|
||||
}
|
||||
result.assign(blob.begin(),blob.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -212,7 +239,8 @@ namespace ORM {
|
||||
int Place=0;
|
||||
|
||||
for(const auto &i:Fields) {
|
||||
FieldNames_[i.Name] = Place;
|
||||
std::string FieldName = Poco::toLower(i.Name);
|
||||
FieldNames_[FieldName] = Place;
|
||||
if(!first) {
|
||||
CreateFields_ += ", ";
|
||||
SelectFields_ += ", ";
|
||||
@@ -222,9 +250,9 @@ namespace ORM {
|
||||
SelectList_ += "(";
|
||||
}
|
||||
|
||||
CreateFields_ += i.Name + " " + FieldTypeToChar(Type_, i.Type,i.Size) + (i.Index ? " unique primary key" : "");
|
||||
SelectFields_ += i.Name ;
|
||||
UpdateFields_ += i.Name + "=?";
|
||||
CreateFields_ += FieldName + " " + FieldTypeToChar(Type_, i.Type,i.Size) + (i.Index ? " unique primary key" : "");
|
||||
SelectFields_ += FieldName ;
|
||||
UpdateFields_ += FieldName + "=?";
|
||||
SelectList_ += "?";
|
||||
first = false;
|
||||
Place++;
|
||||
@@ -239,12 +267,13 @@ namespace ORM {
|
||||
IndexLine = std::string("CREATE INDEX IF NOT EXISTS ") + j.Name + std::string(" ON ") + TableName_+ " (";
|
||||
bool first_entry=true;
|
||||
for(const auto &k:j.Entries) {
|
||||
assert(FieldNames_.find(k.FieldName) != FieldNames_.end());
|
||||
auto IndexFieldName = Poco::toLower(k.FieldName);
|
||||
assert(ValidFieldName(IndexFieldName));
|
||||
if(!first_entry) {
|
||||
IndexLine += " , ";
|
||||
}
|
||||
first_entry = false;
|
||||
IndexLine += k.FieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ;
|
||||
IndexLine += IndexFieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ;
|
||||
}
|
||||
IndexLine += " )";
|
||||
IndexCreation_.template emplace_back(IndexLine);
|
||||
@@ -259,12 +288,13 @@ namespace ORM {
|
||||
IndexLine += " INDEX " + j.Name + " ( " ;
|
||||
bool first_entry=true;
|
||||
for(const auto &k:j.Entries) {
|
||||
assert(FieldNames_.find(k.FieldName) != FieldNames_.end());
|
||||
auto IndexFieldName = Poco::toLower(k.FieldName);
|
||||
assert(FieldNames_.find(IndexFieldName) != FieldNames_.end());
|
||||
if(!first_entry) {
|
||||
IndexLine += " ,";
|
||||
}
|
||||
first_entry = false;
|
||||
IndexLine += k.FieldName + std::string(k.Type == Indextype::ASC ? " ASC" : " DESC");
|
||||
IndexLine += IndexFieldName + std::string(k.Type == Indextype::ASC ? " ASC" : " DESC");
|
||||
}
|
||||
IndexLine += " ) ";
|
||||
}
|
||||
@@ -279,27 +309,27 @@ namespace ORM {
|
||||
[[nodiscard]] const std::string & UpdateFields() const { return UpdateFields_; };
|
||||
|
||||
inline std::string OP(field_name_t F, SqlComparison O , bool V) {
|
||||
assert( FieldNames_.find(F) != FieldNames_.end() );
|
||||
assert(ValidFieldName(F));
|
||||
return std::string{"("} + F + SQLCOMPS[O] + (V ? "true" : "false") + ")" ;
|
||||
}
|
||||
|
||||
inline std::string OP(field_name_t F, SqlComparison O , int V) {
|
||||
assert( FieldNames_.find(F) != FieldNames_.end() );
|
||||
assert(ValidFieldName(F));
|
||||
return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ;
|
||||
}
|
||||
|
||||
inline std::string OP(field_name_t F, SqlComparison O , uint64_t V) {
|
||||
assert( FieldNames_.find(F) != FieldNames_.end() );
|
||||
assert(ValidFieldName(F));
|
||||
return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ;
|
||||
}
|
||||
|
||||
std::string OP(field_name_t F, SqlComparison O , const std::string & V) {
|
||||
assert( FieldNames_.find(F) != FieldNames_.end() );
|
||||
assert(ValidFieldName(F));
|
||||
return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ;
|
||||
}
|
||||
|
||||
std::string OP(field_name_t F, SqlComparison O , const char * V) {
|
||||
assert( FieldNames_.find(F) != FieldNames_.end() );
|
||||
assert(ValidFieldName(F));
|
||||
return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ;
|
||||
}
|
||||
|
||||
@@ -421,7 +451,7 @@ namespace ORM {
|
||||
|
||||
template<typename T> bool GetRecord(field_name_t FieldName, const T & Value, RecordType & R) {
|
||||
try {
|
||||
assert( FieldNames_.find(FieldName) != FieldNames_.end() );
|
||||
assert(ValidFieldName(FieldName));
|
||||
|
||||
if(Cache_) {
|
||||
if(Cache_->GetFromCache(FieldName, Value, R))
|
||||
@@ -459,7 +489,7 @@ namespace ORM {
|
||||
typename T0, typename T1> bool GR(field_name_t FieldName, T & R,T0 &V0, T1 &V1) {
|
||||
try {
|
||||
|
||||
assert( FieldNames_.find(FieldName) != FieldNames_.end() );
|
||||
assert( ValidFieldName(FieldName) );
|
||||
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Poco::Data::Statement Select(Session);
|
||||
@@ -517,7 +547,7 @@ namespace ORM {
|
||||
|
||||
template <typename T> bool UpdateRecord(field_name_t FieldName, const T & Value, const RecordType & R) {
|
||||
try {
|
||||
assert( FieldNames_.find(FieldName) != FieldNames_.end() );
|
||||
assert( ValidFieldName(FieldName) );
|
||||
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Poco::Data::Statement Update(Session);
|
||||
@@ -571,7 +601,7 @@ namespace ORM {
|
||||
|
||||
template <typename T> bool GetNameAndDescription(field_name_t FieldName, const T & Value, std::string & Name, std::string & Description ) {
|
||||
try {
|
||||
assert( FieldNames_.find(FieldName) != FieldNames_.end() );
|
||||
assert( ValidFieldName(FieldName) );
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Poco::Data::Statement Select(Session);
|
||||
RecordTuple RT;
|
||||
@@ -598,7 +628,7 @@ namespace ORM {
|
||||
|
||||
template <typename T> bool DeleteRecord(field_name_t FieldName, const T & Value) {
|
||||
try {
|
||||
assert( FieldNames_.find(FieldName) != FieldNames_.end() );
|
||||
assert( ValidFieldName(FieldName) );
|
||||
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Poco::Data::Statement Delete(Session);
|
||||
@@ -636,7 +666,7 @@ namespace ORM {
|
||||
|
||||
bool Exists(field_name_t FieldName, const std::string & Value) {
|
||||
try {
|
||||
assert( FieldNames_.find(FieldName) != FieldNames_.end() );
|
||||
assert( ValidFieldName(FieldName) );
|
||||
|
||||
RecordType R;
|
||||
if(GetRecord(FieldName,Value,R))
|
||||
@@ -689,7 +719,7 @@ namespace ORM {
|
||||
}
|
||||
if(!ItemList.empty())
|
||||
ItemList += " , ";
|
||||
auto hint = FieldNames_.find(T[0]);
|
||||
auto hint = FieldNames_.find(Poco::toLower(T[0]));
|
||||
if(hint==FieldNames_.end()) {
|
||||
return false;
|
||||
}
|
||||
@@ -725,7 +755,7 @@ namespace ORM {
|
||||
|
||||
template <typename X> bool ManipulateVectorMember( X T, field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID, bool Add) {
|
||||
try {
|
||||
assert( FieldNames_.find(FieldName) != FieldNames_.end() );
|
||||
assert( ValidFieldName(FieldName) );
|
||||
|
||||
RecordType R;
|
||||
if(GetRecord(FieldName, ParentUUID, R)) {
|
||||
@@ -874,6 +904,15 @@ namespace ORM {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool ValidFieldName(const std::string &FieldName) {
|
||||
return FieldNames_.find(Poco::toLower(FieldName)) != FieldNames_.end();
|
||||
}
|
||||
|
||||
inline bool ValidFieldName(const char *FieldName) {
|
||||
std::string Field{FieldName};
|
||||
return ValidFieldName(Field);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) {
|
||||
if(From<1) From=0;
|
||||
switch(Type_) {
|
||||
@@ -890,12 +929,17 @@ namespace ORM {
|
||||
|
||||
Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
bool DeleteRecordsFromCache(const char *FieldName, const std::string &Value ) {
|
||||
inline bool DeleteRecordsFromCache(const char *FieldName, const std::string &Value ) {
|
||||
if(Cache_)
|
||||
Cache_->Delete(FieldName, Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void GetFieldNames( OpenWifi::Types::StringVec & F) {
|
||||
for(const auto &[field,_]:FieldNames_)
|
||||
F.push_back(field);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string TableName_;
|
||||
OpenWifi::DBType Type_;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "Poco/String.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
@@ -18,92 +19,187 @@
|
||||
#endif
|
||||
|
||||
namespace OpenWifi::RESTAPI::Errors {
|
||||
static const std::string MissingUUID{"Missing UUID."};
|
||||
static const std::string MissingSerialNumber{"Missing Serial Number."};
|
||||
static const std::string InternalError{"Internal error. Please try later."};
|
||||
static const std::string InvalidJSONDocument{"Invalid JSON document."};
|
||||
static const std::string UnsupportedHTTPMethod{"Unsupported HTTP Method"};
|
||||
static const std::string StillInUse{"Element still in use."};
|
||||
static const std::string CouldNotBeDeleted{"Element could not be deleted."};
|
||||
static const std::string NameMustBeSet{"The name property must be set."};
|
||||
static const std::string ConfigBlockInvalid{"Configuration block type invalid."};
|
||||
static const std::string UnknownId{"Unknown UUID."};
|
||||
static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."};
|
||||
static const std::string RecordNotCreated{"Record could not be created."};
|
||||
static const std::string RecordNotUpdated{"Record could not be updated."};
|
||||
static const std::string UnknownManagementPolicyUUID{"Unknown management policy UUID."};
|
||||
static const std::string CannotDeleteRoot{"Root Entity cannot be removed, only modified."};
|
||||
static const std::string MustCreateRootFirst{"Root entity must be created first."};
|
||||
static const std::string ParentUUIDMustExist{"Parent UUID must exist."};
|
||||
static const std::string ConfigurationMustExist{"Configuration must exist."};
|
||||
static const std::string MissingOrInvalidParameters{"Invalid or missing parameters."};
|
||||
static const std::string UnknownSerialNumber{"Unknown Serial Number."};
|
||||
static const std::string InvalidSerialNumber{"Invalid Serial Number."};
|
||||
static const std::string SerialNumberExists{"Serial Number already exists."};
|
||||
static const std::string ValidNonRootUUID{"Must be a non-root, and valid UUID."};
|
||||
static const std::string VenueMustExist{"Venue does not exist."};
|
||||
static const std::string NotBoth{"You cannot specify both Entity and Venue"};
|
||||
static const std::string EntityMustExist{"Entity must exist."};
|
||||
static const std::string ParentOrEntityMustBeSet{"Parent or Entity must be set."};
|
||||
static const std::string ContactMustExist{"Contact must exist."};
|
||||
static const std::string LocationMustExist{"Location must exist."};
|
||||
static const std::string OnlyWSSupported{"This endpoint only supports WebSocket."};
|
||||
static const std::string SerialNumberMismatch{"Serial Number mismatch."};
|
||||
static const std::string InvalidCommand{"Invalid command."};
|
||||
static const std::string NoRecordsDeleted{"No records deleted."};
|
||||
static const std::string DeviceNotConnected{"Device is not currently connected."};
|
||||
static const std::string CannotCreateWS{"Telemetry system could not create WS endpoint. Please try again."};
|
||||
static const std::string BothDeviceTypeRevision{"Both deviceType and revision must be set."};
|
||||
static const std::string IdOrSerialEmpty{"SerialNumber and Id must not be empty."};
|
||||
static const std::string MissingUserID{"Missing user ID."};
|
||||
static const std::string IdMustBe0{"To create a user, you must set the ID to 0"};
|
||||
static const std::string InvalidUserRole{"Invalid userRole."};
|
||||
static const std::string InvalidEmailAddress{"Invalid email address."};
|
||||
static const std::string PasswordRejected{"Password was rejected. This maybe an old password."};
|
||||
static const std::string InvalidIPRanges{"Invalid IP range specifications."};
|
||||
static const std::string InvalidLOrderBy{"Invalid orderBy specification."};
|
||||
static const std::string NeedMobileNumber{"You must provide at least one validated phone number."};
|
||||
static const std::string BadMFAMethod{"MFA only supports sms or email."};
|
||||
static const std::string InvalidCredentials{"Invalid credentials (username/password)."};
|
||||
static const std::string InvalidPassword{"Password does not conform to basic password rules."};
|
||||
static const std::string UserPendingVerification{"User access denied pending email verification."};
|
||||
static const std::string PasswordMustBeChanged{"Password must be changed."};
|
||||
static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."};
|
||||
static const std::string MissingAuthenticationInformation{"Missing authentication information."};
|
||||
static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."};
|
||||
static const std::string ExpiredToken{"Token has expired, user must login."};
|
||||
static const std::string SubscriberMustExist{"Subscriber must exist."};
|
||||
static const std::string AuthenticatorVerificationIncomplete{"Authenticator validation is not complete."};
|
||||
static const std::string SMSCouldNotBeSentRetry{"SMS could not be sent to validate device, try later or change the phone number."};
|
||||
static const std::string SMSCouldNotValidate{"Code and number could not be validated"};
|
||||
static const std::string InvalidDeviceClass{"Invalid device class. Must be: any, venue, entity, or subscriber"};
|
||||
static const std::string SerialNumberAlreadyProvisioned{"This device has already been provisioned to a subscriber."};
|
||||
static const std::string SerialNumberNotTheProperClass{"Device is not available to subscribers. It ahs been assigned to another class of devices."};
|
||||
static const std::string UserAlreadyExists{"Username already exists."};
|
||||
static const std::string NotImplemented{"Function not implemented."};
|
||||
static const std::string VariableMustExist{"Specified variable does not exist."};
|
||||
static const std::string InvalidEntityType{"Invalid entity type."};
|
||||
static const std::string CannotDeleteSubEntity{"Cannot delete the default subscriber entity."};
|
||||
static const std::string OperatorIdMustExist{"Missing or bad Operator ID"};
|
||||
static const std::string CannotDeleteDefaultOperator{"Cannot delete the default operator."};
|
||||
static const std::string CannotCreateDefaultOperator{"Cannot create the default operator."};
|
||||
static const std::string InvalidRRM{"Invalid RRM value."};
|
||||
static const std::string InvalidIPAddresses{"Invalid IP addresses."};
|
||||
static const std::string InvalidBillingCode{"Empty of invalid billing code."};
|
||||
static const std::string InvalidBillingPeriod{"Invalid billing period."};
|
||||
static const std::string InvalidSubscriberId{"Invalid subscriber ID."};
|
||||
static const std::string InvalidContactId{"Invalid contact ID."};
|
||||
static const std::string InvalidLocationId{"Invalid location ID."};
|
||||
static const std::string InvalidContactType{"Invalid contact type."};
|
||||
static const std::string InvalidLocationType{"Invalid location type."};
|
||||
static const std::string InvalidOperatorId{"Invalid operator ID."};
|
||||
static const std::string InvalidServiceClassId{"Invalid service class ID."};
|
||||
static const std::string InvalidSubscriberDeviceId{"Invalid subscriber device ID."};
|
||||
static const std::string InvalidRegistrationOperatorId{"Invalid registration operator ID."};
|
||||
static const std::string InvalidRegistrationOperatorName{"Invalid registration operator name."};
|
||||
static const std::string RegistrationNameDuplicate{"Registration name must be unique."};
|
||||
struct msg { uint64_t err_num; std::string err_txt; };
|
||||
static const struct msg Error404{404,"Resource does not exist."};
|
||||
|
||||
static const struct msg SUCCESS{0,"No error."};
|
||||
static const struct msg PASSWORD_CHANGE_REQUIRED{1,"Password change required"};
|
||||
static const struct msg INVALID_CREDENTIALS{2,"Invalid credentials."};
|
||||
static const struct msg PASSWORD_ALREADY_USED{3,"Password already used."};
|
||||
static const struct msg USERNAME_PENDING_VERIFICATION{4,"Username pending verification."};
|
||||
static const struct msg PASSWORD_INVALID{5,"Password is invalid"};
|
||||
static const struct msg INTERNAL_ERROR{6,"Internal error."};
|
||||
static const struct msg ACCESS_DENIED{7,"Access denied."};
|
||||
static const struct msg INVALID_TOKEN{8,"Invalid token."};
|
||||
static const struct msg EXPIRED_TOKEN{9,"Expired token."};
|
||||
static const struct msg RATE_LIMIT_EXCEEDED{10,"Rate limit exceeded."};
|
||||
static const struct msg BAD_MFA_TRANSACTION{11,"Bad MFA transaction."};
|
||||
static const struct msg MFA_FAILURE{12,"MFA failure."};
|
||||
static const struct msg SECURITY_SERVICE_UNREACHABLE{13,"Security service is unreachable, try again later."};
|
||||
static const struct msg CANNOT_REFRESH_TOKEN{14,"Cannot refresh token."};
|
||||
|
||||
static const struct msg MissingUUID{1000,"Missing UUID."};
|
||||
static const struct msg MissingSerialNumber{1001,"Missing Serial Number."};
|
||||
static const struct msg InternalError{1002,"Internal error. Please try later."};
|
||||
static const struct msg InvalidJSONDocument{1003,"Invalid JSON document."};
|
||||
static const struct msg UnsupportedHTTPMethod{1004,"Unsupported HTTP Method"};
|
||||
static const struct msg StillInUse{1005,"Element still in use."};
|
||||
static const struct msg CouldNotBeDeleted{1006,"Element could not be deleted."};
|
||||
static const struct msg NameMustBeSet{1007,"The name property must be set."};
|
||||
static const struct msg ConfigBlockInvalid{1008,"Configuration block type invalid."};
|
||||
static const struct msg UnknownId{1009,"Unknown UUID."};
|
||||
static const struct msg InvalidDeviceTypes{1010,"Unknown or invalid device type(s)."};
|
||||
static const struct msg RecordNotCreated{1011,"Record could not be created."};
|
||||
static const struct msg RecordNotUpdated{1012,"Record could not be updated."};
|
||||
static const struct msg UnknownManagementPolicyUUID{1013,"Unknown management policy UUID."};
|
||||
static const struct msg CannotDeleteRoot{1014,"Root Entity cannot be removed, only modified."};
|
||||
static const struct msg MustCreateRootFirst{1015,"Root entity must be created first."};
|
||||
static const struct msg ParentUUIDMustExist{1016,"Parent UUID must exist."};
|
||||
static const struct msg ConfigurationMustExist{1017,"Configuration must exist."};
|
||||
static const struct msg MissingOrInvalidParameters{1018,"Invalid or missing parameters."};
|
||||
static const struct msg UnknownSerialNumber{1019,"Unknown Serial Number."};
|
||||
static const struct msg InvalidSerialNumber{1020,"Invalid Serial Number."};
|
||||
static const struct msg SerialNumberExists{1021,"Serial Number already exists."};
|
||||
static const struct msg ValidNonRootUUID{1022,"Must be a non-root, and valid UUID."};
|
||||
static const struct msg VenueMustExist{1023,"Venue does not exist."};
|
||||
static const struct msg NotBoth{1024,"You cannot specify both Entity and Venue"};
|
||||
static const struct msg EntityMustExist{1025,"Entity must exist."};
|
||||
static const struct msg ParentOrEntityMustBeSet{1026,"Parent or Entity must be set."};
|
||||
static const struct msg ContactMustExist{1027,"Contact must exist."};
|
||||
static const struct msg LocationMustExist{1028,"Location must exist."};
|
||||
static const struct msg OnlyWSSupported{1029,"This endpoint only supports WebSocket."};
|
||||
static const struct msg SerialNumberMismatch{1030,"Serial Number mismatch."};
|
||||
static const struct msg InvalidCommand{1031,"Invalid command."};
|
||||
static const struct msg NoRecordsDeleted{1032,"No records deleted."};
|
||||
static const struct msg DeviceNotConnected{1033,"Device is not currently connected."};
|
||||
static const struct msg CannotCreateWS{1034,"Telemetry system could not create WS endpoint. Please try again."};
|
||||
static const struct msg BothDeviceTypeRevision{1035,"Both deviceType and revision must be set."};
|
||||
static const struct msg IdOrSerialEmpty{1036,"SerialNumber and Id must not be empty."};
|
||||
static const struct msg MissingUserID{1037,"Missing user ID."};
|
||||
static const struct msg IdMustBe0{1038,"To create a user, you must set the ID to 0"};
|
||||
static const struct msg InvalidUserRole{1039,"Invalid userRole."};
|
||||
static const struct msg InvalidEmailAddress{1040,"Invalid email address."};
|
||||
static const struct msg PasswordRejected{1041,"Password was rejected. This maybe an old password."};
|
||||
static const struct msg InvalidIPRanges{1042,"Invalid IP range specifications."};
|
||||
static const struct msg InvalidLOrderBy{1043,"Invalid orderBy specification."};
|
||||
static const struct msg NeedMobileNumber{1044,"You must provide at least one validated phone number."};
|
||||
static const struct msg BadMFAMethod{1045,"MFA only supports sms or email."};
|
||||
static const struct msg InvalidCredentials{1046,"Invalid credentials (username/password)."};
|
||||
static const struct msg InvalidPassword{1047,"Password does not conform to basic password rules."};
|
||||
static const struct msg UserPendingVerification{1048,"User access denied pending email verification."};
|
||||
static const struct msg PasswordMustBeChanged{1049,"Password must be changed."};
|
||||
static const struct msg UnrecognizedRequest{1050,"Ill-formed request. Please consult documentation."};
|
||||
static const struct msg MissingAuthenticationInformation{1051,"Missing authentication information."};
|
||||
static const struct msg InsufficientAccessRights{1052,"Insufficient access rights to complete the operation."};
|
||||
static const struct msg ExpiredToken{1053,"Token has expired, user must login."};
|
||||
static const struct msg SubscriberMustExist{1054,"Subscriber must exist."};
|
||||
static const struct msg AuthenticatorVerificationIncomplete{1055,"Authenticator validation is not complete."};
|
||||
static const struct msg SMSCouldNotBeSentRetry{1056,"SMS could not be sent to validate device, try later or change the phone number."};
|
||||
static const struct msg SMSCouldNotValidate{1057,"Code and number could not be validated"};
|
||||
static const struct msg InvalidDeviceClass{1058,"Invalid device class. Must be: any, venue, entity, or subscriber"};
|
||||
static const struct msg SerialNumberAlreadyProvisioned{1059,"This device has already been provisioned to a subscriber."};
|
||||
static const struct msg SerialNumberNotTheProperClass{1060,"Device is not available to subscribers. It ahs been assigned to another class of devices."};
|
||||
static const struct msg UserAlreadyExists{1061,"Username already exists."};
|
||||
static const struct msg NotImplemented{1062,"Function not implemented."};
|
||||
static const struct msg VariableMustExist{1063,"Specified variable does not exist."};
|
||||
static const struct msg InvalidEntityType{1064,"Invalid entity type."};
|
||||
static const struct msg CannotDeleteSubEntity{1065,"Cannot delete the default subscriber entity."};
|
||||
static const struct msg OperatorIdMustExist{1066,"Missing or bad Operator ID"};
|
||||
static const struct msg CannotDeleteDefaultOperator{1067,"Cannot delete the default operator."};
|
||||
static const struct msg CannotCreateDefaultOperator{1068,"Cannot create the default operator."};
|
||||
static const struct msg InvalidRRM{1069,"Invalid RRM value."};
|
||||
static const struct msg InvalidIPAddresses{1070,"Invalid IP addresses."};
|
||||
static const struct msg InvalidBillingCode{1071,"Empty of invalid billing code."};
|
||||
static const struct msg InvalidBillingPeriod{1072,"Invalid billing period."};
|
||||
static const struct msg InvalidSubscriberId{1073,"Invalid subscriber ID."};
|
||||
static const struct msg InvalidContactId{1074,"Invalid contact ID."};
|
||||
static const struct msg InvalidLocationId{1075,"Invalid location ID."};
|
||||
static const struct msg InvalidContactType{1076,"Invalid contact type."};
|
||||
static const struct msg InvalidLocationType{1077,"Invalid location type."};
|
||||
static const struct msg InvalidOperatorId{1078,"Invalid operator ID."};
|
||||
static const struct msg InvalidServiceClassId{1079,"Invalid service class ID."};
|
||||
static const struct msg InvalidSubscriberDeviceId{1080,"Invalid subscriber device ID."};
|
||||
static const struct msg InvalidRegistrationOperatorId{1081,"Invalid registration operator ID."};
|
||||
static const struct msg InvalidRegistrationOperatorName{1082,"Invalid registration operator name."};
|
||||
static const struct msg RegistrationNameDuplicate{1083,"Registration name must be unique."};
|
||||
static const struct msg SMSMFANotEnabled{1084,"SMS is not enabled in the security service."};
|
||||
static const struct msg EMailMFANotEnabled{1085,"email is not enabled in the security service."};
|
||||
|
||||
static const struct msg TOTInvalidCode{1086,"Invalid code."};
|
||||
static const struct msg TOTInvalidIndex{1087,"Invalid index."};
|
||||
static const struct msg TOTRepeatedCode{1088,"Code is repeated. Must be new code."};
|
||||
static const struct msg TOTInvalidProtocol{1089,"Invalid protocol sequence."};
|
||||
static const struct msg TOTNoSession{1090,"No validation session present."};
|
||||
|
||||
static const struct msg SignupAlreadySigned{1091,"Code is repeated. Must be new code."};
|
||||
static const struct msg SignupEmailCheck{1092,"Waiting for email check completion."};
|
||||
static const struct msg SignupWaitingForDevice{1093,"Waiting for device."};
|
||||
|
||||
static const struct msg SMSMissingPhoneNumber{1094,"Missing phone number"};
|
||||
static const struct msg SMSTryLater{1095,"SMS could not be sent. Verify the number or try again later."};
|
||||
static const struct msg SMSMissingChallenge{1096,"Missing 'challengeCode'"};
|
||||
static const struct msg MustHaveConfigElement{1097,"Must have 'configuration' element."};
|
||||
|
||||
static const struct msg ModelIDListCannotBeEmpty{1098,"Model ID list cannot be empty."};
|
||||
static const struct msg DefConfigNameExists{1099,"Configuration name already exists."};
|
||||
|
||||
static const struct msg SubNoDeviceActivated{1100,"No devices activated yet."};
|
||||
static const struct msg SubConfigNotRefreshed{1101,"Configuration could not be refreshed."};
|
||||
|
||||
static const struct msg ProvServiceNotAvailable{1102,"Provisioning service not available yet."};
|
||||
static const struct msg SSIDInvalidPassword{1103,"Invalid password length. Must be 8 characters or greater, and a maximum of 32 characters."};
|
||||
static const struct msg InvalidStartingIPAddress{1104,"Invalid starting/ending IP address."};
|
||||
static const struct msg SubnetFormatError{1105,"Subnet must be in format like 192.168.1.1/24."};
|
||||
static const struct msg DeviceModeError{1106,"Device mode subnet must be of the form 192.168.1.1/24."};
|
||||
|
||||
static const struct msg BadDeviceMode{1107,"Mode must be bridge, nat, or manual."};
|
||||
static const struct msg DefaultGatewayFormat{1108,"Default gateway must be in format like 192.168.1.1."};
|
||||
static const struct msg PrimaryDNSFormat{1109,"Primary DNS must be an IP address i.e. 192.168.1.1."};
|
||||
|
||||
static const struct msg SecondaryDNSFormat{1110,"Secondary DNS must be an IP address i.e. 192.168.1.1."};
|
||||
static const struct msg BadConnectionType{1111,"Internet Connection must be automatic, bridge, pppoe, or manual."};
|
||||
static const struct msg InvalidDeviceID{1112,"Invalid deviceID."};
|
||||
static const struct msg InvalidVisibilityAttribute{1113,"Invalid visibility attribute."};
|
||||
static const struct msg UnknownConfigurationSection{1114,"Unknown section."};
|
||||
|
||||
static const struct msg CannotValidatePhoneNumber{1115,"Phone number could not be validated."};
|
||||
static const struct msg RootUsersNoOwners{1116,"ROOT users may not have owners."};
|
||||
static const struct msg PartnerMustHaveEntity{1118,"Partner user must belong to an entity."};
|
||||
static const struct msg RootCannotModifyUsers{1119,"ROOT may not modify user roles."};
|
||||
|
||||
static const struct msg CertificateNotIssued{1120,"Certificate was not issued."};
|
||||
static const struct msg IncompleteCertificate{1121,"Incomplete certificate information. Cannot be downloaded. You must delete and recreate."};
|
||||
static const struct msg InvalidCertificateType{1122,"Invalid certificate type."};
|
||||
static const struct msg InvalidDeviceName{1123,"Invalid device name."};
|
||||
|
||||
static const struct msg InvalidRedirectorName{1124,"Invalid redirector name"};
|
||||
static const struct msg CommonNameAlreadyExists{1125,"A device/server of this name already exists"};
|
||||
static const struct msg CertificateAlreadyExists{1126,"A certificate for this device already exists."};
|
||||
static const struct msg CannotCreateCertTryAgain{1127,"Device certificate could not be created. Please try later."};
|
||||
static const struct msg CouldNotRevoke{1128,"Certificate could not be revoked."};
|
||||
|
||||
static const struct msg CouldNotModifyCert{1129,"Certificate could not me modified. Please verify the information you supplied."};
|
||||
static const struct msg BatchCertNoCreated{1130,"Certificates have not been created for this batch."};
|
||||
static const struct msg BatchTooBig{1131,"Illegal number of MAC Addresses: must be between 1 and 1000."};
|
||||
|
||||
static const struct msg OutstandingJobs{1132,"Batch has running outstanding jobs. Please wait until job is finished."};
|
||||
static const struct msg InvalidSMSNotificationList{1133,"Invalid SMS Notification list."};
|
||||
static const struct msg InvalidEMailNotificationList{1134,"Invalid email Notification list."};
|
||||
static const struct msg CannotChangeCommanNames{1135,"You cannot provide new/modified common names after jobs have been run for a batch."};
|
||||
static const struct msg FailedToVerifyDigicert{1136,"Failed to verify the DigiCert information provided."};
|
||||
static const struct msg CouldNotPerformCommand{1137,"Could not perform command."};
|
||||
|
||||
static const struct msg PoolNameInvalid{1138,"Pool name is invalid."};
|
||||
static const struct msg InvalidRadiusProxyStrategy{1139,"Strategy name must be: random, round_robin, weighted."};
|
||||
static const struct msg InvalidRadiusProxyMonitorMethod{1140,"monitorMethod must be: none, https, radius."};
|
||||
static const struct msg MustHaveAtLeastOneRadiusServer{1141,"Must have at least one RADIUS server."};
|
||||
static const struct msg InvalidRadiusServerEntry{1142,"RADIUS Server IP address invalid or port missing."};
|
||||
static const struct msg InvalidRadiusServerWeigth{1143,"RADIUS Server IP weight cannot be 0."};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace OpenWifi::RESTAPI::Protocol {
|
||||
static const char * CAPABILITIES = "capabilities";
|
||||
static const char * LOGS = "logs";
|
||||
@@ -207,6 +303,9 @@ namespace OpenWifi::RESTAPI::Protocol {
|
||||
static const char * TIMES = "times";
|
||||
static const char * UPTIME = "uptime";
|
||||
static const char * START = "start";
|
||||
static const char * DEBUG = "debug";
|
||||
static const char * SCRIPT = "script";
|
||||
static const char * TIMEOUT = "timeout";
|
||||
|
||||
static const char * NEWPASSWORD = "newPassword";
|
||||
static const char * USERS = "users";
|
||||
@@ -272,6 +371,8 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *CONFIG = "config";
|
||||
static const char *EMPTY_JSON_DOC = "{}";
|
||||
static const char *RESULT = "result";
|
||||
static const char *RESULT_64 = "result_64";
|
||||
static const char *RESULT_SZ = "result_sz";
|
||||
static const char *REQUEST = "request";
|
||||
static const char *PERFORM = "perform";
|
||||
static const char *CONFIGURE = "configure";
|
||||
@@ -284,6 +385,7 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *DURATION = "duration";
|
||||
static const char *PATTERN = "pattern";
|
||||
static const char *LEDS = "leds";
|
||||
static const char *DEBUG = "debug";
|
||||
static const char *ON = "on";
|
||||
static const char *OFF = "off";
|
||||
static const char *BLINK = "blink";
|
||||
@@ -318,7 +420,18 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *CONNECTIONIP = "connectionIp";
|
||||
static const char *TELEMETRY = "telemetry";
|
||||
static const char *BANDWIDTH = "bandwidth";
|
||||
}
|
||||
|
||||
static const char *SCRIPT = "script";
|
||||
static const char *TYPE = "type";
|
||||
|
||||
static const char *RADIUS = "radius";
|
||||
static const char *RADIUSDATA = "data";
|
||||
static const char *RADIUSACCT = "acct";
|
||||
static const char *RADIUSAUTH = "auth";
|
||||
static const char *RADIUSCOA = "coa";
|
||||
static const char *RADIUSDST = "dst";
|
||||
static const char *IES = "ies";
|
||||
}
|
||||
|
||||
namespace OpenWifi::uCentralProtocol::Events {
|
||||
|
||||
@@ -347,25 +460,28 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
ET_TELEMETRY
|
||||
};
|
||||
|
||||
inline static EVENT_MSG EventFromString(const std::string & Method) {
|
||||
static std::vector<std::pair<const char *,EVENT_MSG>> Values{
|
||||
{ CFGPENDING , ET_CFGPENDING },
|
||||
{ CONNECT, ET_CONNECT },
|
||||
{ CRASHLOG, ET_CRASHLOG },
|
||||
{ DEVICEUPDATE, ET_DEVICEUPDATE },
|
||||
{ HEALTHCHECK, ET_HEALTHCHECK },
|
||||
{ LOG, ET_LOG },
|
||||
{ PING, ET_PING },
|
||||
{ RECOVERY, ET_RECOVERY },
|
||||
{ STATE, ET_STATE },
|
||||
{ TELEMETRY, ET_TELEMETRY }
|
||||
};
|
||||
|
||||
std::string L = Poco::toLower(Method);
|
||||
auto hint = std::find_if(cbegin(Values),cend(Values),[&](const std::pair<const char *,EVENT_MSG> &v) ->bool { return strcmp(v.first,L.c_str())==0; });
|
||||
if(hint == cend(Values))
|
||||
return ET_UNKNOWN;
|
||||
return hint->second;
|
||||
inline EVENT_MSG EventFromString(const std::string & Method) {
|
||||
if(strcmp(STATE,Method.c_str())==0)
|
||||
return ET_STATE;
|
||||
else if(strcmp(HEALTHCHECK,Method.c_str())==0)
|
||||
return ET_HEALTHCHECK;
|
||||
else if(strcmp(CONNECT,Method.c_str())==0)
|
||||
return ET_CONNECT;
|
||||
else if(strcmp(CFGPENDING,Method.c_str())==0)
|
||||
return ET_CFGPENDING;
|
||||
else if(strcmp(CRASHLOG,Method.c_str())==0)
|
||||
return ET_CRASHLOG;
|
||||
else if(strcmp(DEVICEUPDATE,Method.c_str())==0)
|
||||
return ET_DEVICEUPDATE;
|
||||
else if(strcmp(LOG,Method.c_str())==0)
|
||||
return ET_LOG;
|
||||
else if(strcmp(PING,Method.c_str())==0)
|
||||
return ET_PING;
|
||||
else if(strcmp(RECOVERY,Method.c_str())==0)
|
||||
return ET_RECOVERY;
|
||||
else if(strcmp(TELEMETRY,Method.c_str())==0)
|
||||
return ET_TELEMETRY;
|
||||
return ET_UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,85 +8,75 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
RTTYS_ClientConnection::RTTYS_ClientConnection(std::unique_ptr<Poco::Net::WebSocket> WS, std::string &Id,
|
||||
Poco::Net::SocketReactor &Reactor)
|
||||
: WS_(std::move(WS)),
|
||||
Id_(std::move(Id)),
|
||||
SR_(Reactor),
|
||||
Logger_(RTTYS_server()->Logger()) {
|
||||
RTTYS_server()->Register(Id_, this);
|
||||
if(RTTYS_server()->CanConnect(Id_,this)) {
|
||||
Logger().information(fmt::format("{}: Starting WS connection, session: {}.", Id_, RTTYS_server()->DeviceSessionID(Id_)));
|
||||
SR_.addEventHandler(*WS_,
|
||||
Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
SR_.addEventHandler(*WS_,
|
||||
Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
|
||||
auto DoLogin = [this]() -> void {
|
||||
int tries = 0 ;
|
||||
while(tries < 10) {
|
||||
if(RTTYS_server()->Login(this->Id_)) {
|
||||
Logger().information(fmt::format("{}: WS client connected to device, session: {}.", Id_, RTTYS_server()->DeviceSessionID(Id_)));
|
||||
this->Connected_=true;
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(2000ms);
|
||||
tries++;
|
||||
}
|
||||
Logger().information(fmt::format("{}: WS client could not connect to device, session: {}.", Id_, RTTYS_server()->DeviceSessionID(Id_)));
|
||||
delete this;
|
||||
};
|
||||
|
||||
std::thread CompleteConnection(DoLogin);
|
||||
CompleteConnection.detach();
|
||||
} else {
|
||||
Logger().information(fmt::format("{}: WS client cannot be connected.", Id_));
|
||||
RTTYS_server()->DeRegister(Id_, this);
|
||||
delete this;
|
||||
RTTYS_ClientConnection::RTTYS_ClientConnection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
Poco::Net::SocketReactor &reactor,
|
||||
const std::string &Id)
|
||||
:
|
||||
Reactor_(reactor),
|
||||
Id_(Id),
|
||||
Logger_(Poco::Logger::get(fmt::format("RTTY-client({})",Id_)))
|
||||
{
|
||||
Logger_.information("Starting connection");
|
||||
Valid_ = true;
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request,response);
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
}
|
||||
}
|
||||
|
||||
RTTYS_ClientConnection::~RTTYS_ClientConnection() {
|
||||
Logger().information(fmt::format("{}: WS client disconnecting.", Id_));
|
||||
if(Connected_) {
|
||||
SR_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
SR_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
}
|
||||
WS_->close();
|
||||
if(Connected_) {
|
||||
RTTYS_server()->Logout(Id_);
|
||||
RTTYS_server()->DeRegister(Id_, this);
|
||||
if(Valid_) {
|
||||
MyGuard G(Mutex_);
|
||||
EndConnection(false);
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::Close() {
|
||||
void RTTYS_ClientConnection::EndConnection(bool SendNotification) {
|
||||
if(Valid_) {
|
||||
Valid_=false;
|
||||
try {
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
// WS_->shutdown();
|
||||
if (SendNotification)
|
||||
RTTYS_server()->NotifyClientDisconnect(Id_, this);
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
Logger_.information("Disconnected.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::onSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
|
||||
int flags;
|
||||
auto n = WS_->receiveFrame(Buffer_, sizeof(Buffer_), flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
switch(Op) {
|
||||
MyGuard G(Mutex_);
|
||||
bool MustDisconnect = false;
|
||||
try {
|
||||
int flags;
|
||||
auto n = WS_->receiveFrame(Buffer_, sizeof(Buffer_), flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS_->sendFrame("", 0,(int)Poco::Net::WebSocket::FRAME_OP_PONG | (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
}
|
||||
break;
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
if (n == 0)
|
||||
return delete this;
|
||||
std::string s((char*)Buffer_, n);
|
||||
// std::cout << "TEXT:" << s << std::endl;
|
||||
if (n == 0) {
|
||||
Logger_.information("Socket readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
std::string s((char *)Buffer_, n);
|
||||
try {
|
||||
auto Doc = nlohmann::json::parse(s);
|
||||
if (Doc.contains("type")) {
|
||||
@@ -94,50 +84,82 @@ namespace OpenWifi {
|
||||
if (Type == "winsize") {
|
||||
auto cols = Doc["cols"];
|
||||
auto rows = Doc["rows"];
|
||||
if(!RTTYS_server()->WindowSize(Id_,cols, rows)) {
|
||||
return delete this;
|
||||
if (!RTTYS_server()->WindowSize(Id_, cols, rows)) {
|
||||
Logger_.information("Winsize shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
// just ignore parse errors
|
||||
Logger_.information("Frame text exception shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_BINARY: {
|
||||
if (n == 0)
|
||||
return delete this;
|
||||
if(!RTTYS_server()->SendKeyStrokes(Id_,Buffer_,n)) {
|
||||
return delete this;
|
||||
if (n == 0) {
|
||||
Logger_.information("Frame binary size shutdown.");
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("Sending {} key strokes to device.", n));
|
||||
if (!RTTYS_server()->SendKeyStrokes(Id_, Buffer_, n)) {
|
||||
Logger_.information("Sendkeystrokes shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
return delete this;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
Logger_.information("Frame frame close shutdown.");
|
||||
MustDisconnect = true;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
Logger_.information("Frame readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
|
||||
if(MustDisconnect)
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::SendData( const u_char *Buf, size_t len ) {
|
||||
WS_->sendFrame(Buf, len, Poco::Net::WebSocket::FRAME_FLAG_FIN | Poco::Net::WebSocket::FRAME_OP_BINARY);
|
||||
if(!Valid_)
|
||||
return;
|
||||
// MyGuard G(Mutex_);
|
||||
try {
|
||||
WS_->sendFrame(Buf, len,
|
||||
Poco::Net::WebSocket::FRAME_FLAG_FIN |
|
||||
Poco::Net::WebSocket::FRAME_OP_BINARY);
|
||||
return;
|
||||
} catch (...) {
|
||||
Logger_.information("SendData shutdown.");
|
||||
}
|
||||
MyGuard G(Mutex_);
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::SendData( const std::string &s , bool login) {
|
||||
if(login) {
|
||||
RTTYS_server()->LoginDone(Id_);
|
||||
void RTTYS_ClientConnection::SendData( const std::string &s) {
|
||||
if(!Valid_)
|
||||
return;
|
||||
// MyGuard G(Mutex_);
|
||||
try {
|
||||
WS_->sendFrame(s.c_str(), s.length());
|
||||
return;
|
||||
} catch (...) {
|
||||
Logger_.information("SendData shutdown.");
|
||||
}
|
||||
WS_->sendFrame( s.c_str(), s.length());
|
||||
MyGuard G(Mutex_);
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::onSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
RTTYS_server()->Close(Id_);
|
||||
delete this;
|
||||
MyGuard G(Mutex_);
|
||||
Logger_.information("Socket shutdown.");
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,28 +12,41 @@
|
||||
#include "Poco/FIFOBuffer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
enum class connection_state {
|
||||
initialized, waiting_for_login, connected, aborting, shutting_down, done
|
||||
};
|
||||
|
||||
class RTTYS_ClientConnection {
|
||||
public:
|
||||
RTTYS_ClientConnection(std::unique_ptr<Poco::Net::WebSocket> WS, std::string &Id,
|
||||
Poco::Net::SocketReactor &Reactor);
|
||||
RTTYS_ClientConnection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
Poco::Net::SocketReactor & reactor,
|
||||
const std::string &Id);
|
||||
~RTTYS_ClientConnection();
|
||||
void onSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
void onSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
|
||||
|
||||
void SendData( const u_char *Buf, size_t len );
|
||||
void SendData( const std::string & S, bool login=false);
|
||||
void SendData( const std::string & S );
|
||||
|
||||
void Close();
|
||||
[[nodiscard]] inline std::string ID() { return Id_; }
|
||||
[[nodiscard]] inline bool Valid() { return Valid_; }
|
||||
using MyMutexType = std::recursive_mutex;
|
||||
using MyGuard = std::lock_guard<MyMutexType>;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
std::string Id_;
|
||||
std::string Sid_;
|
||||
Poco::Net::SocketReactor &SR_;
|
||||
std::atomic_bool Connected_=false;
|
||||
Poco::Logger & Logger_;
|
||||
u_char Buffer_[16000]{0};
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::string Id_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
Poco::Logger &Logger_;
|
||||
std::string Sid_;
|
||||
std::atomic_bool Valid_=false;
|
||||
u_char Buffer_[64000]{0};
|
||||
MyMutexType Mutex_;
|
||||
// volatile connection_state state_ = connection_state::initialized;
|
||||
|
||||
void EndConnection(bool SendNotification=true);
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
};
|
||||
}
|
||||
@@ -9,26 +9,30 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
RTTY_Client_WebSocketRequestHandler::RTTY_Client_WebSocketRequestHandler(Poco::Net::SocketReactor &R)
|
||||
:R_(R) {
|
||||
RTTYS_Client_WebSocketRequestHandler::RTTYS_Client_WebSocketRequestHandler(Poco::Logger & L)
|
||||
:Logger_(L) {
|
||||
}
|
||||
|
||||
void RTTY_Client_WebSocketRequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
void RTTYS_Client_WebSocketRequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) {
|
||||
Poco::URI uri(request.getURI());
|
||||
const auto P = uri.getPath();
|
||||
// std::cout << "WS: " << P << std::endl;
|
||||
const auto & P = uri.getPath();
|
||||
auto T = Poco::StringTokenizer(P, "/");
|
||||
if (T.count() != 3)
|
||||
return;
|
||||
if (T[1] != "connect")
|
||||
return;
|
||||
|
||||
if(!RTTYS_server()->ValidId(T[2])) {
|
||||
response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
||||
response.send();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Poco::Thread::current()->setName(fmt::format("WebRTTYRequest_WSHandler_{}", T[2]));
|
||||
auto ws_ptr = std::make_unique<Poco::Net::WebSocket>(request, response);
|
||||
new RTTYS_ClientConnection(std::move(ws_ptr), T[2], R_);
|
||||
RTTYS_server()->CreateNewClient(request,response,T[2]);
|
||||
} catch (...) {
|
||||
RTTYS_server()->Logger().warning("Exception during WS creation");
|
||||
Logger_.warning("Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,30 +51,51 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void AddCORS(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse & Response, Poco::Logger & Logger_, uint64_t id) {
|
||||
|
||||
Logger_.information(fmt::format("{}: Adding CORS", id));
|
||||
inline void ProcessOptions(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
auto Origin = Request.find("Origin");
|
||||
if (Origin != Request.end()) {
|
||||
Response.set("Access-Control-Allow-Origin", Origin->second);
|
||||
Response.set("Vary", "Origin");
|
||||
} else {
|
||||
Response.set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
auto Referer = Request.find("Referer");
|
||||
if(Referer!=Request.end()) {
|
||||
Response.set("Access-Control-Allow-Origin", Referer->second);
|
||||
} else {
|
||||
Response.set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
Response.set("Access-Control-Allow-Headers", "*");
|
||||
Response.set("Access-Control-Allow-Methods", "GET, OPTIONS");
|
||||
auto RequestHeaders = Request.find("Access-Control-Request-Headers");
|
||||
if(RequestHeaders!=Request.end())
|
||||
Response.set("Access-Control-Allow-Headers", RequestHeaders->second);
|
||||
Response.set("Vary", "Origin, Accept-Encoding");
|
||||
Response.set("Access-Control-Allow-Credentials", "true");
|
||||
Response.set("Access-Control-Max-Age", "86400");
|
||||
Response.set("Access-Control-Allow-Methods", "GET, OPTIONS, HEAD");
|
||||
Response.set("Connection", "Keep-Alive");
|
||||
Response.set("Keep-Alive", "timeout=120");
|
||||
Response.set("Accept-Ranges","bytes");
|
||||
Response.set("Keep-Alive", "timeout=30, max=1000");
|
||||
|
||||
Response.setContentLength(0);
|
||||
Response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
|
||||
Response.send();
|
||||
}
|
||||
|
||||
inline void SetCommonHeaders(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response, bool CloseConnection) {
|
||||
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
Response.setContentType("application/json");
|
||||
auto Origin = Request.find("Origin");
|
||||
if (Origin != Request.end()) {
|
||||
Response.set("Access-Control-Allow-Origin", Origin->second);
|
||||
} else {
|
||||
Response.set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
Response.set("Vary", "Origin, Accept-Encoding");
|
||||
if(CloseConnection) {
|
||||
Response.set("Connection", "close");
|
||||
Response.setKeepAlive(false);
|
||||
} else {
|
||||
Response.setKeepAlive(true);
|
||||
Response.set("Connection", "Keep-Alive");
|
||||
Response.set("Keep-Alive", "timeout=30, max=1000");
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::atomic_uint64_t rtty_ws_id = 1;
|
||||
@@ -78,22 +103,21 @@ namespace OpenWifi {
|
||||
void PageRequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) {
|
||||
|
||||
Poco::Logger & Logger_ = RTTYS_server()->Logger();
|
||||
uint64_t id = rtty_ws_id++;
|
||||
Utils::SetThreadName("rt:webserver");
|
||||
[[maybe_unused]] uint64_t id = rtty_ws_id++;
|
||||
|
||||
Logger_.information(fmt::format("{}: Starting request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Starting request.",id));
|
||||
Poco::URI uri(request.getURI());
|
||||
auto Path = uri.getPath();
|
||||
|
||||
if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) {
|
||||
AddCORS(request,response, Logger_, id);
|
||||
return ProcessOptions(request, response);
|
||||
}
|
||||
|
||||
if(request.getMethod() != Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
SetCommonHeaders(request,response,false);
|
||||
response.setStatus(Poco::Net::HTTPResponse::HTTP_METHOD_NOT_ALLOWED);
|
||||
response.send();
|
||||
Logger_.information(fmt::format("{}: Finishing OPTIONS request.",id));
|
||||
return;
|
||||
} else if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD){
|
||||
AddCORS(request,response, Logger_, id);
|
||||
response.send();
|
||||
Logger_.information(fmt::format("{}: Finishing HEAD request.",id));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,51 +128,48 @@ namespace OpenWifi {
|
||||
if (ParsedPath.count() > 1) {
|
||||
if (ParsedPath[1] == "connect") {
|
||||
response.redirect(Poco::replace(Path,"/connect/","/rtty/"));
|
||||
RTTYS_server()->Logger().information(fmt::format("redirect: {}",Path));
|
||||
poco_debug(Logger(),fmt::format("{}: Redirect: {}",id,Path));
|
||||
return;
|
||||
} else if (ParsedPath[1] == "authorized") {
|
||||
AddCORS(request,response, Logger_, id);
|
||||
SetCommonHeaders(request,response, false);
|
||||
nlohmann::json doc;
|
||||
doc["authorized"] = true;
|
||||
response.setContentType("application/json");
|
||||
std::ostream &answer = response.send();
|
||||
answer << to_string(doc);
|
||||
Logger_.information(fmt::format("{}: Finishing authorization request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Finishing authorization request.",id));
|
||||
return;
|
||||
} else if (ParsedPath[1] == "fontsize") {
|
||||
AddCORS(request,response, Logger_, id);
|
||||
SetCommonHeaders(request,response, false);
|
||||
nlohmann::json doc;
|
||||
doc["size"] = 16;
|
||||
response.setContentType("application/json");
|
||||
std::ostream &answer = response.send();
|
||||
answer << to_string(doc);
|
||||
Logger_.information(fmt::format("{}: Finishing fonstize request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Finishing font size request.",id));
|
||||
return;
|
||||
}
|
||||
}
|
||||
Path = RTTYS_server()->UIAssets() + Path;
|
||||
}
|
||||
|
||||
// std::cout << id << ": Serving path '" << Path << "'" << std::endl;
|
||||
|
||||
// simple test to block .. or ~ in path names.
|
||||
if(Path.find("../")!=std::string::npos) {
|
||||
Logger_.information(fmt::format("{}: Finishing request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Finishing request.",id));
|
||||
return;
|
||||
}
|
||||
|
||||
if(Path.find("~/")!=std::string::npos) {
|
||||
Logger_.information(fmt::format("{}: Finishing request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Finishing request.",id));
|
||||
return;
|
||||
}
|
||||
|
||||
Poco::File F(Path);
|
||||
AddCORS(request,response, Logger_, id);
|
||||
SetCommonHeaders(request,response, false);
|
||||
if(!F.exists()) {
|
||||
// std::cout << id << ": Path " << Path << " does not exist" << std::endl;
|
||||
Path = RTTYS_server()->UIAssets() + "/index.html";
|
||||
response.sendFile(Path,"text/html");
|
||||
Logger_.information(fmt::format("{}: Finishing request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Finishing request.",id));
|
||||
return;
|
||||
}
|
||||
Poco::Path P(Path);
|
||||
@@ -165,7 +186,7 @@ namespace OpenWifi {
|
||||
} else if (Ext == "css") {
|
||||
Type = "text/css; charset=utf-8";
|
||||
if(IsFileGZipped(Path)) {
|
||||
Logger_.information(fmt::format("{}: Downloading UI Assets.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Downloading UI Assets.",id));
|
||||
response.set("Content-Encoding", "gzip");
|
||||
}
|
||||
} else if (Ext == "ico")
|
||||
@@ -179,22 +200,22 @@ namespace OpenWifi {
|
||||
|
||||
response.setContentLength(F.getSize());
|
||||
response.sendFile(Path, Type);
|
||||
Logger_.information(fmt::format("{}: Finishing request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Finishing request.",id));
|
||||
}
|
||||
|
||||
RTTY_Client_RequestHandlerFactory::RTTY_Client_RequestHandlerFactory(Poco::Net::SocketReactor &R)
|
||||
: Reactor_(R) {}
|
||||
RTTYS_Client_RequestHandlerFactory::RTTYS_Client_RequestHandlerFactory(Poco::Logger & L)
|
||||
: Logger_(L) {}
|
||||
|
||||
Poco::Net::HTTPRequestHandler *
|
||||
RTTY_Client_RequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &request) {
|
||||
RTTYS_Client_RequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &request) {
|
||||
try {
|
||||
if (request.find("Upgrade") != request.end() &&
|
||||
Poco::icompare(request["Upgrade"], "websocket") == 0) {
|
||||
Poco::Thread::current()->setName("WebRTTYRequest_WSHandler");
|
||||
return new RTTY_Client_WebSocketRequestHandler(Reactor_);
|
||||
return new RTTYS_Client_WebSocketRequestHandler(Logger_);
|
||||
} else {
|
||||
Poco::Thread::current()->setName("WebRTTYRequest_PageHandler");
|
||||
return new PageRequestHandler;
|
||||
return new PageRequestHandler(Logger_);
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
|
||||
@@ -10,31 +10,39 @@
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RTTY_Client_WebSocketRequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
class RTTYS_Client_WebSocketRequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit RTTY_Client_WebSocketRequestHandler(Poco::Net::SocketReactor &R);
|
||||
explicit RTTYS_Client_WebSocketRequestHandler(Poco::Logger &L);
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
|
||||
private:
|
||||
Poco::Net::SocketReactor &R_;
|
||||
Poco::Logger &Logger_;
|
||||
};
|
||||
|
||||
class PageRequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
PageRequestHandler(Poco::Logger &L)
|
||||
: Logger_(L) {
|
||||
}
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
inline Poco::Logger &Logger() { return Logger_; }
|
||||
};
|
||||
|
||||
class RTTY_Client_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
class RTTYS_Client_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
explicit RTTY_Client_RequestHandlerFactory(Poco::Net::SocketReactor &R);
|
||||
explicit RTTYS_Client_RequestHandlerFactory(Poco::Logger &L);
|
||||
|
||||
Poco::Net::HTTPRequestHandler *
|
||||
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override;
|
||||
|
||||
private:
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
Poco::Logger &Logger_;
|
||||
};
|
||||
}
|
||||
@@ -4,188 +4,244 @@
|
||||
|
||||
#include "RTTYS_device.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
#include "rttys/RTTYS_ClientConnection.h"
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
RTTY_Device_ConnectionHandler::RTTY_Device_ConnectionHandler(const Poco::Net::StreamSocket & socket) :
|
||||
Poco::Net::TCPServerConnection(socket),
|
||||
Logger_(RTTYS_server()->Logger()) {
|
||||
conn_id_ = global_device_connection_id++;
|
||||
RTTYS_Device_ConnectionHandler::RTTYS_Device_ConnectionHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor & reactor):
|
||||
socket_(socket),
|
||||
reactor_(reactor),
|
||||
Logger_(Poco::Logger::get(fmt::format("RTTY-device({})",socket_.peerAddress().toString())))
|
||||
{
|
||||
// std::thread T([=]() { CompleteConnection(); });
|
||||
// T.detach();
|
||||
CompleteConnection();
|
||||
}
|
||||
|
||||
RTTY_Device_ConnectionHandler::~RTTY_Device_ConnectionHandler() {
|
||||
running_ = false;
|
||||
while(!loop_done_) {
|
||||
Poco::Thread::sleep(10);
|
||||
}
|
||||
RTTYS_server()->DeRegister(id_, this);
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::AddCommand(u_char C) {
|
||||
std::lock_guard G(M_);
|
||||
// std::cout << conn_id_ << ": Adding command " << (int)C << std::endl;
|
||||
commands_.push_back(C);
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::ProcessCommands() {
|
||||
std::lock_guard G(M_);
|
||||
if(!commands_.empty()) {
|
||||
// std::cout << conn_id_ << ": Commands: " << commands_.size() << std::endl;
|
||||
for(const auto &i:commands_) {
|
||||
// std::cout << "Command: " << (int)i << std::endl;
|
||||
if(i==msgTypeLogin) {
|
||||
// std::cout << "Doing login..." << std::endl;
|
||||
Login();
|
||||
void RTTYS_Device_ConnectionHandler::CompleteConnection() {
|
||||
try {
|
||||
valid_=true;
|
||||
device_address_ = socket_.peerAddress();
|
||||
if (MicroService::instance().NoAPISecurity()) {
|
||||
poco_information(Logger(),"Unsecured connection.");
|
||||
} else {
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl *>(socket_.impl());
|
||||
while (true) {
|
||||
auto V = SS->completeHandshake();
|
||||
if (V == 1)
|
||||
break;
|
||||
}
|
||||
else if(i==msgTypeLogout) {
|
||||
// std::cout << "Doing logout..." << std::endl;
|
||||
Logout();
|
||||
if ((SS->secure())) {
|
||||
poco_information(Logger(), "Secure connection.");
|
||||
}
|
||||
}
|
||||
commands_.clear();
|
||||
reactor_.addEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketReadable));
|
||||
reactor_.addEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketShutdown));
|
||||
} catch (...) {
|
||||
poco_warning(Logger(), "Device caused exception while completing connection.");
|
||||
Guard G(M_);
|
||||
EndConnection();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RTTYS_Device_ConnectionHandler::~RTTYS_Device_ConnectionHandler() {
|
||||
if(valid_) {
|
||||
Guard G(M_);
|
||||
poco_warning(Logger(), "Device connection being deleted.");
|
||||
EndConnection(false);
|
||||
}
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::run() {
|
||||
running_ = true ;
|
||||
void RTTYS_Device_ConnectionHandler::EndConnection(bool SendNotification) {
|
||||
try {
|
||||
if(valid_) {
|
||||
valid_ = false;
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketReadable));
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketShutdown));
|
||||
if(SendNotification)
|
||||
RTTYS_server()->NotifyDeviceDisconnect(Id_,this);
|
||||
poco_information(Logger(), "Connection done.");
|
||||
socket_.close();
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
Poco::Timespan pollTimeOut(0,100);
|
||||
Poco::Timespan pollError(0,1);
|
||||
Poco::Timespan recvTimeOut(120,0);
|
||||
}
|
||||
}
|
||||
|
||||
socket().setKeepAlive(true);
|
||||
socket().setNoDelay(true);
|
||||
socket().setReceiveBufferSize(64000);
|
||||
socket().setLinger(false,0);
|
||||
socket().setSendBufferSize(64000);
|
||||
socket().setReceiveTimeout(recvTimeOut);
|
||||
[[maybe_unused]] static void dump(unsigned char *p,uint l) {
|
||||
for(uint i=0;i<l;i++) {
|
||||
std::cout << std::hex << (uint) p[i] << " ";
|
||||
if(i % 16 == 0)
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::dec << std::endl ;
|
||||
}
|
||||
|
||||
while(running_) {
|
||||
void RTTYS_Device_ConnectionHandler::onSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
bool good = true;
|
||||
|
||||
if(!ProcessCommands()) {
|
||||
running_=false;
|
||||
break;
|
||||
Guard G(M_);
|
||||
|
||||
try {
|
||||
auto received_bytes = socket_.receiveBytes(inBuf_);
|
||||
if (received_bytes == 0) {
|
||||
poco_information(Logger(), fmt::format("{}: Device Closing connection - 0 bytes received.",Id_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
std::lock_guard G(M_);
|
||||
if (socket().poll(pollError, Poco::Net::Socket::SELECT_ERROR) == true) {
|
||||
running_=false;
|
||||
continue;
|
||||
}
|
||||
while (inBuf_.isReadable() && good) {
|
||||
uint32_t msg_len = 0;
|
||||
if (waiting_for_bytes_ != 0) {
|
||||
|
||||
if (socket().poll(pollTimeOut, Poco::Net::Socket::SELECT_READ) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int received = socket().receiveBytes(inBuf_);
|
||||
if(received<0) {
|
||||
running_ = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(received==0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (!inBuf_.isEmpty() && running_) {
|
||||
// std::cout << conn_id_ << ": processing buffer" << std::endl;
|
||||
std::size_t msg_len;
|
||||
if (waiting_for_bytes_ == 0) {
|
||||
u_char header[3]{0};
|
||||
inBuf_.read((char *)&header[0], 3);
|
||||
last_command_ = header[0];
|
||||
msg_len = header[1] * 256 + header[2];
|
||||
} else {
|
||||
msg_len = received;
|
||||
if (inBuf_.used() >= 3) {
|
||||
auto *head = (unsigned char *)inBuf_.begin();
|
||||
last_command_ = head[0];
|
||||
msg_len = head[1] * 256 + head[2];
|
||||
inBuf_.drain(3);
|
||||
} else {
|
||||
good = false;
|
||||
if (!good)
|
||||
std::cout << "do_msgTypeTermData:5 " << inBuf_.used() << std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (last_command_) {
|
||||
case msgTypeRegister: {
|
||||
do_msgTypeRegister(msg_len);
|
||||
good = do_msgTypeRegister(msg_len);
|
||||
} break;
|
||||
case msgTypeLogin: {
|
||||
do_msgTypeLogin(msg_len);
|
||||
good = do_msgTypeLogin(msg_len);
|
||||
} break;
|
||||
case msgTypeLogout: {
|
||||
do_msgTypeLogout(msg_len);
|
||||
good = do_msgTypeLogout(msg_len);
|
||||
} break;
|
||||
case msgTypeTermData: {
|
||||
do_msgTypeTermData(msg_len);
|
||||
good = do_msgTypeTermData(msg_len);
|
||||
} break;
|
||||
case msgTypeWinsize: {
|
||||
do_msgTypeWinsize(msg_len);
|
||||
good = do_msgTypeWinsize(msg_len);
|
||||
} break;
|
||||
case msgTypeCmd: {
|
||||
do_msgTypeCmd(msg_len);
|
||||
good = do_msgTypeCmd(msg_len);
|
||||
} break;
|
||||
case msgTypeHeartbeat: {
|
||||
do_msgTypeHeartbeat(msg_len);
|
||||
good = do_msgTypeHeartbeat(msg_len);
|
||||
} break;
|
||||
case msgTypeFile: {
|
||||
do_msgTypeFile(msg_len);
|
||||
good = do_msgTypeFile(msg_len);
|
||||
} break;
|
||||
case msgTypeHttp: {
|
||||
do_msgTypeHttp(msg_len);
|
||||
good = do_msgTypeHttp(msg_len);
|
||||
} break;
|
||||
case msgTypeAck: {
|
||||
do_msgTypeAck(msg_len);
|
||||
good = do_msgTypeAck(msg_len);
|
||||
} break;
|
||||
case msgTypeMax: {
|
||||
do_msgTypeMax(msg_len);
|
||||
good = do_msgTypeMax(msg_len);
|
||||
} break;
|
||||
default:
|
||||
Logger().warning(fmt::format("{}: ID:{} Unknown command {}", conn_id_, id_, (int)last_command_));
|
||||
running_ = false;
|
||||
continue;
|
||||
default: {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("{}: Unknown command {} from device. GW closing connection.", Id_,
|
||||
(int)last_command_));
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
good = false;
|
||||
Logger().log(E,__FILE__,__LINE__);
|
||||
poco_warning(Logger(),fmt::format("{}: Exception. GW closing connection.", Id_));
|
||||
} catch (const std::exception &E) {
|
||||
poco_warning(Logger(),fmt::format("{}: Exception. GW closing connection.", Id_));
|
||||
good = false;
|
||||
}
|
||||
|
||||
if(!good) {
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_Device_ConnectionHandler::onSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
Guard G(M_);
|
||||
poco_information(Logger(),fmt::format("{}: Connection being closed - socket shutdown.",Id_));
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::SendToClient(const u_char *Buf, int Len) {
|
||||
return RTTYS_server()->SendToClient(Id_, Buf, Len);
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::SendToClient(const std::string &S) {
|
||||
return RTTYS_server()->SendToClient(Id_, S);
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::KeyStrokes(const u_char *buf, size_t len) {
|
||||
if(!valid_)
|
||||
return false;
|
||||
|
||||
if(len<=(sizeof(small_buf_)-3)) {
|
||||
small_buf_[0] = msgTypeTermData;
|
||||
small_buf_[1] = (len & 0xff00) >> 8;
|
||||
small_buf_[2] = (len & 0x00ff);
|
||||
memcpy(&small_buf_[3],buf,len);
|
||||
try {
|
||||
socket_.sendBytes(small_buf_,len+3);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
auto Msg = std::make_unique<unsigned char []>(len + 3);
|
||||
Msg.get()[0] = msgTypeTermData;
|
||||
Msg.get()[1] = (len & 0xff00) >> 8;
|
||||
Msg.get()[2] = (len & 0x00ff);
|
||||
memcpy((void *)(Msg.get() + 3), buf, len);
|
||||
try {
|
||||
socket_.sendBytes(Msg.get(), len + 3);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Logger().information(fmt::format("{}: ID:{} Exiting", conn_id_, id_));
|
||||
loop_done_=true;
|
||||
RTTYS_server()->DeRegister(id_, this);
|
||||
std::cout << conn_id_ << ": loop exiting" << std::endl;
|
||||
}
|
||||
/*
|
||||
unsigned char Msg[64];
|
||||
Msg[0] = msgTypeTermData;
|
||||
Msg[1] = (len & 0xff00) >> 8;
|
||||
Msg[2] = (len & 0x00ff);
|
||||
|
||||
void RTTY_Device_ConnectionHandler::Stop() {
|
||||
running_ = true;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::SendToClient(const u_char *Buf, int Len) {
|
||||
RTTYS_server()->SendToClient(id_, Buf, Len);
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::SendToClient(const std::string &S) {
|
||||
RTTYS_server()->SendToClient(id_, S);
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::KeyStrokes(const u_char *buf, size_t len) {
|
||||
std::lock_guard G(M_);
|
||||
u_char outBuf[16]{0};
|
||||
|
||||
if(len>(sizeof(outBuf)-5))
|
||||
return false;
|
||||
|
||||
auto total_len = 3 + 1 + len-1;
|
||||
outBuf[0] = msgTypeTermData;
|
||||
outBuf[1] = 0 ;
|
||||
outBuf[2] = len +1-1;
|
||||
outBuf[3] = sid_;
|
||||
memcpy( &outBuf[4], &buf[1], len-1);
|
||||
Poco::Net::SocketBufVec MsgParts{ Poco::Net::SocketBuf{ .iov_base=Msg, .iov_len=3},
|
||||
Poco::Net::SocketBuf{ .iov_base=(unsigned char *)buf, .iov_len=len}};
|
||||
try {
|
||||
socket().sendBytes(outBuf, total_len);
|
||||
socket_.sendBytes(MsgParts);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::WindowSize(int cols, int rows) {
|
||||
std::lock_guard G(M_);
|
||||
bool RTTYS_Device_ConnectionHandler::WindowSize(int cols, int rows) {
|
||||
if(!valid_)
|
||||
return false;
|
||||
|
||||
// Guard G(M_);
|
||||
|
||||
u_char outBuf[8]{0};
|
||||
outBuf[0] = msgTypeWinsize;
|
||||
outBuf[1] = 0 ;
|
||||
@@ -196,7 +252,7 @@ namespace OpenWifi {
|
||||
outBuf[6] = rows >> 8;
|
||||
outBuf[7] = rows & 0x00ff;
|
||||
try {
|
||||
socket().sendBytes(outBuf, 8);
|
||||
socket_.sendBytes(outBuf, 8);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
@@ -204,35 +260,40 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::Login() {
|
||||
std::lock_guard G(M_);
|
||||
bool RTTYS_Device_ConnectionHandler::Login() {
|
||||
if(!valid_)
|
||||
return false;
|
||||
|
||||
// Guard G(M_);
|
||||
u_char outBuf[3]{0};
|
||||
outBuf[0] = msgTypeLogin;
|
||||
outBuf[1] = 0;
|
||||
outBuf[2] = 0;
|
||||
try {
|
||||
socket().sendBytes(outBuf, 3);
|
||||
socket_.sendBytes(outBuf, 3);
|
||||
} catch (const Poco::IOException &E) {
|
||||
// std::cout << "1 " << E.what() << " " << E.name() << " "<< E.className() << " "<< E.message() << std::endl;
|
||||
return false;
|
||||
} catch (const Poco::Exception &E) {
|
||||
// std::cout << "2 " << E.what() << " " << E.name() << std::endl;
|
||||
return false;
|
||||
}
|
||||
Logger().debug(fmt::format("{}: Device {} login", conn_id_, id_));
|
||||
poco_information(Logger(),fmt::format("{}: Device login", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::Logout() {
|
||||
std::lock_guard G(M_);
|
||||
bool RTTYS_Device_ConnectionHandler::Logout() {
|
||||
if(!valid_)
|
||||
return false;
|
||||
|
||||
Guard G(M_);
|
||||
|
||||
u_char outBuf[4]{0};
|
||||
outBuf[0] = msgTypeLogout;
|
||||
outBuf[1] = 0;
|
||||
outBuf[2] = 1;
|
||||
outBuf[3] = sid_;
|
||||
Logger().debug(fmt::format("{}: ID:{} Logout", conn_id_, id_));
|
||||
poco_information(Logger(),fmt::format("{}: Logout", Id_));
|
||||
try {
|
||||
socket().sendBytes(outBuf, 4);
|
||||
socket_.sendBytes(outBuf, 4);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
@@ -240,7 +301,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string RTTY_Device_ConnectionHandler::ReadString() {
|
||||
std::string RTTYS_Device_ConnectionHandler::ReadString() {
|
||||
std::string Res;
|
||||
|
||||
while(inBuf_.used()) {
|
||||
@@ -255,16 +316,16 @@ namespace OpenWifi {
|
||||
return Res;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeRegister([[maybe_unused]] std::size_t msg_len) {
|
||||
socket().receiveBytes(inBuf_);
|
||||
id_ = ReadString();
|
||||
desc_ = ReadString();
|
||||
token_ = ReadString();
|
||||
serial_ = RTTYS_server()->SerialNumber(id_);
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeRegister([[maybe_unused]] std::size_t msg_len) {
|
||||
bool good = true;
|
||||
try {
|
||||
Id_ = ReadString();
|
||||
desc_ = ReadString();
|
||||
token_ = ReadString();
|
||||
|
||||
Poco::Thread::current()->setName(fmt::format("RTTY-device-thread-{}:{}:{}", conn_id_, id_, serial_));
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Description:{} Device registration", conn_id_, id_, serial_, desc_));
|
||||
if (RTTYS_server()->Register(id_, token_, this)) {
|
||||
poco_information(Logger(),
|
||||
fmt::format("{}: Description:{} Device registration", Id_, desc_));
|
||||
RTTYS_server()->NotifyDeviceRegistration(Id_,token_,this);
|
||||
u_char OutBuf[8];
|
||||
OutBuf[0] = msgTypeRegister;
|
||||
OutBuf[1] = 0;
|
||||
@@ -273,18 +334,20 @@ namespace OpenWifi {
|
||||
OutBuf[4] = 'O';
|
||||
OutBuf[5] = 'K';
|
||||
OutBuf[6] = 0;
|
||||
if(socket().sendBytes(OutBuf, 7) !=7) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Description:{} Could not complete registration", conn_id_, id_, serial_, desc_));
|
||||
running_ = false;
|
||||
if (socket_.sendBytes(OutBuf, 7) != 7) {
|
||||
poco_information(Logger(),
|
||||
fmt::format("{}: Description:{} Could not send data to complete registration",
|
||||
Id_, desc_));
|
||||
good = false;
|
||||
}
|
||||
} else {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Description:{} Could not complete registration", conn_id_, id_, serial_, desc_));
|
||||
running_ = false;
|
||||
} catch (...) {
|
||||
good = false;
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeLogin([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for login", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeLogin([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for login", Id_));
|
||||
nlohmann::json doc;
|
||||
char Error;
|
||||
inBuf_.read(&Error, 1);
|
||||
@@ -292,66 +355,79 @@ namespace OpenWifi {
|
||||
doc["type"] = "login";
|
||||
doc["err"] = Error;
|
||||
const auto login_msg = to_string(doc);
|
||||
SendToClient(login_msg);
|
||||
return SendToClient(login_msg);
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeLogout([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for logout", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeLogout([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for logout", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeTermData(std::size_t msg_len) {
|
||||
if(waiting_for_bytes_!=0) {
|
||||
// std::cout << conn_id_ << ": S2:" << inBuf_.used() << std::endl;
|
||||
auto to_read = std::min(inBuf_.used(),waiting_for_bytes_);
|
||||
inBuf_.read(&scratch_[0], to_read);
|
||||
SendToClient((u_char *)&scratch_[0], (int) to_read);
|
||||
if(to_read<waiting_for_bytes_)
|
||||
waiting_for_bytes_ -= to_read;
|
||||
else
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeTermData(std::size_t msg_len) {
|
||||
bool good;
|
||||
if(waiting_for_bytes_>0) {
|
||||
if(inBuf_.used()<waiting_for_bytes_) {
|
||||
waiting_for_bytes_ = waiting_for_bytes_ - inBuf_.used();
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), (int) inBuf_.used());
|
||||
if(!good) std::cout << "do_msgTypeTermData:1" << std::endl;
|
||||
inBuf_.drain();
|
||||
} else {
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), waiting_for_bytes_);
|
||||
if(!good) std::cout << "do_msgTypeTermData:2" << std::endl;
|
||||
inBuf_.drain(waiting_for_bytes_);
|
||||
waiting_for_bytes_ = 0 ;
|
||||
}
|
||||
} else {
|
||||
if(inBuf_.used()<msg_len) {
|
||||
// std::cout << conn_id_ << ": S1:" << msg_len << std::endl;
|
||||
auto read_count = inBuf_.read(&scratch_[0], inBuf_.used());
|
||||
SendToClient((u_char *)&scratch_[0], read_count);
|
||||
waiting_for_bytes_ = msg_len - read_count;
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), inBuf_.used());
|
||||
if(!good) std::cout << "do_msgTypeTermData:3" << std::endl;
|
||||
waiting_for_bytes_ = msg_len - inBuf_.used();
|
||||
inBuf_.drain();
|
||||
} else {
|
||||
// std::cout << conn_id_ << ": S0:" << msg_len << std::endl;
|
||||
inBuf_.read(&scratch_[0], msg_len);
|
||||
SendToClient((u_char *)&scratch_[0], (int)msg_len);
|
||||
waiting_for_bytes_=0;
|
||||
waiting_for_bytes_ = 0 ;
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), msg_len);
|
||||
if(!good) std::cout << "do_msgTypeTermData:4" << std::endl;
|
||||
inBuf_.drain(msg_len);
|
||||
}
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeWinsize([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for msgTypeWinsize", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeWinsize([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeWinsize", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeCmd([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for msgTypeCmd", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeCmd([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeCmd", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeHeartbeat([[maybe_unused]] std::size_t msg_len) {
|
||||
// std::cout << conn_id_ << ": Device msgTypeHeartbeat: " << std::endl;
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeHeartbeat([[maybe_unused]] std::size_t msg_len) {
|
||||
if(!RTTYS_server()->ValidClient(Id_))
|
||||
return false;
|
||||
u_char MsgBuf[3]{0};
|
||||
MsgBuf[0] = msgTypeHeartbeat;
|
||||
socket().sendBytes(MsgBuf, 3);
|
||||
return socket_.sendBytes(MsgBuf, 3)==3;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeFile([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for msgTypeFile", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeFile([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeFile", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeHttp([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for msgTypeHttp", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeHttp([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeHttp", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeAck([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for msgTypeAck", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeAck([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeAck", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::do_msgTypeMax([[maybe_unused]] std::size_t msg_len) {
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Asking for msgTypeMax", conn_id_, id_, serial_));
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeMax([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeMax", Id_));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -7,77 +7,79 @@
|
||||
#include <array>
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/FIFOBuffer.h"
|
||||
#include "Poco/Net/TCPServerConnectionFactory.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
inline static const std::size_t RTTY_DEVICE_BUFSIZE=64000;
|
||||
constexpr std::size_t RTTY_DEVICE_BUFSIZE=64000;
|
||||
|
||||
inline static std::atomic_uint64_t global_device_connection_id = 1;
|
||||
class RTTYS_Device_ConnectionHandler{
|
||||
public:
|
||||
enum RTTY_MSG_TYPE {
|
||||
msgTypeRegister = 0,
|
||||
msgTypeLogin,
|
||||
msgTypeLogout,
|
||||
msgTypeTermData,
|
||||
msgTypeWinsize,
|
||||
msgTypeCmd,
|
||||
msgTypeHeartbeat,
|
||||
msgTypeFile,
|
||||
msgTypeHttp,
|
||||
msgTypeAck,
|
||||
msgTypeMax };
|
||||
|
||||
class RTTY_Device_ConnectionHandler : public Poco::Net::TCPServerConnection {
|
||||
public:
|
||||
enum RTTY_MSG_TYPE {
|
||||
msgTypeRegister = 0,
|
||||
msgTypeLogin,
|
||||
msgTypeLogout,
|
||||
msgTypeTermData,
|
||||
msgTypeWinsize,
|
||||
msgTypeCmd,
|
||||
msgTypeHeartbeat,
|
||||
msgTypeFile,
|
||||
msgTypeHttp,
|
||||
msgTypeAck,
|
||||
msgTypeMax };
|
||||
explicit RTTYS_Device_ConnectionHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor& reactor);
|
||||
~RTTYS_Device_ConnectionHandler();
|
||||
|
||||
explicit RTTY_Device_ConnectionHandler(const Poco::Net::StreamSocket & socket) ;
|
||||
~RTTY_Device_ConnectionHandler();
|
||||
bool Login();
|
||||
bool Logout();
|
||||
|
||||
void run() final;
|
||||
bool Login();
|
||||
bool Logout();
|
||||
void Stop();
|
||||
[[nodiscard]] bool SendToClient(const u_char *buf, int len);
|
||||
[[nodiscard]] bool SendToClient(const std::string &S);
|
||||
[[nodiscard]] bool WindowSize(int cols, int rows);
|
||||
[[nodiscard]] bool KeyStrokes(const u_char *buf, size_t len);
|
||||
std::string ReadString();
|
||||
// inline auto SessionID() const { return conn_id_; }
|
||||
|
||||
void SendToClient(const u_char *buf, int len);
|
||||
void SendToClient(const std::string &S);
|
||||
bool WindowSize(int cols, int rows);
|
||||
bool KeyStrokes(const u_char *buf, size_t len);
|
||||
std::string ReadString();
|
||||
inline auto SessionID() const { return conn_id_; }
|
||||
void AddCommand(u_char C);
|
||||
void onSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void onSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);
|
||||
|
||||
private:
|
||||
std::atomic_bool running_=false;
|
||||
std::atomic_bool loop_done_=false;
|
||||
std::recursive_mutex M_;
|
||||
Poco::Logger &Logger_;
|
||||
std::string id_;
|
||||
std::string token_;
|
||||
std::string desc_;
|
||||
std::string serial_;
|
||||
char sid_=0;
|
||||
Poco::FIFOBuffer inBuf_{64000};
|
||||
std::array<char,32000> scratch_{0};
|
||||
std::size_t waiting_for_bytes_{0};
|
||||
u_char last_command_=0;
|
||||
uint64_t conn_id_=0;
|
||||
std::vector<u_char> commands_;
|
||||
using My_mutex_type = std::recursive_mutex;
|
||||
using Guard = std::lock_guard<My_mutex_type>;
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
inline Poco::Logger &Logger() { return Logger_; }
|
||||
inline bool Valid() { return valid_; }
|
||||
|
||||
void do_msgTypeRegister(std::size_t msg_len);
|
||||
void do_msgTypeLogin(std::size_t msg_len);
|
||||
void do_msgTypeLogout(std::size_t msg_len);
|
||||
void do_msgTypeTermData(std::size_t msg_len);
|
||||
void do_msgTypeWinsize(std::size_t msg_len);
|
||||
void do_msgTypeCmd(std::size_t msg_len);
|
||||
void do_msgTypeHeartbeat(std::size_t msg_len);
|
||||
void do_msgTypeFile(std::size_t msg_len);
|
||||
void do_msgTypeHttp(std::size_t msg_len);
|
||||
void do_msgTypeAck(std::size_t msg_len);
|
||||
void do_msgTypeMax(std::size_t msg_len);
|
||||
private:
|
||||
Poco::Net::StreamSocket socket_;
|
||||
Poco::Net::SocketReactor &reactor_;
|
||||
Poco::FIFOBuffer inBuf_{RTTY_DEVICE_BUFSIZE};
|
||||
Poco::Logger &Logger_;
|
||||
|
||||
bool ProcessCommands();
|
||||
};
|
||||
std::atomic_bool valid_=false;
|
||||
Poco::Net::SocketAddress device_address_;
|
||||
My_mutex_type M_;
|
||||
std::string Id_;
|
||||
std::string token_;
|
||||
std::string desc_;
|
||||
char sid_=0;
|
||||
std::size_t waiting_for_bytes_{0};
|
||||
u_char last_command_=0;
|
||||
unsigned char small_buf_[64];
|
||||
|
||||
void EndConnection(bool SendNotification=true) ;
|
||||
void CompleteConnection();
|
||||
|
||||
[[nodiscard]] bool do_msgTypeRegister(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeLogin(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeLogout(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeTermData(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeWinsize(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeCmd(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeHeartbeat(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeFile(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeHttp(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeAck(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeMax(std::size_t msg_len);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,284 +13,292 @@ namespace OpenWifi {
|
||||
|
||||
Internal_ = MicroService::instance().ConfigGetBool("rtty.internal",false);
|
||||
if(Internal_) {
|
||||
int DSport = MicroService::instance().ConfigGetInt("rtty.port", 5912);
|
||||
int CSport = MicroService::instance().ConfigGetInt("rtty.viewport", 5913);
|
||||
RTTY_UIAssets_ =
|
||||
MicroService::instance().ConfigPath("rtty.assets", "$OWGW_ROOT/rtty_ui");
|
||||
int DSport = (int) MicroService::instance().ConfigGetInt("rtty.port", 5912);
|
||||
int CSport = (int) MicroService::instance().ConfigGetInt("rtty.viewport", 5913);
|
||||
RTTY_UIAssets_ = MicroService::instance().ConfigPath("rtty.assets", "$OWGW_ROOT/rtty_ui");
|
||||
|
||||
auto CertFileName = MicroService::instance().ConfigPath("openwifi.restapi.host.0.cert");
|
||||
auto KeyFileName = MicroService::instance().ConfigPath("openwifi.restapi.host.0.key");
|
||||
auto RootCa = MicroService::instance().ConfigPath("openwifi.restapi.host.0.rootca");
|
||||
Poco::Crypto::X509Certificate Root(RootCa);
|
||||
const auto & CertFileName = MicroService::instance().ConfigPath("openwifi.restapi.host.0.cert");
|
||||
const auto & KeyFileName = MicroService::instance().ConfigPath("openwifi.restapi.host.0.key");
|
||||
const auto & RootCa = MicroService::instance().ConfigPath("openwifi.restapi.host.0.rootca");
|
||||
|
||||
auto DeviceSecureContext = new Poco::Net::Context(Poco::Net::Context::SERVER_USE,
|
||||
KeyFileName, CertFileName, "",
|
||||
Poco::Net::Context::VERIFY_RELAXED);
|
||||
auto TcpServerParams = new Poco::Net::TCPServerParams();
|
||||
TcpServerParams->setMaxThreads(50);
|
||||
TcpServerParams->setMaxQueued(100);
|
||||
TcpServerParams->setThreadIdleTime(Poco::Timespan(10,0));
|
||||
|
||||
DeviceSecureContext->addCertificateAuthority(Root);
|
||||
DeviceSecureContext->disableStatelessSessionResumption();
|
||||
DeviceSecureContext->enableSessionCache();
|
||||
DeviceSecureContext->setSessionCacheSize(0);
|
||||
DeviceSecureContext->setSessionTimeout(10);
|
||||
DeviceSecureContext->enableExtendedCertificateVerification(true);
|
||||
SSL_CTX *SSLCtxDevice = DeviceSecureContext->sslContext();
|
||||
SSL_CTX_dane_enable(SSLCtxDevice);
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Poco::Net::ServerSocket DeviceSocket(DSport, 64);
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>>(DeviceSocket,DeviceReactor_);
|
||||
} else {
|
||||
auto DeviceSecureContext = new Poco::Net::Context(Poco::Net::Context::SERVER_USE,
|
||||
KeyFileName, CertFileName, "",
|
||||
Poco::Net::Context::VERIFY_RELAXED);
|
||||
Poco::Crypto::X509Certificate DeviceRoot(RootCa);
|
||||
DeviceSecureContext->addCertificateAuthority(DeviceRoot);
|
||||
DeviceSecureContext->disableStatelessSessionResumption();
|
||||
DeviceSecureContext->enableSessionCache();
|
||||
DeviceSecureContext->setSessionCacheSize(0);
|
||||
DeviceSecureContext->setSessionTimeout(10);
|
||||
DeviceSecureContext->enableExtendedCertificateVerification(true);
|
||||
SSL_CTX *SSLCtxDevice = DeviceSecureContext->sslContext();
|
||||
SSL_CTX_dane_enable(SSLCtxDevice);
|
||||
|
||||
Poco::Net::SecureServerSocket DeviceSocket(DSport, 64, DeviceSecureContext);
|
||||
Poco::Net::TCPServerParams* pParams = new Poco::Net::TCPServerParams();
|
||||
pParams->setMaxThreads(50);
|
||||
pParams->setMaxQueued(100);
|
||||
// pParams->setThreadIdleTime(100);
|
||||
Poco::Net::SecureServerSocket DeviceSocket(DSport, 64, DeviceSecureContext);
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>>(DeviceSocket,DeviceReactor_);
|
||||
}
|
||||
DeviceReactorThread_.start(DeviceReactor_);
|
||||
Utils::SetThreadName(DeviceReactorThread_,"rt:devreactor");
|
||||
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::TCPServer>(new Poco::Net::TCPServerConnectionFactoryImpl<RTTY_Device_ConnectionHandler>(), DeviceSocket, pParams);
|
||||
DeviceAcceptor_->start();
|
||||
auto WebServerHttpParams = new Poco::Net::HTTPServerParams;
|
||||
WebServerHttpParams->setMaxThreads(50);
|
||||
WebServerHttpParams->setMaxQueued(200);
|
||||
WebServerHttpParams->setKeepAlive(true);
|
||||
|
||||
auto ClientSecureContext =
|
||||
new Poco::Net::Context(Poco::Net::Context::SERVER_USE, KeyFileName, CertFileName,
|
||||
"", Poco::Net::Context::VERIFY_RELAXED);
|
||||
ClientSecureContext->addCertificateAuthority(Root);
|
||||
ClientSecureContext->disableStatelessSessionResumption();
|
||||
ClientSecureContext->enableSessionCache();
|
||||
ClientSecureContext->setSessionCacheSize(0);
|
||||
ClientSecureContext->setSessionTimeout(10);
|
||||
ClientSecureContext->enableExtendedCertificateVerification(true);
|
||||
SSL_CTX *SSLCtxClient = ClientSecureContext->sslContext();
|
||||
SSL_CTX_dane_enable(SSLCtxClient);
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Poco::Net::ServerSocket ClientSocket(CSport, 64);
|
||||
ClientSocket.setNoDelay(true);
|
||||
WebServer_ = std::make_unique<Poco::Net::HTTPServer>(new RTTYS_Client_RequestHandlerFactory(Logger()), ClientSocket, WebServerHttpParams);
|
||||
} else {
|
||||
auto WebClientSecureContext = new Poco::Net::Context(Poco::Net::Context::SERVER_USE, KeyFileName, CertFileName,
|
||||
"", Poco::Net::Context::VERIFY_RELAXED);
|
||||
Poco::Crypto::X509Certificate WebRoot(RootCa);
|
||||
WebClientSecureContext->addCertificateAuthority(WebRoot);
|
||||
WebClientSecureContext->disableStatelessSessionResumption();
|
||||
WebClientSecureContext->enableSessionCache();
|
||||
WebClientSecureContext->setSessionCacheSize(0);
|
||||
WebClientSecureContext->setSessionTimeout(10);
|
||||
WebClientSecureContext->enableExtendedCertificateVerification(true);
|
||||
SSL_CTX *SSLCtxClient = WebClientSecureContext->sslContext();
|
||||
SSL_CTX_dane_enable(SSLCtxClient);
|
||||
|
||||
Poco::Net::SecureServerSocket ClientSocket(CSport, 64, ClientSecureContext);
|
||||
ClientSocket.setNoDelay(true);
|
||||
|
||||
auto HttpParams = new Poco::Net::HTTPServerParams;
|
||||
HttpParams->setMaxThreads(50);
|
||||
HttpParams->setMaxQueued(200);
|
||||
HttpParams->setKeepAlive(true);
|
||||
|
||||
WebServer_ = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new RTTY_Client_RequestHandlerFactory(ClientReactor_), ClientSocket, HttpParams);
|
||||
ClientReactorThread_.setName("RTTYWebServerClientThread");
|
||||
ClientReactorThread_.start(ClientReactor_);
|
||||
Poco::Net::SecureServerSocket ClientSocket(CSport, 64, WebClientSecureContext);
|
||||
ClientSocket.setNoDelay(true);
|
||||
WebServer_ = std::make_unique<Poco::Net::HTTPServer>(new RTTYS_Client_RequestHandlerFactory(Logger()), ClientSocket, WebServerHttpParams);
|
||||
};
|
||||
WebServer_->start();
|
||||
ClientReactorThread_.start(ClientReactor_);
|
||||
Utils::SetThreadName(ClientReactorThread_,"rt:clntreactor");
|
||||
}
|
||||
|
||||
GCCallBack_ = std::make_unique<Poco::TimerCallback<RTTYS_server>>(*this, &RTTYS_server::onTimer);
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 30 seconds
|
||||
Timer_.setPeriodicInterval(20 * 1000);
|
||||
Timer_.start(*GCCallBack_);
|
||||
|
||||
NotificationManager_.start(*this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RTTYS_server::Stop() {
|
||||
if(Internal_) {
|
||||
NotificationManagerRunning_=false;
|
||||
ResponseQueue_.wakeUpAll();
|
||||
NotificationManager_.wakeUp();
|
||||
NotificationManager_.join();
|
||||
Timer_.stop();
|
||||
WebServer_->stopAll();
|
||||
DeviceAcceptor_->stop();
|
||||
WebServer_->stop();
|
||||
DeviceAcceptor_->unregisterAcceptor();
|
||||
DeviceReactor_.stop();
|
||||
DeviceReactorThread_.join();
|
||||
ClientReactor_.stop();
|
||||
ClientReactorThread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::Register(const std::string &Id, RTTYS_ClientConnection *Client) {
|
||||
std::lock_guard G(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end()) {
|
||||
It->second.Client = Client;
|
||||
It->second.ClientConnected = OpenWifi::Now();
|
||||
void RTTYS_server::onTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
poco_debug(Logger(),"Removing stale connections.");
|
||||
Utils::SetThreadName("rt:janitor");
|
||||
static int count = 0;
|
||||
// MutexLockerDbg L(__func__ ,M_);
|
||||
|
||||
std::unique_lock G(M_);
|
||||
for(auto element=EndPoints_.begin();element!=EndPoints_.end();) {
|
||||
if(element->second->TooOld()) {
|
||||
auto c = fmt::format("Removing {}. Serial: {} Device connection time: {}s. Client connection time: {}s",
|
||||
element->first,
|
||||
element->second->SerialNumber(),
|
||||
element->second->TimeDeviceConnected(),
|
||||
element->second->TimeClientConnected());
|
||||
Logger().information(c);
|
||||
TotalConnectedClientTime_ += element->second->TimeClientConnected();
|
||||
TotalConnectedDeviceTime_ += element->second->TimeDeviceConnected();
|
||||
element = EndPoints_.erase(element);
|
||||
} else {
|
||||
++element;
|
||||
}
|
||||
}
|
||||
FailedDevices.clear();
|
||||
FailedClients.clear();
|
||||
count++;
|
||||
if(count==10) {
|
||||
count=0;
|
||||
Logger().information(fmt::format("Total connections:{} Total Device Connection Time: {}s Total Client Connection Time: {}s Device failures: {} Client failures: {}",
|
||||
TotalEndPoints_,
|
||||
TotalConnectedDeviceTime_,
|
||||
TotalConnectedClientTime_,
|
||||
FaildedNumDevices_,
|
||||
FailedNumClients_));
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::CreateNewClient(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response, const std::string &id) {
|
||||
|
||||
auto NewClient = new RTTYS_ClientConnection(request, response, ClientReactor_, id);
|
||||
NotifyClientRegistration(id,NewClient);
|
||||
}
|
||||
|
||||
void RTTYS_server::run() {
|
||||
Utils::SetThreadName("rtty-mgr");
|
||||
NotificationManagerRunning_ = true;
|
||||
Poco::AutoPtr<Poco::Notification> NextNotification(ResponseQueue_.waitDequeueNotification());
|
||||
while (NextNotification && NotificationManagerRunning_) {
|
||||
auto Notification = dynamic_cast<RTTYS_Notification *>(NextNotification.get());
|
||||
if (Notification != nullptr) {
|
||||
std::unique_lock G(M_);
|
||||
auto It = EndPoints_.find(Notification->id_);
|
||||
if (It != EndPoints_.end()) {
|
||||
switch (Notification->type_) {
|
||||
case RTTYS_Notification_type::device_disconnection: {
|
||||
It->second->DisconnectDevice();
|
||||
} break;
|
||||
case RTTYS_Notification_type::client_disconnection: {
|
||||
It->second->DisconnectClient();
|
||||
} break;
|
||||
case RTTYS_Notification_type::device_registration: {
|
||||
auto ptr = std::unique_ptr<RTTYS_Device_ConnectionHandler>{Notification->device_};
|
||||
It->second->SetDevice(std::move(ptr));
|
||||
if(!It->second->Joined() && It->second->ValidClient()) {
|
||||
It->second->Join();
|
||||
It->second->Login();
|
||||
}
|
||||
} break;
|
||||
case RTTYS_Notification_type::client_registration: {
|
||||
auto ptr = std::unique_ptr<RTTYS_ClientConnection>{Notification->client_};
|
||||
It->second->SetClient(std::move(ptr));
|
||||
if(!It->second->Joined() && It->second->ValidDevice()) {
|
||||
It->second->Join();
|
||||
It->second->Login();
|
||||
}
|
||||
} break;
|
||||
case RTTYS_Notification_type::unknown: {
|
||||
} break;
|
||||
};
|
||||
} else {
|
||||
if(Notification->type_==RTTYS_Notification_type::device_registration) {
|
||||
FaildedNumDevices_++;
|
||||
auto ptr = std::unique_ptr<RTTYS_Device_ConnectionHandler>{Notification->device_};
|
||||
FailedDevices.push_back(std::move(ptr));
|
||||
} else if(Notification->type_==RTTYS_Notification_type::client_registration) {
|
||||
FailedNumClients_++;
|
||||
auto ptr = std::unique_ptr<RTTYS_ClientConnection>{Notification->client_};
|
||||
FailedClients.push_back(std::move(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
NextNotification = ResponseQueue_.waitDequeueNotification();
|
||||
}
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendToClient(const std::string &Id, const u_char *Buf, std::size_t Len) {
|
||||
std::lock_guard G(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Client!= nullptr) {
|
||||
It->second.Client->SendData(Buf,Len);
|
||||
return true;
|
||||
std::shared_lock Guard(M_);
|
||||
try {
|
||||
auto It = EndPoints_.find(Id);
|
||||
if (It != EndPoints_.end()) {
|
||||
return It->second->SendToClient(Buf,Len);
|
||||
}
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
std::cout << "Exception in SendToClient 1" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendToClient(const std::string &Id, const std::string &s) {
|
||||
std::lock_guard G(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Client!= nullptr) {
|
||||
It->second.Client->SendData(s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void RTTYS_server::DeRegister(const std::string &Id, RTTYS_ClientConnection *Client) {
|
||||
std::lock_guard G(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end() && It->second.Client==Client) {
|
||||
if(It->second.Device!= nullptr) {
|
||||
It->second.Device->Stop();
|
||||
std::shared_lock Guard(M_);
|
||||
try {
|
||||
auto It = EndPoints_.find(Id);
|
||||
if (It != EndPoints_.end()) {
|
||||
return It->second->SendToClient(s);
|
||||
}
|
||||
It->second.ClientConnected=0;
|
||||
It->second.Client= nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool RTTYS_server::Register(const std::string &Id, const std::string &Token, RTTY_Device_ConnectionHandler *Device) {
|
||||
std::lock_guard G(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end()) {
|
||||
It->second.Device = Device;
|
||||
It->second.Token = Token;
|
||||
It->second.DeviceConnected = OpenWifi::Now();
|
||||
Logger().information(fmt::format("Creating session: {}, device:'{}'",Id,It->second.SerialNumber));
|
||||
return true;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
std::cout << "Exception in SendToClient 2" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RTTYS_server::DeRegister(const std::string &Id, RTTY_Device_ConnectionHandler *Device) {
|
||||
std::lock_guard G(M_);
|
||||
bool RTTYS_server::ValidClient(const std::string &Id) {
|
||||
std::shared_lock Guard(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Device==Device) {
|
||||
It->second.Device = nullptr;
|
||||
It->second.DeviceConnected = 0 ;
|
||||
return;
|
||||
}
|
||||
return It!=EndPoints_.end() && It->second->ValidClient();
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendKeyStrokes(const std::string &Id, const u_char *buffer, std::size_t s) {
|
||||
std::lock_guard G(M_);
|
||||
bool RTTYS_server::SendKeyStrokes(const std::string &Id, const u_char *buffer, std::size_t len) {
|
||||
std::shared_lock Guard(M_);
|
||||
|
||||
auto It=EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(It->second.Device!= nullptr)
|
||||
return It->second.Device->KeyStrokes(buffer,s);
|
||||
try {
|
||||
return It->second->KeyStrokes(buffer, len);
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::WindowSize(const std::string &Id, int cols, int rows) {
|
||||
std::lock_guard G(M_);
|
||||
std::shared_lock Guard(M_);
|
||||
auto It=EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(It->second.Device!= nullptr)
|
||||
return It->second.Device->WindowSize(cols,rows);
|
||||
try {
|
||||
return It->second->WindowSize(cols,rows);
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool RTTYS_server::CreateEndPoint(const std::string &Id, const std::string & Token, const std::string & UserName, const std::string & SerialNumber ) {
|
||||
std::lock_guard G(M_);
|
||||
std::unique_lock Guard(M_);
|
||||
|
||||
EndPoint E;
|
||||
E.Done = false;
|
||||
E.Token = Token;
|
||||
E.TimeStamp = std::time(nullptr);
|
||||
E.SerialNumber = SerialNumber;
|
||||
E.UserName = UserName;
|
||||
EndPoints_[Id] = E;
|
||||
auto NewEP = std::make_unique<RTTYS_EndPoint>(Token, SerialNumber, UserName );
|
||||
EndPoints_[Id] = std::move(NewEP);
|
||||
++TotalEndPoints_;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string RTTYS_server::SerialNumber(const std::string & Id) {
|
||||
std::lock_guard G(M_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end())
|
||||
return "";
|
||||
return It->second.SerialNumber;
|
||||
}
|
||||
|
||||
void RTTYS_server::LoginDone(const std::string & Id) {
|
||||
std::lock_guard G(M_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end())
|
||||
return;
|
||||
Logger().information(fmt::format("User: {}, Serial: {} logged in.",It->second.UserName, It->second.SerialNumber ));
|
||||
}
|
||||
|
||||
bool RTTYS_server::ValidEndPoint(const std::string &Id, const std::string &Token) {
|
||||
std::lock_guard G(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
uint64_t Now = std::time(nullptr);
|
||||
return ((It->second.Token == Token) && ((Now-It->second.TimeStamp)<30));
|
||||
}
|
||||
|
||||
bool RTTYS_server::CanConnect( const std::string &Id, RTTYS_ClientConnection *Conn) {
|
||||
std::lock_guard G(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Client==Conn) {
|
||||
It->second.ClientConnected = std::time(nullptr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::IsDeviceRegistered( const std::string &Id, const std::string &Token, [[maybe_unused]] RTTY_Device_ConnectionHandler *Conn) {
|
||||
std::lock_guard G(M_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It == EndPoints_.end() || It->second.Token != Token )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t RTTYS_server::DeviceSessionID(const std::string & Id) {
|
||||
auto it = EndPoints_.find(Id);
|
||||
if(it==EndPoints_.end()) {
|
||||
std::cout << "No ID found" << std::endl;
|
||||
return 0;
|
||||
} else {
|
||||
if(it->second.Device== nullptr) {
|
||||
std::cout << "No device for ID found" << std::endl;
|
||||
return 0;
|
||||
} else {
|
||||
return it->second.Device->SessionID();
|
||||
}
|
||||
}
|
||||
bool RTTYS_server::ValidId(const std::string &Token) {
|
||||
std::shared_lock Guard(M_);
|
||||
return EndPoints_.find(Token) != EndPoints_.end();
|
||||
}
|
||||
|
||||
bool RTTYS_server::Login(const std::string & Id) {
|
||||
std::lock_guard G(M_);
|
||||
std::shared_lock Guard(M_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It == EndPoints_.end()) {
|
||||
std::cout << "cannot find login " << Id << std::endl;
|
||||
auto ep = EndPoints_.find(Id);
|
||||
if(ep == EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(It->second.Device!= nullptr) {
|
||||
// std::cout << "login " << Id << " session " << It->second.Device->SessionID() << std::endl;
|
||||
// It->second.Device->AddCommand(RTTY_Device_ConnectionHandler::msgTypeLogin);
|
||||
// std::cout << "login done" << Id << std::endl;
|
||||
return It->second.Device->Login();
|
||||
try {
|
||||
return ep->second->Login();
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
std::cout << "no device so cannot login " << Id << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::Logout(const std::string & Id) {
|
||||
std::lock_guard G(M_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It == EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
if(It->second.Device!= nullptr)
|
||||
It->second.Device->Logout();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::Close(const std::string & Id) {
|
||||
std::lock_guard G(M_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It == EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(It->second.Device!= nullptr)
|
||||
It->second.Device->Stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,205 @@
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
|
||||
// #include "rttys/RTTYS_ClientConnection.h"
|
||||
|
||||
#include "Poco/Timer.h"
|
||||
#include "rttys/RTTYS_device.h"
|
||||
#include "rttys/RTTYS_ClientConnection.h"
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RTTY_Device_ConnectionHandler;
|
||||
class RTTYS_Device_ConnectionHandler;
|
||||
class RTTYS_ClientConnection;
|
||||
|
||||
class RTTYS_server : public SubSystemServer
|
||||
template <typename T> class MutexLockerDbg {
|
||||
public:
|
||||
MutexLockerDbg(const std::string &name, T &L) :
|
||||
name_(name),
|
||||
L_(L)
|
||||
{
|
||||
std::cout << name_ << ":L:0:" << Poco::Thread::current()->name() << ":" << Poco::Thread::currentTid() << std::endl;
|
||||
L_.lock();
|
||||
std::cout << name_ << ":L:1:" << Poco::Thread::current()->name() << ":" << Poco::Thread::currentTid() << std::endl;
|
||||
}
|
||||
|
||||
~MutexLockerDbg() {
|
||||
std::cout << name_ << ":U:0:" << Poco::Thread::current()->name() << ":" << Poco::Thread::currentTid() << std::endl;
|
||||
L_.unlock();
|
||||
std::cout << name_ << ":U:1:" << Poco::Thread::current()->name() << ":" << Poco::Thread::currentTid() << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
T & L_;
|
||||
};
|
||||
|
||||
enum class RTTYS_Notification_type {
|
||||
unknown,
|
||||
device_disconnection,
|
||||
client_disconnection,
|
||||
client_registration,
|
||||
device_registration
|
||||
};
|
||||
|
||||
class RTTYS_Notification: public Poco::Notification {
|
||||
public:
|
||||
RTTYS_Notification(const RTTYS_Notification_type &type, const std::string &id,
|
||||
RTTYS_Device_ConnectionHandler * device) :
|
||||
type_(type),
|
||||
id_(id),
|
||||
device_(device) {
|
||||
}
|
||||
|
||||
RTTYS_Notification(const RTTYS_Notification_type &type, const std::string &id,
|
||||
RTTYS_ClientConnection * client) :
|
||||
type_(type),
|
||||
id_(id),
|
||||
client_(client) {
|
||||
}
|
||||
|
||||
RTTYS_Notification(const RTTYS_Notification_type &type,
|
||||
const std::string &id,
|
||||
const std::string &token,
|
||||
RTTYS_Device_ConnectionHandler * device) :
|
||||
type_(type),
|
||||
id_(id),
|
||||
token_(token),
|
||||
device_(device) {
|
||||
}
|
||||
|
||||
RTTYS_Notification_type type_=RTTYS_Notification_type::unknown;
|
||||
std::string id_;
|
||||
std::string token_;
|
||||
RTTYS_Device_ConnectionHandler *device_= nullptr;
|
||||
RTTYS_ClientConnection *client_ = nullptr;
|
||||
};
|
||||
|
||||
class RTTYS_EndPoint {
|
||||
public:
|
||||
RTTYS_EndPoint(const std::string &Token, const std::string &SerialNumber, const std::string &UserName ):
|
||||
Token_(Token),
|
||||
SerialNumber_(SerialNumber),
|
||||
UserName_(UserName)
|
||||
{
|
||||
Created_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
inline void SetClient(std::unique_ptr<RTTYS_ClientConnection> Client) {
|
||||
ClientConnected_ = std::chrono::high_resolution_clock::now();
|
||||
Client_ = std::move(Client);
|
||||
}
|
||||
|
||||
inline void SetDevice(std::unique_ptr<RTTYS_Device_ConnectionHandler> Device) {
|
||||
DeviceConnected_ = std::chrono::high_resolution_clock::now();
|
||||
Device_ = std::move(Device);
|
||||
}
|
||||
|
||||
inline bool Login() {
|
||||
if(Device_!= nullptr) {
|
||||
return Device_->Login();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RTTYS_EndPoint & operator=(RTTYS_EndPoint Other) {
|
||||
Other.Client_ = std::move(Client_);
|
||||
Other.Device_ = std::move(Device_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void DisconnectClient() {
|
||||
ClientDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
inline void DisconnectDevice() {
|
||||
DeviceDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool TooOld() {
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();
|
||||
if(ClientDisconnected_!=std::chrono::time_point<std::chrono::high_resolution_clock>{0s} && (now-ClientDisconnected_)>15s) {
|
||||
if(DeviceDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
DeviceDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(DeviceDisconnected_!=std::chrono::time_point<std::chrono::high_resolution_clock>{0s} && (now-DeviceDisconnected_)>15s) {
|
||||
if(ClientDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
ClientDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!Joined_ && (now-Created_)>30s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// std::cout << ClientDisconnected_ << " " << ClientConnected_ << " " << DeviceDisconnected_ << " " << DeviceConnected_ << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SendToClient(const u_char *Buf, std::size_t Len) {
|
||||
if(Client_!= nullptr && Client_->Valid()) {
|
||||
Client_->SendData(Buf,Len);
|
||||
return true;
|
||||
}
|
||||
std::cout << "SendToClientFailure: " << (Client_!= nullptr) << " " << Client_->Valid() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool KeyStrokes(const u_char *buffer, std::size_t len) {
|
||||
if( Device_!= nullptr && Device_->Valid() )
|
||||
return Device_->KeyStrokes(buffer,len);
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool WindowSize( int cols, int rows) {
|
||||
if(Device_!= nullptr && Device_->Valid())
|
||||
return Device_->WindowSize(cols,rows);
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool ValidClient() const {
|
||||
return Client_!= nullptr && Client_->Valid();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool ValidDevice() const {
|
||||
return Device_!= nullptr && Device_->Valid();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool Joined() volatile const { return Joined_; }
|
||||
void Join() {
|
||||
Joined_=true;
|
||||
}
|
||||
|
||||
inline bool SendToClient(const std::string &S) {
|
||||
if(Client_!= nullptr && Client_->Valid()) {
|
||||
Client_->SendData(S);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const std::string & UserName() const { return UserName_; }
|
||||
[[nodiscard]] inline const std::string & SerialNumber() const { return SerialNumber_; }
|
||||
|
||||
[[nodiscard]] inline auto TimeDeviceConnected() const { return std::chrono::duration<double>{DeviceDisconnected_ - DeviceConnected_}.count(); }
|
||||
[[nodiscard]] inline auto TimeClientConnected() const { return std::chrono::duration<double>{ClientDisconnected_ - ClientConnected_}.count(); }
|
||||
|
||||
private:
|
||||
std::string Token_;
|
||||
std::string SerialNumber_;
|
||||
std::string UserName_;
|
||||
std::unique_ptr<RTTYS_ClientConnection> Client_;
|
||||
std::unique_ptr<RTTYS_Device_ConnectionHandler> Device_;
|
||||
std::string Id_;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock>
|
||||
Created_{0s},DeviceDisconnected_{0s},
|
||||
ClientDisconnected_{0s},DeviceConnected_{0s} ,ClientConnected_{0s};
|
||||
volatile bool Joined_=false;
|
||||
};
|
||||
|
||||
class RTTYS_server : public SubSystemServer, Poco::Runnable
|
||||
{
|
||||
public:
|
||||
static auto instance() {
|
||||
@@ -29,51 +218,71 @@ namespace OpenWifi {
|
||||
|
||||
inline auto UIAssets() { return RTTY_UIAssets_; }
|
||||
|
||||
void Register(const std::string &Id, RTTYS_ClientConnection *Client);
|
||||
void DeRegister(const std::string &Id, RTTYS_ClientConnection *Client);
|
||||
bool Register(const std::string &Id, const std::string &Token, RTTY_Device_ConnectionHandler *Device);
|
||||
void DeRegister(const std::string &Id, RTTY_Device_ConnectionHandler *Device);
|
||||
bool CreateEndPoint(const std::string &Id, const std::string & Token, const std::string & UserName, const std::string & SerialNumber );
|
||||
std::string SerialNumber(const std::string & Id);
|
||||
void LoginDone(const std::string & Id);
|
||||
bool ValidEndPoint(const std::string &Id, const std::string &Token);
|
||||
bool CanConnect( const std::string &Id, RTTYS_ClientConnection *Conn);
|
||||
bool IsDeviceRegistered( const std::string &Id, const std::string &Token, [[maybe_unused]] RTTY_Device_ConnectionHandler *Conn);
|
||||
bool Login(const std::string & Id_);
|
||||
bool Logout(const std::string & Id_);
|
||||
bool Close(const std::string & Id_);
|
||||
uint64_t DeviceSessionID(const std::string & Id);
|
||||
bool SendKeyStrokes(const std::string &Id, const u_char *buffer, std::size_t s);
|
||||
bool WindowSize(const std::string &Id, int cols, int rows);
|
||||
bool SendToClient(const std::string &id, const u_char *Buf, std::size_t Len);
|
||||
bool SendToClient(const std::string &id, const std::string &s);
|
||||
bool ValidClient(const std::string &id);
|
||||
bool ValidId(const std::string &Id);
|
||||
|
||||
struct EndPoint {
|
||||
std::string Token;
|
||||
RTTYS_ClientConnection * Client = nullptr;
|
||||
RTTY_Device_ConnectionHandler * Device = nullptr;
|
||||
uint64_t TimeStamp = std::time(nullptr);
|
||||
uint64_t DeviceConnected = 0;
|
||||
uint64_t ClientConnected = 0;
|
||||
std::string UserName;
|
||||
std::string SerialNumber;
|
||||
bool Done = false;
|
||||
};
|
||||
void run() final;
|
||||
|
||||
inline void NotifyDeviceDisconnect(const std::string &id, RTTYS_Device_ConnectionHandler *device) {
|
||||
ResponseQueue_.enqueueNotification(new RTTYS_Notification(RTTYS_Notification_type::device_disconnection,id,device));
|
||||
}
|
||||
|
||||
inline void NotifyClientDisconnect(const std::string &id, RTTYS_ClientConnection *client) {
|
||||
ResponseQueue_.enqueueNotification(new RTTYS_Notification(RTTYS_Notification_type::client_disconnection,id,client));
|
||||
}
|
||||
|
||||
inline void NotifyDeviceRegistration(const std::string &id, const std::string &token, RTTYS_Device_ConnectionHandler *device) {
|
||||
ResponseQueue_.enqueueNotification(new RTTYS_Notification(RTTYS_Notification_type::device_registration,id,token,device));
|
||||
}
|
||||
|
||||
inline void NotifyClientRegistration(const std::string &id, RTTYS_ClientConnection *client) {
|
||||
ResponseQueue_.enqueueNotification(new RTTYS_Notification(RTTYS_Notification_type::client_registration,id,client));
|
||||
}
|
||||
|
||||
void CreateNewClient(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response, const std::string &id);
|
||||
|
||||
void onTimer(Poco::Timer & timer);
|
||||
|
||||
inline bool UseInternal() const {
|
||||
return Internal_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex M_;
|
||||
Poco::Net::SocketReactor ClientReactor_;
|
||||
Poco::Thread ClientReactorThread_;
|
||||
std::string RTTY_UIAssets_;
|
||||
std::atomic_bool Internal_ = false;
|
||||
inline Poco::Net::SocketReactor & ClientReactor() { return ClientReactor_; }
|
||||
|
||||
private:
|
||||
Poco::Net::SocketReactor ClientReactor_;
|
||||
Poco::Net::SocketReactor DeviceReactor_;
|
||||
Poco::Thread ClientReactorThread_;
|
||||
std::string RTTY_UIAssets_;
|
||||
bool Internal_ = false;
|
||||
|
||||
std::map<std::string,std::unique_ptr<RTTYS_EndPoint>> EndPoints_; // id, endpoint
|
||||
std::unique_ptr<Poco::Net::HTTPServer> WebServer_;
|
||||
std::unique_ptr<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>> DeviceAcceptor_;
|
||||
Poco::Thread DeviceReactorThread_;
|
||||
Poco::NotificationQueue ResponseQueue_;
|
||||
mutable bool NotificationManagerRunning_=false;
|
||||
Poco::Thread NotificationManager_;
|
||||
|
||||
Poco::Timer Timer_;
|
||||
std::unique_ptr<Poco::TimerCallback<RTTYS_server>> GCCallBack_;
|
||||
std::list<std::unique_ptr<RTTYS_Device_ConnectionHandler>> FailedDevices;
|
||||
std::list<std::unique_ptr<RTTYS_ClientConnection>> FailedClients;
|
||||
mutable std::shared_mutex M_;
|
||||
|
||||
uint64_t TotalEndPoints_=0;
|
||||
uint64_t FaildedNumDevices_=0;
|
||||
uint64_t FailedNumClients_=0;
|
||||
double TotalConnectedDeviceTime_=0.0;
|
||||
double TotalConnectedClientTime_=0.0;
|
||||
|
||||
std::map<std::string, EndPoint> EndPoints_; // id, endpoint
|
||||
std::unique_ptr<Poco::Net::HTTPServer> WebServer_;
|
||||
std::unique_ptr<Poco::Net::TCPServer> DeviceAcceptor_;
|
||||
|
||||
explicit RTTYS_server() noexcept:
|
||||
SubSystemServer("RTTY_Server", "RTTY-SVR", "rtty.server")
|
||||
|
||||
@@ -20,7 +20,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement UpSert(Sess);
|
||||
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
std::string St{ "insert into Capabilities (SerialNumber, Capabilities, FirstUpdate, LastUpdate) values(?,?,?,?) on conflict (SerialNumber) do "
|
||||
" update set Capabilities=?, LastUpdate=?"};
|
||||
UpSert << ConvertParams(St),
|
||||
@@ -44,7 +44,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement UpSert(Sess);
|
||||
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
OpenWifi::Config::Capabilities Caps(Capabilities);
|
||||
Compat = Caps.Compatible();
|
||||
if(!Caps.Compatible().empty() && !Caps.Platform().empty())
|
||||
|
||||
@@ -202,8 +202,6 @@ typedef Poco::Tuple<
|
||||
std::string FullQuery = IntroStatement + DateSelector +
|
||||
" ORDER BY Submitted ASC " + ComputeRange(Offset, HowMany);
|
||||
|
||||
// std::cout << "Offset: " << Offset << " >> " << FullQuery << std::endl;
|
||||
|
||||
Select << FullQuery,
|
||||
Poco::Data::Keywords::into(Records);
|
||||
Select.execute();
|
||||
@@ -396,7 +394,7 @@ typedef Poco::Tuple<
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -430,7 +428,7 @@ typedef Poco::Tuple<
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -451,7 +449,7 @@ typedef Poco::Tuple<
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -503,7 +501,7 @@ typedef Poco::Tuple<
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -536,16 +534,81 @@ typedef Poco::Tuple<
|
||||
|
||||
}
|
||||
|
||||
bool Storage::AttachFileToCommand(std::string &UUID) {
|
||||
/* bool Storage::AttachFileToCommand(std::string &UUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
uint64_t Now = time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
uint64_t WaitForFile = 0;
|
||||
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
Poco::File FileName = FileUploader()->Path() + "/" + UUID;
|
||||
std::cout << __LINE__ << std::endl;
|
||||
uint64_t Size = FileName.getSize();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
std::string St{
|
||||
"UPDATE CommandList SET WaitingForFile=?, AttachDate=?, AttachSize=? WHERE UUID=?"};
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(WaitForFile),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Size),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
if (FileName.getSize() < FileUploader()->MaxSize()) {
|
||||
|
||||
Poco::Data::BLOB TheBlob;
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
std::ifstream f(FileName.path(), std::ios::binary);
|
||||
std::ostringstream SS;
|
||||
Poco::StreamCopier::copyStream(f, SS);
|
||||
TheBlob.appendRaw((const unsigned char *)SS.str().c_str(),SS.str().size());
|
||||
|
||||
std::cout << "Attach file size: " << SS.str().size() << std::endl;
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
std::string FileType{"trace"};
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
std::string St2{
|
||||
"INSERT INTO FileUploads (UUID,Type,Created,FileContent) VALUES(?,?,?,?)"};
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Insert << ConvertParams(St2), Poco::Data::Keywords::use(UUID),
|
||||
Poco::Data::Keywords::use(FileType),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(TheBlob);
|
||||
Insert.execute();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
FileName.remove();
|
||||
return true;
|
||||
} else {
|
||||
Logger().warning(fmt::format("File {} is too large.", FileName.path()));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
bool Storage::AttachFileDataToCommand(std::string & UUID, const std::stringstream & FileContent) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
uint64_t WaitForFile = 0;
|
||||
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
Poco::File FileName = FileUploader()->Path() + "/" + UUID;
|
||||
uint64_t Size = FileName.getSize();
|
||||
uint64_t Size = FileContent.str().size();
|
||||
|
||||
std::string St{
|
||||
"UPDATE CommandList SET WaitingForFile=?, AttachDate=?, AttachSize=? WHERE UUID=?"};
|
||||
@@ -557,19 +620,12 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
|
||||
Poco::Data::LOB<char> L;
|
||||
Poco::Data::LOBOutputStream OL(L);
|
||||
if (Size < FileUploader()->MaxSize()) {
|
||||
|
||||
if (FileName.getSize() < FileUploader()->MaxSize()) {
|
||||
Poco::Data::BLOB TheBlob;
|
||||
|
||||
TheBlob.appendRaw((const unsigned char *)FileContent.str().c_str(),FileContent.str().size());
|
||||
|
||||
std::ifstream f(FileName.path(), std::ios::binary);
|
||||
Poco::StreamCopier::copyStream(f, OL);
|
||||
/*
|
||||
"UUID VARCHAR(64) PRIMARY KEY, "
|
||||
"Type VARCHAR(32), "
|
||||
"Created BIGINT, "
|
||||
"FileContent BYTEA"
|
||||
*/
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
std::string FileType{"trace"};
|
||||
|
||||
@@ -579,30 +635,21 @@ typedef Poco::Tuple<
|
||||
Insert << ConvertParams(St2), Poco::Data::Keywords::use(UUID),
|
||||
Poco::Data::Keywords::use(FileType),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(L);
|
||||
Poco::Data::Keywords::use(TheBlob);
|
||||
Insert.execute();
|
||||
|
||||
FileName.remove();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
Logger().warning(fmt::format("File {} is too large.", FileName.path()));
|
||||
Logger().warning(fmt::format("File {} is too large.", UUID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetAttachedFile(std::string &UUID, const std::string & SerialNumber, const std::string &FileName, std::string &Type) {
|
||||
/* bool Storage::GetAttachedFile(std::string &UUID, const std::string & SerialNumber, const std::string &FileName, std::string &Type) {
|
||||
try {
|
||||
Poco::Data::LOB<char> L;
|
||||
/*
|
||||
"UUID VARCHAR(64) PRIMARY KEY, "
|
||||
"Type VARCHAR(32), "
|
||||
"Created BIGINT, "
|
||||
"FileContent BYTEA"
|
||||
*/
|
||||
Poco::Data::BLOB L;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select1(Sess);
|
||||
|
||||
@@ -626,10 +673,55 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Select2.execute();
|
||||
|
||||
Poco::Data::LOBInputStream IL(L);
|
||||
std::ofstream f(FileName, std::ios::binary);
|
||||
Poco::StreamCopier::copyStream(IL, f);
|
||||
// Poco::Data::BLOBInputStream IL(L);
|
||||
std::ofstream f(FileName, std::ios::binary | std::ios::trunc );
|
||||
auto Content = L.content();
|
||||
std::string SS(L.content().begin(),L.content().end());
|
||||
f << SS;
|
||||
|
||||
std::cout << "Get Attach Size: " << L.content().size() << std::endl;
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
bool Storage::GetAttachedFileContent(std::string &UUID, const std::string & SerialNumber, std::string &FileContent, std::string &Type) {
|
||||
try {
|
||||
Poco::Data::BLOB L;
|
||||
/*
|
||||
"UUID VARCHAR(64) PRIMARY KEY, "
|
||||
"Type VARCHAR(32), "
|
||||
"Created BIGINT, "
|
||||
"FileContent BYTEA"
|
||||
*/
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select1(Sess);
|
||||
|
||||
std::string TmpSerialNumber;
|
||||
std::string st1{"SELECT SerialNumber FROM CommandList WHERE UUID=?"};
|
||||
Select1 << ConvertParams(st1),
|
||||
Poco::Data::Keywords::into(TmpSerialNumber),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Select1.execute();
|
||||
|
||||
if(TmpSerialNumber!=SerialNumber) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string St2{"SELECT FileContent, Type FROM FileUploads WHERE UUID=?"};
|
||||
|
||||
Poco::Data::Statement Select2(Sess);
|
||||
Select2 << ConvertParams(St2),
|
||||
Poco::Data::Keywords::into(L),
|
||||
Poco::Data::Keywords::into(Type),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Select2.execute();
|
||||
|
||||
FileContent.assign(L.content().begin(),L.content().end());
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -651,7 +743,7 @@ typedef Poco::Tuple<
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -709,7 +801,7 @@ typedef Poco::Tuple<
|
||||
}
|
||||
return true;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string St{"SELECT FROM DefaultConfigs WHERE Name=?"};
|
||||
std::string St{"SELECT name FROM DefaultConfigs WHERE Name=?"};
|
||||
Select << ConvertParams(St) ,
|
||||
Poco::Data::Keywords::into(TmpName) ,
|
||||
Name;
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace OpenWifi {
|
||||
"subscriber, "
|
||||
"entity, "
|
||||
"modified, "
|
||||
"locale "
|
||||
"locale"
|
||||
};
|
||||
|
||||
const static std::string DB_DeviceUpdateFields{
|
||||
@@ -169,12 +169,16 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany, std::vector<std::string> &SerialNumbers) {
|
||||
bool Storage::GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany, std::vector<std::string> &SerialNumbers, const std::string & orderBy) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT SerialNumber From Devices ORDER BY SerialNumber ASC " };
|
||||
std::string st;
|
||||
if(orderBy.empty())
|
||||
st = "SELECT SerialNumber From Devices ORDER BY SerialNumber ASC ";
|
||||
else
|
||||
st = "SELECT SerialNumber From Devices " + orderBy;
|
||||
|
||||
Select << st + ComputeRange(From, HowMany),
|
||||
Poco::Data::Keywords::into(SerialNumbers);
|
||||
@@ -244,7 +248,7 @@ namespace OpenWifi {
|
||||
|
||||
if (Select.rowsExtracted()==0) {
|
||||
Config::Config Cfg(DeviceDetails.Configuration);
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
|
||||
DeviceDetails.modified = OpenWifi::Now();
|
||||
DeviceDetails.CreationTimestamp = DeviceDetails.LastConfigurationDownload =
|
||||
@@ -351,7 +355,7 @@ namespace OpenWifi {
|
||||
D.MACAddress = Utils::SerialToMAC(SerialNumber);
|
||||
D.Manufacturer = Caps.Model();
|
||||
D.Firmware = Firmware;
|
||||
D.Notes = SecurityObjects::NoteInfoVec { SecurityObjects::NoteInfo{ (uint64_t)std::time(nullptr), "", "Auto-provisioned."}};
|
||||
D.Notes = SecurityObjects::NoteInfoVec { SecurityObjects::NoteInfo{ (uint64_t)OpenWifi::Now(), "", "Auto-provisioned."}};
|
||||
|
||||
CreateDeviceCapabilities(SerialNumber, Capabilities);
|
||||
|
||||
@@ -410,7 +414,7 @@ namespace OpenWifi {
|
||||
if(TmpFirmware != Firmware) {
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::string St2{"UPDATE Devices SET Firmware=?, LastFWUpdate=? WHERE SerialNumber=?"};
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
|
||||
Update << ConvertParams(St2),
|
||||
Poco::Data::Keywords::use(Firmware),
|
||||
@@ -522,7 +526,7 @@ namespace OpenWifi {
|
||||
|
||||
NewDeviceDetails.modified = OpenWifi::Now();
|
||||
ConvertDeviceRecord(NewDeviceDetails,R);
|
||||
// NewDeviceDetails.LastConfigurationChange = std::time(nullptr);
|
||||
// NewDeviceDetails.LastConfigurationChange = OpenWifi::Now();
|
||||
std::string St2{"UPDATE Devices SET " +
|
||||
DB_DeviceUpdateFields +
|
||||
" WHERE SerialNumber=?"};
|
||||
@@ -539,13 +543,19 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices) {
|
||||
bool Storage::GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices, const std::string & orderBy) {
|
||||
DeviceRecordList Records;
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
std::string st{"SELECT " + DB_DeviceSelectFields + " FROM Devices ORDER BY SerialNumber ASC " + ComputeRange(From, HowMany)};
|
||||
|
||||
// std::string st{"SELECT " + DB_DeviceSelectFields + " FROM Devices " + orderBy.empty() ? " ORDER BY SerialNumber ASC " + ComputeRange(From, HowMany)};
|
||||
std::string st = fmt::format("SELECT {} FROM Devices {} {}",
|
||||
DB_DeviceSelectFields,
|
||||
orderBy.empty() ? " ORDER BY SerialNumber ASC " : orderBy ,
|
||||
ComputeRange(From, HowMany));
|
||||
|
||||
Select << ConvertParams(st),
|
||||
Poco::Data::Keywords::into(Records);
|
||||
Select.execute();
|
||||
@@ -645,7 +655,7 @@ namespace OpenWifi {
|
||||
static const uint64_t SECONDS_HOUR = 60*60;
|
||||
|
||||
static std::string ComputeUpLastContactTag(uint64_t T1) {
|
||||
uint64_t T = T1 - std::time(nullptr);
|
||||
uint64_t T = T1 - OpenWifi::Now();
|
||||
if( T>SECONDS_MONTH) return ">month";
|
||||
if( T>SECONDS_WEEK) return ">week";
|
||||
if( T>SECONDS_DAY) return ">day";
|
||||
@@ -677,8 +687,10 @@ namespace OpenWifi {
|
||||
return ">75%";
|
||||
}
|
||||
|
||||
static std::string ComputeFreeMemoryTag(uint64_t Free, uint64_t Total) {
|
||||
auto V = 100.0 * ((float)Free/(float(Total)));
|
||||
static std::string ComputeUsedMemoryTag(uint64_t Free, uint64_t Total) {
|
||||
if(Total==0)
|
||||
return "< 5%";
|
||||
auto V = 100.0 * ((float)(Total-Free)/(float(Total)));
|
||||
if(V<5.0) return "< 5%";
|
||||
if(V<25.0) return "< 25%";
|
||||
if(V<50.0) return "< 50%";
|
||||
@@ -735,7 +747,7 @@ namespace OpenWifi {
|
||||
auto Memory = Unit->getObject("memory");
|
||||
uint64_t Free = Memory->get("free");
|
||||
uint64_t Total = Memory->get("total");
|
||||
UpdateCountedMap(Dashboard.memoryUsed, ComputeFreeMemoryTag(Free, Total));
|
||||
UpdateCountedMap(Dashboard.memoryUsed, ComputeUsedMemoryTag(Free, Total));
|
||||
}
|
||||
if (Unit->has("load")) {
|
||||
auto Load = Unit->getArray("load");
|
||||
@@ -765,5 +777,12 @@ namespace OpenWifi {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Storage::GetDeviceDbFieldList( Types::StringVec & FieldList) {
|
||||
const auto fields = Poco::StringTokenizer(DB_DeviceSelectFields,",",Poco::StringTokenizer::TOK_TRIM);
|
||||
for(const auto &field:fields)
|
||||
FieldList.push_back(field);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
Logger().information("Device:" + Stats.SerialNumber + " Stats size:" + std::to_string(Stats.Data.size()));
|
||||
poco_debug(Logger(),"Device:" + Stats.SerialNumber + " Stats size:" + std::to_string(Stats.Data.size()));
|
||||
std::string St{"INSERT INTO Statistics ( " +
|
||||
DB_StatsSelectFields +
|
||||
" ) VALUES ( " +
|
||||
|
||||
54
templates/livinlab-radius.json
Normal file
54
templates/livinlab-radius.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"pools": [
|
||||
{
|
||||
"acctConfig": {
|
||||
"methodParameters": [],
|
||||
"monitor": false,
|
||||
"monitorMethod": "none",
|
||||
"servers": [
|
||||
{
|
||||
"ip": "69.157.193.71",
|
||||
"name": "svr1",
|
||||
"port": 1813,
|
||||
"weight": 10,
|
||||
"secret": "testing123"
|
||||
}
|
||||
],
|
||||
"strategy": "random"
|
||||
},
|
||||
"authConfig": {
|
||||
"methodParameters": [],
|
||||
"monitor": false,
|
||||
"monitorMethod": "none",
|
||||
"servers": [
|
||||
{
|
||||
"ip": "69.157.193.71",
|
||||
"name": "svr1",
|
||||
"port": 1812,
|
||||
"weight": 10,
|
||||
"secret": "testing123"
|
||||
}
|
||||
],
|
||||
"strategy": "weighted"
|
||||
},
|
||||
"coaConfig": {
|
||||
"methodParameters": [],
|
||||
"monitor": false,
|
||||
"monitorMethod": "none",
|
||||
"servers": [
|
||||
{
|
||||
"ip": "69.157.193.71",
|
||||
"name": "svr1",
|
||||
"port": 3799,
|
||||
"weight": 10,
|
||||
"secret": "testing123"
|
||||
}
|
||||
],
|
||||
"strategy": "round_robin"
|
||||
},
|
||||
"description": "master pool",
|
||||
"name": "master",
|
||||
"useByDefault" : true
|
||||
}
|
||||
]
|
||||
}
|
||||
89
templates/radius_pools.json
Normal file
89
templates/radius_pools.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"pools" :
|
||||
[
|
||||
{
|
||||
"name" : "pool1_name",
|
||||
"description" : "This is the big pool 1",
|
||||
"authPolicy" : "weighted",
|
||||
"acctPolicy" : "round-robin",
|
||||
"authMonitor" : true ,
|
||||
"authMonitorMethod" : {
|
||||
},
|
||||
"acctMonitor" : false,
|
||||
"authServers" : [{
|
||||
"name" : "server 1 in pool 1",
|
||||
"ip" : "1.2.3.4",
|
||||
"port" : 1812,
|
||||
"weight" : 50
|
||||
},
|
||||
{
|
||||
"name" : "server 2 in pool 1",
|
||||
"ip" : "1.2.3.5",
|
||||
"port" : 1812,
|
||||
"weight" : 25
|
||||
},
|
||||
{
|
||||
"name" : "server 3 in pool 1",
|
||||
"ip" : "1.2.3.6",
|
||||
"port" : 1812,
|
||||
"weight" : 25
|
||||
}
|
||||
],
|
||||
"acctServers" : [{
|
||||
"name" : "server 1 in pool 1",
|
||||
"ip" : "1.2.3.4",
|
||||
"port" : 1813
|
||||
},
|
||||
{
|
||||
"name" : "server 2 in pool 1",
|
||||
"ip" : "1.2.3.5",
|
||||
"port" : 1813
|
||||
},
|
||||
{
|
||||
"name" : "server 3 in pool 1",
|
||||
"ip" : "1.2.3.6",
|
||||
"port" : 1813
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "pool2_name",
|
||||
"description" : "This is the big pool 2",
|
||||
"authServers" : [{
|
||||
"name" : "server 1 in pool 2",
|
||||
"ip" : "1.2.4.4",
|
||||
"port" : 1812
|
||||
},
|
||||
{
|
||||
"name" : "server 2 in pool 2",
|
||||
"ip" : "1.2.4.5",
|
||||
"port" : 1812
|
||||
},
|
||||
{
|
||||
"name" : "server 3 in pool 2",
|
||||
"ip" : "1.2.4.6",
|
||||
"port" : 1812
|
||||
}
|
||||
],
|
||||
"acctServers" : [{
|
||||
"name" : "server 1 in pool 2",
|
||||
"ip" : "1.2.4.4",
|
||||
"port" : 1813,
|
||||
"weight" : 25
|
||||
},
|
||||
{
|
||||
"name" : "server 2 in pool 2",
|
||||
"ip" : "1.2.4.5",
|
||||
"port" : 1813,
|
||||
"weight" : 25
|
||||
},
|
||||
{
|
||||
"name" : "server 3 in pool 2",
|
||||
"ip" : "1.2.4.6",
|
||||
"port" : 1813,
|
||||
"weight" : 25
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
54
test_scripts/curl/living-lab-radius-config.json
Normal file
54
test_scripts/curl/living-lab-radius-config.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"pools": [
|
||||
{
|
||||
"acctConfig": {
|
||||
"methodParameters": [],
|
||||
"monitor": false,
|
||||
"monitorMethod": "none",
|
||||
"servers": [
|
||||
{
|
||||
"ip": "69.157.193.71",
|
||||
"name": "svr1",
|
||||
"port": 1813,
|
||||
"weight": 10,
|
||||
"secret": "testing123"
|
||||
}
|
||||
],
|
||||
"strategy": "random"
|
||||
},
|
||||
"authConfig": {
|
||||
"methodParameters": [],
|
||||
"monitor": false,
|
||||
"monitorMethod": "none",
|
||||
"servers": [
|
||||
{
|
||||
"ip": "69.157.193.71",
|
||||
"name": "svr1",
|
||||
"port": 1812,
|
||||
"weight": 10,
|
||||
"secret": "testing123"
|
||||
}
|
||||
],
|
||||
"strategy": "weighted"
|
||||
},
|
||||
"coaConfig": {
|
||||
"methodParameters": [],
|
||||
"monitor": false,
|
||||
"monitorMethod": "none",
|
||||
"servers": [
|
||||
{
|
||||
"ip": "69.157.193.71",
|
||||
"name": "svr1",
|
||||
"port": 3799,
|
||||
"weight": 10,
|
||||
"secret": "testing123"
|
||||
}
|
||||
],
|
||||
"strategy": "round_robin"
|
||||
},
|
||||
"description": "master pool",
|
||||
"name": "master",
|
||||
"useByDefault" : true
|
||||
}
|
||||
]
|
||||
}
|
||||
50
test_scripts/curl/living_lab_radius_config.json
Normal file
50
test_scripts/curl/living_lab_radius_config.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"pools" : [
|
||||
{
|
||||
"name" : "master" ,
|
||||
"description" : "master pool",
|
||||
"authConfig" : {
|
||||
"strategy" : "weighted",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "69.157.193.71",
|
||||
"port" : 1812,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
},
|
||||
"acctConfig" : {
|
||||
"strategy" : "random",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "69.157.193.71",
|
||||
"port" : 1813,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
},
|
||||
"coaConfig" : {
|
||||
"strategy" : "round_robin",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "69.157.193.71",
|
||||
"port" : 3799,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user