mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-11-02 03:37:57 +00:00
Compare commits
696 Commits
v2.6.0-RC4
...
v2.7.0-RC3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f264a2e556 | ||
|
|
f11751ac89 | ||
|
|
fa9d59852a | ||
|
|
51d1df8150 | ||
|
|
37e910e1c2 | ||
|
|
9c08f5194b | ||
|
|
c31ea8f632 | ||
|
|
08b2d7a278 | ||
|
|
82688aa4ca | ||
|
|
96e6ebdfa1 | ||
|
|
986cb57389 | ||
|
|
a39efd3204 | ||
|
|
350eeca6ec | ||
|
|
f686179f7a | ||
|
|
33d908db96 | ||
|
|
8e90917e5f | ||
|
|
aa39497793 | ||
|
|
fe2f170f1f | ||
|
|
20cdc999f3 | ||
|
|
ad7fa81b5e | ||
|
|
5cbf25260d | ||
|
|
9c9e6cb593 | ||
|
|
81fa16fb9c | ||
|
|
82e877393d | ||
|
|
0cf6a4cf19 | ||
|
|
e1a3e40326 | ||
|
|
ecf7ab790e | ||
|
|
e743a97d39 | ||
|
|
02320b616a | ||
|
|
bf1137a99b | ||
|
|
c7bafec390 | ||
|
|
5e2d3e7c81 | ||
|
|
61ab1f7904 | ||
|
|
d6a61c45ec | ||
|
|
f6e7693e39 | ||
|
|
0e605f9ada | ||
|
|
613a2adfca | ||
|
|
6a2dcb1d29 | ||
|
|
53a7c9c78a | ||
|
|
8955c614a8 | ||
|
|
1685aefda3 | ||
|
|
c7d5cd96d3 | ||
|
|
3a70f669ee | ||
|
|
cbfb278675 | ||
|
|
57771f411a | ||
|
|
c5991bc6f8 | ||
|
|
22df3fb8ef | ||
|
|
ea369afabf | ||
|
|
26b74e503f | ||
|
|
4a450269f5 | ||
|
|
e8fe17c906 | ||
|
|
e44bb3199c | ||
|
|
f327708f83 | ||
|
|
eee680686f | ||
|
|
74522dbaf8 | ||
|
|
0e9b13f2b3 | ||
|
|
117f24e0b6 | ||
|
|
0deeb7403f | ||
|
|
f639710d38 | ||
|
|
c70daf5c9c | ||
|
|
6d59b45e6f | ||
|
|
e81f1a8fcc | ||
|
|
540205763c | ||
|
|
ec450c30e5 | ||
|
|
ef9902c75a | ||
|
|
e367aa72f0 | ||
|
|
9384bed03d | ||
|
|
29e61bf432 | ||
|
|
510e56518a | ||
|
|
82004e3f2e | ||
|
|
2620baca91 | ||
|
|
f105b9386c | ||
|
|
83e5feec49 | ||
|
|
24dffe09a4 | ||
|
|
28052bff3c | ||
|
|
c2c37ad0d2 | ||
|
|
e5ac94421e | ||
|
|
5a306f1a70 | ||
|
|
ecb58fe3ed | ||
|
|
629a3b390b | ||
|
|
071b13f401 | ||
|
|
3b5b9636f3 | ||
|
|
8e125732b3 | ||
|
|
4ed6fe70ec | ||
|
|
8e0ae5f6c8 | ||
|
|
e6ec2c65bf | ||
|
|
45a4211793 | ||
|
|
68e85d8c5a | ||
|
|
8625a81689 | ||
|
|
61deb1f589 | ||
|
|
f68ada1013 | ||
|
|
a1df232de9 | ||
|
|
3ac0875b83 | ||
|
|
658dbad1b1 | ||
|
|
94f4930bd7 | ||
|
|
0bc515e3ab | ||
|
|
f7a00e0426 | ||
|
|
81e49026f8 | ||
|
|
1ae68019d3 | ||
|
|
fde5a2c353 | ||
|
|
2e316478d7 | ||
|
|
6c23a969d0 | ||
|
|
8e900aea69 | ||
|
|
16c32e53bd | ||
|
|
fde3cfa9ce | ||
|
|
fb15504294 | ||
|
|
dc219aa34f | ||
|
|
8357cd76ed | ||
|
|
6ef36ae53d | ||
|
|
716d3755fe | ||
|
|
3299aadf57 | ||
|
|
71ed6c90d1 | ||
|
|
0cc391141b | ||
|
|
f45b2baa4b | ||
|
|
e00aa23775 | ||
|
|
83c9476720 | ||
|
|
0f38bcab99 | ||
|
|
18d9947c0e | ||
|
|
3de2dd1931 | ||
|
|
847648f1ee | ||
|
|
d77a4a6bb9 | ||
|
|
05767cc1a7 | ||
|
|
0e5c7ef5c6 | ||
|
|
bc6773ac28 | ||
|
|
d39574aa22 | ||
|
|
b6795a4f04 | ||
|
|
b8fe03c74d | ||
|
|
9e877270a4 | ||
|
|
47b182e481 | ||
|
|
f680135e53 | ||
|
|
f3aecbd034 | ||
|
|
15776c01ac | ||
|
|
8fc342770b | ||
|
|
27c1bbeb20 | ||
|
|
b5be0eb8ba | ||
|
|
277abfa036 | ||
|
|
a4bb7a1c0e | ||
|
|
89134305e8 | ||
|
|
f7b4fe84e1 | ||
|
|
eb085ea9a9 | ||
|
|
2c29200bbf | ||
|
|
1e2728423a | ||
|
|
24c9283a55 | ||
|
|
92e1afedfb | ||
|
|
b86f06b818 | ||
|
|
2f3a0cc756 | ||
|
|
713cd01b6b | ||
|
|
888cc94709 | ||
|
|
0926f57391 | ||
|
|
78396d28d7 | ||
|
|
9edcd5a330 | ||
|
|
dc9a04dbc3 | ||
|
|
1d675067fe | ||
|
|
f69bc3434a | ||
|
|
17c8d5ceaf | ||
|
|
caf133b6a2 | ||
|
|
dcfdb6d242 | ||
|
|
40535390b1 | ||
|
|
b86d7425ac | ||
|
|
907803eafa | ||
|
|
050a3e3584 | ||
|
|
f182b12f54 | ||
|
|
1052bbee57 | ||
|
|
16a970feb3 | ||
|
|
a185377258 | ||
|
|
0871045b3c | ||
|
|
4e2b1e4ecc | ||
|
|
b3f7b16f30 | ||
|
|
2b7d96728b | ||
|
|
13e5eab8f4 | ||
|
|
fd3fbb3dbf | ||
|
|
7abd8af2e6 | ||
|
|
3d97f5a9e3 | ||
|
|
d70ed3cae2 | ||
|
|
814fe872f6 | ||
|
|
354f0057c1 | ||
|
|
390e050801 | ||
|
|
f8a157ddbe | ||
|
|
8d4abd42ec | ||
|
|
4a82af2bcd | ||
|
|
bfeb9f64e2 | ||
|
|
071a2ff47f | ||
|
|
6678669188 | ||
|
|
3c6299ecc6 | ||
|
|
afe989205f | ||
|
|
5955e2e845 | ||
|
|
6c038e1d64 | ||
|
|
d75836e88f | ||
|
|
2500dfdd80 | ||
|
|
cfa496653f | ||
|
|
e4b9920b56 | ||
|
|
ec156c203e | ||
|
|
13fd91b135 | ||
|
|
123a638080 | ||
|
|
c165a1d3de | ||
|
|
40d2cdf1b3 | ||
|
|
df850c1a82 | ||
|
|
565199df70 | ||
|
|
c9599c3d86 | ||
|
|
988c90643d | ||
|
|
62951a502c | ||
|
|
05ec034f7a | ||
|
|
4e5bf7929c | ||
|
|
e39149337c | ||
|
|
d14da5612b | ||
|
|
e42852297d | ||
|
|
1501e0f037 | ||
|
|
2d3fd0b736 | ||
|
|
17a77ba02b | ||
|
|
2541e25ee6 | ||
|
|
0c831f0dd8 | ||
|
|
7799b3f904 | ||
|
|
1762fdc859 | ||
|
|
339ce4734b | ||
|
|
3f6b469c3c | ||
|
|
1db1a6c86d | ||
|
|
aca62368d9 | ||
|
|
c0bf3f8872 | ||
|
|
00f94a6d81 | ||
|
|
442f614f1b | ||
|
|
2be63c60ee | ||
|
|
039cf7a83f | ||
|
|
0b502b9f8f | ||
|
|
a77fec4475 | ||
|
|
dfa9a09ded | ||
|
|
40f9d2d4fb | ||
|
|
1da30b61ef | ||
|
|
175fab0eb5 | ||
|
|
b311fbe44d | ||
|
|
636b82c28d | ||
|
|
183f06e5fa | ||
|
|
ac7d4ef048 | ||
|
|
0c5087960e | ||
|
|
e4be8c84f3 | ||
|
|
ce93663cb5 | ||
|
|
952442b32d | ||
|
|
e06f367eb9 | ||
|
|
c0bab98714 | ||
|
|
616f3864fb | ||
|
|
5f3974aac7 | ||
|
|
98a4bfc6c5 | ||
|
|
a518f13a2d | ||
|
|
981f6f7e6d | ||
|
|
253982a63f | ||
|
|
03e342a24d | ||
|
|
7b9db4bf4d | ||
|
|
fc92130fa4 | ||
|
|
e6d56fec79 | ||
|
|
c3094ce73b | ||
|
|
330577edb0 | ||
|
|
de6d5288f4 | ||
|
|
6e96e8bc9a | ||
|
|
10f8638d73 | ||
|
|
0b25e94a68 | ||
|
|
3d769634c6 | ||
|
|
17f8ca60cf | ||
|
|
544577bad8 | ||
|
|
24a0035ac0 | ||
|
|
cdea03bbb2 | ||
|
|
2783809ae9 | ||
|
|
565c05b4f3 | ||
|
|
e1d90f8ea3 | ||
|
|
60321902ec | ||
|
|
9ac0995fd4 | ||
|
|
00551fae2c | ||
|
|
42c937848d | ||
|
|
f0d63c69c1 | ||
|
|
d09f980a64 | ||
|
|
f09a8bd0fe | ||
|
|
7dcc8cabbb | ||
|
|
a816e0d1c1 | ||
|
|
01b3daa051 | ||
|
|
2bf9bb8935 | ||
|
|
218a49cb95 | ||
|
|
66ea0cf308 | ||
|
|
99a77cdcc4 | ||
|
|
b021d80300 | ||
|
|
798c40df23 | ||
|
|
d95007fae1 | ||
|
|
2745f1cfa0 | ||
|
|
9f7b78d0f1 | ||
|
|
91b0c95101 | ||
|
|
6d193699c1 | ||
|
|
a63cd8bb7b | ||
|
|
599c8d6fd3 | ||
|
|
305ea52737 | ||
|
|
7f26d8d49e | ||
|
|
09dbad5e05 | ||
|
|
de20856cc1 | ||
|
|
5c1e7f97dd | ||
|
|
ee9fdc8d1a | ||
|
|
c5269a9a3c | ||
|
|
79599e9b06 | ||
|
|
dd47234b4e | ||
|
|
9f14dc8196 | ||
|
|
286d313e69 | ||
|
|
e69f2cabf1 | ||
|
|
246c4dc8f2 | ||
|
|
7d7a12a903 | ||
|
|
69809eb243 | ||
|
|
db85dc82b5 | ||
|
|
a291a473b5 | ||
|
|
e8ae32d6d4 | ||
|
|
1d79d26dac | ||
|
|
b1f06462da | ||
|
|
f0de5dbf80 | ||
|
|
ad0f28d9ae | ||
|
|
bb89e49856 | ||
|
|
f4952d5865 | ||
|
|
ab655910ec | ||
|
|
b0666a0efd | ||
|
|
d6540a8c1c | ||
|
|
1016a98712 | ||
|
|
1a8574ea86 | ||
|
|
eeee8b2818 | ||
|
|
010d1f736b | ||
|
|
e2c71a7555 | ||
|
|
1bb6a68b4b | ||
|
|
055ea2e3f1 | ||
|
|
ad8b6163ac | ||
|
|
2c405c1cad | ||
|
|
cea975da8b | ||
|
|
217241eb6a | ||
|
|
85783e49c9 | ||
|
|
1d5e1a443b | ||
|
|
e31a5e69a2 | ||
|
|
59eae1535f | ||
|
|
622dcbaf78 | ||
|
|
bc736863dc | ||
|
|
5306cb4666 | ||
|
|
2e30a954b6 | ||
|
|
f170f5dc90 | ||
|
|
7901bca172 | ||
|
|
736a168233 | ||
|
|
556f4bd9d1 | ||
|
|
2c9fe98ab4 | ||
|
|
a8003a3f5f | ||
|
|
5a31c2be5f | ||
|
|
e32f3fc265 | ||
|
|
5a26c55ffb | ||
|
|
6aa18fa8ec | ||
|
|
995f8eedc3 | ||
|
|
ea3ba39e33 | ||
|
|
580cd0dcb0 | ||
|
|
1e95a45649 | ||
|
|
db6af2d2eb | ||
|
|
1008d10112 | ||
|
|
7b27970e64 | ||
|
|
c9c7d7194f | ||
|
|
9f364009ca | ||
|
|
58dd4f0002 | ||
|
|
4ca16d2c35 | ||
|
|
bc3b8eee00 | ||
|
|
7ea327df08 | ||
|
|
94f12c9e5b | ||
|
|
b273d0ecc9 | ||
|
|
ff44166aa4 | ||
|
|
2a06316d46 | ||
|
|
aae437df20 | ||
|
|
cfc516ce02 | ||
|
|
db6e547d3a | ||
|
|
e51fe3cd3b | ||
|
|
14a6e541e5 | ||
|
|
f9d3bc3c43 | ||
|
|
ad6f15671b | ||
|
|
f1f946c9ef | ||
|
|
38ca54ac55 | ||
|
|
341609bb39 | ||
|
|
1875d2a980 | ||
|
|
d888ba6ee4 | ||
|
|
b9fd3acf75 | ||
|
|
ed9ee69f2f | ||
|
|
d436b4b157 | ||
|
|
2855f87544 | ||
|
|
07ae3bad4d | ||
|
|
81651a4120 | ||
|
|
c456e73ab1 | ||
|
|
e919e35ea0 | ||
|
|
bea768bf8f | ||
|
|
32ec94b3b9 | ||
|
|
48553494ca | ||
|
|
163ee377c4 | ||
|
|
d3b5bd1f13 | ||
|
|
624242bbab | ||
|
|
6b49921e54 | ||
|
|
3439de3222 | ||
|
|
f74f48def7 | ||
|
|
0fd25c7089 | ||
|
|
eeb1044718 | ||
|
|
c32da56c92 | ||
|
|
02d5bce712 | ||
|
|
1baf06adea | ||
|
|
60a5049d05 | ||
|
|
692f0c0326 | ||
|
|
7ddcb36ad2 | ||
|
|
91700a3c1c | ||
|
|
5da93336fa | ||
|
|
feb1faec4f | ||
|
|
82e28f1728 | ||
|
|
bf3912a67f | ||
|
|
fe68b1e778 | ||
|
|
546ca9d0b2 | ||
|
|
14d5309637 | ||
|
|
e871708f41 | ||
|
|
135eae4931 | ||
|
|
beee84775e | ||
|
|
62a13bfaf5 | ||
|
|
42e0f67ce8 | ||
|
|
50a7d3a79e | ||
|
|
300f91db17 | ||
|
|
8fad2a1981 | ||
|
|
0e427d4799 | ||
|
|
0cb700ac7b | ||
|
|
23f03813eb | ||
|
|
44bedc6b8c | ||
|
|
4acfe59f78 | ||
|
|
cc66db4a33 | ||
|
|
cf87b00781 | ||
|
|
85b6e70132 | ||
|
|
446c2c7206 | ||
|
|
a66a472e9e | ||
|
|
d438f99f25 | ||
|
|
a2ae008755 | ||
|
|
12333b2bd3 | ||
|
|
f09106c3a9 | ||
|
|
05226c912e | ||
|
|
ef9eb0972d | ||
|
|
19b7803ca9 | ||
|
|
9f1726cc99 | ||
|
|
85c68d2fff | ||
|
|
0f924cdbba | ||
|
|
9433f337be | ||
|
|
feacd6544a | ||
|
|
0b79b180bb | ||
|
|
28bce56334 | ||
|
|
d26e7efb6a | ||
|
|
3d3b5b4404 | ||
|
|
db3cabb768 | ||
|
|
3ccf4b40b8 | ||
|
|
3c77fd1415 | ||
|
|
ff14d887bb | ||
|
|
10221f8b16 | ||
|
|
178fcccaac | ||
|
|
4f6f0aea26 | ||
|
|
332d093e72 | ||
|
|
6c275aefe8 | ||
|
|
1dd5efeb22 | ||
|
|
2ad0ec12dd | ||
|
|
b09cec0bc2 | ||
|
|
d14ca95010 | ||
|
|
2df1100795 | ||
|
|
2f961f992a | ||
|
|
ecdc5b3531 | ||
|
|
5f08a581f2 | ||
|
|
87b4a5d626 | ||
|
|
6aa2ef2878 | ||
|
|
9267a36529 | ||
|
|
72db313d8d | ||
|
|
93f0b2500e | ||
|
|
76b7aba5bd | ||
|
|
0585884033 | ||
|
|
c31fa08579 | ||
|
|
d9c3fea93d | ||
|
|
6325476325 | ||
|
|
054e172b64 | ||
|
|
7ae51f0fec | ||
|
|
531c0e24ba | ||
|
|
d97a31e002 | ||
|
|
70e5b1d0db | ||
|
|
63516e85db | ||
|
|
35b1dbdc2e | ||
|
|
c9abe16cfe | ||
|
|
aee7530b2b | ||
|
|
ceda99fa84 | ||
|
|
ce78b144e6 | ||
|
|
3fd3717978 | ||
|
|
9be3f1dfa9 | ||
|
|
2249367696 | ||
|
|
b68af82771 | ||
|
|
884d2e323b | ||
|
|
5a21b6f197 | ||
|
|
62c0178aa9 | ||
|
|
041452cf93 | ||
|
|
89ebaf78bc | ||
|
|
295a6496ef | ||
|
|
48fb10bcec | ||
|
|
525e464592 | ||
|
|
5f20866a31 | ||
|
|
05f60cd08b | ||
|
|
bd7b56757d | ||
|
|
bc3c85fe2d | ||
|
|
22c87decdc | ||
|
|
d13216e0e2 | ||
|
|
992d977312 | ||
|
|
9cb789d0b0 | ||
|
|
b4e9747bfa | ||
|
|
5ec9d6a2c8 | ||
|
|
3abb24919f | ||
|
|
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 | ||
|
|
c14abf8aa0 | ||
|
|
d779fca535 | ||
|
|
7e1d545f26 | ||
|
|
9c2d60ed3a | ||
|
|
b8516cad84 | ||
|
|
eba979d9da | ||
|
|
d163f7522d | ||
|
|
132fdafd32 | ||
|
|
3d6527f30b | ||
|
|
dc114de8fa | ||
|
|
0592537b71 | ||
|
|
eddaaa0cd6 | ||
|
|
46e72369ae | ||
|
|
58648d7dc5 | ||
|
|
b2bd6aab9e | ||
|
|
3781f5283f | ||
|
|
7b990a7d2f | ||
|
|
c1347fc3b8 | ||
|
|
888fcbbcd3 | ||
|
|
4e4156c420 | ||
|
|
ee98a7b8a5 | ||
|
|
0b5518d265 | ||
|
|
7bc0656f25 | ||
|
|
177a8b40ee | ||
|
|
85ee78f35e | ||
|
|
9043b3a558 | ||
|
|
4d2d488812 | ||
|
|
adf226f2e8 | ||
|
|
749d425d80 | ||
|
|
a6f9deb315 | ||
|
|
f4236408fc | ||
|
|
377c7bfc0b | ||
|
|
2e3efd97e4 | ||
|
|
58abf04e42 | ||
|
|
5e002899b5 | ||
|
|
d43c8f63ab | ||
|
|
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 | ||
|
|
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 | ||
|
|
c84f05cd22 | ||
|
|
a532520044 |
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owgw VERSION 2.6.0)
|
||||
project(owgw VERSION 2.7.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -30,6 +30,13 @@ else()
|
||||
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
|
||||
endif()
|
||||
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
add_compile_options(-fsanitize=undefined)
|
||||
add_link_options(-fsanitize=undefined)
|
||||
endif()
|
||||
|
||||
find_package(Git QUIET)
|
||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
|
||||
@@ -42,7 +49,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
||||
endif()
|
||||
|
||||
add_definitions(-DTIP_GATEWAY_SERVICE="1")
|
||||
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -64,12 +71,6 @@ include_directories(/usr/local/include /usr/local/opt/openssl/include src inclu
|
||||
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
|
||||
|
||||
add_compile_options(-Wall -Wextra)
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
add_compile_options(-fsanitize=undefined)
|
||||
add_link_options(-fsanitize=undefined)
|
||||
endif()
|
||||
|
||||
add_executable( owgw
|
||||
build
|
||||
@@ -78,6 +79,7 @@ add_executable( owgw
|
||||
src/framework/KafkaTopics.h
|
||||
src/framework/MicroService.h
|
||||
src/framework/OpenWifiTypes.h
|
||||
src/framework/MicroServiceErrorHandler.h
|
||||
src/framework/orm.h
|
||||
src/framework/StorageClass.h
|
||||
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
|
||||
@@ -105,7 +107,7 @@ add_executable( owgw
|
||||
src/storage/storage_tables.cpp
|
||||
src/RESTAPI/RESTAPI_routers.cpp
|
||||
src/Daemon.cpp src/Daemon.h
|
||||
src/WS_Server.cpp src/WS_Server.h
|
||||
src/AP_WS_Server.cpp src/AP_WS_Server.h
|
||||
src/StorageService.cpp src/StorageService.h
|
||||
src/DeviceRegistry.cpp src/DeviceRegistry.h
|
||||
src/CommandManager.cpp src/CommandManager.h
|
||||
@@ -118,7 +120,20 @@ add_executable( owgw
|
||||
src/TelemetryStream.cpp src/TelemetryStream.h
|
||||
src/framework/ConfigurationValidator.cpp src/framework/ConfigurationValidator.h
|
||||
src/ConfigurationCache.h
|
||||
src/CapabilitiesCache.h src/FindCountry.h src/rttys/RTTYS_server.cpp src/rttys/RTTYS_server.h src/rttys/RTTYS_device.cpp src/rttys/RTTYS_device.h src/rttys/RTTYS_ClientConnection.cpp src/rttys/RTTYS_ClientConnection.h src/rttys/RTTYS_WebServer.cpp src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h src/SDKcalls.cpp src/SDKcalls.h src/StateUtils.cpp src/StateUtils.h src/WS_ReactorPool.h src/WS_Connection.h src/WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h src/framework/ow_constants.h src/GwWebSocketClient.cpp src/GwWebSocketClient.h src/framework/WebSocketClientNotifications.h src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h src/ParseWifiScan.h src/RADIUS_helpers.h)
|
||||
src/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/AP_WS_ReactorPool.h src/AP_WS_Connection.h src/AP_WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h src/framework/ow_constants.h src/GwWebSocketClient.cpp src/GwWebSocketClient.h src/framework/WebSocketClientNotifications.h src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h src/ParseWifiScan.h src/RADIUS_helpers.h src/VenueBroadcaster.h src/sdks/sdk_prov.h
|
||||
src/AP_WS_Process_connect.cpp
|
||||
src/AP_WS_Process_state.cpp
|
||||
src/AP_WS_Process_healthcheck.cpp
|
||||
src/AP_WS_Process_log.cpp
|
||||
src/AP_WS_Process_crashlog.cpp src/AP_WS_Process_ping.cpp src/AP_WS_Process_cfgpending.cpp src/AP_WS_Process_recovery.cpp src/AP_WS_Process_deviceupdate.cpp src/AP_WS_Process_telemetry.cpp src/AP_WS_Process_venuebroadcast.cpp src/RADSECserver.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
|
||||
|
||||
36
Dockerfile
36
Dockerfile
@@ -1,15 +1,23 @@
|
||||
FROM alpine:3.15 AS build-base
|
||||
ARG ALPINE_VERSION=3.16.2
|
||||
ARG POCO_VERSION=poco-tip-v1
|
||||
ARG FMTLIB_VERSION=9.0.0
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
ARG JSON_VALIDATOR_VERSION=2.1.0
|
||||
|
||||
FROM alpine:$ALPINE_VERSION AS build-base
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
make cmake g++ git \
|
||||
unixodbc-dev postgresql-dev mariadb-dev \
|
||||
librdkafka-dev boost-dev openssl-dev \
|
||||
zlib-dev nlohmann-json
|
||||
zlib-dev nlohmann-json ca-certificates
|
||||
|
||||
FROM build-base AS poco-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
ARG POCO_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -20,8 +28,10 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt /fmtlib
|
||||
ARG FMTLIB_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
@@ -32,8 +42,10 @@ RUN make install
|
||||
|
||||
FROM build-base AS cppkafka-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
ARG CPPKAFKA_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -44,8 +56,10 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
ARG JSON_VALIDATOR_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
@@ -76,7 +90,7 @@ WORKDIR /owgw/cmake-build
|
||||
RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM alpine:3.15
|
||||
FROM alpine:$ALPINE_VERSION
|
||||
|
||||
ENV OWGW_USER=owgw \
|
||||
OWGW_ROOT=/owgw-data \
|
||||
|
||||
@@ -18,17 +18,29 @@ System messages are what maintains the collection of micro-services working on t
|
||||
}
|
||||
```
|
||||
|
||||
### Responsibilities
|
||||
Each micro service is responsible to generate its own messages and keep track of messages coming from other
|
||||
micro services. This is necessary so that any micro service may reach our any other micro service. This provides
|
||||
discovery for any micro service. All current micro services provided in OpenWiFi perform these functions. If you leverage
|
||||
the C++ framework, this functionality if performed automatically.
|
||||
|
||||
### `event-type`
|
||||
When a service joins the bus, it should generate an event-type of `join`. When a service shutdown, it should generate a `leave` event-type. Every 30 seconds, a service
|
||||
should generate a `keep-alive` message.
|
||||
Each micro service is responsible to generate and consume these events
|
||||
|
||||
#### `join` event
|
||||
When a service start and joins the bus, it should generate an event-type of `join`.
|
||||
|
||||
### `leave` event
|
||||
When a service shuts down, it should generate a `leave` event-type.
|
||||
|
||||
### `keep-alive` event
|
||||
Every 30 seconds, a service should generate a `keep-alive` message.
|
||||
|
||||
|
||||
### `id`
|
||||
You should generate a random number from some unique factor for the system. This ID is used to identify different services. You should reuse that ID
|
||||
when you restart.
|
||||
|
||||
## Micro-service maintaining bus state
|
||||
A micro-service should maintain its own lists of available micro-services by looking at the messages it receives and keep a list.
|
||||
|
||||
## The `type`
|
||||
The `type` in the system message is oen of the following:
|
||||
```c++
|
||||
@@ -47,11 +59,11 @@ The `type` in the system message is oen of the following:
|
||||
The `type` is what you should use to find the `privateEndPoint` you are looking to communicate with.
|
||||
|
||||
### Example
|
||||
Assume you want to communicate with the gateway t pconfigure a device.
|
||||
Assume you want to communicate with the gateway to configure a device.
|
||||
|
||||
```text
|
||||
1. Look into my list of current Micro-services for the type=owgw.
|
||||
2. Use the priovateEndPoint associated with that entry
|
||||
2. Use the privateEndPoint associated with that entry
|
||||
```
|
||||
|
||||
## REST API calls on the private interface
|
||||
@@ -72,9 +84,9 @@ This is the `publicEndPoint` you included in your `system-messages`.
|
||||
This method can _only_ be used to any another `privateEndPoint` in the system. You can use the exact same EndPoints provided in the OpenAPI files for any of the services.
|
||||
|
||||
## OpenAPI Integration
|
||||
To appear in the UI consoles, a micro-service should ne able to handle a get to the `/api/v1/system` endpoint on its `publicEndPoint` interface.
|
||||
To appear in the UI consoles, a microservice should be able to handle a get to the `/api/v1/system` endpoint on its `publicEndPoint` interface.
|
||||
|
||||
Here is a brief description of what the micro-service should answer:
|
||||
Here is a brief description of what the microservice should answer:
|
||||
```yaml
|
||||
/system:
|
||||
get:
|
||||
|
||||
23
PROTOCOL.md
23
PROTOCOL.md
@@ -184,6 +184,21 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Device requests a venue broadcast message
|
||||
Device send this message when it wants to reach out to all other APs in the same venue. The GW will find the
|
||||
venue where this device belongs and resend the same message to all other devices in the venue.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "venue_broadcast" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"timestamp" : <the UTC timestamp when the message was sent>,
|
||||
"data" : <an opaque string from the AP. This could be Zipped and so on and most likely base64 encoded>
|
||||
}
|
||||
}
|
||||
```
|
||||
Upon receiving a `venue_broadcast` message, the GW will simply resent the message to all the APs in the venue.
|
||||
|
||||
### Controller commands
|
||||
Most controller commands include a `when` member. This is a UTC clock time asking the AP
|
||||
to perform the command at that time. This is a suggestion only. The AP may ignore this
|
||||
@@ -734,7 +749,10 @@ Should other messages get larger, the client may decide to compress the. Only me
|
||||
|
||||
#### Identifying a compressed message
|
||||
A compressed message has a single member to the `params` field. It's only parameter must be called `compress_64`. Any other elements under
|
||||
params will be dropped. Additional compression schemes may be developed later.
|
||||
params will be dropped. Additional compression schemes may be developed later. The device should also include
|
||||
a hint to the actual size of the uncompressed data. This would allow listeners to create sufficiently sized
|
||||
buffers right away instead of guessing. If the device includes `compressed_sz` as the second field in the
|
||||
params objects. This should be an unsigned int representing the total size of the uncompressed data.
|
||||
|
||||
#### How to compress
|
||||
The original `params` element should be run through `zlib:compress` and then encoded using base64, and passed as a string. Here is an example
|
||||
@@ -744,7 +762,8 @@ of the completed message. The following should how the `state` event could be co
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "state" ,
|
||||
"params" : {
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk"
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk",
|
||||
"compress_sz" : 212322
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
92
README.md
92
README.md
@@ -11,16 +11,16 @@ In order to build the uCentralGW, you will need to install its dependencies, whi
|
||||
- boost
|
||||
- POCO 1.10.1 or later
|
||||
- a C++17 compiler
|
||||
- libyaml
|
||||
- openssl
|
||||
- libpq-dev (PortgreSQL development libraries)
|
||||
- mysql-client (MySQL client)
|
||||
- librdkafka
|
||||
- cppkafka
|
||||
-
|
||||
|
||||
The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
|
||||
framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
|
||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/stephb9959/poco). Building
|
||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/AriliaWireless/poco). Building
|
||||
Poco may take several minutes depending on the platform you are building on.
|
||||
|
||||
### Ubuntu
|
||||
@@ -29,9 +29,10 @@ These instructions have proven to work on Ubuntu 20.4.
|
||||
sudo apt install git cmake g++ libssl-dev libmariadb-dev
|
||||
sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
|
||||
sudo apt install librdkafka-dev // default-libmysqlclient-dev
|
||||
sudo apt install nlohmann-json-dev
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -40,7 +41,7 @@ cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -49,17 +50,7 @@ cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/nlohmann/json.git
|
||||
cd json
|
||||
git checkout tags/v3.10.2
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -67,6 +58,14 @@ cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
|
||||
cd fmtlib
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -81,12 +80,12 @@ make -j 8
|
||||
### Fedora
|
||||
The following instructions have proven to work on Fedora 33
|
||||
```
|
||||
sudo yum install cmake g++ openssl-devel unixODBC-devel mysql-devel mysql apr-util-devel boost boost-devel
|
||||
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
|
||||
sudo yum install yaml-cpp-devel lua-devel
|
||||
sudo dnf install postgresql.x86_64 librdkafka-devel
|
||||
sudo dnf install postgresql-devel
|
||||
sudo dnf install postgresql-devel json-devel
|
||||
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -94,7 +93,7 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -102,6 +101,15 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -124,18 +132,18 @@ brew install apr-util
|
||||
brew install boost
|
||||
brew install yaml-cpp
|
||||
brew install postgresql
|
||||
brew install unixodbc
|
||||
brew install librdkafka
|
||||
brew install nlohmann-json
|
||||
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release -j
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -143,6 +151,15 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -249,7 +266,7 @@ little changes if you keep the suggested directory structure. For the sample con
|
||||
environment variables.
|
||||
```
|
||||
export OWGW_ROOT=`pwd`
|
||||
export UCENTRALGW_CONFIG=`pwd`
|
||||
export OWGW_CONFIG=`pwd`
|
||||
```
|
||||
If you current working directory is the root of the project, this will set the variables properly. Otherwise, you can set the variables
|
||||
to point to wherever is necessary.
|
||||
@@ -561,6 +578,31 @@ Toe read more about Kafka, follow the [document](https://github.com/Telecominfra
|
||||
#### Securing `kafka`
|
||||
This is beyond the scope of this document. As it stands today, the communication between the gateway and `kafka` is expected to be behind a firewall.
|
||||
|
||||
#### `iptocountry` feature
|
||||
In the UI, you will notice the presence of small flags showing where the device connections are from. This feature is
|
||||
available through the `iptocountry` settings in the configuration. This feature is then also available through the `OpenAPI` for the CLI
|
||||
and other applications.
|
||||
|
||||
##### Config file entries
|
||||
In the configuration file, you must include the following lines:
|
||||
|
||||
```asm
|
||||
iptocountry.default = US
|
||||
iptocountry.provider = ipinfo
|
||||
#iptocountry.provider = ipdata
|
||||
#iptocountry.provider = ipdata
|
||||
iptocountry.ipinfo.token =
|
||||
#ip2location.ipinfo.token =
|
||||
#iptocountry.ipdata.apikey =
|
||||
#iptocountry.ip2location.apikey =
|
||||
```
|
||||
So you select your provider with the `iptocountry.provider` be specifying ipinfo, or ipdata, or ip2location.
|
||||
And then you provide the corresponding api key or token.
|
||||
Only select one. If you select 2, undefined behaviour. All the line you do not need, just put a `#` before to comment it
|
||||
out.
|
||||
You will find the supported providers at: `ip2location.com`, `ipinfo.io`, or `ipdata.co`. You MUST supply a valid default
|
||||
country code in `iptocountry.default`.
|
||||
|
||||
## Contributors
|
||||
We love ya! We need more of ya! If you want to contribute, make sure you review
|
||||
the [coding style](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CODING_STYLE.md) document.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,12 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
|
||||
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
|
||||
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
|
||||
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
|
||||
SIMULATORID=${SIMULATORID:-""} \
|
||||
IPTOCOUNTRY_PROVIDER=${IPTOCOUNTRY_PROVIDER:-"ipinfo"} \
|
||||
IPTOCOUNTRY_IPINFO_TOKEN=${IPTOCOUNTRY_IPINFO_TOKEN:-""} \
|
||||
IPTOCOUNTRY_IPDATA_APIKEY=${IPTOCOUNTRY_IPDATA_APIKEY:-""} \
|
||||
AUTOPROVISIONING_PROCESS=${AUTOPROVISIONING_PROCESS:-"prov,default"} \
|
||||
RTTY_INTERNAL=${RTTY_INTERNAL:-"true"} \
|
||||
RTTY_ENABLED=${RTTY_ENABLED:-"true"} \
|
||||
RTTY_SERVER=${RTTY_SERVER:-"localhost"} \
|
||||
@@ -47,6 +52,10 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
|
||||
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
|
||||
RTTY_ASSETS=${RTTY_ASSETS:-"\$OWGW_ROOT/rtty_ui"} \
|
||||
RADIUS_PROXY_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
|
||||
RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
|
||||
RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \
|
||||
RADIUS_PROXY_COA_PORT=${RADIUS_PROXY_COA_PORT:-"3799"} \
|
||||
KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \
|
||||
KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \
|
||||
KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \
|
||||
|
||||
@@ -79,7 +79,8 @@ The following table lists the configurable parameters of the chart and their def
|
||||
| persistence.size | string | Defines PV size | `'10Gi'` |
|
||||
| public_env_variables | hash | Defines list of environment variables to be passed to the Gateway | |
|
||||
| configProperties | hash | Configuration properties that should be passed to the application in `owgw.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owgw` on where it is mounted) | |
|
||||
| existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owgw` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. | |
|
||||
| certsCAs | hash | Defines files with CAs that should be passed to the Gateway (see `volumes.owgw` on where it is mounted) | |
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{{- $root := . -}}
|
||||
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -48,6 +49,38 @@ spec:
|
||||
- tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }}
|
||||
- -timeout
|
||||
- 600s
|
||||
{{- if eq $storageType "postgresql" }}
|
||||
- name: wait-postgres
|
||||
image: "{{ .Values.images.owgw.repository }}:{{ .Values.images.owgw.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.owgw.pullPolicy }}
|
||||
command:
|
||||
- /wait-for-postgres.sh
|
||||
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
|
||||
- echo
|
||||
- "PostgreSQL is ready"
|
||||
env:
|
||||
- name: KUBERNETES_DEPLOYED
|
||||
value: "{{ now }}"
|
||||
{{- range $key, $value := .Values.public_env_variables }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := .Values.secret_env_variables }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "owgw.fullname" $root }}-env
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owgw }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
{{- if .subPath }}
|
||||
subPath: {{ .subPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
containers:
|
||||
|
||||
@@ -76,6 +109,11 @@ spec:
|
||||
containerPort: {{ $portValue.targetPort }}
|
||||
protocol: {{ $portValue.protocol }}
|
||||
{{- end }}
|
||||
{{- range $port, $portValue := .Values.services.radius.ports }}
|
||||
- name: {{ $port }}
|
||||
containerPort: {{ $portValue.targetPort }}
|
||||
protocol: {{ $portValue.protocol }}
|
||||
{{- end }}
|
||||
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owgw }}
|
||||
|
||||
195
helm/values.yaml
195
helm/values.yaml
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owgw:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
|
||||
tag: master
|
||||
tag: v2.7.0-RC3
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
@@ -46,6 +46,21 @@ services:
|
||||
rttys-view:
|
||||
servicePort: 5913
|
||||
targetPort: 5913
|
||||
radius:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
acc:
|
||||
servicePort: 1813
|
||||
targetPort: 1813
|
||||
protocol: UDP
|
||||
auth:
|
||||
servicePort: 1812
|
||||
targetPort: 1812
|
||||
protocol: UDP
|
||||
coa:
|
||||
servicePort: 3799
|
||||
targetPort: 3799
|
||||
protocol: UDP
|
||||
|
||||
checks:
|
||||
owgw:
|
||||
@@ -97,7 +112,7 @@ volumes:
|
||||
mountPath: /owgw-data/certs
|
||||
volumeDefinition: |
|
||||
secret:
|
||||
secretName: {{ include "owgw.fullname" . }}-certs
|
||||
secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owgw.fullname" . }}-certs{{ end }}
|
||||
- name: certs-cas
|
||||
mountPath: /owgw-data/certs/cas
|
||||
volumeDefinition: |
|
||||
@@ -231,6 +246,11 @@ configProperties:
|
||||
rtty.timeout: 60
|
||||
rtty.viewport: 5913
|
||||
rtty.assets: $OWGW_ROOT/rtty_ui
|
||||
# RADIUS proxy
|
||||
radius.proxy.enable: "true"
|
||||
radius.proxy.accounting.port: 1813
|
||||
radius.proxy.authentication.port: 1812
|
||||
radius.proxy.coa.port: 3799
|
||||
# ALB
|
||||
alb.enable: "true"
|
||||
alb.port: 16102
|
||||
@@ -271,6 +291,7 @@ configProperties:
|
||||
openwifi.system.debug: "true"
|
||||
openwifi.system.uri.private: https://localhost:17002
|
||||
openwifi.system.uri.public: https://localhost:16002
|
||||
openwifi.system.uri.ui: https://localhost
|
||||
openwifi.system.commandchannel: /tmp/app_owgw
|
||||
# Logging
|
||||
logging.type: console
|
||||
@@ -310,166 +331,22 @@ configProperties:
|
||||
storage.type.mysql.username: stephb
|
||||
storage.type.mysql.password: snoopy99
|
||||
|
||||
# NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr
|
||||
existingCertsSecret: ""
|
||||
|
||||
certs:
|
||||
clientcas.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
|
||||
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
|
||||
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
|
||||
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
|
||||
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
|
||||
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
|
||||
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
|
||||
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
|
||||
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
|
||||
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
|
||||
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
|
||||
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
|
||||
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
|
||||
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
|
||||
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
|
||||
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
|
||||
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
|
||||
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
|
||||
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
|
||||
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
|
||||
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
|
||||
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
|
||||
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
|
||||
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
|
||||
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
|
||||
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
|
||||
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
issuer.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
|
||||
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
|
||||
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
|
||||
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
|
||||
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
|
||||
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
|
||||
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
|
||||
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
|
||||
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
|
||||
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
|
||||
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
|
||||
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
|
||||
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
|
||||
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
|
||||
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
|
||||
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
|
||||
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
|
||||
-----END CERTIFICATE-----
|
||||
# restapi-ca.pem: ""
|
||||
# restapi-cert.pem: ""
|
||||
# restapi-key.pem: ""
|
||||
root.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
|
||||
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
|
||||
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
|
||||
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
|
||||
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
|
||||
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
|
||||
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
|
||||
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
|
||||
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
|
||||
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
|
||||
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
# websocket-cert.pem: ""
|
||||
# websocket-key.pem: ""
|
||||
clientcas.pem: ""
|
||||
issuer.pem: ""
|
||||
restapi-ca.pem: ""
|
||||
restapi-cert.pem: ""
|
||||
restapi-key.pem: ""
|
||||
root.pem: ""
|
||||
websocket-cert.pem: ""
|
||||
websocket-key.pem: ""
|
||||
|
||||
certsCAs:
|
||||
issuer.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
|
||||
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
|
||||
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
|
||||
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
|
||||
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
|
||||
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
|
||||
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
|
||||
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
|
||||
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
|
||||
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
|
||||
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
|
||||
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
|
||||
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
|
||||
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
|
||||
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
|
||||
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
|
||||
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
|
||||
-----END CERTIFICATE-----
|
||||
root.pem: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
|
||||
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
|
||||
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
|
||||
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
|
||||
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
|
||||
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
|
||||
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
|
||||
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
|
||||
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
|
||||
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
|
||||
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
issuer.pem: ""
|
||||
root.pem: ""
|
||||
|
||||
# PostgreSQL (https://github.com/bitnami/charts/tree/master/bitnami/postgresql)
|
||||
postgresql:
|
||||
|
||||
@@ -190,6 +190,18 @@ components:
|
||||
type: string
|
||||
minLength: 2
|
||||
maxLength: 2
|
||||
started:
|
||||
type: integer
|
||||
format: int64
|
||||
sessionId:
|
||||
type: integer
|
||||
format: int64
|
||||
connectionCompletionTime:
|
||||
type: number
|
||||
format: double
|
||||
totalConnectionTime:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
DeviceList:
|
||||
type: object
|
||||
@@ -282,6 +294,17 @@ components:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
DeviceConnectionStatistics:
|
||||
type: object
|
||||
description: Return some basic device statistics.
|
||||
properties:
|
||||
connectedDevices:
|
||||
type: integer
|
||||
format: int64
|
||||
averageConnectionTime:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
StatisticsDetails:
|
||||
type: object
|
||||
properties:
|
||||
@@ -1049,6 +1072,33 @@ components:
|
||||
type: string
|
||||
certificate:
|
||||
type: string
|
||||
radsec:
|
||||
type: boolean
|
||||
default: false
|
||||
radsecPort:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 65535
|
||||
radsecSecret:
|
||||
type: string
|
||||
radsecCacerts:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
radsecCert:
|
||||
type: string
|
||||
description: this must be the base64 encoded of the entire content of the certificate file, including the -----BEGIN lines
|
||||
radsecKey:
|
||||
type: string
|
||||
description: this must be the base64 encoded of the entire content of the key file, including the -----BEGIN lines
|
||||
radsecRealms:
|
||||
description: each entry must be the base64 encoded of the entire content of the ca files, including the -----BEGIN lines
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ignore:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
RadiusProxyServerConfig:
|
||||
type: object
|
||||
@@ -1162,6 +1212,13 @@ paths:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: connectionStatistics
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List devices
|
||||
@@ -1173,6 +1230,7 @@ paths:
|
||||
- $ref: '#/components/schemas/DeviceListWithStatus'
|
||||
- $ref: '#/components/schemas/SerialNumberList'
|
||||
- $ref: '#/components/schemas/DeviceCount'
|
||||
- $ref: '#/components/schemas/DeviceConnectionStatistics'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
|
||||
@@ -65,6 +65,7 @@ openwifi.system.debug = true
|
||||
openwifi.system.uri.private = https://localhost:17002
|
||||
openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16002
|
||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
|
||||
openwifi.security.restapi.disable = false
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralgw
|
||||
|
||||
#
|
||||
@@ -177,4 +178,4 @@ archiver.db.3.keep = 7
|
||||
########################################################################
|
||||
logging.type = file
|
||||
logging.path = $OWGW_ROOT/logs
|
||||
logging.level = debug
|
||||
logging.level = debug
|
||||
|
||||
@@ -52,8 +52,8 @@ openwifi.fileuploader.host.0.cert = ${FILEUPLOADER_HOST_CERT}
|
||||
openwifi.fileuploader.host.0.key = ${FILEUPLOADER_HOST_KEY}
|
||||
openwifi.fileuploader.host.0.key.password = ${FILEUPLOADER_HOST_KEY_PASSWORD}
|
||||
openwifi.fileuploader.path = ${FILEUPLOADER_PATH}
|
||||
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
|
||||
openwifi.fileuploader.maxsize = 10000
|
||||
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
|
||||
|
||||
#
|
||||
# Generic section that all microservices must have
|
||||
@@ -65,6 +65,7 @@ openwifi.system.debug = true
|
||||
openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
|
||||
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
|
||||
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
|
||||
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralgw
|
||||
|
||||
#
|
||||
@@ -75,8 +76,13 @@ 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://standards-oui.ieee.org/oui/oui.txt
|
||||
firmware.autoupdate.policy.default = auto
|
||||
simulatorid = ${SIMULATORID}
|
||||
iptocountry.default = US
|
||||
iptocountry.provider = ${IPTOCOUNTRY_PROVIDER}
|
||||
iptocountry.ipinfo.token = ${IPTOCOUNTRY_IPINFO_TOKEN}
|
||||
iptocountry.ipdata.apikey = ${IPTOCOUNTRY_IPDATA_APIKEY}
|
||||
|
||||
autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
|
||||
|
||||
#
|
||||
# rtty
|
||||
@@ -90,6 +96,12 @@ rtty.timeout = ${RTTY_TIMEOUT}
|
||||
rtty.viewport = ${RTTY_VIEWPORT}
|
||||
rtty.assets = ${RTTY_ASSETS}
|
||||
|
||||
### RADIUS proxy config
|
||||
radius.proxy.enable = ${RADIUS_PROXY_ENABLE}
|
||||
radius.proxy.accounting.port = ${RADIUS_PROXY_ACCOUNTING_PORT}
|
||||
radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
|
||||
radius.proxy.coa.port = ${RADIUS_PROXY_COA_PORT}
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
#############################
|
||||
@@ -108,6 +120,7 @@ openwifi.kafka.enable = ${KAFKA_ENABLE}
|
||||
openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST}
|
||||
openwifi.kafka.auto.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
|
||||
openwifi.kafka.ssl.ca.location = ${KAFKA_SSL_CA_LOCATION}
|
||||
openwifi.kafka.ssl.certificate.location = ${KAFKA_SSL_CERTIFICATE_LOCATION}
|
||||
openwifi.kafka.ssl.key.location = ${KAFKA_SSL_KEY_LOCATION}
|
||||
|
||||
205
radius-proxy-orion.json
Normal file
205
radius-proxy-orion.json
Normal file
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "wan",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh"
|
||||
],
|
||||
"ssids": []
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 100,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"gateway": "192.168.1.1",
|
||||
"send-hostname": true,
|
||||
"subnet": "192.168.1.1/24",
|
||||
"use-dns": []
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "lan",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"wifi-steering",
|
||||
"ssh"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "required",
|
||||
"proto": "wpa"
|
||||
},
|
||||
"hidden-ssid": false,
|
||||
"isolate-clients": false,
|
||||
"maximum-clients": 64,
|
||||
"name": "arilia-rad",
|
||||
"radius": {
|
||||
"authentication": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1812,
|
||||
"secret": "radsec"
|
||||
},
|
||||
"accounting": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1813,
|
||||
"secret": "radsec"
|
||||
}
|
||||
},
|
||||
"services": [
|
||||
"radius-gw-proxy"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G",
|
||||
"5G"
|
||||
],
|
||||
"pass-point": {
|
||||
"venue-name": [
|
||||
"eng:Example passpoint_venue",
|
||||
"fra:Exemple de lieu"
|
||||
],
|
||||
"domain-name": [
|
||||
"onboard.almondlabs.net",
|
||||
"test.com"
|
||||
],
|
||||
"asra": false,
|
||||
"internet": true,
|
||||
"esr": false,
|
||||
"uesa": false,
|
||||
"access-network-type": 0,
|
||||
"hessid":"11:22:33:44:55:66",
|
||||
"venue-group": 2,
|
||||
"venue-type": 8,
|
||||
"connection-capability":[
|
||||
"1:0:2",
|
||||
"6:22:1",
|
||||
"17:5060:0"
|
||||
],
|
||||
"roaming-consortium": [
|
||||
"F4F5E8F5F4",
|
||||
"BAA2D00100",
|
||||
"BAA2D00000"
|
||||
],
|
||||
"disable-dgaf": true,
|
||||
"anqp-domain": 8888,
|
||||
"ipaddr-type-available": 14,
|
||||
"nai-realm": [
|
||||
],
|
||||
"osen": false,
|
||||
"anqp-3gpp-cell-net": [
|
||||
],
|
||||
"friendly-name": [
|
||||
"eng:AlmondLabs",
|
||||
"fra:AlmondLabs"
|
||||
],
|
||||
"venue-url": [
|
||||
"http://www.example.com/info-fra",
|
||||
"http://www.example.com/info-eng"
|
||||
],
|
||||
"auth-type": {
|
||||
"type": "terms-and-conditions"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 60
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"bandwidth": 10,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HT",
|
||||
"channel-width": 20,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 0
|
||||
},
|
||||
{
|
||||
"band": "5G",
|
||||
"bandwidth": 20,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"channel-width": 40,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 0
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"ssh": {
|
||||
"password-authentication": true,
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 1661312631
|
||||
}
|
||||
32
radsec-config-sample.json
Normal file
32
radsec-config-sample.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"pools" : [
|
||||
{
|
||||
"name" : "master" ,
|
||||
"description" : "master pool",
|
||||
"useByDefault" : true,
|
||||
"authConfig" : {
|
||||
"strategy" : "weighted",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "orion",
|
||||
"ip" : "216.239.32.91",
|
||||
"port" : 2083,
|
||||
"weight" : 10,
|
||||
"radsec" : true,
|
||||
"radsecPort" : 2083,
|
||||
"radsecSecret" : "radsec",
|
||||
"radsecKey" : "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUR6RnpXeTZlYXg0QVoxTySG9VUURRZ0FFS3BnWVBHMktPTVd2S0w1Z3NMRXpUc09rREg1M3NHaEQyS3RsRXBDTXVnNDNIZlFnTFVpUgpTR1R2S1l0bDFmbmJaU1lnY0RJdncxdjNYRy9hVDhOY2JBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=",
|
||||
"radsecCert" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNRVENDQWVpZ0F3SUJBZ0lVY3BKS3pVM0Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa0oxZEhSdmJuZHZiMlF4SFRBYkJnTlZCQU1URkVKMQpkSFJ2Ym5kdmIyUWdVbUZrYzJWaklFTkJNQjRYRFRJeU1EY3dNekExTWpVeE5Gb1hEVEkzTURVeE9UQTFNalV4Ck5Gb3dkVEVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFvVENrSjFkSFJ2Ym5kdmIyUXhOakEwQmdOVkJBTVQKTFdGeWFXeHBZUzVqWWpFd2FtTnVjemgxYlhCbk9HWnBjRFowTUM1dmNtbHZiaTVoY21WaE1USXdMbU52YlRFWgpNQmNHQ2dtU0pvbVQ4aXhrQVFFVENVZHZiMmRzWlRwVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQ3FZR0R4dGlqakZyeWkrWUxDeE0wN0RwQXgrZDdCb1E5aXJaUktRakxvT054MzBJQzFJa1Voazd5bUwKWmRYNTIyVW1JSEF5TDhOYjkxeHYyay9EWEd5amdZa3dnWVl3RGdZRFZSMFBBUUgvQkFRREFnZUFNQk1HQTFVZApKUVFNTUFvR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3T0FZRFZSMFJCREV3TDRJdFlYSnBiR2xoCkxtTmlNVEJxWTI1ek9IVnRjR2M0Wm1sd05uUXdMbTl5YVc5dUxtRnlaV0V4TWpBdVkyOXRNQmNHQTFVZElBUVEKTUE0d0RBWUtLd1lCQkFIdUtnRUJCVEFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFwTmM1dUNBSkp6KzVyakdqdwpCWGtOdHE3UU83bWU5dUg5bkNsTDZnSVE5Z0lnUHM2VkVKVW5CcEZ0RktXbFF4eWJ1YlBxYnpJNjBPSERHQ0ExCmhXUk1PS1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
|
||||
"radsecCacerts" : [
|
||||
"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ0akNDQVZ1Z0F3SUJBZ0lCQyOXZaREVkTUJzR0ExVUVBeE1VUW5WMGRHOXVkMjl2WkNCU1lXUnpaV01nUTBFdwpJQmNOTVRrd05qQTJNVFV4TlRNeVdoZ1BNalV4T1RBMk1EY3hOVEUxTXpKYU1FRXhDekFKQmdOVkJBWVRBbFZUCk1STXdFUVlEVlFRS0V3cENkWFIwYjI1M2IyOWtNUjB3R3dZRFZRUURFeFJDZFhSMGIyNTNiMjlrSUZKaFpITmwKWXlCRFFUQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJJUW40QVBKaXdvUVFQblR1cFgrZTk1Ugp0ZzVoQVFVbUhCN1E0UkpwSG4welF6TUJpMDdSejkxV05RamFHeERydktLVlQ1OThIM2dxYkI4TTViOHN3aytqClFqQkFNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBZ1lJS3dZQkJRVUgKQXdFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQTkrbHUwN2NlaGc1OQpxSi81dWtzN05oL3F2aXFHWCs1WDFwSVVxdENGVlJjQ0lRREZmUGhwZzZJOFE0SUdBbzNuamlHRTdDWC9nMm56CkRzSW5FcG9vRlkxV0xRPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
|
||||
],
|
||||
"radsecRealms" : [],
|
||||
"ignore" : false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
926
src/AP_WS_Connection.cpp
Normal file
926
src/AP_WS_Connection.cpp
Normal file
@@ -0,0 +1,926 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/HTTPServerResponseImpl.h"
|
||||
#include "Poco/Net/HTTPServerRequestImpl.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
|
||||
#include "Poco/zlib.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "CommandManager.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
#include "Poco/Net/WebSocketImpl.h"
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
#define DBL { std::cout << __LINE__ << " ID: " << ConnectionId_ << " Ser: " << SerialNumber_ << std::endl; }
|
||||
|
||||
void AP_WS_Connection::LogException(const Poco::Exception &E) {
|
||||
poco_information(Logger_,fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
|
||||
}
|
||||
|
||||
AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
std::uint64_t connection_id,
|
||||
Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R)
|
||||
: Logger_(L) ,
|
||||
Reactor_(R)
|
||||
{
|
||||
State_.sessionId = connection_id;
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request,response);
|
||||
|
||||
auto TS = Poco::Timespan(360, 0);
|
||||
|
||||
WS_->setMaxPayloadSize(BufSize);
|
||||
WS_->setReceiveTimeout(TS);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
WS_->setBlocking(false);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
Registered_ = true;
|
||||
}
|
||||
|
||||
class ThreadedCounter {
|
||||
public:
|
||||
ThreadedCounter(bool T, std::atomic_uint64_t &C) :
|
||||
C_(C),
|
||||
Threaded_(T) {
|
||||
if(Threaded_) {
|
||||
C_++;
|
||||
}
|
||||
}
|
||||
|
||||
~ThreadedCounter() {
|
||||
if(Threaded_ && C_>0) {
|
||||
C_--;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_uint64_t &C_;
|
||||
bool Threaded_;
|
||||
};
|
||||
|
||||
bool AP_WS_Connection::ValidatedDevice() {
|
||||
if(DeviceValidated_)
|
||||
return true;
|
||||
|
||||
try {
|
||||
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(SockImpl->streamSocketImpl());
|
||||
|
||||
PeerAddress_ = SS->peerAddress().host();
|
||||
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
|
||||
|
||||
State_.started = OpenWifi::Now();
|
||||
|
||||
if (!SS->secure()) {
|
||||
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is NOT secure. Device is not allowed.", CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
poco_debug(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is secure.", CId_, State_.sessionId ));
|
||||
|
||||
if (!SS->havePeerCertificate()) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
|
||||
if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not valid. Device is not allowed.",
|
||||
CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_debug(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_, State_.sessionId , CN_));
|
||||
|
||||
if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is not allowed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumber_)) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
poco_debug(Logger_, fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, State_.sessionId , CN_, ConcurrentStartingDevices_));
|
||||
DeviceValidated_ = true;
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate Validation failed during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket error during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionAbortedException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}):Session:{} Poco::ConnectionAbortedException Connection was aborted during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection was reset during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(Logger_,fmt::format(
|
||||
"CONNECTION({}): Session:{} Poco::InvalidCertificateException Invalid certificate. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::Exception caught during device connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. Device will have to retry. Unsecure connect denied.",
|
||||
CId_, State_.sessionId ));
|
||||
}
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::CompleteStartup() {
|
||||
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto TC = ThreadedCounter(Threaded_,ConcurrentStartingDevices_);
|
||||
|
||||
try {
|
||||
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(SockImpl->streamSocketImpl());
|
||||
|
||||
/* while (true) {
|
||||
auto V = SS->completeHandshake();
|
||||
if (V == 1)
|
||||
break;
|
||||
}
|
||||
*/
|
||||
PeerAddress_ = SS->peerAddress().host();
|
||||
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
|
||||
|
||||
State_.started = OpenWifi::Now();
|
||||
|
||||
if (!SS->secure()) {
|
||||
poco_warning(Logger_,fmt::format("CONNECTION({}): Session={} Connection is NOT secure. Device is not allowed.", CId_, State_.sessionId ));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
poco_debug(Logger_,fmt::format("CONNECTION({}): Session={} Connection is secure.", CId_, State_.sessionId ));
|
||||
|
||||
if (!SS->havePeerCertificate()) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_,fmt::format("CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId ));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
|
||||
if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_, fmt::format("CONNECTION({}): Session={} Device certificate is not valid. Device is not allowed.",
|
||||
CId_, State_.sessionId ));
|
||||
return EndConnection();
|
||||
}
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_debug(Logger_,
|
||||
fmt::format("CONNECTION({}): Session={} Valid certificate: CN={}", CId_, State_.sessionId , CN_));
|
||||
|
||||
if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("CONNECTION({}): Session={} Sim Device {} is not allowed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumber_)) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
WS_->setMaxPayloadSize(BufSize);
|
||||
auto TS = Poco::Timespan(360, 0);
|
||||
WS_->setReceiveTimeout(TS);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
WS_->setBlocking(false);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
Registered_ = true;
|
||||
poco_debug(Logger_, fmt::format("CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, State_.sessionId , CN_, ConcurrentStartingDevices_));
|
||||
return;
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate Validation failed during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket error during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionAbortedException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}):Session:{} Poco::ConnectionAbortedException Connection was aborted during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection was reset during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(Logger_,fmt::format(
|
||||
"CONNECTION({}): Session:{} Poco::InvalidCertificateException Invalid certificate. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::Exception caught during device connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. Device will have to retry. Unsecure connect denied.",
|
||||
CId_, State_.sessionId ));
|
||||
}
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string & SerialNumber) {
|
||||
try {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(Disconnect, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
if(!Dead_)
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection() {
|
||||
Dead_=true;
|
||||
poco_information(Logger_,fmt::format("CONNECTION-CLOSING({}): Session={} Serial={}.", CId_, State_.sessionId, SerialNumber_));
|
||||
auto SessionDeleted = DeviceRegistry()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
|
||||
if (Registered_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
}
|
||||
WS_->close();
|
||||
|
||||
if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
|
||||
std::string s(SerialNumber_);
|
||||
std::thread t([s]() { NotifyKafkaDisconnect(s); });
|
||||
t.detach();
|
||||
}
|
||||
if(SessionDeleted)
|
||||
WebSocketClientNotificationDeviceDisconnected(SerialNumber_);
|
||||
AP_WS_Server()->DeleteConnection(State_.sessionId);
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::LookForUpgrade(const uint64_t UUID, uint64_t & UpgradedUUID) {
|
||||
|
||||
// A UUID of zero means ignore updates for that connection.
|
||||
if (UUID == 0)
|
||||
return false;
|
||||
|
||||
uint64_t GoodConfig = ConfigurationCache().CurrentConfig(SerialNumberInt_);
|
||||
if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) {
|
||||
UpgradedUUID = UUID;
|
||||
return false;
|
||||
}
|
||||
|
||||
GWObjects::Device D;
|
||||
if (StorageService()->GetDevice(SerialNumber_, D)) {
|
||||
|
||||
// This is the case where the cache is empty after a restart. So GoodConfig will 0. If the device already has the right UUID, we just return.
|
||||
if (D.UUID == UUID) {
|
||||
UpgradedUUID = UUID;
|
||||
ConfigurationCache().Add(SerialNumberInt_, UUID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(UUID>D.UUID) {
|
||||
// so we have a problem, the device has a newer config than we have. So we need to make sure our config
|
||||
// is newer.
|
||||
Config::Config Cfg(D.Configuration);
|
||||
D.UUID = UUID+2;
|
||||
UpgradedUUID = D.UUID;
|
||||
Cfg.SetUUID(D.UUID);
|
||||
D.Configuration = Cfg.get();
|
||||
StorageService()->UpdateDevice(D);
|
||||
}
|
||||
|
||||
UpgradedUUID = D.UUID;
|
||||
State_.PendingUUID = D.UUID;
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroService::CreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::CONFIGURE;
|
||||
Poco::JSON::Parser P;
|
||||
auto ParsedConfig = P.parse(D.Configuration).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::UUID, D.UUID);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
|
||||
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
poco_information(Logger_,fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
|
||||
CId_, UUID, D.UUID));
|
||||
bool Sent;
|
||||
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
CommandManager()->PostCommand(CommandManager()->NextRPCId(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
|
||||
WebSocketClientNotificationDeviceConfigurationChange(D.SerialNumber, UUID, UpgradedUUID);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
|
||||
poco_debug(Logger_,fmt::format("RECEIVED-RPC({}): {}.", CId_, Doc->get(uCentralProtocol::ID).toString()));
|
||||
CommandManager()->PostCommandResult(SerialNumber_, *Doc);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc) {
|
||||
auto Method = Doc->get(uCentralProtocol::METHOD).toString();
|
||||
auto EventType = uCentralProtocol::Events::EventFromString(Method);
|
||||
if (EventType == uCentralProtocol::Events::ET_UNKNOWN) {
|
||||
poco_warning(Logger_,fmt::format("ILLEGAL-PROTOCOL({}): Unknown message type '{}'", CId_, Method));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Doc->isObject(uCentralProtocol::PARAMS)) {
|
||||
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): params must be an object.", CId_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
// expand params if necessary
|
||||
auto ParamsObj = Doc->get(uCentralProtocol::PARAMS).extract<Poco::JSON::Object::Ptr>();
|
||||
if (ParamsObj->has(uCentralProtocol::COMPRESS_64)) {
|
||||
std::string UncompressedData;
|
||||
try {
|
||||
auto CompressedData = ParamsObj->get(uCentralProtocol::COMPRESS_64).toString();
|
||||
uint64_t compress_sz = 0 ;
|
||||
if(ParamsObj->has("compress_sz")) {
|
||||
compress_sz = ParamsObj->get("compress_sz");
|
||||
}
|
||||
|
||||
if (Utils::ExtractBase64CompressedData(CompressedData, UncompressedData, compress_sz)) {
|
||||
poco_trace(Logger_,fmt::format("EVENT({}): Found compressed payload expanded to '{}'.",
|
||||
CId_, UncompressedData));
|
||||
Poco::JSON::Parser Parser;
|
||||
ParamsObj = Parser.parse(UncompressedData).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-DATA({}): Compressed cannot be uncompressed - content must be corrupt..: size={}",
|
||||
CId_, CompressedData.size()));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-JSON-DATA({}): Compressed cannot be parsed - JSON must be corrupt..",
|
||||
CId_));
|
||||
Logger_.log(E);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParamsObj->has(uCentralProtocol::SERIAL)) {
|
||||
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): Serial number is missing in message.", CId_));
|
||||
return;
|
||||
}
|
||||
|
||||
auto Serial = Poco::trim(Poco::toLower(ParamsObj->get(uCentralProtocol::SERIAL).toString()));
|
||||
if (!Utils::ValidSerialNumber(Serial)) {
|
||||
Poco::Exception E(
|
||||
fmt::format(
|
||||
"ILLEGAL-DEVICE-NAME({}): device name is illegal and not allowed to connect.",
|
||||
Serial),
|
||||
EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
if (StorageService()->IsBlackListed(Serial)) {
|
||||
Poco::Exception E(
|
||||
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
|
||||
Serial),
|
||||
EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
switch (EventType) {
|
||||
case uCentralProtocol::Events::ET_CONNECT: {
|
||||
Process_connect(ParamsObj, Serial);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_STATE: {
|
||||
Process_state(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_HEALTHCHECK: {
|
||||
Process_healthcheck(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_LOG: {
|
||||
Process_log(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_CRASHLOG: {
|
||||
Process_crashlog(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_PING: {
|
||||
Process_ping(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_CFGPENDING: {
|
||||
Process_cfgpending(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_RECOVERY: {
|
||||
Process_recovery(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_DEVICEUPDATE: {
|
||||
Process_deviceupdate(ParamsObj, Serial);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_TELEMETRY: {
|
||||
Process_telemetry(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_VENUEBROADCAST: {
|
||||
Process_venuebroadcast(ParamsObj);
|
||||
} break;
|
||||
|
||||
// this will never be called but some compilers will complain if we do not have a case for
|
||||
// every single values of an enum
|
||||
case uCentralProtocol::Events::ET_UNKNOWN: {
|
||||
poco_warning(Logger_, fmt::format("ILLEGAL-EVENT({}): Event '{}' unknown. CN={}", CId_, Method, CN_));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StartTelemetry(std::uint64_t RPCID) {
|
||||
poco_information(Logger_, fmt::format("TELEMETRY({}): Starting.", CId_));
|
||||
Poco::JSON::Object StartMessage;
|
||||
StartMessage.set("jsonrpc", "2.0");
|
||||
StartMessage.set("method", "telemetry");
|
||||
Poco::JSON::Object Params;
|
||||
Params.set("serial", SerialNumber_);
|
||||
Params.set("interval", TelemetryInterval_);
|
||||
Poco::JSON::Array Types;
|
||||
Types.add("wifi-frames");
|
||||
Types.add("dhcp-snooping");
|
||||
Types.add("state");
|
||||
Params.set(RESTAPI::Protocol::TYPES, Types);
|
||||
StartMessage.set("id", RPCID);
|
||||
StartMessage.set("params", Params);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(StartMessage, OS);
|
||||
return Send(OS.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopTelemetry(std::uint64_t RPCID) {
|
||||
poco_information(Logger_, fmt::format("TELEMETRY({}): Stopping.", CId_));
|
||||
Poco::JSON::Object StopMessage;
|
||||
StopMessage.set("jsonrpc", "2.0");
|
||||
StopMessage.set("method", "telemetry");
|
||||
Poco::JSON::Object Params;
|
||||
Params.set("serial", SerialNumber_);
|
||||
Params.set("interval", 0);
|
||||
StopMessage.set("id", RPCID);
|
||||
StopMessage.set("params", Params);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(StopMessage, OS);
|
||||
TelemetryKafkaPackets_ = TelemetryWebSocketPackets_ = TelemetryInterval_ =
|
||||
TelemetryKafkaTimer_ = TelemetryWebSocketTimer_ = 0;
|
||||
return Send(OS.str());
|
||||
}
|
||||
|
||||
void AP_WS_Connection::UpdateCounts() {
|
||||
State_.kafkaClients = TelemetryKafkaRefCount_;
|
||||
State_.webSocketClients = TelemetryWebSocketRefCount_;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t Interval,
|
||||
uint64_t LifeTime) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryWebSocketRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
|
||||
auto TelemetryWebSocketTimer = LifeTime + OpenWifi::Now();
|
||||
TelemetryWebSocketTimer_ = std::max(TelemetryWebSocketTimer, TelemetryWebSocketTimer_);
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
return StartTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t Interval, uint64_t LifeTime) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryKafkaRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
|
||||
auto TelemetryKafkaTimer = LifeTime + OpenWifi::Now();
|
||||
TelemetryKafkaTimer_ = std::max(TelemetryKafkaTimer, TelemetryKafkaTimer_);
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
return StartTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopWebSocketTelemetry(std::uint64_t RPCID) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
if (TelemetryWebSocketRefCount_)
|
||||
TelemetryWebSocketRefCount_--;
|
||||
UpdateCounts();
|
||||
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
|
||||
TelemetryReporting_ = false;
|
||||
StopTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopKafkaTelemetry(std::uint64_t RPCID) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
if (TelemetryKafkaRefCount_)
|
||||
TelemetryKafkaRefCount_--;
|
||||
UpdateCounts();
|
||||
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
|
||||
TelemetryReporting_ = false;
|
||||
StopTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
if(!AP_WS_Server()->Running())
|
||||
return EndConnection();
|
||||
|
||||
if(!ValidatedDevice())
|
||||
return;
|
||||
|
||||
try {
|
||||
return ProcessIncomingFrame();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
return EndConnection();
|
||||
} catch (const std::exception &E) {
|
||||
std::string W = E.what();
|
||||
poco_information(Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_));
|
||||
return EndConnection();
|
||||
} catch (...) {
|
||||
poco_information(Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingFrame() {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
try {
|
||||
int Op, flags;
|
||||
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
|
||||
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
poco_information(Logger_, fmt::format("DISCONNECT({}): device has disconnected. Session={}", CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
IncomingFrame.append(0);
|
||||
|
||||
State_.RX += IncomingSize;
|
||||
State_.MessageCount++;
|
||||
State_.LastContact = OpenWifi::Now();
|
||||
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
State_.MessageCount++;
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Object PingObject;
|
||||
Poco::JSON::Object PingDetails;
|
||||
PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware);
|
||||
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
|
||||
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
PingDetails.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
PingDetails.set("locale", State_.locale );
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(PingObject, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
poco_trace(Logger_, fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", CId_,
|
||||
IncomingSize, flags, IncomingFrame.begin()));
|
||||
|
||||
Poco::JSON::Parser parser;
|
||||
auto ParsedMessage = parser.parse(IncomingFrame.begin());
|
||||
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
|
||||
if (IncomingJSON->has(uCentralProtocol::METHOD) &&
|
||||
IncomingJSON->has(uCentralProtocol::PARAMS)) {
|
||||
ProcessJSONRPCEvent(IncomingJSON);
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
|
||||
IncomingJSON->has(uCentralProtocol::ID)) {
|
||||
poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, IncomingFrame.begin()));
|
||||
ProcessJSONRPCResult(IncomingJSON);
|
||||
} else {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
|
||||
CId_, IncomingFrame.begin()));
|
||||
}
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
|
||||
ProcessIncomingRadiusData(IncomingJSON);
|
||||
} else {
|
||||
std::ostringstream iS;
|
||||
IncomingJSON->stringify(iS);
|
||||
std::cout << iS.str() << std::endl;
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"FRAME({}): illegal transaction header, missing 'jsonrpc'", CId_));
|
||||
Errors_++;
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
poco_information(Logger_,
|
||||
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
|
||||
return EndConnection();
|
||||
} break;
|
||||
|
||||
default: {
|
||||
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", CId_,
|
||||
std::to_string(Op)));
|
||||
} break;
|
||||
}
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_warning(Logger_, fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
poco_warning(Logger_, fmt::format("JSONException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_warning(Logger_, fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_warning(Logger_, fmt::format("SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_warning(Logger_, fmt::format("SSLException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_, fmt::format("NetException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::IOException &E) {
|
||||
poco_warning(Logger_, fmt::format("IOException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_, fmt::format("Exception({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const std::exception &E) {
|
||||
poco_warning(Logger_, fmt::format("std::exception({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.what(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("UnknownException({}): Device must be disconnected. Unknown exception. Session:{}", CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
if (Errors_ < 10)
|
||||
return;
|
||||
|
||||
poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::Send(const std::string &Payload) {
|
||||
try {
|
||||
size_t BytesSent = WS_->sendFrame(Payload.c_str(), (int)Payload.size());
|
||||
State_.TX += BytesSent;
|
||||
return BytesSent == Payload.size();
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Base64Encode(const unsigned char *buffer, std::size_t size) {
|
||||
return Utils::base64encode(buffer,size);
|
||||
}
|
||||
|
||||
std::string Base64Decode(const std::string &F) {
|
||||
std::istringstream ifs(F);
|
||||
Poco::Base64Decoder b64in(ifs);
|
||||
std::ostringstream ofs;
|
||||
Poco::StreamCopier::copyStream(b64in, ofs);
|
||||
return ofs.str();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSAUTH);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusAccountingData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSACCT);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusCoAData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSCOA);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
|
||||
if( Doc->has(uCentralProtocol::RADIUSDATA)) {
|
||||
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();
|
||||
if(Type==uCentralProtocol::RADIUSACCT) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAccountingData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
} else if(Type==uCentralProtocol::RADIUSAUTH) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
} else if(Type==uCentralProtocol::RADIUSCOA) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendCoAData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
src/AP_WS_Connection.h
Normal file
126
src/AP_WS_Connection.h
Normal file
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_Connection {
|
||||
static constexpr int BufSize = 256000;
|
||||
public:
|
||||
explicit AP_WS_Connection( Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
std::uint64_t connection_id,
|
||||
Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R);
|
||||
~AP_WS_Connection();
|
||||
|
||||
void EndConnection();
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr & Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
|
||||
void ProcessIncomingFrame();
|
||||
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
|
||||
|
||||
bool Send(const std::string &Payload);
|
||||
|
||||
bool SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusCoAData(const unsigned char * buffer, std::size_t size);
|
||||
|
||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);
|
||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf);
|
||||
bool LookForUpgrade(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_; }
|
||||
bool SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryWebSocketTimer);
|
||||
bool SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryKafkaTimer);
|
||||
bool StopWebSocketTelemetry(std::uint64_t RPCID);
|
||||
bool StopKafkaTelemetry(std::uint64_t RPCID);
|
||||
|
||||
void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
|
||||
void Process_state(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
|
||||
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
bool ValidatedDevice();
|
||||
|
||||
inline bool GetTelemetryParameters(bool & Reporting, uint64_t & Interval,
|
||||
uint64_t & WebSocketTimer, uint64_t & KafkaTimer,
|
||||
uint64_t &WebSocketCount, uint64_t & KafkaCount,
|
||||
uint64_t &WebSocketPackets,
|
||||
uint64_t &KafkaPackets ) const {
|
||||
Reporting = TelemetryReporting_;
|
||||
WebSocketTimer = TelemetryWebSocketTimer_;
|
||||
KafkaTimer = TelemetryKafkaTimer_;
|
||||
WebSocketCount = TelemetryWebSocketRefCount_;
|
||||
KafkaCount = TelemetryKafkaRefCount_;
|
||||
Interval = TelemetryInterval_;
|
||||
WebSocketPackets = TelemetryWebSocketPackets_;
|
||||
KafkaPackets = TelemetryKafkaPackets_;
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class DeviceRegistry;
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
std::shared_mutex TelemetryMutex_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
std::string SerialNumber_;
|
||||
uint64_t SerialNumberInt_=0;
|
||||
std::string Compatible_;
|
||||
std::atomic_bool Registered_ = false ;
|
||||
std::string CId_;
|
||||
std::string CN_;
|
||||
uint64_t Errors_=0;
|
||||
Poco::Net::IPAddress PeerAddress_;
|
||||
std::atomic_bool TelemetryReporting_ = false;
|
||||
std::atomic_uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
uint64_t TelemetryKafkaTimer_ = 0 ;
|
||||
uint64_t TelemetryInterval_ = 0;
|
||||
std::atomic_uint64_t TelemetryWebSocketPackets_=0;
|
||||
std::atomic_uint64_t TelemetryKafkaPackets_=0;
|
||||
GWObjects::ConnectionState State_;
|
||||
std::string LastStats_;
|
||||
GWObjects::HealthCheck LastHealthcheck_;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
|
||||
bool Threaded_=false;
|
||||
std::atomic_bool Dead_=false;
|
||||
std::atomic_bool DeviceValidated_=false;
|
||||
|
||||
static inline std::atomic_uint64_t ConcurrentStartingDevices_=0;
|
||||
|
||||
void CompleteStartup();
|
||||
bool StartTelemetry(std::uint64_t RPCID);
|
||||
bool StopTelemetry(std::uint64_t RPCID);
|
||||
void UpdateCounts();
|
||||
};
|
||||
|
||||
}
|
||||
24
src/AP_WS_Process_cfgpending.cpp
Normal file
24
src/AP_WS_Process_cfgpending.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::ACTIVE)) {
|
||||
|
||||
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
[[maybe_unused]] uint64_t Active = ParamsObj->get(uCentralProtocol::ACTIVE);
|
||||
poco_trace(Logger_, fmt::format("CFG-PENDING({}): Active: {} Target: {}", CId_, Active, UUID));
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("CFG-PENDING({}): Missing some parameters", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
124
src/AP_WS_Process_connect.cpp
Normal file
124
src/AP_WS_Process_connect.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
#include "FindCountry.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::FIRMWARE) &&
|
||||
ParamsObj->has(uCentralProtocol::CAPABILITIES)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
|
||||
auto Capabilities = ParamsObj->get(uCentralProtocol::CAPABILITIES).toString();
|
||||
|
||||
//// change this
|
||||
SerialNumber_ = Serial;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
CommandManager()->ClearQueue(SerialNumberInt_);
|
||||
|
||||
DeviceRegistry()->SetSessionDetails(State_.sessionId,SerialNumberInt_);
|
||||
State_.UUID = UUID;
|
||||
State_.Firmware = Firmware;
|
||||
State_.PendingUUID = 0;
|
||||
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
|
||||
CId_ = SerialNumber_ + "@" + CId_;
|
||||
|
||||
auto IP = PeerAddress_.toString();
|
||||
if(IP.substr(0,7)=="::ffff:") {
|
||||
IP = IP.substr(7);
|
||||
}
|
||||
|
||||
State_.locale = FindCountryFromIP()->Get(IP);
|
||||
GWObjects::Device DeviceInfo;
|
||||
auto DeviceExists = StorageService()->GetDevice(SerialNumber_,DeviceInfo);
|
||||
if (Daemon()->AutoProvisioning() && !DeviceExists) {
|
||||
StorageService()->CreateDefaultDevice(SerialNumber_, Capabilities, Firmware,
|
||||
Compatible_, PeerAddress_);
|
||||
} else if (DeviceExists) {
|
||||
StorageService()->UpdateDeviceCapabilities(SerialNumber_, Capabilities,
|
||||
Compatible_);
|
||||
bool Updated = false;
|
||||
if(!Firmware.empty() && Firmware!=DeviceInfo.Firmware) {
|
||||
DeviceInfo.Firmware = Firmware;
|
||||
Updated = true;
|
||||
WebSocketClientNotificationDeviceFirmwareUpdated(SerialNumber_, Firmware);
|
||||
}
|
||||
|
||||
if(DeviceInfo.locale != State_.locale) {
|
||||
DeviceInfo.locale = State_.locale;
|
||||
Updated = true;
|
||||
}
|
||||
|
||||
if(Compatible_ != DeviceInfo.DeviceType) {
|
||||
DeviceInfo.DeviceType = Compatible_;
|
||||
Updated = true;
|
||||
}
|
||||
|
||||
if(Updated) {
|
||||
StorageService()->UpdateDevice(DeviceInfo);
|
||||
}
|
||||
uint64_t UpgradedUUID=0;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
}
|
||||
|
||||
State_.Compatible = Compatible_;
|
||||
State_.Connected = true;
|
||||
ConnectionCompletionTime_ = std::chrono::high_resolution_clock::now() - ConnectionStart_;
|
||||
State_.connectionCompletionTime = ConnectionCompletionTime_.count();
|
||||
|
||||
if(State_.VerifiedCertificate == GWObjects::VALID_CERTIFICATE) {
|
||||
if (( Utils::SerialNumberMatch(CN_, SerialNumber_, AP_WS_Server()->MismatchDepth())) ||
|
||||
AP_WS_Server()->IsSimSerialNumber(CN_)) {
|
||||
State_.VerifiedCertificate = GWObjects::VERIFIED;
|
||||
poco_information(Logger_, fmt::format("CONNECT({}): Fully validated and authenticated device. Session={} ConnectionCompletion Time={}",
|
||||
CId_,
|
||||
State_.sessionId,
|
||||
State_.connectionCompletionTime ));
|
||||
} else {
|
||||
State_.VerifiedCertificate = GWObjects::MISMATCH_SERIAL;
|
||||
if(AP_WS_Server()->AllowSerialNumberMismatch()) {
|
||||
poco_information(
|
||||
Logger_, fmt::format("CONNECT({}): Serial number mismatch allowed. CN={} Serial={} Session={} ConnectionCompletion Time={}",
|
||||
CId_, CN_, SerialNumber_, State_.sessionId,
|
||||
State_.connectionCompletionTime));
|
||||
} else {
|
||||
poco_information(
|
||||
Logger_, fmt::format("CONNECT({}): Serial number mismatch disallowed. Device rejected. CN={} Serial={} Session={} ConnectionCompletion Time={}",
|
||||
CId_, CN_, SerialNumber_, State_.sessionId,
|
||||
State_.connectionCompletionTime));
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketClientNotificationDeviceConnected(SerialNumber_);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
ParamsObj->set("locale", State_.locale );
|
||||
ParamsObj->set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,fmt::format("INVALID-PROTOCOL({}): Missing one of uuid, firmware, or capabilities", CId_));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
34
src/AP_WS_Process_crashlog.cpp
Normal file
34
src/AP_WS_Process_crashlog.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
poco_trace(Logger_, fmt::format("CRASH-LOG({}): new entry.", CId_));
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/AP_WS_Process_deviceupdate.cpp
Normal file
25
src/AP_WS_Process_deviceupdate.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has("currentPassword")) {
|
||||
auto Password = ParamsObj->get("currentPassword").toString();
|
||||
|
||||
StorageService()->SetDevicePassword(Serial, Password);
|
||||
poco_trace(Logger_, fmt::format("DEVICEUPDATE({}): Device is updating its login password.", Serial));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
71
src/AP_WS_Process_healthcheck.cpp
Normal file
71
src/AP_WS_Process_healthcheck.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
|
||||
ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
|
||||
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
|
||||
if (CheckData.empty())
|
||||
CheckData = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("HEALTHCHECK({}): UUID={} Updating.", CId_, UUID));
|
||||
} else {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("HEALTHCHECK({}): UUID={} Updating for CMD={}.", CId_,
|
||||
UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
|
||||
GWObjects::HealthCheck Check;
|
||||
|
||||
Check.SerialNumber = SerialNumber_;
|
||||
Check.Recorded = OpenWifi::Now();
|
||||
Check.UUID = UUID;
|
||||
Check.Data = CheckData;
|
||||
Check.Sanity = Sanity;
|
||||
|
||||
StorageService()->AddHealthCheckData(Check);
|
||||
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, CheckData);
|
||||
}
|
||||
|
||||
LastHealthcheck_ = Check;
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
ParamsObj->set("timestamp", OpenWifi::Now());
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
41
src/AP_WS_Process_log.cpp
Normal file
41
src/AP_WS_Process_log.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::LOG) && ParamsObj->has(uCentralProtocol::SEVERITY)) {
|
||||
poco_trace(Logger_, fmt::format("LOG({}): new entry.", CId_));
|
||||
auto Log = ParamsObj->get(uCentralProtocol::LOG).toString();
|
||||
auto Severity = ParamsObj->get(uCentralProtocol::SEVERITY);
|
||||
std::string DataStr = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
if (ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
auto DataObj = ParamsObj->get(uCentralProtocol::DATA);
|
||||
if (DataObj.isStruct())
|
||||
DataStr = DataObj.toString();
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = Log,
|
||||
.Data = DataStr,
|
||||
.Severity = Severity,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 0,
|
||||
.UUID = State_.UUID};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/AP_WS_Process_ping.cpp
Normal file
16
src/AP_WS_Process_ping.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_ping(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID)) {
|
||||
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
poco_trace(Logger_, fmt::format("PING({}): Current config is {}", CId_, UUID));
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("PING({}): Missing parameter.", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/AP_WS_Process_recovery.cpp
Normal file
62
src/AP_WS_Process_recovery.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_recovery(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::SERIAL) &&
|
||||
ParamsObj->has(uCentralProtocol::FIRMWARE) && ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::REBOOT) &&
|
||||
ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
|
||||
LogText = "Firmware: " + ParamsObj->get(uCentralProtocol::FIRMWARE).toString() + "\r\n";
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
|
||||
if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroService::CreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::REBOOT;
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
bool Sent;
|
||||
CommandManager()->PostCommand(CommandManager()->NextRPCId(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
poco_information(Logger_, fmt::format("RECOVERY({}): Recovery mode received, need for a reboot.", CId_));
|
||||
} else {
|
||||
poco_information(Logger_, fmt::format(
|
||||
"RECOVERY({}): Recovery mode received, no need for a reboot.", CId_));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("RECOVERY({}): Recovery missing one of serialnumber, firmware, uuid, loglines, reboot",
|
||||
CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/AP_WS_Process_state.cpp
Normal file
67
src/AP_WS_Process_state.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
#include "StateUtils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_state(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::STATE)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto StateStr = ParamsObj->get(uCentralProtocol::STATE).toString();
|
||||
auto StateObj = ParamsObj->getObject(uCentralProtocol::STATE);
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty()) {
|
||||
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating.", CId_, UUID));
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating for CMD={}.",
|
||||
CId_, UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
LastStats_ = StateStr;
|
||||
|
||||
GWObjects::Statistics Stats{
|
||||
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
|
||||
Stats.Recorded = OpenWifi::Now();
|
||||
StorageService()->AddStatisticsData(Stats);
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, StateStr);
|
||||
}
|
||||
|
||||
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
|
||||
State_.Associations_5G);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
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_));
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/AP_WS_Process_telemetry.cpp
Normal file
54
src/AP_WS_Process_telemetry.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_telemetry(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (TelemetryReporting_) {
|
||||
if (ParamsObj->has("data")) {
|
||||
auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
|
||||
Payload->set("timestamp", OpenWifi::Now());
|
||||
std::ostringstream SS;
|
||||
Payload->stringify(SS);
|
||||
auto now=OpenWifi::Now();
|
||||
if (TelemetryWebSocketRefCount_) {
|
||||
if(now<TelemetryWebSocketTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
|
||||
TelemetryWebSocketPackets_++;
|
||||
State_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->UpdateEndPoint(SerialNumberInt_, SS.str());
|
||||
} else {
|
||||
StopWebSocketTelemetry(CommandManager()->NextRPCId());
|
||||
}
|
||||
}
|
||||
if (TelemetryKafkaRefCount_) {
|
||||
if(KafkaManager()->Enabled() && now<TelemetryKafkaTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl;
|
||||
TelemetryKafkaPackets_++;
|
||||
State_.kafkaPackets = TelemetryKafkaPackets_;
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
|
||||
SS.str());
|
||||
} else {
|
||||
StopKafkaTelemetry(CommandManager()->NextRPCId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poco_debug(Logger_,fmt::format("TELEMETRY({}): Invalid telemetry packet.",SerialNumber_));
|
||||
}
|
||||
} else {
|
||||
// if we are ignoring telemetry, then close it down on the device.
|
||||
poco_debug(Logger_,fmt::format("TELEMETRY({}): Stopping runaway telemetry.",SerialNumber_));
|
||||
StopTelemetry(CommandManager()->NextRPCId());
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/AP_WS_Process_venuebroadcast.cpp
Normal file
17
src/AP_WS_Process_venuebroadcast.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "VenueBroadcaster.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if(ParamsObj->has("data") && ParamsObj->has("serial") && ParamsObj->has("timestamp")) {
|
||||
VenueBroadcaster()->Broadcast(
|
||||
ParamsObj->get("serial").toString(),
|
||||
ParamsObj->get("data").toString(),
|
||||
ParamsObj->get("timestamp"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,63 +5,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include "Poco/Environment.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ReactorThreadPool {
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit ReactorThreadPool() {
|
||||
if(Poco::Environment::processorCount()>8)
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()/2;
|
||||
else
|
||||
NumberOfThreads_ = 2;
|
||||
Start("ReactorThreadPool");
|
||||
explicit AP_WS_ReactorThreadPool() {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()*2;
|
||||
if(NumberOfThreads_==0)
|
||||
NumberOfThreads_=4;
|
||||
}
|
||||
|
||||
~ ReactorThreadPool() {
|
||||
~ AP_WS_ReactorThreadPool() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Start(const std::string & ThreadNamePrefix) {
|
||||
void Start() {
|
||||
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
|
||||
auto NewReactor = std::make_unique<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->setStackSize(2000000);
|
||||
NewThread->start(*NewReactor);
|
||||
std::string ThreadName{ThreadNamePrefix + "#" + std::to_string(i)};
|
||||
std::string ThreadName{"ap:react:" + std::to_string(i)};
|
||||
Utils::SetThreadName(*NewThread,ThreadName.c_str());
|
||||
Reactors_.emplace_back(std::move(NewReactor));
|
||||
Threads_.emplace_back(std::move(NewThread));
|
||||
}
|
||||
}
|
||||
|
||||
inline static auto instance() {
|
||||
static auto instance_ = new ReactorThreadPool;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for (auto &i : Reactors_)
|
||||
i->stop();
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor &NextReactor() {
|
||||
std::lock_guard G(Mutex_);
|
||||
std::shared_lock Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
std::shared_mutex Mutex_;
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
|
||||
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
|
||||
};
|
||||
inline auto ReactorThreadPool() { return ReactorThreadPool::instance(); }
|
||||
}
|
||||
163
src/AP_WS_Server.cpp
Normal file
163
src/AP_WS_Server.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/JSON/Array.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "TelemetryStream.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) {
|
||||
try {
|
||||
AP_WS_Server()->AddConnection(id_,std::make_shared<AP_WS_Connection>(request,response,id_, Logger_, AP_WS_Server()->NextReactor()));
|
||||
} catch (...) {
|
||||
poco_warning(Logger_,"Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
bool AP_WS_Server::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
|
||||
if(IsCertOk()) {
|
||||
if(!Certificate.issuedBy(*IssuerCert_)) {
|
||||
poco_warning(Logger(),fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AP_WS_Server::Start() {
|
||||
|
||||
AllowSerialNumberMismatch_ = MicroService::instance().ConfigGetBool("openwifi.certificates.allowmismatch",true);
|
||||
MismatchDepth_ = MicroService::instance().ConfigGetInt("openwifi.certificates.mismatchdepth",2);
|
||||
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
|
||||
Reactor_pool_->Start();
|
||||
|
||||
for(const auto & Svr : ConfigServersList_ ) {
|
||||
|
||||
poco_notice(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(),
|
||||
Svr.Port(), Svr.KeyFile(), Svr.CertFile()));
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if (!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
|
||||
if (!IsCertOk()) {
|
||||
IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
|
||||
poco_information(Logger(),
|
||||
fmt::format("Certificate Issuer Name:{}", IssuerCert_->issuerName()));
|
||||
}
|
||||
|
||||
Poco::Net::Context::Params P;
|
||||
|
||||
P.verificationMode = Poco::Net::Context::VERIFY_ONCE;
|
||||
P.verificationDepth = 9;
|
||||
P.loadDefaultCAs = Svr.RootCA().empty();
|
||||
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
|
||||
P.dhUse2048Bits = true;
|
||||
P.caLocation = Svr.Cas();
|
||||
|
||||
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
|
||||
|
||||
if(!Svr.KeyFilePassword().empty()) {
|
||||
auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(Svr.KeyFilePassword(),Logger()));
|
||||
Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr,Context);
|
||||
}
|
||||
|
||||
Poco::Crypto::X509Certificate Cert(Svr.CertFile());
|
||||
Poco::Crypto::X509Certificate Root(Svr.RootCA());
|
||||
|
||||
Context->useCertificate(Cert);
|
||||
Context->addChainCertificate(Root);
|
||||
|
||||
Context->addCertificateAuthority(Root);
|
||||
Poco::Crypto::X509Certificate Issuing(Svr.IssuerCertFile());
|
||||
Context->addChainCertificate(Issuing);
|
||||
Context->addCertificateAuthority(Issuing);
|
||||
|
||||
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
|
||||
Context->usePrivateKey(Key);
|
||||
|
||||
Context->setSessionCacheSize(0);
|
||||
Context->setSessionTimeout(120);
|
||||
Context->flushSessionCache();
|
||||
Context->enableSessionCache(true);
|
||||
Context->enableExtendedCertificateVerification(false);
|
||||
// Context->disableStatelessSessionResumption();
|
||||
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 | Poco::Net::Context::PROTO_TLSV1_1);
|
||||
|
||||
auto WebServerHttpParams = new Poco::Net::HTTPServerParams;
|
||||
WebServerHttpParams->setMaxThreads(50);
|
||||
WebServerHttpParams->setMaxQueued(200);
|
||||
WebServerHttpParams->setKeepAlive(true);
|
||||
WebServerHttpParams->setName("ws:ap_dispatch");
|
||||
|
||||
if (Svr.Address() == "*") {
|
||||
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
|
||||
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
|
||||
: Poco::Net::AddressFamily::IPv4));
|
||||
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
|
||||
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
} else {
|
||||
Poco::Net::IPAddress Addr(Svr.Address());
|
||||
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
|
||||
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &server:WebServers_) {
|
||||
server->start();
|
||||
}
|
||||
|
||||
ReactorThread_.start(Reactor_);
|
||||
|
||||
auto ProvString = MicroService::instance().ConfigGetString("autoprovisioning.process","default");
|
||||
if(ProvString!="default") {
|
||||
auto Tokens = Poco::StringTokenizer(ProvString, ",");
|
||||
for (const auto &i : Tokens) {
|
||||
if (i == "prov")
|
||||
LookAtProvisioning_ = true;
|
||||
else
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
} else {
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
|
||||
SimulatorId_ = MicroService::instance().ConfigGetString("simulatorid","");
|
||||
SimulatorEnabled_ = !SimulatorId_.empty();
|
||||
Utils::SetThreadName(ReactorThread_,"dev:react:head");
|
||||
|
||||
Running_ = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_Server::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
|
||||
for(auto &server:WebServers_) {
|
||||
server->stopAll();
|
||||
}
|
||||
Reactor_pool_->Stop();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
} //namespace
|
||||
145
src/AP_WS_Server.h
Normal file
145
src/AP_WS_Server.h
Normal file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/ParallelSocketAcceptor.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t id)
|
||||
: Logger_(L),
|
||||
id_(id){
|
||||
};
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
std::uint64_t id_=0;
|
||||
};
|
||||
|
||||
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L)
|
||||
: Logger_(L) {
|
||||
}
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *
|
||||
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
|
||||
if (request.find("Upgrade") != request.end() &&
|
||||
Poco::icompare(request["Upgrade"], "websocket") == 0) {
|
||||
Utils::SetThreadName("ws:conn-init");
|
||||
return new AP_WS_RequestHandler(Logger_,id_++);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static std::uint64_t id_=1;
|
||||
};
|
||||
|
||||
class AP_WS_Server : public SubSystemServer {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new AP_WS_Server;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool IsCertOk() { return IssuerCert_!= nullptr; }
|
||||
bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
|
||||
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
|
||||
|
||||
inline bool IsSimSerialNumber(const std::string & SerialNumber) const {
|
||||
return IsSim(Poco::toLower(SerialNumber)) && Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
|
||||
}
|
||||
|
||||
inline static bool IsSim(const std::string & SerialNumber) {
|
||||
return SerialNumber.substr(0,6) == "53494d";
|
||||
}
|
||||
|
||||
inline bool IsSimEnabled() const {
|
||||
return SimulatorEnabled_;
|
||||
}
|
||||
|
||||
inline bool AllowSerialNumberMismatch() const {
|
||||
return AllowSerialNumberMismatch_;
|
||||
}
|
||||
|
||||
inline std::uint64_t MismatchDepth() const {
|
||||
return MismatchDepth_;
|
||||
}
|
||||
|
||||
inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
|
||||
[[nodiscard]] inline Poco::Net::SocketReactor & NextReactor() { return Reactor_pool_->NextReactor(); }
|
||||
[[nodiscard]] inline bool Running() const { return Running_; }
|
||||
|
||||
inline void AddConnection(std::uint64_t session_id, std::shared_ptr<AP_WS_Connection> Connection ) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
Connections_[session_id] = Connection;
|
||||
}
|
||||
|
||||
inline void DeleteConnection(std::uint64_t session_id) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
Connections_.erase(session_id);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<AP_WS_Connection> FindConnection(std::uint64_t session_id) const {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
auto Connection = Connections_.find(session_id);
|
||||
if(Connection!=end(Connections_))
|
||||
return Connection->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex LocalMutex_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
std::string SimulatorId_;
|
||||
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 2, 32};
|
||||
bool LookAtProvisioning_ = false;
|
||||
bool UseDefaultConfig_ = true;
|
||||
bool SimulatorEnabled_=false;
|
||||
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
|
||||
std::atomic_bool Running_=false;
|
||||
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Connections_;
|
||||
std::atomic_bool AllowSerialNumberMismatch_=true;
|
||||
std::atomic_uint64_t MismatchDepth_=2;
|
||||
|
||||
AP_WS_Server() noexcept:
|
||||
SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto AP_WS_Server() { return AP_WS_Server::instance(); }
|
||||
|
||||
} //namespace
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -7,115 +7,148 @@
|
||||
//
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/File.h"
|
||||
|
||||
#include "CentralConfig.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace OpenWifi::Config {
|
||||
|
||||
const static std::string BasicConfig {
|
||||
R"lit({
|
||||
"uuid": 1,
|
||||
"radios": [
|
||||
{
|
||||
"band": "5G",
|
||||
"country": "CA",
|
||||
"channel-mode": "HE",
|
||||
"channel-width": 80,
|
||||
"channel": 32
|
||||
}
|
||||
],
|
||||
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "WAN",
|
||||
"role": "upstream",
|
||||
"services": [ "lldp" ],
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ssids": [
|
||||
{
|
||||
"name": "OpenWifi",
|
||||
"wifi-bands": [
|
||||
"5G"
|
||||
],
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"proto": "psk2",
|
||||
"key": "OpenWifi",
|
||||
"ieee80211w": "optional"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LAN",
|
||||
"role": "downstream",
|
||||
"services": [ "ssh", "lldp" ],
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "192.168.1.1/24",
|
||||
"dhcp": {
|
||||
"lease-first": 10,
|
||||
"lease-count": 100,
|
||||
"lease-time": "6h"
|
||||
}
|
||||
},
|
||||
"ssids": [
|
||||
{
|
||||
"name": "OpenWifi",
|
||||
"wifi-bands": [
|
||||
"5G"
|
||||
],
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"proto": "psk2",
|
||||
"key": "OpenWifi",
|
||||
"ieee80211w": "optional"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"statistics": {
|
||||
"interval": 120,
|
||||
"types": [ "ssids", "lldp", "clients" ]
|
||||
},
|
||||
"health": {
|
||||
"interval": 120
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"lldp": {
|
||||
"describe": "uCentral",
|
||||
"location": "universe"
|
||||
},
|
||||
"ssh": {
|
||||
"port": 22
|
||||
}
|
||||
}
|
||||
})lit"};
|
||||
R"lit(
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "WAN",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh",
|
||||
"lldp",
|
||||
"dhcp-snooping"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "optional",
|
||||
"key": "OpenWifi",
|
||||
"proto": "psk2"
|
||||
},
|
||||
"name": "OpenWifi",
|
||||
"services": [
|
||||
"wifi-frames"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G","5G"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 10000,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"subnet": "192.168.1.1/16"
|
||||
},
|
||||
"name": "LAN",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"ssh",
|
||||
"lldp",
|
||||
"dhcp-snooping"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 120
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"country": "CA"
|
||||
},
|
||||
{
|
||||
"allow-dfs": true,
|
||||
"band": "5G",
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"country": "CA"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"lldp": {
|
||||
"describe": "TIP OpenWiFi",
|
||||
"location": "QA"
|
||||
},
|
||||
"ssh": {
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 2
|
||||
}
|
||||
)lit"};
|
||||
|
||||
void Config::SetBasicConfigFile() {
|
||||
try {
|
||||
|
||||
@@ -8,224 +8,277 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void CommandManager::run() {
|
||||
Utils::SetThreadName("command-mgr");
|
||||
Utils::SetThreadName("cmd:mgr");
|
||||
Running_ = true;
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while(NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification*>(NextMsg.get());
|
||||
|
||||
if(Resp!= nullptr) {
|
||||
const Poco::JSON::Object & Payload = Resp->Payload_;
|
||||
const std::string & SerialNumber = Resp->SerialNumber_;
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while (NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification *>(NextMsg.get());
|
||||
|
||||
std::ostringstream SS;
|
||||
Payload.stringify(SS);
|
||||
try {
|
||||
if (Resp != nullptr) {
|
||||
const Poco::JSON::Object &Payload = Resp->Payload_;
|
||||
const std::string &SerialNumber = Resp->SerialNumber_;
|
||||
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
// std::cout << "Got RPC Answer: " << SerialNumber << " Payload:" << SS.str() << std::endl;
|
||||
Logger().debug(fmt::format("({}): RPC Response received.", SerialNumber));
|
||||
if(!Payload.has(uCentralProtocol::ID)){
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
Logger().error(fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
} else {
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
if (ID < 2) {
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
std::ostringstream SS;
|
||||
Payload.stringify(SS);
|
||||
|
||||
if (!Payload.has(uCentralProtocol::ID)) {
|
||||
poco_error(Logger(), fmt::format("({}): Invalid 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()) {
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
Logger().warning(
|
||||
fmt::format("({}): Outdated RPC {}", SerialNumber, ID));
|
||||
} else {
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
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);
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
if (RPC->second->rpc_entry) {
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
RPC->second->rpc_entry->set_value(Payload);
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
poco_debug(Logger(),fmt::format("({}): Processing {} response.", SerialNumber, ID));
|
||||
if (ID > 1) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
auto RPC = OutStandingRequests_.find(ID);
|
||||
if (RPC == OutStandingRequests_.end() ||
|
||||
RPC->second.SerialNumber !=
|
||||
Utils::SerialNumberToInt(Resp->SerialNumber_)) {
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): RPC {} completed.", 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);
|
||||
}
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): Received RPC answer {}. Command={}",
|
||||
SerialNumber, ID, RPC->second.Command));
|
||||
OutStandingRequests_.erase(ID);
|
||||
}
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(
|
||||
fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
// std::cout << SerialNumber << ": " << __LINE__ << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),"Exception occurred during run.");
|
||||
}
|
||||
NextMsg = ResponseQueue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger(),"RPC Command processor stopping.");
|
||||
}
|
||||
|
||||
int CommandManager::Start() {
|
||||
Logger().notice("Starting...");
|
||||
ManagerThread.setStackSize(2000000);
|
||||
ManagerThread.start(*this);
|
||||
poco_notice(Logger(),"Starting...");
|
||||
|
||||
ManagerThread.start(*this);
|
||||
|
||||
JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onJanitorTimer);
|
||||
JanitorTimer_.setStartInterval( 10000 );
|
||||
JanitorTimer_.setPeriodicInterval(10 * 60 * 1000); // 1 hours
|
||||
JanitorTimer_.start(*JanitorCallback_);
|
||||
JanitorTimer_.start(*JanitorCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
CommandRunnerCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onCommandRunnerTimer);
|
||||
CommandRunnerTimer_.setStartInterval( 10000 );
|
||||
CommandRunnerTimer_.setPeriodicInterval(30 * 1000); // 1 hours
|
||||
CommandRunnerTimer_.start(*CommandRunnerCallback_);
|
||||
CommandRunnerTimer_.start(*CommandRunnerCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
// 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);
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
JanitorTimer_.stop();
|
||||
CommandRunnerTimer_.stop();
|
||||
ResponseQueue_.wakeUpAll();
|
||||
ManagerThread.wakeUp();
|
||||
ManagerThread.join();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void CommandManager::WakeUp() {
|
||||
Logger().notice("Waking up...");
|
||||
poco_notice(Logger(),"Waking up...");
|
||||
ManagerThread.wakeUp();
|
||||
}
|
||||
|
||||
void CommandManager::onJanitorTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Utils::SetThreadName("command-janitor");
|
||||
Logger().information(
|
||||
fmt::format("Removing expired commands: start. {} outstanding-requests {} outstanding-uuids commands.",
|
||||
OutStandingRequests_.size(), OutstandingUUIDs_.size() ));
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
Utils::SetThreadName("cmd:janitor");
|
||||
Poco::Logger & MyLogger = Poco::Logger::get("CMD-MGR-JANITOR");
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
for(auto i=OutStandingRequests_.begin();i!=OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - i->second->submitted;
|
||||
if(delta > 6000000ms) {
|
||||
Logger().debug(fmt::format("{}: Timed out.", i->second->uuid));
|
||||
OutstandingUUIDs_.erase(i->second->uuid);
|
||||
i = OutStandingRequests_.erase(i);
|
||||
for(auto request=OutStandingRequests_.begin();request!=OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
|
||||
if(delta > 10min) {
|
||||
MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.",
|
||||
request->second.UUID,
|
||||
request->second.Command,
|
||||
Utils::IntToSerialNumber(request->second.SerialNumber)));
|
||||
request = OutStandingRequests_.erase(request);
|
||||
} else {
|
||||
++i;
|
||||
++request;
|
||||
}
|
||||
}
|
||||
Logger().information("Removing expired commands: done.");
|
||||
poco_information(MyLogger,
|
||||
fmt::format("Outstanding-requests {}", OutStandingRequests_.size()));
|
||||
}
|
||||
|
||||
bool CommandManager::IsCommandRunning(const std::string &C) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
for (const auto &request : OutStandingRequests_) {
|
||||
if (request.second.UUID == C) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandManager::onCommandRunnerTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
Utils::SetThreadName("command-runner");
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if(StorageService()->GetReadyToExecuteCommands(0,200,Commands))
|
||||
{
|
||||
for(auto & Cmd: Commands)
|
||||
{
|
||||
if(!Running_)
|
||||
break;
|
||||
try {
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
if(OutstandingUUIDs_.find(Cmd.UUID)!=OutstandingUUIDs_.end())
|
||||
continue;
|
||||
}
|
||||
Utils::SetThreadName("cmd:schdlr");
|
||||
Poco::Logger &MyLogger = Poco::Logger::get("CMD-MGR-SCHEDULER");
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
Logger().information(fmt::format("{}: Preparing execution of {} for {}.", Cmd.UUID, Cmd.Command, Cmd.SerialNumber));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk( Cmd.SerialNumber,
|
||||
Cmd.Command,
|
||||
*Params,
|
||||
Cmd.UUID,
|
||||
Sent);
|
||||
if(Sent) {
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
std::lock_guard M(Mutex_);
|
||||
OutstandingUUIDs_.insert(Cmd.UUID);
|
||||
Logger().information(fmt::format("{}: Queued command.", Cmd.UUID));
|
||||
} else {
|
||||
Logger().information(fmt::format("{}: Could queue command.", Cmd.UUID));
|
||||
poco_trace(MyLogger,"Scheduler starting.");
|
||||
|
||||
try {
|
||||
|
||||
StorageService()->RemovedExpiredCommands();
|
||||
StorageService()->RemoveTimedOutCommands();
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
|
||||
poco_trace(MyLogger,fmt::format("Scheduler about to process {} commands.", Commands.size()));
|
||||
for (auto &Cmd : Commands) {
|
||||
if (!Running_) {
|
||||
poco_warning(MyLogger,"Scheduler quitting because service is stopping.");
|
||||
break;
|
||||
}
|
||||
poco_trace(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} Starting processing.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
try {
|
||||
|
||||
// Skip an already running command
|
||||
if(IsCommandRunning(Cmd.UUID))
|
||||
continue;
|
||||
|
||||
auto now = OpenWifi::Now();
|
||||
// 2 hour timeout for commands
|
||||
if ((now - Cmd.Submitted) > (1 * 60 * 60)) {
|
||||
poco_information(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandTimedOut(Cmd.UUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DeviceRegistry()->Connected(
|
||||
Utils::SerialNumberToInt(Cmd.SerialNumber))) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Device is not connected.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string ExecutingCommand, ExecutingUUID;
|
||||
if (CommandRunningForDevice(Utils::SerialNumberToInt(Cmd.SerialNumber),
|
||||
ExecutingUUID, ExecutingCommand)) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Device is already busy with command {} (Command={})."
|
||||
, Cmd.UUID, Cmd.SerialNumber, Cmd.Command,ExecutingUUID, ExecutingCommand));
|
||||
continue;
|
||||
}
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
poco_information(MyLogger, fmt::format("{}: Serial={} Command={} Preparing execution.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk(NextRPCId(), Cmd.SerialNumber, Cmd.Command,
|
||||
*Params, Cmd.UUID, Sent);
|
||||
if (Sent) {
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Sent.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
} else {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Re-queued command.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Failed. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Hard failure. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().information(fmt::format("{}: Failed. Command marked as completed.", Cmd.UUID));
|
||||
Logger().log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
Logger().information(fmt::format("{}: Hard failure.", Cmd.UUID));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
}
|
||||
}
|
||||
} catch (Poco::Exception &E) {
|
||||
MyLogger.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(MyLogger,"Exception during command processing.");
|
||||
}
|
||||
poco_trace(MyLogger,"Scheduler done.");
|
||||
}
|
||||
|
||||
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool oneway_rpc,
|
||||
bool disk_only,
|
||||
bool & Sent) {
|
||||
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Command,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool oneway_rpc,
|
||||
bool disk_only,
|
||||
bool & Sent) {
|
||||
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(SerialNumber);
|
||||
Sent=false;
|
||||
if(!DeviceRegistry()->Connected(SerialNumber)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::stringstream ToSend;
|
||||
auto Object = std::make_shared<RpcObject>();
|
||||
|
||||
CommandTagIndex Idx;
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
if (oneway_rpc)
|
||||
Idx.Id = 1;
|
||||
else
|
||||
Idx.Id = ++Id_;
|
||||
Idx.SerialNumber = SerialNumber;
|
||||
CommandInfo Idx;
|
||||
Idx.Id = oneway_rpc ? 1 : RPCID;
|
||||
Idx.SerialNumber = SerialNumberInt;
|
||||
Idx.Command = Command;
|
||||
Idx.UUID = UUID;
|
||||
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, Idx.Id);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
Object->submitted = std::chrono::high_resolution_clock::now();
|
||||
Object->uuid = UUID;
|
||||
if(disk_only) {
|
||||
Object->rpc_entry = nullptr;
|
||||
} else {
|
||||
Object->rpc_entry = std::make_shared<CommandManager::promise_type_t>();
|
||||
}
|
||||
if(!oneway_rpc) {
|
||||
OutStandingRequests_[Idx] = Object;
|
||||
OutstandingUUIDs_.insert(UUID);
|
||||
}
|
||||
}
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, RPCID);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Command);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
Idx.rpc_entry = disk_only ? nullptr : std::make_shared<CommandManager::promise_type_t>();
|
||||
|
||||
poco_debug(Logger(), fmt::format("{}: Sending command. ID: {}", UUID, RPCID));
|
||||
if(DeviceRegistry()->SendFrame(SerialNumber, ToSend.str())) {
|
||||
Logger().information(fmt::format("{}: Sent command. ID: {}", UUID, Idx.Id));
|
||||
if(!oneway_rpc) {
|
||||
std::lock_guard M(Mutex_);
|
||||
OutStandingRequests_[RPCID] = Idx;
|
||||
}
|
||||
poco_debug(Logger(), fmt::format("{}: Sent command. ID: {}", UUID, RPCID));
|
||||
Sent=true;
|
||||
return Object->rpc_entry;
|
||||
return Idx.rpc_entry;
|
||||
}
|
||||
|
||||
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPCID));
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
@@ -13,6 +13,9 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
@@ -20,29 +23,9 @@
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
struct CommandTagIndex {
|
||||
uint64_t Id=0;
|
||||
std::string SerialNumber;
|
||||
};
|
||||
|
||||
inline bool operator <(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id<rhs.Id)
|
||||
return true;
|
||||
if(lhs.Id>rhs.Id)
|
||||
return false;
|
||||
return lhs.SerialNumber<rhs.SerialNumber;
|
||||
}
|
||||
|
||||
inline bool operator ==(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id == rhs.Id && lhs.SerialNumber == rhs.SerialNumber)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
class RPCResponseNotification: public Poco::Notification {
|
||||
public:
|
||||
RPCResponseNotification(const std::string &ser,
|
||||
@@ -61,8 +44,12 @@ namespace OpenWifi {
|
||||
public:
|
||||
typedef Poco::JSON::Object objtype_t;
|
||||
typedef std::promise<objtype_t> promise_type_t;
|
||||
struct RpcObject {
|
||||
std::string uuid;
|
||||
|
||||
struct CommandInfo {
|
||||
std::uint64_t Id=0;
|
||||
std::uint64_t SerialNumber=0;
|
||||
std::string Command;
|
||||
std::string UUID;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> submitted = std::chrono::high_resolution_clock::now();
|
||||
std::shared_ptr<promise_type_t> rpc_entry;
|
||||
};
|
||||
@@ -82,18 +69,17 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
void WakeUp();
|
||||
inline void PostCommandResult(const std::string &SerialNumber, const Poco::JSON::Object &Obj) {
|
||||
std::lock_guard G(Mutex_);
|
||||
// RPCResponseQueue_->Write(RPCResponse{.serialNumber=SerialNumber, .payload = Obj});
|
||||
ResponseQueue_.enqueueNotification(new RPCResponseNotification(SerialNumber,Obj));
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID, SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -101,12 +87,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandDisk(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -114,12 +102,13 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommand(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID, SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -128,12 +117,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWay(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -141,6 +132,8 @@ namespace OpenWifi {
|
||||
false, Sent );
|
||||
}
|
||||
|
||||
bool IsCommandRunning(const std::string &C);
|
||||
|
||||
void run() override;
|
||||
|
||||
static auto instance() {
|
||||
@@ -152,21 +145,50 @@ namespace OpenWifi {
|
||||
void onJanitorTimer(Poco::Timer & timer);
|
||||
void onCommandRunnerTimer(Poco::Timer & timer);
|
||||
void onRPCAnswer(bool& b);
|
||||
inline uint64_t NextRPCId() { return ++Id_; }
|
||||
|
||||
void RemovePendingCommand(std::uint64_t Id) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
OutStandingRequests_.erase(Id);
|
||||
}
|
||||
|
||||
inline bool CommandRunningForDevice(std::uint64_t SerialNumber, std::string & uuid, std::string &command) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
for(const auto &[Request,Command]:OutStandingRequests_) {
|
||||
if(Command.SerialNumber==SerialNumber) {
|
||||
uuid = Command.UUID;
|
||||
command = Command.Command;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void ClearQueue(std::uint64_t SerialNumber) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
for(auto Request = OutStandingRequests_.begin(); Request != OutStandingRequests_.end() ; ) {
|
||||
if(Request->second.SerialNumber==SerialNumber)
|
||||
Request = OutStandingRequests_.erase(Request);
|
||||
else
|
||||
++Request;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
mutable std::shared_mutex LocalMutex_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
mutable uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
std::map<CommandTagIndex,std::shared_ptr<RpcObject>> OutStandingRequests_;
|
||||
std::set<std::string> OutstandingUUIDs_;
|
||||
std::atomic_uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
std::map<std::uint64_t , CommandInfo> OutStandingRequests_;
|
||||
Poco::Timer JanitorTimer_;
|
||||
std::unique_ptr<Poco::TimerCallback<CommandManager>> JanitorCallback_;
|
||||
Poco::Timer CommandRunnerTimer_;
|
||||
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(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
|
||||
@@ -6,25 +6,29 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CommandManager.h"
|
||||
#include "Daemon.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "FileUploader.h"
|
||||
#include "FindCountry.h"
|
||||
#include "OUIServer.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "StorageArchiver.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "WS_Server.h"
|
||||
#include "VenueBroadcaster.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "FindCountry.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class Daemon *Daemon::instance() {
|
||||
@@ -46,8 +50,9 @@ namespace OpenWifi {
|
||||
StorageArchiver(),
|
||||
TelemetryStream(),
|
||||
RTTYS_server(),
|
||||
WebSocketServer(),
|
||||
RADIUS_proxy_server()
|
||||
RADIUS_proxy_server(),
|
||||
VenueBroadcaster(),
|
||||
AP_WS_Server()
|
||||
});
|
||||
return &instance;
|
||||
}
|
||||
@@ -103,16 +108,25 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ExitCode;
|
||||
try {
|
||||
|
||||
Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr);
|
||||
auto App = OpenWifi::Daemon::instance();
|
||||
auto ExitCode = App->run(argc, argv);
|
||||
return ExitCode;
|
||||
|
||||
ExitCode = App->run(argc, argv);
|
||||
Poco::Net::SSLManager::instance().shutdown();
|
||||
} catch (Poco::Exception &exc) {
|
||||
std::cerr << exc.displayText() << std::endl;
|
||||
return Poco::Util::Application::EXIT_SOFTWARE;
|
||||
ExitCode = Poco::Util::Application::EXIT_SOFTWARE;
|
||||
std::cout << exc.displayText() << std::endl;
|
||||
} catch (std::exception &exc) {
|
||||
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
|
||||
std::cout << exc.what() << std::endl;
|
||||
} catch (...) {
|
||||
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
|
||||
std::cout << "Exception on closure" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Exitcode: " << ExitCode << std::endl;
|
||||
return ExitCode;
|
||||
}
|
||||
|
||||
// end of namespace
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/ServerApplication.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
@@ -25,7 +27,6 @@
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
|
||||
#include "Dashboard.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "GwWebSocketClient.h"
|
||||
|
||||
|
||||
@@ -7,195 +7,257 @@
|
||||
//
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "WS_Server.h"
|
||||
#include "OUIServer.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int DeviceRegistry::Start() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Starting ");
|
||||
return 0;
|
||||
poco_notice(Logger(),"Starting");
|
||||
|
||||
ArchiverCallback_ = std::make_unique<Poco::TimerCallback<DeviceRegistry>>(*this,&DeviceRegistry::onConnectionJanitor);
|
||||
Timer_.setStartInterval(60 * 1000);
|
||||
Timer_.setPeriodicInterval(20 * 1000); // every minute
|
||||
Timer_.start(*ArchiverCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeviceRegistry::Stop() {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Stopping ");
|
||||
Timer_.stop();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
Statistics = Device->second->LastStats;
|
||||
return true;
|
||||
}
|
||||
void DeviceRegistry::onConnectionJanitor([[maybe_unused]] Poco::Timer &timer) {
|
||||
|
||||
void DeviceRegistry::SetStatistics(uint64_t SerialNumber, const std::string &Statistics) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
static std::uint64_t last_log = OpenWifi::Now();
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->Conn_.LastContact = time(nullptr);
|
||||
Device->second->LastStats = Statistics;
|
||||
}
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
std::uint64_t total_connected_time=0;
|
||||
|
||||
State = Device->second->Conn_;
|
||||
return true;
|
||||
}
|
||||
auto now = OpenWifi::Now();
|
||||
for (auto connection=SerialNumbers_.begin(); connection!=SerialNumbers_.end();) {
|
||||
|
||||
void DeviceRegistry::SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->Conn_.LastContact = time(nullptr);
|
||||
Device->second->Conn_ = State;
|
||||
}
|
||||
}
|
||||
if(connection->second.second== nullptr) {
|
||||
connection++;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end()) {
|
||||
CheckData = Device->second->LastHealthcheck;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck & CheckData) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->LastHealthcheck = CheckData;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceRegistry::ConnectionEntry> DeviceRegistry::Register(uint64_t SerialNumber, WSConnection *Ptr, uint64_t & ConnectionId )
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
const auto & E = Devices_[SerialNumber] = std::make_shared<ConnectionEntry>();
|
||||
E->WSConn_ = Ptr;
|
||||
E->Conn_.LastContact = OpenWifi::Now();
|
||||
E->Conn_.Connected = true ;
|
||||
E->Conn_.UUID = 0 ;
|
||||
E->Conn_.MessageCount = 0 ;
|
||||
E->Conn_.Address = "";
|
||||
E->Conn_.TX = 0 ;
|
||||
E->Conn_.RX = 0;
|
||||
E->Conn_.VerifiedCertificate = GWObjects::CertificateValidation::NO_CERTIFICATE;
|
||||
ConnectionId = E->ConnectionId = ++Id_;
|
||||
return E;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::Connected(uint64_t SerialNumber) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
return Device->second->Conn_.Connected;
|
||||
}
|
||||
|
||||
void DeviceRegistry::UnRegister(uint64_t SerialNumber, uint64_t ConnectionId) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto It = Devices_.find(SerialNumber);
|
||||
if(It!=Devices_.end()) {
|
||||
if(It->second->ConnectionId == ConnectionId)
|
||||
Devices_.erase(SerialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->Send(Payload);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
if (connection->second.second->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time += (now - connection->second.second->State_.started);
|
||||
connection++;
|
||||
} else {
|
||||
NumberOfConnectingDevices_++;
|
||||
connection++;
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ = (NumberOfConnectedDevices_!=0) ? total_connected_time/NumberOfConnectedDevices_ : 0;
|
||||
if((now-last_log)>120) {
|
||||
last_log = now;
|
||||
poco_information(Logger(),
|
||||
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
|
||||
NumberOfConnectedDevices_, NumberOfConnectingDevices_, AverageDeviceConnectionTime_));
|
||||
}
|
||||
WebSocketClientNotificationNumberOfConnections(NumberOfConnectedDevices_,
|
||||
AverageDeviceConnectionTime_,
|
||||
NumberOfConnectingDevices_);
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
|
||||
return false;
|
||||
Statistics = Device->second.second->LastStats_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
|
||||
return false;
|
||||
State = Device->second.second->State_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
|
||||
return false;
|
||||
|
||||
CheckData = Device->second.second->LastHealthcheck_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::EndSession(std::uint64_t connection_id, std::uint64_t serial_number) {
|
||||
std::unique_lock G(LocalMutex_);
|
||||
|
||||
auto Connection = SerialNumbers_.find(serial_number);
|
||||
if(Connection==end(SerialNumbers_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Connection->second.first!=connection_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SerialNumbers_.erase(Connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber) {
|
||||
auto Connection = AP_WS_Server()->FindConnection(connection_id);
|
||||
|
||||
if(Connection== nullptr)
|
||||
return;
|
||||
|
||||
std::unique_lock G(LocalMutex_);
|
||||
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
|
||||
if( (CurrentSerialNumber==SerialNumbers_.end()) ||
|
||||
(CurrentSerialNumber->second.first<connection_id)) {
|
||||
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Connection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceRegistry::Connected(uint64_t SerialNumber) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
return Device->second.second->State_.Connected;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
// std::cout << "Device connection pointer: " << (std::uint64_t) Device->second.second << std::endl;
|
||||
return Device->second.second->Send(Payload);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
|
||||
return;
|
||||
Device->second.second->StopWebSocketTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
|
||||
return;
|
||||
Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
|
||||
return;
|
||||
Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
|
||||
}
|
||||
|
||||
void DeviceRegistry::StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
|
||||
return;
|
||||
Device->second.second->StopKafkaTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void DeviceRegistry::GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
|
||||
uint64_t & TelemetryInterval,
|
||||
uint64_t & TelemetryWebSocketTimer,
|
||||
uint64_t & TelemetryKafkaTimer,
|
||||
uint64_t & TelemetryWebSocketCount,
|
||||
uint64_t & TelemetryKafkaCount,
|
||||
uint64_t & TelemetryWebSocketPackets,
|
||||
uint64_t & TelemetryKafkaPackets) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_)|| Device->second.second== nullptr)
|
||||
return;
|
||||
Device->second.second->GetTelemetryParameters(TelemetryRunning,
|
||||
TelemetryInterval,
|
||||
TelemetryWebSocketTimer,
|
||||
TelemetryKafkaTimer,
|
||||
TelemetryWebSocketCount,
|
||||
TelemetryKafkaCount,
|
||||
TelemetryWebSocketPackets,
|
||||
TelemetryKafkaPackets);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
return Device->second.second->SendRadiusAccountingData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
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;
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
return Device->second.second->SendRadiusAuthenticationData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
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;
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
return Device->second.second->SendRadiusCoAData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end()) {
|
||||
Device->second->Conn_.PendingUUID = PendingUUID;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -8,25 +8,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
// class uCentral::WebSocket::WSConnection;
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Timer.h"
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WSConnection;
|
||||
class AP_WS_Connection;
|
||||
class DeviceRegistry : public SubSystemServer {
|
||||
public:
|
||||
struct ConnectionEntry {
|
||||
WSConnection * WSConn_ = nullptr;
|
||||
GWObjects::ConnectionState Conn_;
|
||||
std::string LastStats;
|
||||
GWObjects::HealthCheck LastHealthcheck;
|
||||
uint64_t ConnectionId=0;
|
||||
};
|
||||
|
||||
DeviceRegistry() noexcept:
|
||||
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
|
||||
}
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new DeviceRegistry;
|
||||
@@ -36,84 +34,68 @@ namespace OpenWifi {
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) {
|
||||
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) const {
|
||||
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
|
||||
}
|
||||
bool GetStatistics(uint64_t SerialNumber, std::string & Statistics);
|
||||
bool GetStatistics(std::uint64_t SerialNumber, std::string & Statistics) const;
|
||||
|
||||
inline void SetStatistics(const std::string &SerialNumber, const std::string &Statistics) {
|
||||
return SetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
|
||||
}
|
||||
void SetStatistics(uint64_t SerialNumber, const std::string &stats);
|
||||
|
||||
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) {
|
||||
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) const {
|
||||
return GetState(Utils::SerialNumberToInt(SerialNumber), State);
|
||||
}
|
||||
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State);
|
||||
bool GetState(std::uint64_t SerialNumber, GWObjects::ConnectionState & State) const;
|
||||
|
||||
inline void SetState(const std::string & SerialNumber, const GWObjects::ConnectionState & State) {
|
||||
return SetState(Utils::SerialNumberToInt(SerialNumber), State);
|
||||
}
|
||||
void SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State);
|
||||
|
||||
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) {
|
||||
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) const {
|
||||
return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
|
||||
}
|
||||
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData);
|
||||
bool GetHealthcheck(std::uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const ;
|
||||
|
||||
inline void SetHealthcheck(const std::string &SerialNumber, const GWObjects::HealthCheck &H) {
|
||||
return SetHealthcheck(Utils::SerialNumberToInt(SerialNumber),H);
|
||||
}
|
||||
void SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck &H);
|
||||
bool Connected(uint64_t SerialNumber) const ;
|
||||
|
||||
std::shared_ptr<ConnectionEntry> Register(uint64_t SerialNumber, WSConnection *Conn, uint64_t & ConnectionId);
|
||||
|
||||
inline void UnRegister(const std::string & SerialNumber, uint64_t ConnectionId) {
|
||||
return UnRegister(Utils::SerialNumberToInt(SerialNumber),ConnectionId);
|
||||
}
|
||||
void UnRegister(uint64_t SerialNumber, uint64_t ConnectionId);
|
||||
|
||||
inline bool Connected(const std::string & SerialNumber) {
|
||||
return Connected(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
|
||||
bool Connected(uint64_t SerialNumber);
|
||||
|
||||
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) {
|
||||
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) const {
|
||||
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
|
||||
}
|
||||
|
||||
bool SendFrame(uint64_t SerialNumber, const std::string & Payload);
|
||||
|
||||
inline void SetPendingUUID(const std::string & SerialNumber, uint64_t PendingUUID) {
|
||||
return SetPendingUUID(Utils::SerialNumberToInt(SerialNumber), PendingUUID);
|
||||
}
|
||||
void SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID);
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(const std::string & SerialNumber) {
|
||||
return GetDeviceConnection(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(uint64_t SerialNumber) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
return Device->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
bool SendFrame(std::uint64_t SerialNumber, const std::string & Payload) const ;
|
||||
|
||||
bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
|
||||
private:
|
||||
inline static std::atomic_uint64_t Id_=1;
|
||||
std::map<uint64_t ,std::shared_ptr<ConnectionEntry>> Devices_;
|
||||
void SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber);
|
||||
bool EndSession(std::uint64_t connection_id, std::uint64_t serial_number);
|
||||
|
||||
DeviceRegistry() noexcept:
|
||||
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
|
||||
void SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
|
||||
void StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
|
||||
void SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
|
||||
void StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
|
||||
void GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
|
||||
uint64_t & TelemetryInterval,
|
||||
uint64_t & TelemetryWebSocketTimer,
|
||||
uint64_t & TelemetryKafkaTimer,
|
||||
uint64_t & TelemetryWebSocketCount,
|
||||
uint64_t & TelemetryKafkaCount,
|
||||
uint64_t & TelemetryWebSocketPackets,
|
||||
uint64_t & TelemetryKafkaPackets);
|
||||
|
||||
void onConnectionJanitor(Poco::Timer & timer);
|
||||
|
||||
inline void AverageDeviceStatistics( std::uint64_t & Connections, std::uint64_t & AverageConnectionTime, std::uint64_t & NumberOfConnectingDevices) const {
|
||||
Connections = NumberOfConnectedDevices_;
|
||||
AverageConnectionTime = AverageDeviceConnectionTime_;
|
||||
NumberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex LocalMutex_;
|
||||
std::map<std::uint64_t, std::pair<std::uint64_t,std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
|
||||
|
||||
std::unique_ptr<Poco::TimerCallback<DeviceRegistry>> ArchiverCallback_;
|
||||
Poco::Timer Timer_;
|
||||
Poco::Thread ConnectionJanitor_;
|
||||
std::atomic_uint64_t NumberOfConnectedDevices_=0;
|
||||
std::atomic_uint64_t AverageDeviceConnectionTime_=0;
|
||||
std::atomic_uint64_t NumberOfConnectingDevices_=0;
|
||||
|
||||
};
|
||||
|
||||
inline auto DeviceRegistry() { return DeviceRegistry::instance(); }
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/HTTPServerParams.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
@@ -22,14 +22,13 @@
|
||||
|
||||
#include "FileUploader.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string URI_BASE{"/v1/upload/"};
|
||||
|
||||
int FileUploader::Start() {
|
||||
Logger().notice("Starting.");
|
||||
poco_notice(Logger(),"Starting.");
|
||||
|
||||
Poco::File UploadsDir(MicroService::instance().ConfigPath("openwifi.fileuploader.path","/tmp"));
|
||||
Path_ = UploadsDir.path();
|
||||
@@ -44,13 +43,14 @@ namespace OpenWifi {
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Logger().information(fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
poco_notice(Logger(), fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
|
||||
auto Sock{Svr.CreateSocket(Logger())};
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
@@ -61,17 +61,18 @@ namespace OpenWifi {
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
Logger().information(fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
poco_information(Logger(),fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
|
||||
Params->setName("file-upldr");
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
} else {
|
||||
std::string l{"Starting: " + Svr.Address() + ":" + std::to_string(Svr.Port()) +
|
||||
" key:" + Svr.KeyFile() + " cert:" + Svr.CertFile()};
|
||||
Logger().information(l);
|
||||
poco_information(Logger(),l);
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
|
||||
@@ -82,6 +83,7 @@ namespace OpenWifi {
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
@@ -92,7 +94,7 @@ namespace OpenWifi {
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
Logger().information(fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
poco_information(Logger(), fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
@@ -109,7 +111,7 @@ namespace OpenWifi {
|
||||
|
||||
void FileUploader::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
MicroService::instance().LoadConfigurationFile();
|
||||
Logger().information("Reinitializing.");
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
@@ -198,7 +200,7 @@ namespace OpenWifi {
|
||||
const auto ContentType = Request.getContentType();
|
||||
const auto Tokens = Poco::StringTokenizer(ContentType,";",Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
Logger().debug(fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
try {
|
||||
@@ -223,7 +225,7 @@ namespace OpenWifi {
|
||||
Poco::StreamCopier::copyStream(Reader.stream(), FileContent);
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 0);
|
||||
Logger().debug(fmt::format("{}: Trace file uploaded.", UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Trace file uploaded.", UUID_));
|
||||
StorageService()->AttachFileDataToCommand(UUID_, FileContent);
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
@@ -241,10 +243,10 @@ namespace OpenWifi {
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
Logger().debug("Exception while receiving trace file.");
|
||||
poco_debug(Logger(),"Exception while receiving trace file.");
|
||||
}
|
||||
|
||||
Logger().debug(fmt::format("{}: Failed to upload trace file.",UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Failed to upload trace file.",UUID_));
|
||||
std::string Error{"Trace file rejected"};
|
||||
StorageService()->CancelWaitFile(UUID_, Error);
|
||||
Answer.set("filename", UUID_);
|
||||
@@ -264,7 +266,13 @@ namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler *FileUpLoaderRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest & Request) {
|
||||
|
||||
Logger().debug(fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
poco_debug(Logger(),fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
|
||||
if(Request.getMethod()!=Poco::Net::HTTPRequest::HTTP_POST ||
|
||||
Request.getURI().size()<(URI_BASE.size()+36)) {
|
||||
poco_warning(Logger(),fmt::format("ILLEGAL-REQUEST({}): {} {}. Dropped.", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The UUID should be after the /v1/upload/ part...
|
||||
auto UUIDLocation = Request.getURI().find_first_of(URI_BASE);
|
||||
@@ -280,17 +288,18 @@ namespace OpenWifi {
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger().warning(fmt::format("Unknown UUID={}",UUID));
|
||||
poco_warning(Logger(),fmt::format("Unknown UUID={}",UUID));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FileUploader::Stop() {
|
||||
Logger().notice("Stopping ");
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
for( const auto & svr : Servers_ )
|
||||
svr->stop();
|
||||
svr->stopAll(true);
|
||||
Servers_.clear();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
@@ -8,12 +8,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/HTTPRequestHandler.h"
|
||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/IPAddress.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
@@ -133,6 +134,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline int Start() final {
|
||||
poco_notice(Logger(),"Starting...");
|
||||
ProviderName_ = MicroService::instance().ConfigGetString("iptocountry.provider","");
|
||||
if(!ProviderName_.empty()) {
|
||||
Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(ProviderName_);
|
||||
@@ -145,6 +147,9 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline void Stop() final {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
// Nothing to do - just to provide the same look at the others.
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline std::string ReformatAddress(const std::string & I )
|
||||
|
||||
@@ -37,7 +37,6 @@ namespace OpenWifi {
|
||||
bool &Done, std::string &Answer) {
|
||||
Done = false;
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
Logger().information(Poco::format("serial_number_search: %s", Prefix));
|
||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||
std::vector<uint64_t> Numbers;
|
||||
SerialNumberCache()->FindNumbers(Prefix, 50, Numbers);
|
||||
|
||||
@@ -5,13 +5,10 @@
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "OUIServer.h"
|
||||
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/URIStreamOpener.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/File.h"
|
||||
|
||||
#include "OUIServer.h"
|
||||
@@ -27,18 +24,20 @@ namespace OpenWifi {
|
||||
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);
|
||||
Timer_.start(*UpdaterCallBack_);
|
||||
Timer_.start(*UpdaterCallBack_, MicroService::instance().TimerPool());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OUIServer::Stop() {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
Running_=false;
|
||||
Timer_.stop();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void OUIServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
MicroService::instance().LoadConfigurationFile();
|
||||
Logger().information("Reinitializing.");
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
@@ -46,14 +45,14 @@ 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")));
|
||||
poco_information(Logger(), 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;
|
||||
OS.open(FileName);
|
||||
Poco::StreamCopier::copyStream(*pStr, OS);
|
||||
OS.close();
|
||||
Logger().information(fmt::format("Done: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
poco_information(Logger(), fmt::format("Done: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -111,7 +110,7 @@ namespace OpenWifi {
|
||||
if(ProcessFile(CurrentOUIFileName_, OUIs_)) {
|
||||
Initialized_ = true;
|
||||
Updating_=false;
|
||||
Logger().information("Using cached file.");
|
||||
poco_information(Logger(), "Using cached file.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -131,7 +130,7 @@ namespace OpenWifi {
|
||||
F1.remove();
|
||||
Poco::File F2(LatestOUIFileName_);
|
||||
F2.renameTo(CurrentOUIFileName_);
|
||||
Logger().information(fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
poco_information(Logger(), fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
} else if(OUIs_.empty()) {
|
||||
if(ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace OpenWifi {
|
||||
uint64_t LastUpdate_ = 0 ;
|
||||
bool Initialized_ = false;
|
||||
OUIMap OUIs_;
|
||||
mutable std::atomic_bool Updating_=false;
|
||||
mutable 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_;
|
||||
|
||||
@@ -1565,6 +1565,7 @@ namespace OpenWifi {
|
||||
ie["TLV Block"] = BufferToHex(&b[offset],l-offset);
|
||||
} break;
|
||||
default:
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1612,7 +1613,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_wfa(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Wi-Fi Alliance";
|
||||
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1620,6 +1621,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_aironet(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Cisco Wireless (Aironet)";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1627,6 +1629,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_marvell(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Marvell Semiconductor";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1634,6 +1637,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_atheros(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Atheros Communications";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1641,6 +1645,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_aruba(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Aruba Networks";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1648,6 +1653,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_nintendo(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Nintendo";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1705,7 +1711,7 @@ namespace OpenWifi {
|
||||
nlohmann::json new_ie;
|
||||
nlohmann::json content;
|
||||
|
||||
std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
// std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
uint offset=0;
|
||||
auto sub_ie = data[offset++];
|
||||
switch (sub_ie) {
|
||||
@@ -1737,92 +1743,112 @@ namespace OpenWifi {
|
||||
std::ostringstream ofs;
|
||||
Obj->stringify(ofs);
|
||||
|
||||
nlohmann::json D = nlohmann::json::parse(ofs.str());
|
||||
std::cout << "Start of parsing wifi" << std::endl;
|
||||
if (D.contains("status")) {
|
||||
auto Status = D["status"];
|
||||
|
||||
if (Status.contains("scan") && Status["scan"].is_array()) {
|
||||
nlohmann::json ScanArray = Status["scan"];
|
||||
nlohmann::json ParsedScan = nlohmann::json::array();
|
||||
for (auto &scan_entry : ScanArray) {
|
||||
if (scan_entry.contains("ies") && scan_entry["ies"].is_array()) {
|
||||
auto ies = scan_entry["ies"];
|
||||
nlohmann::json new_ies=nlohmann::json::array();
|
||||
for (auto &ie : ies) {
|
||||
try {
|
||||
if (ie.contains("type") && ie.contains("data")) {
|
||||
uint64_t ie_type = ie["type"];
|
||||
std::string ie_data = ie["data"];
|
||||
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data << std::endl;
|
||||
auto data = Base64Decode2Vec(ie_data);
|
||||
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_FH_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_FH_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_DS_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_DS_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TIM) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TIM(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_QBSS_LOAD) {
|
||||
new_ies.push_back(WFS_WLAN_EID_QBSS_LOAD(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_PWR_CONSTRAINT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_PWR_CONSTRAINT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_ERP_INFO) {
|
||||
new_ies.push_back(WFS_WLAN_EID_ERP_INFO(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPPORTED_REGULATORY_CLASSES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPPORTED_REGULATORY_CLASSES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_HT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_HT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXT_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TX_POWER_ENVELOPE) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TX_POWER_ENVELOPE(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_VHT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VHT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RRM_ENABLED_CAPABILITIES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RRM_ENABLED_CAPABILITIES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TPC_REPORT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TPC_REPORT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RSN) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RSN(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_VENDOR_SPECIFIC) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VENDOR_SPECIFIC(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
|
||||
try {
|
||||
nlohmann::json D = nlohmann::json::parse(ofs.str());
|
||||
// std::cout << "Start of parsing wifi" << std::endl;
|
||||
if (D.contains("status")) {
|
||||
auto Status = D["status"];
|
||||
if (Status.contains("scan") && Status["scan"].is_array()) {
|
||||
nlohmann::json ScanArray = Status["scan"];
|
||||
nlohmann::json ParsedScan = nlohmann::json::array();
|
||||
for (auto &scan_entry : ScanArray) {
|
||||
if (scan_entry.contains("ies") && scan_entry["ies"].is_array()) {
|
||||
auto ies = scan_entry["ies"];
|
||||
nlohmann::json new_ies = nlohmann::json::array();
|
||||
for (auto &ie : ies) {
|
||||
try {
|
||||
if (ie.contains("type") && ie.contains("data")) {
|
||||
uint64_t ie_type = ie["type"];
|
||||
std::string ie_data = ie["data"];
|
||||
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data << std::endl;
|
||||
auto data = Base64Decode2Vec(ie_data);
|
||||
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_FH_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_FH_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_DS_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_DS_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TIM) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TIM(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_QBSS_LOAD) {
|
||||
new_ies.push_back(WFS_WLAN_EID_QBSS_LOAD(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_PWR_CONSTRAINT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_PWR_CONSTRAINT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_ERP_INFO) {
|
||||
new_ies.push_back(WFS_WLAN_EID_ERP_INFO(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES) {
|
||||
new_ies.push_back(
|
||||
WFS_WLAN_EID_SUPPORTED_REGULATORY_CLASSES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_HT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_HT_CAPABILITY(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_EXT_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_SUPP_RATES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_TX_POWER_ENVELOPE) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TX_POWER_ENVELOPE(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_VHT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VHT_CAPABILITY(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::
|
||||
WLAN_EID_RRM_ENABLED_CAPABILITIES) {
|
||||
new_ies.push_back(
|
||||
WFS_WLAN_EID_RRM_ENABLED_CAPABILITIES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_EXT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TPC_REPORT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TPC_REPORT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RSN) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RSN(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_VENDOR_SPECIFIC) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VENDOR_SPECIFIC(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
|
||||
} else {
|
||||
// std::cout
|
||||
// << "Skipping IE: no parsing available: " << ie_type
|
||||
// << std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} else {
|
||||
std::cout
|
||||
<< "Skipping IE: no parsing available: " << ie_type
|
||||
<< std::endl;
|
||||
// std::cout << "Skipping IE: no data and type" << std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} else {
|
||||
std::cout << "Skipping IE: no data and type" << std::endl;
|
||||
} catch (...) {
|
||||
// std::cout << "Skipping IE: exception" << std::endl;
|
||||
Logger.information(fmt::format("Error parsing IEs"));
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} catch (...) {
|
||||
std::cout << "Skipping IE: exception" << std::endl;
|
||||
Logger.information(fmt::format("Error parsing IEs"));
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
// std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
Status["scan"] = ParsedScan;
|
||||
D["status"] = Status;
|
||||
}
|
||||
Status["scan"] = ParsedScan;
|
||||
D["status"] = Status;
|
||||
}
|
||||
Result << to_string(D);
|
||||
// std::cout << "End of parsing wifi" << std::endl;
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger.log(E);
|
||||
Logger.error(fmt::format("Failure to parse WifiScan."));
|
||||
} catch (...) {
|
||||
Logger.error(fmt::format("Failure to parse WifiScan."));
|
||||
}
|
||||
Result << to_string(D);
|
||||
std::cout << "End of parsing wifi" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,255 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "Poco/HMACEngine.h"
|
||||
#include "Poco/MD5Engine.h"
|
||||
|
||||
namespace OpenWifi::RADIUS {
|
||||
|
||||
#define RADCMD_ACCESS_REQ 1 /* Access-Request */
|
||||
#define RADCMD_ACCESS_ACC 2 /* Access-Accept */
|
||||
#define RADCMD_ACCESS_REJ 3 /* Access-Reject */
|
||||
#define RADCMD_ACCOUN_REQ 4 /* Accounting-Request */
|
||||
#define RADCMD_ACCOUN_RES 5 /* Accounting-Response */
|
||||
#define RADCMD_ACCOUN_STATUS 6 /* Accounting-Status */
|
||||
#define RADCMD_PASSWORD_REQUEST 7 /* Password-Request [RFC3575] */
|
||||
#define RADCMD_PASSWORD_ACK 8 /* Password-Ack [RFC3575] */
|
||||
#define RADCMD_PASSWORD_REJECT 9 /* Password-Reject [RFC3575] */
|
||||
#define RADCMD_ACCOUN_MESSAGE 10 /* Accounting-Message [RFC3575] */
|
||||
|
||||
#define RADCMD_RES_FREE_REQ 21 /* Resource-Free-Request [RFC3575] */
|
||||
#define RADCMD_RES_FREE_RES 22 /* Resource-Free-Response [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_REQ 23 /* Resource-Query-Request [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_RES 24 /* Resource-Query-Response [RFC3575] */
|
||||
#define RADCMD_RES_ALT_RECLAIM_REQ 25 /* Alternate-Resource-Reclaim-Request [RFC3575] */
|
||||
|
||||
#define RADCMD_ACCESS_CHA 11 /* Access-Challenge */
|
||||
#define RADCMD_STATUS_SER 12 /* Status-Server */
|
||||
#define RADCMD_STATUS_CLI 13 /* Status-Client */
|
||||
#define RADCMD_DISCON_REQ 40 /* Disconnect-Request */
|
||||
#define RADCMD_DISCON_ACK 41 /* Disconnect-ACK */
|
||||
#define RADCMD_DISCON_NAK 42 /* Disconnect-NAK */
|
||||
#define RADCMD_COA_REQ 43 /* CoA-Request */
|
||||
#define RADCMD_COA_ACK 44 /* CoA-ACK */
|
||||
#define RADCMD_COA_NAK 45 /* CoA-NAK */
|
||||
#define RADCMD_RESERVED 255 /* Reserved */
|
||||
|
||||
/*
|
||||
21 Resource-Free-Request [RFC3575]
|
||||
22 Resource-Free-Response [RFC3575]
|
||||
23 Resource-Query-Request [RFC3575]
|
||||
24 Resource-Query-Response [RFC3575]
|
||||
25 Alternate-Resource-Reclaim-Request [RFC3575]
|
||||
|
||||
26 NAS-Reboot-Request [RFC3575]
|
||||
27 NAS-Reboot-Response [RFC3575]
|
||||
28 Reserved
|
||||
29 Next-Passcode [RFC3575]
|
||||
30 New-Pin [RFC3575]
|
||||
31 Terminate-Session [RFC3575]
|
||||
32 Password-Expired [RFC3575]
|
||||
33 Event-Request [RFC3575]
|
||||
34 Event-Response [RFC3575]
|
||||
35-39 Unassigned
|
||||
40 Disconnect-Request [RFC3575][RFC5176]
|
||||
41 Disconnect-ACK [RFC3575][RFC5176]
|
||||
42 Disconnect-NAK [RFC3575][RFC5176]
|
||||
43 CoA-Request [RFC3575][RFC5176]
|
||||
44 CoA-ACK [RFC3575][RFC5176]
|
||||
45 CoA-NAK [RFC3575][RFC5176]
|
||||
46-49 Unassigned
|
||||
50 IP-Address-Allocate [RFC3575]
|
||||
51 IP-Address-Release [RFC3575]
|
||||
52 Protocol-Error [RFC7930]
|
||||
53-249 Unassigned
|
||||
250-253 Experimental Use [RFC3575]
|
||||
254 Reserved [RFC3575]
|
||||
255 Reserved [RFC3575]
|
||||
*/
|
||||
|
||||
struct tok {
|
||||
uint cmd;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Radius commands
|
||||
|
||||
char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
|
||||
"", //!< 0
|
||||
"Access-Request",
|
||||
"Access-Accept",
|
||||
"Access-Reject",
|
||||
"Accounting-Request",
|
||||
"Accounting-Response",
|
||||
"Accounting-Status",
|
||||
"Password-Request",
|
||||
"Password-Accept",
|
||||
"Password-Reject",
|
||||
"Accounting-Message", //!< 10
|
||||
"Access-Challenge",
|
||||
"Status-Server",
|
||||
"Status-Client",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
"18",
|
||||
"19",
|
||||
"20", //!< 20
|
||||
"Resource-Free-Request",
|
||||
"Resource-Free-Response",
|
||||
"Resource-Query-Request",
|
||||
"Resource-Query-Response",
|
||||
"Alternate-Resource-Reclaim-Request",
|
||||
"NAS-Reboot-Request",
|
||||
"NAS-Reboot-Response",
|
||||
"28",
|
||||
"Next-Passcode",
|
||||
"New-Pin", //!< 30
|
||||
"Terminate-Session",
|
||||
"Password-Expired",
|
||||
"Event-Request",
|
||||
"Event-Response",
|
||||
"35",
|
||||
"36",
|
||||
"37",
|
||||
"38",
|
||||
"39",
|
||||
"Disconnect-Request", //!< 40
|
||||
"Disconnect-ACK",
|
||||
"Disconnect-NAK",
|
||||
"CoA-Request",
|
||||
"CoA-ACK",
|
||||
"CoA-NAK",
|
||||
"46",
|
||||
"47",
|
||||
"48",
|
||||
"49",
|
||||
"IP-Address-Allocate",
|
||||
"IP-Address-Release", //!< 50
|
||||
};
|
||||
|
||||
|
||||
*/
|
||||
|
||||
static const struct tok radius_command_values[] = {
|
||||
{ RADCMD_ACCESS_REQ, "Access-Request" },
|
||||
{ RADCMD_ACCESS_ACC, "Access-Accept" },
|
||||
{ RADCMD_ACCESS_REJ, "Access-Reject" },
|
||||
{ RADCMD_ACCOUN_REQ, "Accounting-Request" },
|
||||
{ RADCMD_ACCOUN_RES, "Accounting-Response" },
|
||||
{ RADCMD_ACCESS_CHA, "Access-Challenge" },
|
||||
{ RADCMD_STATUS_SER, "Status-Server" },
|
||||
{ RADCMD_STATUS_CLI, "Status-Client" },
|
||||
{ RADCMD_DISCON_REQ, "Disconnect-Request" },
|
||||
{ RADCMD_DISCON_ACK, "Disconnect-ACK" },
|
||||
{ RADCMD_DISCON_NAK, "Disconnect-NAK" },
|
||||
{ RADCMD_COA_REQ, "CoA-Request" },
|
||||
{ RADCMD_COA_ACK, "CoA-ACK" },
|
||||
{ RADCMD_COA_NAK, "CoA-NAK" },
|
||||
{ RADCMD_RESERVED, "Reserved" },
|
||||
{ RADCMD_ACCOUN_STATUS, "Accounting-Status"},
|
||||
{ RADCMD_PASSWORD_REQUEST, "Password-Request"},
|
||||
{ RADCMD_PASSWORD_ACK, "Password-Ack"},
|
||||
{ RADCMD_PASSWORD_REJECT, "Password-Reject"},
|
||||
{ RADCMD_ACCOUN_MESSAGE, "Accounting-Message"},
|
||||
{ RADCMD_RES_FREE_REQ, "Resource-Free-Request"},
|
||||
{ RADCMD_RES_FREE_RES, "Resource-Free-Response"},
|
||||
{ RADCMD_RES_QUERY_REQ, "Resource-Query-Request"},
|
||||
{ RADCMD_RES_QUERY_RES, "Resource-Query-Response"},
|
||||
{ RADCMD_RES_ALT_RECLAIM_REQ, "Alternate-Resource-Reclaim-Request"},
|
||||
{ 0, nullptr}
|
||||
};
|
||||
|
||||
static const struct tok radius_attribute_names[] = {
|
||||
{1,"User-Name"},
|
||||
{2,"User-Password"},
|
||||
{3,"CHAP-Password"},
|
||||
{4,"NAS-IP Address"},
|
||||
{5,"NAS-Port"},
|
||||
{6,"Service-Type"},
|
||||
{7,"Framed-Protocol"},
|
||||
{8,"Framed-IP-Address"},
|
||||
{9,"Framed-IP-Netmask"},
|
||||
{10,"Framed-Routing"},
|
||||
{11,"Filter-Id"},
|
||||
{12,"Framed-MTU"},
|
||||
{13,"Framed-Compression"},
|
||||
{14,"Login-IP-Host"},
|
||||
{15,"Login-Service"},
|
||||
{16,"Login-TCP-Port"},
|
||||
{18,"Reply-Message"},
|
||||
{19,"Callback-Number"},
|
||||
{20,"Callback-ID"},
|
||||
{22,"Framed-Route"},
|
||||
{23,"Framed-IPX-Network"},
|
||||
{24,"State"},
|
||||
{25,"Class"},
|
||||
{26,"Vendor-Specific"},
|
||||
{27,"Session-Timeout"},
|
||||
{28,"Idle-Timeout"},
|
||||
{29,"Termination-Action"},
|
||||
{30,"Called-Station-Id"},
|
||||
{31,"Calling-Station-Id"},
|
||||
{32,"NAS-Identifier"},
|
||||
{33,"Proxy-State"},
|
||||
{34,"Login-LAT-Service"},
|
||||
{35,"Login-LAT-Node"},
|
||||
{36,"Login-LAT-Group"},
|
||||
{37,"Framed-AppleTalk-Link"},
|
||||
{38,"Framed-AppleTalk-Network"},
|
||||
{39,"Framed-AppleTalk-Zone"},
|
||||
{40,"Acct-Status-Type"},
|
||||
{41,"Acct-Delay-Time"},
|
||||
{42,"Acct-Input-Octets"},
|
||||
{43,"Acct-Output-Octets"},
|
||||
{44,"Acct-Session-Id"},
|
||||
{45,"Acct-Authentic"},
|
||||
{46,"Acct-Session-Time"},
|
||||
{47,"Acct-Input-Packets"},
|
||||
{48,"Acct-Output-Packets"},
|
||||
{49,"Acct-Terminate-Cause"},
|
||||
{50,"Acct-Multi-Session-Id"},
|
||||
{51,"Acct-Link-Count"},
|
||||
{52,"Acct-Input-Gigawords"},
|
||||
{53,"Acct-Output-Gigawords"},
|
||||
{55,"Event-Timestamp"},
|
||||
{60,"CHAP-Challenge"},
|
||||
{61,"NAS-Port-Type"},
|
||||
{62,"Port-Limit"},
|
||||
{63,"Login-LAT-Port"},
|
||||
{64,"Tunnel-Type3"},
|
||||
{65,"Tunnel-Medium-Type1"},
|
||||
{66,"Tunnel-Client-Endpoint"},
|
||||
{67,"Tunnel-Server-Endpoint1"},
|
||||
{68,"Acct-Tunnel-Connection-ID"},
|
||||
{69,"Tunnel-Password1"},
|
||||
{70,"ARAP-Password"},
|
||||
{71,"ARAP-Features"},
|
||||
{72,"ARAP-Zone-Access"},
|
||||
{73,"ARAP-Security"},
|
||||
{74,"ARAP-Security-Data"},
|
||||
{75,"Password-Retry"},
|
||||
{76,"Prompt"},
|
||||
{77,"Connect-Info"},
|
||||
{78,"Configuration-Token"},
|
||||
{79,"EAP-Message"},
|
||||
{80,"Message-Authenticator"},
|
||||
{81,"Tunnel-Private-Group-ID"},
|
||||
{82,"Tunnel-Assignment-ID1"},
|
||||
{83,"Tunnel-Preference"},
|
||||
{84,"ARAP-Challenge-Response"},
|
||||
{85,"Acct-Interim-Interval"},
|
||||
{86,"Acct-Tunnel-Packets-Lost"},
|
||||
{87,"NAS-Port-ID"},
|
||||
{88,"Framed-Pool"},
|
||||
{90,"Tunnel-Client-Auth-ID"},
|
||||
{91,"Tunnel-Server-Auth-ID"},
|
||||
{0, nullptr}
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct RadiusAttribute {
|
||||
unsigned char type{0};
|
||||
@@ -20,12 +267,68 @@ namespace OpenWifi::RADIUS {
|
||||
struct RawRadiusPacket {
|
||||
unsigned char code{1};
|
||||
unsigned char identifier{0};
|
||||
uint16_t len{0};
|
||||
uint16_t rawlen{0};
|
||||
unsigned char authenticator[16]{0};
|
||||
unsigned char attributes[4096]{0};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr unsigned char Access_Request = 1;
|
||||
constexpr unsigned char Access_Accept = 2;
|
||||
constexpr unsigned char Access_Reject = 3;
|
||||
constexpr unsigned char Access_Challenge = 11;
|
||||
|
||||
constexpr unsigned char Accounting_Request = 4;
|
||||
constexpr unsigned char Accounting_Response = 5;
|
||||
constexpr unsigned char Accounting_Status = 6;
|
||||
constexpr unsigned char Accounting_Message = 10;
|
||||
|
||||
constexpr unsigned char Disconnect_Request = 40;
|
||||
constexpr unsigned char Disconnect_ACK = 41;
|
||||
constexpr unsigned char Disconnect_NAK = 42;
|
||||
constexpr unsigned char CoA_Request = 43;
|
||||
constexpr unsigned char CoA_ACK = 44;
|
||||
constexpr unsigned char CoA_NAK = 45;
|
||||
|
||||
inline bool IsAuthentication(unsigned char t) {
|
||||
return (t == RADIUS::Access_Request ||
|
||||
t == RADIUS::Access_Accept ||
|
||||
t == RADIUS::Access_Challenge ||
|
||||
t == RADIUS::Access_Reject);
|
||||
}
|
||||
|
||||
inline bool IsAccounting(unsigned char t) {
|
||||
return (t == RADIUS::Accounting_Request ||
|
||||
t == RADIUS::Accounting_Response ||
|
||||
t == RADIUS::Accounting_Status ||
|
||||
t == RADIUS::Accounting_Message);
|
||||
}
|
||||
|
||||
inline bool IsAuthority(unsigned char t) {
|
||||
return (t == RADIUS::Disconnect_Request ||
|
||||
t == RADIUS::Disconnect_ACK ||
|
||||
t == RADIUS::Disconnect_NAK ||
|
||||
t == RADIUS::CoA_Request ||
|
||||
t == RADIUS::CoA_ACK ||
|
||||
t == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
inline const char * CommandName(uint cmd) {
|
||||
auto cmds = radius_command_values;
|
||||
while(cmds->cmd && (cmds->cmd!=cmd))
|
||||
cmds++;
|
||||
if(cmds->cmd==cmd) return cmds->name;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char * AttributeName(uint cmd) {
|
||||
auto cmds = radius_attribute_names;
|
||||
while(cmds->cmd && (cmds->cmd!=cmd))
|
||||
cmds++;
|
||||
if(cmds->cmd==cmd) return cmds->name;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
//
|
||||
// From: https://github.com/Telecominfraproject/wlan-dictionary/blob/main/dictionary.tip
|
||||
//
|
||||
@@ -34,23 +337,21 @@ namespace OpenWifi::RADIUS {
|
||||
static const unsigned char TIP_AAAipaddr = 2;
|
||||
static const unsigned char TIP_AAAipv6addr = 3;
|
||||
|
||||
|
||||
using AttributeList = std::list<RadiusAttribute>;
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, AttributeList const &P) {
|
||||
inline std::ostream &operator<<(std::ostream &os, AttributeList const &P) {
|
||||
for(const auto &attr:P) {
|
||||
os << "\tAttr: " << (uint16_t) attr.type << " Size: " << (uint16_t) attr.len << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
bool ParseRadius(uint32_t offset, const unsigned char *Buffer, uint16_t Size, AttributeList &Attrs) {
|
||||
inline bool ParseRadius(uint32_t offset, const unsigned char *Buffer, uint16_t Size, AttributeList &Attrs) {
|
||||
Attrs.clear();
|
||||
uint16_t pos=0;
|
||||
auto x=25;
|
||||
while(pos<Size && x) {
|
||||
RadiusAttribute Attr{ .type=Buffer[pos], .pos=(uint16_t )(pos+2+offset), .len=Buffer[pos+1]};
|
||||
// std::cout << "POS: " << pos << " P:" << (uint32_t) Attr.pos << " T:" << (uint32_t) Attr.type << " L:" << (uint32_t) Attr.len << " S:" << (uint32_t) Size << std::endl;
|
||||
RadiusAttribute Attr{ .type=Buffer[pos], .pos=(uint16_t)(pos+2+offset), .len=(unsigned int)(Buffer[pos+1]-2)};
|
||||
if(pos+Attr.len<=Size) {
|
||||
Attrs.emplace_back(Attr);
|
||||
} else {
|
||||
@@ -64,25 +365,55 @@ namespace OpenWifi::RADIUS {
|
||||
pos+=Buffer[pos+1];
|
||||
x--;
|
||||
}
|
||||
// std::cout << "Good parse" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
class RadiusPacket {
|
||||
public:
|
||||
explicit RadiusPacket(const Poco::Buffer<char> & Buf) {
|
||||
if(Buf.size() >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,Buf.begin(), Buf.size());
|
||||
Size_=Buf.size();
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const unsigned char *buffer, uint16_t size) {
|
||||
if(size >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,buffer, size);
|
||||
Size_=size;
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const std::string &p) {
|
||||
if(p.size() >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,(const unsigned char*) p.c_str(), p.size());
|
||||
Size_=p.size();
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
RadiusPacket() = default;
|
||||
explicit RadiusPacket(const RadiusPacket &P) {
|
||||
Valid_ = P.Valid_;
|
||||
Size_ = P.Size_;
|
||||
P_ = P.P_;
|
||||
Attrs_ = P.Attrs_;
|
||||
}
|
||||
|
||||
explicit RadiusPacket() = default;
|
||||
|
||||
unsigned char * Buffer() { return (unsigned char *)&P_; }
|
||||
[[nodiscard]] uint16_t BufferLen() const { return sizeof(P_);}
|
||||
@@ -92,11 +423,39 @@ namespace OpenWifi::RADIUS {
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.len); }
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.rawlen); }
|
||||
[[nodiscard]] uint16_t Size() const { return Size_; }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
|
||||
|
||||
inline bool IsAuthentication() {
|
||||
return (P_.code == RADIUS::Access_Request ||
|
||||
P_.code == RADIUS::Access_Accept ||
|
||||
P_.code == RADIUS::Access_Challenge ||
|
||||
P_.code == RADIUS::Access_Reject ||
|
||||
P_.code == RADCMD_RES_FREE_REQ ||
|
||||
P_.code == RADCMD_RES_FREE_RES ||
|
||||
P_.code == RADCMD_RES_QUERY_REQ ||
|
||||
P_.code == RADCMD_RES_QUERY_RES ||
|
||||
P_.code == RADCMD_RES_ALT_RECLAIM_REQ);
|
||||
}
|
||||
|
||||
inline bool IsAccounting() {
|
||||
return (P_.code == RADIUS::Accounting_Request ||
|
||||
P_.code == RADIUS::Accounting_Response ||
|
||||
P_.code == RADIUS::Accounting_Status ||
|
||||
P_.code == RADIUS::Accounting_Message);
|
||||
}
|
||||
|
||||
inline bool IsAuthority() {
|
||||
return (P_.code == RADIUS::Disconnect_Request ||
|
||||
P_.code == RADIUS::Disconnect_ACK ||
|
||||
P_.code == RADIUS::Disconnect_NAK ||
|
||||
P_.code == RADIUS::CoA_Request ||
|
||||
P_.code == RADIUS::CoA_ACK ||
|
||||
P_.code == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
void Log(std::ostream &os) {
|
||||
uint16_t p = 0;
|
||||
|
||||
@@ -110,9 +469,102 @@ namespace OpenWifi::RADIUS {
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec << std::endl;
|
||||
os << std::dec << std::endl << std::endl;
|
||||
Print(os);
|
||||
}
|
||||
|
||||
inline const char * PacketType() {
|
||||
return CommandName(P_.code);
|
||||
}
|
||||
|
||||
inline int PacketTypeInt() {
|
||||
return (int)(P_.code);
|
||||
}
|
||||
|
||||
void ComputeMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
|
||||
if(P_.code==1) {
|
||||
unsigned char OldAuthenticator[16]{0};
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
|
||||
memset(&P.attributes[attr.pos], 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char NewAuthenticator[16]{0};
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(secret);
|
||||
H.update((const unsigned char *)&P, Size_);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
NewAuthenticator[p++] = i;
|
||||
|
||||
if (memcmp(OldAuthenticator, NewAuthenticator, 16) == 0) {
|
||||
std::cout << "Authenticator match..." << std::endl;
|
||||
} else {
|
||||
std::cout << "Authenticator MIS-match..." << std::endl;
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(&P_.attributes[attr.pos], NewAuthenticator, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VerifyMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
if(P_.code==1) {
|
||||
unsigned char OldAuthenticator[16]{0};
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
|
||||
memset(&P.attributes[attr.pos], 0, 16);
|
||||
}
|
||||
}
|
||||
unsigned char NewAuthenticator[16]{0};
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(secret);
|
||||
H.update((const unsigned char *)&P, Size_);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
NewAuthenticator[p++] = i;
|
||||
return memcmp(OldAuthenticator, NewAuthenticator, 16) == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void BufLog(std::ostream & os, const char * pre, const unsigned char *b, uint s) {
|
||||
uint16_t p = 0;
|
||||
while(p<s) {
|
||||
os << pre << std::setfill('0') << std::setw(4) << p << ": ";
|
||||
uint16_t v=0;
|
||||
while(v<16 && p+v<s) {
|
||||
os << std::setfill('0') << std::setw(2) << std::right << std::hex << (uint16_t )b[p+v] << " ";
|
||||
v++;
|
||||
}
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec ;
|
||||
}
|
||||
|
||||
inline void Print(std::ostream &os) {
|
||||
os << "Packet type: (" << (uint) P_.code << ") " << CommandName(P_.code) << std::endl;
|
||||
os << " Identifier: " << (uint) P_.identifier << std::endl;
|
||||
os << " Length: " << Size_ << std::endl;
|
||||
os << " Authenticator: " ;
|
||||
BufLog(os, "", P_.authenticator, sizeof(P_.authenticator));
|
||||
os << " Attributes: " << std::endl;
|
||||
for(const auto &attr:Attrs_) {
|
||||
os << " " << std::setfill(' ') << "(" << std::setw(4) << (uint) attr.type << ") " << AttributeName(attr.type) << " Len:" << attr.len << std::endl;
|
||||
BufLog(os, " " , &P_.attributes[attr.pos], attr.len);
|
||||
}
|
||||
os << std::dec << std::endl << std::endl;
|
||||
}
|
||||
|
||||
std::string ExtractSerialNumberTIP() {
|
||||
std::string R;
|
||||
|
||||
@@ -121,7 +573,7 @@ namespace OpenWifi::RADIUS {
|
||||
AttributeList VendorAttributes;
|
||||
uint32_t VendorId = htonl( *(const uint32_t *)&(P_.attributes[attribute.pos]));
|
||||
// std::cout << VendorId << std::endl;
|
||||
if(VendorId==TIP_vendor_id) {
|
||||
if(VendorId==TIP_vendor_id && attribute.len>(4+2)) {
|
||||
if (ParseRadius(attribute.pos + 4, &P_.attributes[attribute.pos + 4], attribute.len - 4 - 2,
|
||||
VendorAttributes)) {
|
||||
// std::cout << VendorAttributes << std::endl;
|
||||
@@ -139,7 +591,6 @@ namespace OpenWifi::RADIUS {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
@@ -197,6 +648,16 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string UserName() const {
|
||||
for(const auto &attr:Attrs_) {
|
||||
if(attr.type==1) {
|
||||
std::string user_name{(const char *)&P_.attributes[attr.pos],attr.len};
|
||||
return user_name;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
RawRadiusPacket P_;
|
||||
uint16_t Size_{0};
|
||||
@@ -204,7 +665,7 @@ namespace OpenWifi::RADIUS {
|
||||
bool Valid_=false;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
inline std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
os << P.Attrs_ ;
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -15,13 +15,14 @@ namespace OpenWifi {
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
ConfigFilename_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
|
||||
Poco::File Config(ConfigFilename_);
|
||||
|
||||
enabled_ = MicroService::instance().ConfigGetBool("radius.proxy.enable",false);
|
||||
if(!enabled_)
|
||||
if(!enabled_ && !Config.exists())
|
||||
return 0;
|
||||
|
||||
ConfigFilename_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
|
||||
|
||||
|
||||
enabled_ = true;
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
@@ -44,74 +45,88 @@ namespace OpenWifi {
|
||||
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>(
|
||||
RadiusReactor_.addEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
AccountingReactor_.addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
|
||||
CoAReactor_.addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
CoAReactor_.addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
ParseConfig();
|
||||
|
||||
AuthenticationReactorThread_.start(AuthenticationReactor_);
|
||||
AccountingReactorThread_.start(AccountingReactor_);
|
||||
CoAReactorThread_.start(CoAReactor_);
|
||||
// start RADSEC servers...
|
||||
StartRADSECServers();
|
||||
RadiusReactorThread_.start(RadiusReactor_);
|
||||
|
||||
Utils::SetThreadName(AuthenticationReactorThread_,"radproxy-auth");
|
||||
Utils::SetThreadName(AccountingReactorThread_,"radproxy-acct");
|
||||
Utils::SetThreadName(CoAReactorThread_,"radproxy-coa");
|
||||
Utils::SetThreadName(RadiusReactorThread_,"rad:reactor");
|
||||
|
||||
running_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::Stop() {
|
||||
if(enabled_) {
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(enabled_ && running_) {
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
AccountingReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
CoAReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
CoAReactor_.removeEventHandler(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
AuthenticationReactor_.stop();
|
||||
AuthenticationReactorThread_.join();
|
||||
for(auto &[_,radsec_server]:RADSECservers_)
|
||||
radsec_server->Stop();
|
||||
|
||||
AccountingReactor_.stop();
|
||||
AccountingReactorThread_.join();
|
||||
|
||||
CoAReactor_.stop();
|
||||
CoAReactorThread_.join();
|
||||
RadiusReactor_.stop();
|
||||
RadiusReactorThread_.join();
|
||||
enabled_=false;
|
||||
running_=false;
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StartRADSECServers() {
|
||||
for(const auto &pool:PoolList_.pools) {
|
||||
for(const auto &entry:pool.authConfig.servers) {
|
||||
if(entry.radsec) {
|
||||
StartRADSECServer(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E) {
|
||||
RADSECservers_[ Poco::Net::SocketAddress(E.ip,0) ] = std::make_unique<RADSECserver>(RadiusReactor_,E);
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
@@ -120,19 +135,19 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("Accounting: bad packet received.");
|
||||
poco_warning(Logger(),"Accounting: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("Accounting: missing serial number.");
|
||||
poco_warning(Logger(),"Accounting: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
poco_information(Logger(), fmt::format("Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAccountingData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
@@ -142,19 +157,19 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("Authentication: bad packet received.");
|
||||
poco_warning(Logger(),"Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("Authentication: missing serial number.");
|
||||
poco_warning(Logger(),"Authentication: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
poco_information(Logger(), fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAuthenticationData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
@@ -164,19 +179,19 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("CoA/DM: bad packet received.");
|
||||
poco_warning(Logger(),"CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("CoA/DM: missing serial number.");
|
||||
poco_warning(Logger(),"CoA/DM: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
poco_information(Logger(), fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusCoAData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
@@ -188,12 +203,27 @@ namespace OpenWifi {
|
||||
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 UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
|
||||
: *AccountingSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),fmt::format("{}: Could not send Accounting packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_information(Logger(), 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) {
|
||||
@@ -208,19 +238,32 @@ namespace OpenWifi {
|
||||
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));
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AuthenticationSocketV4_
|
||||
: *AuthenticationSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),fmt::format("{}: Could not send Authentication packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_information(Logger(), 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";
|
||||
@@ -228,12 +271,25 @@ namespace OpenWifi {
|
||||
|
||||
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()));
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
auto AllSent = SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_
|
||||
: *CoASocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),fmt::format("{}: Could not send CoA packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_information(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
|
||||
FinalDestination.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault) {
|
||||
@@ -242,7 +298,7 @@ namespace OpenWifi {
|
||||
for(const auto &server:Config.servers) {
|
||||
Poco::Net::IPAddress a;
|
||||
if(!Poco::Net::IPAddress::tryParse(server.ip,a)) {
|
||||
Logger().error(fmt::format("RADIUS-PARSE Config: server address {} is nto a valid address in v4 or v6. Entry skipped.",server.ip));
|
||||
poco_error(Logger(),fmt::format("RADIUS-PARSE Config: server address {} is nto a valid address in v4 or v6. Entry skipped.",server.ip));
|
||||
continue;
|
||||
}
|
||||
auto S = Poco::Net::SocketAddress(fmt::format("{}:{}",server.ip,server.port));
|
||||
@@ -256,9 +312,14 @@ namespace OpenWifi {
|
||||
.monitor = Config. monitor,
|
||||
.monitorMethod = Config.monitorMethod,
|
||||
.methodParameters = Config.methodParameters,
|
||||
.useAsDefault = setAsDefault
|
||||
.useAsDefault = setAsDefault,
|
||||
.useRADSEC = server.radsec,
|
||||
.realms = server.radsecRealms
|
||||
};
|
||||
|
||||
if(setAsDefault && D.useRADSEC)
|
||||
defaultIsRADSEC_ = true;
|
||||
|
||||
if(S.family()==Poco::Net::IPAddress::IPv4) {
|
||||
TotalV4 += server.weight;
|
||||
V4.push_back(D);
|
||||
@@ -308,82 +369,119 @@ namespace OpenWifi {
|
||||
Pools_.push_back(NewPool);
|
||||
}
|
||||
} else {
|
||||
Logger().warning(fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
poco_warning(Logger(),fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
}
|
||||
} else {
|
||||
Logger().warning(fmt::format("No configuration file '{}' exists.",ConfigFilename_));
|
||||
poco_warning(Logger(),fmt::format("No configuration file '{}' exists.",ConfigFilename_));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
Logger().error(fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
|
||||
poco_error(Logger(),fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
static bool RealmMatch(const std::string &user_realm, const std::string & realm) {
|
||||
if(realm.find_first_of('*') == std::string::npos)
|
||||
return user_realm == realm;
|
||||
return realm.find(user_realm) != std::string::npos;
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::DefaultRoute(radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
|
||||
// find the realm...
|
||||
auto UserName = P.UserName();
|
||||
if(!UserName.empty()) {
|
||||
auto UserTokens = Poco::StringTokenizer(UserName, "@");
|
||||
auto UserRealm = ((UserTokens.count() > 1) ? UserTokens[1] : UserName);
|
||||
Poco::toLowerInPlace(UserRealm);
|
||||
|
||||
for(const auto &pool:Pools_) {
|
||||
for(const auto &server:pool.AuthV4) {
|
||||
if(!server.realms.empty()) {
|
||||
for(const auto &realm:server.realms) {
|
||||
if (RealmMatch(UserRealm,realm)) {
|
||||
std::cout << "Realm match..." << std::endl;
|
||||
UseRADSEC = true;
|
||||
return server.Addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(defaultIsRADSEC_) {
|
||||
UseRADSEC = true;
|
||||
return (IsV4 ? Pools_[defaultPoolIndex_].AuthV4[0].Addr : Pools_[defaultPoolIndex_].AuthV6[0].Addr );
|
||||
}
|
||||
|
||||
switch(rtype) {
|
||||
case radius_type::coa: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].CoaV4
|
||||
: Pools_[defaultPoolIndex_].CoaV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::auth: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AuthV4
|
||||
: Pools_[defaultPoolIndex_].AuthV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::acct:
|
||||
default: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AcctV4
|
||||
: Pools_[defaultPoolIndex_].AcctV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
}
|
||||
case radius_type::auth: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AuthV4
|
||||
: Pools_[defaultPoolIndex_].AuthV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::acct:
|
||||
default: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AcctV4
|
||||
: Pools_[defaultPoolIndex_].AcctV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::coa: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].CoaV4
|
||||
: Pools_[defaultPoolIndex_].CoaV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if(Pools_.empty()) {
|
||||
UseRADSEC = false;
|
||||
return RequestedAddress;
|
||||
}
|
||||
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
bool useDefault = false;
|
||||
bool useDefault;
|
||||
useDefault = IsV4 ? RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4) : RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6) ;
|
||||
|
||||
if(useDefault) {
|
||||
return DefaultRoute(rtype, RequestedAddress);
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
|
||||
}
|
||||
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D) -> bool {
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D, bool &UseRADSEC) -> bool {
|
||||
for(const auto &entry:D)
|
||||
if(entry.Addr.host()==RequestedAddress.host())
|
||||
if(entry.Addr.host()==RequestedAddress.host()) {
|
||||
UseRADSEC = entry.useRADSEC;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for(auto &i:Pools_) {
|
||||
switch(rtype) {
|
||||
case radius_type::coa: {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::auth: {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::acct: {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return DefaultRoute(rtype, RequestedAddress);
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress) {
|
||||
@@ -459,6 +557,10 @@ namespace OpenWifi {
|
||||
Disk.stringify(ofs);
|
||||
ofs.close();
|
||||
|
||||
if(!running_) {
|
||||
Start();
|
||||
}
|
||||
|
||||
ParseConfig();
|
||||
}
|
||||
|
||||
@@ -479,6 +581,7 @@ namespace OpenWifi {
|
||||
|
||||
}
|
||||
ResetConfig();
|
||||
Stop();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::GetConfig(GWObjects::RadiusProxyPoolList &C) {
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Net/DatagramSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "RADSECserver.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -15,6 +18,7 @@ namespace OpenWifi {
|
||||
auth, acct, coa
|
||||
};
|
||||
|
||||
|
||||
class RADIUS_proxy_server : public SubSystemServer {
|
||||
public:
|
||||
inline static auto instance() {
|
||||
@@ -38,6 +42,9 @@ namespace OpenWifi {
|
||||
void DeleteConfig();
|
||||
void GetConfig(GWObjects::RadiusProxyPoolList &C);
|
||||
|
||||
void StartRADSECServers();
|
||||
void StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E);
|
||||
|
||||
struct Destination {
|
||||
Poco::Net::SocketAddress Addr;
|
||||
uint64_t state = 0;
|
||||
@@ -49,6 +56,8 @@ namespace OpenWifi {
|
||||
std::string monitorMethod;
|
||||
std::vector<std::string> methodParameters;
|
||||
bool useAsDefault=false;
|
||||
bool useRADSEC=false;
|
||||
std::vector<std::string> realms;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -58,16 +67,14 @@ namespace OpenWifi {
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
|
||||
Poco::Net::SocketReactor AccountingReactor_;
|
||||
Poco::Net::SocketReactor AuthenticationReactor_;
|
||||
Poco::Net::SocketReactor CoAReactor_;
|
||||
Poco::Thread AuthenticationReactorThread_;
|
||||
Poco::Thread AccountingReactorThread_;
|
||||
Poco::Thread CoAReactorThread_;
|
||||
Poco::Net::SocketReactor RadiusReactor_;
|
||||
Poco::Thread RadiusReactorThread_;
|
||||
|
||||
GWObjects::RadiusProxyPoolList PoolList_;
|
||||
std::string ConfigFilename_;
|
||||
|
||||
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSECserver>> RADSECservers_;
|
||||
|
||||
struct RadiusPool {
|
||||
std::vector<Destination> AuthV4;
|
||||
std::vector<Destination> AuthV6;
|
||||
@@ -80,6 +87,8 @@ namespace OpenWifi {
|
||||
std::vector<RadiusPool> Pools_;
|
||||
uint defaultPoolIndex_=0;
|
||||
bool enabled_=false;
|
||||
bool defaultIsRADSEC_=false;
|
||||
std::atomic_bool running_=false;
|
||||
|
||||
RADIUS_proxy_server() noexcept:
|
||||
SubSystemServer("RADIUS-PROXY", "RADIUS-PROXY", "radius.proxy")
|
||||
@@ -90,10 +99,10 @@ namespace OpenWifi {
|
||||
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A);
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
void ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault);
|
||||
static Poco::Net::SocketAddress ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
};
|
||||
|
||||
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
|
||||
|
||||
251
src/RADSECserver.h
Normal file
251
src/RADSECserver.h
Normal file
@@ -0,0 +1,251 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-08-15.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
|
||||
#include "RADIUS_helpers.h"
|
||||
#include "DeviceRegistry.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RADSECserver : public Poco::Runnable {
|
||||
public:
|
||||
RADSECserver(Poco::Net::SocketReactor & R, GWObjects::RadiusProxyServerEntry E) :
|
||||
Reactor_(R),
|
||||
Server_(std::move(E)),
|
||||
Logger_(Poco::Logger::get(fmt::format("RADSEC: {}@{}:{}",
|
||||
Server_.name ,
|
||||
Server_.ip,
|
||||
Server_.port)))
|
||||
{
|
||||
ReconnectorThr_.start(*this);
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
while(TryAgain_) {
|
||||
if(!Connected_) {
|
||||
std::unique_lock G(Mutex_);
|
||||
Connect();
|
||||
}
|
||||
Poco::Thread::trySleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SendData(const std::string &serial_number, const unsigned char *buffer, int length) {
|
||||
try {
|
||||
if (Connected_) {
|
||||
RADIUS::RadiusPacket P(buffer, length);
|
||||
// std::cout << serial_number << " Sending " << P.PacketType() << " " << length << " bytes" << std::endl;
|
||||
int sent_bytes;
|
||||
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
|
||||
Logger_.debug(fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
sent_bytes = Socket_->sendBytes(buffer, length);
|
||||
} else {
|
||||
Logger_.debug(fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
P.ComputeMessageAuthenticator(Server_.radsecSecret);
|
||||
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
|
||||
}
|
||||
return (sent_bytes == length);
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
unsigned char Buffer[4096];
|
||||
|
||||
try {
|
||||
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer,sizeof(Buffer));
|
||||
if(NumberOfReceivedBytes>40) {
|
||||
RADIUS::RadiusPacket P(Buffer,NumberOfReceivedBytes);
|
||||
// P.Log(std::cout);
|
||||
// std::cout << "RADSEC: " << P.PacketType() << " " << (int) P.PacketTypeInt() << " Received " << NumberOfReceivedBytes << " bytes" << std::endl;
|
||||
if (P.IsAuthentication()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
Logger_.debug(fmt::format("{}: {} Received {} bytes.", SerialNumber, P.PacketType(), NumberOfReceivedBytes));
|
||||
DeviceRegistry()->SendRadiusAuthenticationData(
|
||||
SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else if (P.IsAccounting()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
Logger_.debug(fmt::format("{}: {} Received {} bytes.", SerialNumber, P.PacketType(), NumberOfReceivedBytes));
|
||||
DeviceRegistry()->SendRadiusAccountingData(
|
||||
SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else if (P.IsAuthority()) {
|
||||
}
|
||||
} else {
|
||||
Disconnect();
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
inline void onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
|
||||
std::cout << "onError" << std::endl;
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
std::cout << "onShutdown" << std::endl;
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline bool Connect() {
|
||||
if(TryAgain_) {
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroService::instance().DataDir());
|
||||
Poco::TemporaryFile KeyFile_(MicroService::instance().DataDir());
|
||||
std::vector<Poco::TemporaryFile> CaCertFiles_;
|
||||
|
||||
DecodeFile(CertFile_.path(), Server_.radsecCert);
|
||||
DecodeFile(KeyFile_.path(), Server_.radsecKey);
|
||||
|
||||
for(auto &cert:Server_.radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(Poco::TemporaryFile(MicroService::instance().DataDir()));
|
||||
DecodeFile(CaCertFiles_[CaCertFiles_.size()-1].path(), cert);
|
||||
}
|
||||
|
||||
Poco::Net::Context::Ptr SecureContext = Poco::AutoPtr<Poco::Net::Context>(
|
||||
new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE,
|
||||
KeyFile_.path(),
|
||||
CertFile_.path(),""));
|
||||
|
||||
for(const auto &ca:CaCertFiles_) {
|
||||
Poco::Crypto::X509Certificate cert(ca.path());
|
||||
SecureContext->addCertificateAuthority(cert);
|
||||
}
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
|
||||
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
|
||||
|
||||
try {
|
||||
poco_information(Logger_, "Attempting to connect");
|
||||
Socket_->connect(Destination, Poco::Timespan(100, 0));
|
||||
Socket_->completeHandshake();
|
||||
Socket_->verifyPeerCertificate();
|
||||
|
||||
if(Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADSECserver, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSECserver::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSECserver::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADSECserver, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSECserver::onShutdown));
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_,fmt::format("Connected. CN={}",CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Disconnect() {
|
||||
if(Connected_) {
|
||||
std::unique_lock G(Mutex_);
|
||||
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSECserver::onData));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSECserver::onError));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSECserver::onShutdown));
|
||||
Connected_ = false;
|
||||
}
|
||||
poco_information(Logger_,"Disconnecting.");
|
||||
}
|
||||
|
||||
inline void Stop() {
|
||||
TryAgain_ = false;
|
||||
Disconnect();
|
||||
ReconnectorThr_.wakeUp();
|
||||
ReconnectorThr_.join();
|
||||
}
|
||||
|
||||
static void DecodeFile(const std::string &filename, const std::string &s) {
|
||||
std::ofstream sec_file(filename,std::ios_base::out|std::ios_base::trunc|std::ios_base::binary);
|
||||
std::stringstream is(s);
|
||||
Poco::Base64Decoder ds(is);
|
||||
Poco::StreamCopier::copyStream(ds,sec_file);
|
||||
sec_file.close();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string CommonName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->commonName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string IssuerName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->issuerName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string SubjectName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->subjectName();
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_mutex Mutex_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
GWObjects::RadiusProxyServerEntry Server_;
|
||||
Poco::Logger &Logger_;
|
||||
std::atomic_bool Connected_=false;
|
||||
std::atomic_bool TryAgain_=true;
|
||||
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
|
||||
Poco::Thread ReconnectorThr_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
|
||||
};
|
||||
}
|
||||
@@ -31,7 +31,9 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
void WaitForCommand(GWObjects::CommandDetails &Cmd,
|
||||
void WaitForCommand(uint64_t RPCID,
|
||||
bool RetryLater,
|
||||
GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
@@ -40,15 +42,19 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger) {
|
||||
|
||||
Logger.information(fmt::format("{}: New {} command. User={} Serial={}. ", Cmd.UUID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
|
||||
Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID, RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
|
||||
|
||||
// if the command should be executed in the future, or if the device is not connected,
|
||||
// then we should just add the command to
|
||||
// the DB and let it figure out when to deliver the command.
|
||||
if (Cmd.RunAt || !DeviceRegistry()->Connected(Cmd.SerialNumber)) {
|
||||
Logger.information(fmt::format("{}: Command will be run in the future or when device is connected again.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
|
||||
if (Cmd.RunAt || (!DeviceRegistry()->Connected(SerialNumberInt) && RetryLater)) {
|
||||
Logger.information(fmt::format("{},{}: Command will be run in the future or when device is connected again.", Cmd.UUID, RPCID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
return;
|
||||
} else if ((!DeviceRegistry()->Connected(SerialNumberInt) && !RetryLater)){
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
|
||||
Cmd.Executed = OpenWifi::Now();
|
||||
@@ -56,25 +62,27 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
bool Sent;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> rpc_submitted = std::chrono::high_resolution_clock::now();
|
||||
std::shared_ptr<CommandManager::promise_type_t> rpc_endpoint =
|
||||
CommandManager()->PostCommand(Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
CommandManager()->PostCommand(RPCID, Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
|
||||
if(!Sent || rpc_endpoint== nullptr) {
|
||||
Logger.information(fmt::format("{}: Pending completion. Device is not connected.", Cmd.UUID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
if(RetryLater && (!Sent || rpc_endpoint== nullptr)) {
|
||||
Logger.information(fmt::format("{},{}: Pending completion. Device is not connected.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
}
|
||||
|
||||
Logger.information(fmt::format("{}: Command sent.", Cmd.UUID));
|
||||
|
||||
Poco::JSON::Object L;
|
||||
if(!RetryLater && !Sent) {
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
|
||||
Logger.information(fmt::format("{},{}: Command sent.", Cmd.UUID, RPCID));
|
||||
std::future<CommandManager::objtype_t> rpc_future(rpc_endpoint->get_future());
|
||||
auto rpc_result = rpc_future.wait_for(WaitTimeInMs);
|
||||
if (rpc_result == std::future_status::ready) {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - rpc_submitted;
|
||||
auto rpc_answer = rpc_future.get();
|
||||
if (!rpc_answer.has(uCentralProtocol::RESULT) || !rpc_answer.isObject(uCentralProtocol::RESULT)) {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response. Missing result.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response. Missing result.", Cmd.UUID, RPCID));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,11 +90,11 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if (!ResultFields->has(uCentralProtocol::STATUS) || !ResultFields->isObject(uCentralProtocol::STATUS)) {
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
if(Cmd.Command=="ping") {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_COMPLETED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response from device (ping: fix override). Missing status.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_COMPLETED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response from device (ping: fix override). Missing status.", Cmd.UUID, RPCID));
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response from device. Missing status.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response from device. Missing status.", Cmd.UUID,RPCID));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +134,7 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
}
|
||||
|
||||
// Add the completed command to the database...
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::COMMAND_COMPLETED);
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
|
||||
if (ObjectToReturn && Handler) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
@@ -136,10 +144,16 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if(Handler)
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
Logger.information( fmt::format("{}: Completed in {:.3f}ms.", Cmd.UUID, Cmd.executionTime));
|
||||
Logger.information( fmt::format("{},{}: Completed in {:.3f}ms.", Cmd.UUID, RPCID, Cmd.executionTime));
|
||||
return;
|
||||
}
|
||||
Logger.information(fmt::format( "{}: Pending completion.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
CommandManager()->RemovePendingCommand(RPCID);
|
||||
if(RetryLater) {
|
||||
Logger.information(fmt::format("{},{}: Pending completion.", Cmd.UUID, RPCID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
} else {
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,14 +20,17 @@
|
||||
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
|
||||
void WaitForCommand( GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger);
|
||||
void WaitForCommand(
|
||||
uint64_t RPCID,
|
||||
bool RetryLater,
|
||||
GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger);
|
||||
|
||||
void SetCommandStatus( GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_blacklist::DoDelete() {
|
||||
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_blacklist::DoGet() {
|
||||
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -51,13 +51,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RESTAPI_blacklist::DoPost() {
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!D.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(D.serialNumber.empty()) {
|
||||
if(D.serialNumber.empty() || !Utils::NormalizeMac(D.serialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_blacklist::DoPut() {
|
||||
auto SerialNumber = Poco::toLower(GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""));
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_commands::DoGet() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (QB_.Newest) {
|
||||
StorageService()->GetNewestCommands(SerialNumber, QB_.Limit, Commands);
|
||||
@@ -33,10 +37,10 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_commands::DoDelete() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
if (StorageService()->DeleteCommands(SerialNumber, QB_.StartDate, QB_.EndDate)) {
|
||||
return OK();
|
||||
}
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "framework/orm.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_default_configuration::DoGet() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (StorageService()->GetDefaultConfiguration(Name, DefConfig)) {
|
||||
Poco::JSON::Object Obj;
|
||||
@@ -28,7 +29,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RESTAPI_default_configuration::DoDelete() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
|
||||
if(Name.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_device_commandHandler : public RESTAPIHandler {
|
||||
@@ -30,22 +31,22 @@ namespace OpenWifi {
|
||||
void GetStatistics();
|
||||
void DeleteStatistics();
|
||||
void GetStatus();
|
||||
void ExecuteCommand();
|
||||
void Configure();
|
||||
void GetChecks();
|
||||
void DeleteChecks();
|
||||
void Upgrade();
|
||||
void Reboot();
|
||||
void Factory();
|
||||
void LEDs();
|
||||
void Trace();
|
||||
void MakeRequest();
|
||||
void WifiScan();
|
||||
void EventQueue();
|
||||
void Rtty();
|
||||
void Telemetry();
|
||||
void Ping();
|
||||
void Script();
|
||||
void ExecuteCommand(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Configure(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Upgrade(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Reboot(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Factory(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void LEDs(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Trace(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void MakeRequest(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void WifiScan(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void EventQueue(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Rtty(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Telemetry(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Ping(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"}; };
|
||||
void DoGet() final;
|
||||
@@ -53,6 +54,9 @@ namespace OpenWifi {
|
||||
void DoPost() final;
|
||||
void DoPut() final {};
|
||||
|
||||
void CallCanceled(const char * Cmd,const std::string &UUID, uint64_t RPC, const OpenWifi::RESTAPI::Errors::msg & Err);
|
||||
void CallCanceled(const char * Cmd, const OpenWifi::RESTAPI::Errors::msg &Err, const std::string & Details="");
|
||||
|
||||
inline bool ValidateParameters() {
|
||||
Command_ = GetBinding(RESTAPI::Protocol::COMMAND, "");
|
||||
if (Command_.empty()) {
|
||||
@@ -66,6 +70,8 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string SerialNumber_, Command_;
|
||||
std::string SerialNumber_,
|
||||
Command_;
|
||||
std::uint64_t SerialNumberInt_=0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoGet() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoDelete() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoPost() {
|
||||
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -116,6 +116,10 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(!Utils::NormalizeMac(Device.SerialNumber)) {
|
||||
return BadRequest( RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
if(SerialNumber!=Device.SerialNumber) {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
}
|
||||
@@ -149,7 +153,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoPut() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::ValidSerialNumber(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTAPI/RESTAPI_device_helper.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "framework/orm.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
bool PrepareOrderBy(const std::string &OrderByList, std::string &OrderByString) {
|
||||
bool PrepareOrderBy(const std::string &OrderByListRaw, std::string &OrderByString) {
|
||||
auto OrderByList = ORM::Escape(OrderByListRaw);
|
||||
auto items = Poco::StringTokenizer(OrderByList,",");
|
||||
std::string ItemList;
|
||||
|
||||
@@ -55,6 +57,15 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_devices_handler::DoGet() {
|
||||
|
||||
if(GetBoolParameter("connectionStatistics")) {
|
||||
GWObjects::DeviceConnectionStatistics DCS;
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
DeviceRegistry()->AverageDeviceStatistics(DCS.connectedDevices,DCS.averageConnectionTime, DCS.connectingDevices);
|
||||
DCS.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
if(GetBoolParameter("orderSpec")) {
|
||||
Types::StringVec Fields;
|
||||
StorageService()->GetDeviceDbFieldList(Fields);
|
||||
@@ -80,6 +91,8 @@ namespace OpenWifi {
|
||||
Poco::JSON::Array Objects;
|
||||
for (auto &i : SelectedRecords()) {
|
||||
auto SerialNumber = i;
|
||||
if(!Utils::ValidSerialNumber(i))
|
||||
continue;
|
||||
GWObjects::Device D;
|
||||
if (StorageService()->GetDevice(SerialNumber, D)) {
|
||||
if(completeInfo) {
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
GWObjects::RadiusProxyPoolList C;
|
||||
if(!C.from_json(ParsedBody_)) {
|
||||
if(!C.from_json(ParsedBody_) || C.pools.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace OpenWifi {
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
|
||||
|
||||
Poco::Thread::current()->setName("ExtWebServerThread_" + std::to_string(TransactionId));
|
||||
return RESTAPI_Router<
|
||||
RESTAPI_devices_handler,
|
||||
RESTAPI_device_handler,
|
||||
@@ -50,7 +49,6 @@ namespace OpenWifi {
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
|
||||
|
||||
Poco::Thread::current()->setName("IntWebServerThread_" + std::to_string(TransactionId));
|
||||
return RESTAPI_Router_I<
|
||||
RESTAPI_devices_handler,
|
||||
RESTAPI_device_handler,
|
||||
|
||||
@@ -11,7 +11,6 @@ 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 {
|
||||
@@ -26,6 +25,10 @@ void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
}
|
||||
}
|
||||
|
||||
if(!Utils::NormalizeMac(SNum)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
auto SerialNumber = Utils::SerialNumberToInt(SNum);
|
||||
|
||||
if(!TelemetryStream()->IsValidEndPoint(SerialNumber,UUID)) {
|
||||
|
||||
@@ -203,6 +203,10 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"kafkaClients", kafkaClients);
|
||||
field_to_json(Obj,"kafkaPackets", kafkaPackets);
|
||||
field_to_json(Obj,"locale", locale);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"sessionId", sessionId);
|
||||
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
|
||||
field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started);
|
||||
|
||||
switch(VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
@@ -218,6 +222,23 @@ namespace OpenWifi::GWObjects {
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_to_json(Obj,"connectedDevices", connectedDevices );
|
||||
field_to_json(Obj,"connectingDevices", connectingDevices );
|
||||
}
|
||||
|
||||
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_from_json(Obj,"connectedDevices", connectedDevices );
|
||||
field_from_json(Obj,"connectingDevices", connectingDevices );
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"server", Server);
|
||||
@@ -293,7 +314,6 @@ namespace OpenWifi::GWObjects {
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
|
||||
@@ -361,11 +381,13 @@ namespace OpenWifi::GWObjects {
|
||||
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);
|
||||
field_to_json(Obj,"radsecPort",radsecPort);
|
||||
field_to_json(Obj,"radsecSecret",radsecSecret);
|
||||
field_to_json(Obj,"radsecCacerts",radsecCacerts);
|
||||
field_to_json(Obj,"radsecCert",radsecCert);
|
||||
field_to_json(Obj,"radsecKey",radsecKey);
|
||||
field_to_json(Obj,"radsecRealms",radsecRealms);
|
||||
field_to_json(Obj,"ignore",ignore);
|
||||
}
|
||||
|
||||
bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -377,11 +399,13 @@ namespace OpenWifi::GWObjects {
|
||||
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);
|
||||
field_from_json(Obj,"radsecSecret",radsecSecret);
|
||||
field_from_json(Obj,"radsecPort",radsecPort);
|
||||
field_from_json(Obj,"radsecCacerts",radsecCacerts);
|
||||
field_from_json(Obj,"radsecCert",radsecCert);
|
||||
field_from_json(Obj,"radsecKey",radsecKey);
|
||||
field_from_json(Obj,"radsecRealms",radsecRealms);
|
||||
field_from_json(Obj,"ignore",ignore);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ namespace OpenWifi::GWObjects {
|
||||
uint64_t kafkaPackets=0;
|
||||
uint64_t websocketPackets=0;
|
||||
std::string locale;
|
||||
uint64_t started=0;
|
||||
uint64_t sessionId=0;
|
||||
double connectionCompletionTime=0.0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
@@ -71,6 +75,15 @@ namespace OpenWifi::GWObjects {
|
||||
void Print() const;
|
||||
};
|
||||
|
||||
struct DeviceConnectionStatistics {
|
||||
std::uint64_t connectedDevices = 0;
|
||||
std::uint64_t averageConnectionTime = 0;
|
||||
std::uint64_t connectingDevices = 0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID = 0 ;
|
||||
@@ -219,11 +232,13 @@ namespace OpenWifi::GWObjects {
|
||||
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;
|
||||
uint16_t radsecPort=2083;
|
||||
std::string radsecSecret;
|
||||
std::string radsecKey;
|
||||
std::string radsecCert;
|
||||
std::vector<std::string> radsecCacerts;
|
||||
std::vector<std::string> radsecRealms;
|
||||
bool ignore=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
|
||||
@@ -2,20 +2,24 @@
|
||||
// Created by stephane bourque on 2021-08-11.
|
||||
//
|
||||
|
||||
#include "SerialNumberCache.h"
|
||||
#include <mutex>
|
||||
|
||||
#include "SerialNumberCache.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int SerialNumberCache::Start() {
|
||||
poco_notice(Logger(),"Starting...");
|
||||
StorageService()->UpdateSerialNumberCache();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SerialNumberCache::Stop() {
|
||||
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
SNs_.clear();
|
||||
Reverse_SNs_.clear();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void SerialNumberCache::AddSerialNumber(const std::string &S) {
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "StorageArchiver.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -15,23 +16,23 @@ namespace OpenWifi {
|
||||
auto now = OpenWifi::Now();
|
||||
for(const auto &i:DBs_) {
|
||||
if (!Poco::icompare(i.DBName, "healthchecks")) {
|
||||
Logger().information("Archiving HealthChecks...");
|
||||
poco_information(Logger(),"Archiving HealthChecks...");
|
||||
StorageService()->RemoveHealthChecksRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else if (!Poco::icompare(i.DBName, "statistics")) {
|
||||
Logger().information("Archiving Statistics...");
|
||||
poco_information(Logger(),"Archiving Statistics...");
|
||||
StorageService()->RemoveStatisticsRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else if (!Poco::icompare(i.DBName, "devicelogs")) {
|
||||
Logger().information("Archiving Device Logs...");
|
||||
poco_information(Logger(),"Archiving Device Logs...");
|
||||
StorageService()->RemoveDeviceLogsRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else if (!Poco::icompare(i.DBName, "commandlist")) {
|
||||
Logger().information("Archiving Command History...");
|
||||
poco_information(Logger(),"Archiving Command History...");
|
||||
StorageService()->RemoveCommandListRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else {
|
||||
Logger().information(fmt::format("Cannot archive DB '{}'", i.DBName));
|
||||
poco_information(Logger(),fmt::format("Cannot archive DB '{}'", i.DBName));
|
||||
}
|
||||
}
|
||||
AppServiceRegistry().Set("lastStorageArchiverRun", (uint64_t) Now);
|
||||
@@ -54,11 +55,12 @@ namespace OpenWifi {
|
||||
|
||||
Enabled_ = MicroService::instance().ConfigGetBool("archiver.enabled",false);
|
||||
if(!Enabled_) {
|
||||
Logger().information("Archiver is disabled.");
|
||||
poco_information(Logger(),"Archiver is disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ArchiverCallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer);
|
||||
Archiver_ = std::make_unique<Archiver>(Logger());
|
||||
ArchiverCallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(*Archiver_,&Archiver::onTimer);
|
||||
|
||||
auto Schedule = MicroService::instance().ConfigGetString("archiver.schedule","03:00");
|
||||
auto S = Poco::StringTokenizer(Schedule,":");
|
||||
@@ -80,7 +82,7 @@ namespace OpenWifi {
|
||||
if(Poco::icompare(DBName,DB)==0) {
|
||||
std::string Key = "archiver.db." + std::to_string(i) + ".keep";
|
||||
auto Keep = MicroService::instance().ConfigGetInt(Key,7);
|
||||
Archiver_.AddDb(Archiver::ArchiverDBEntry{
|
||||
Archiver_->AddDb(Archiver::ArchiverDBEntry{
|
||||
.DBName = DB,
|
||||
.HowManyDays = Keep
|
||||
});
|
||||
@@ -91,19 +93,21 @@ namespace OpenWifi {
|
||||
|
||||
int NextRun = CalculateDelta(RunAtHour_,RunAtMin_);
|
||||
|
||||
Logger().information(fmt::format("Next run in {} seconds.",NextRun));
|
||||
poco_information(Logger(),fmt::format("Next run in {} seconds.",NextRun));
|
||||
|
||||
Timer_.setStartInterval( NextRun * 1000);
|
||||
Timer_.setPeriodicInterval(24 * 60 * 60 * 1000); // 1 hours
|
||||
Timer_.start(*ArchiverCallback_);
|
||||
Timer_.start(*ArchiverCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StorageArchiver::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(Enabled_) {
|
||||
Timer_.stop();
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace OpenWifi {
|
||||
private:
|
||||
std::atomic_bool Enabled_ = false;
|
||||
Poco::Timer Timer_;
|
||||
Archiver Archiver_{Logger()};
|
||||
std::unique_ptr<Archiver> Archiver_;
|
||||
std::unique_ptr<Poco::TimerCallback<Archiver>> ArchiverCallback_;
|
||||
|
||||
StorageArchiver() noexcept:
|
||||
|
||||
@@ -22,8 +22,9 @@ namespace OpenWifi {
|
||||
|
||||
void Storage::Stop() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Stopping.");
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
StorageClass::Stop();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
}
|
||||
// namespace
|
||||
@@ -19,14 +19,30 @@ namespace OpenWifi {
|
||||
|
||||
public:
|
||||
|
||||
enum CommandExecutionType {
|
||||
enum class CommandExecutionType {
|
||||
COMMAND_PENDING,
|
||||
COMMAND_EXECUTED,
|
||||
COMMAND_COMPLETED,
|
||||
COMMAND_TIMEDOUT,
|
||||
COMMAND_FAILED
|
||||
COMMAND_FAILED,
|
||||
COMMAND_EXPIRED,
|
||||
COMMAND_EXECUTING
|
||||
};
|
||||
|
||||
inline std::string to_string(const CommandExecutionType &C) {
|
||||
switch(C) {
|
||||
case CommandExecutionType::COMMAND_PENDING: return "pending";
|
||||
case CommandExecutionType::COMMAND_EXECUTED: return "executed";
|
||||
case CommandExecutionType::COMMAND_COMPLETED: return "completed";
|
||||
case CommandExecutionType::COMMAND_TIMEDOUT: return "timedout";
|
||||
case CommandExecutionType::COMMAND_FAILED: return "failed";
|
||||
case CommandExecutionType::COMMAND_EXPIRED: return "expired";
|
||||
case CommandExecutionType::COMMAND_EXECUTING:
|
||||
default:
|
||||
return "executing";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) {
|
||||
if(dbType_==sqlite) {
|
||||
return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " ";
|
||||
@@ -125,7 +141,7 @@ namespace OpenWifi {
|
||||
bool DeleteCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate);
|
||||
bool GetNonExecutedCommands( uint64_t Offset, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands );
|
||||
bool UpdateCommand( std::string &UUID, GWObjects::CommandDetails & Command );
|
||||
bool GetCommand( std::string &UUID, GWObjects::CommandDetails & Command );
|
||||
bool GetCommand( const std::string &UUID, GWObjects::CommandDetails & Command );
|
||||
bool DeleteCommand( std::string &UUID );
|
||||
bool GetReadyToExecuteCommands( uint64_t Offset, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands );
|
||||
bool CommandExecuted(std::string & UUID);
|
||||
@@ -139,6 +155,10 @@ namespace OpenWifi {
|
||||
bool SetCommandResult(std::string & UUID, std::string & Result);
|
||||
bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands);
|
||||
bool SetCommandExecuted(std::string & CommandUUID);
|
||||
bool SetCommandTimedOut(std::string &CommandUUID);
|
||||
|
||||
void RemovedExpiredCommands();
|
||||
void RemoveTimedOutCommands();
|
||||
|
||||
bool RemoveOldCommands(std::string & SerilNumber, std::string & Command);
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/SSLException.h"
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "TelemetryClient.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "WS_Connection.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include "Poco/Net/SSLException.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace OpenWifi {
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
WS_->setMaxPayloadSize(2048);
|
||||
WS_->setBlocking(false);
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<TelemetryClient, Poco::Net::ReadableNotification>(
|
||||
*this, &TelemetryClient::OnSocketReadable));
|
||||
@@ -56,7 +57,7 @@ namespace OpenWifi {
|
||||
*WS_, Poco::NObserver<TelemetryClient, Poco::Net::ErrorNotification>(
|
||||
*this, &TelemetryClient::OnSocketError));
|
||||
Registered_ = true;
|
||||
Logger().information(fmt::format("CONNECTION({}): Connection completed.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-CONNECTION({}): Connection completed.", CId_));
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
@@ -69,7 +70,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
TelemetryClient::~TelemetryClient() {
|
||||
Logger().information(fmt::format("CONNECTION({}): Closing connection.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-CONNECTION({}): Closing connection.", CId_));
|
||||
if(Registered_ && WS_)
|
||||
{
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
@@ -92,23 +93,19 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void TelemetryClient::SendTelemetryShutdown() {
|
||||
Logger().information(fmt::format("TELEMETRY-SHUTDOWN({}): Closing.",CId_));
|
||||
auto Device = DeviceRegistry()->GetDeviceConnection(SerialNumber_);
|
||||
if(Device) {
|
||||
if(Device->WSConn_)
|
||||
Device->WSConn_->StopWebSocketTelemetry();
|
||||
}
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-SHUTDOWN({}): Closing.",CId_));
|
||||
DeviceRegistry()->StopWebSocketTelemetry(CommandManager()->NextRPCId(), SerialNumber_);
|
||||
TelemetryStream()->DeRegisterClient(UUID_);
|
||||
delete this;
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
Logger().information(fmt::format("SOCKET-SHUTDOWN({}): Orderly shutdown.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-SOCKET-SHUTDOWN({}): Orderly shutdown.", CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
|
||||
Logger().information(fmt::format("SOCKET-ERROR({}): Closing.",CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-SOCKET-ERROR({}): Closing.",CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
@@ -125,11 +122,11 @@ namespace OpenWifi {
|
||||
}
|
||||
catch (const std::exception & E) {
|
||||
std::string W = E.what();
|
||||
Logger().information(fmt::format("std::exception caught: {}. Connection terminated with {}",W,CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-std::exception caught: {}. Connection terminated with {}",W,CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
catch ( ... ) {
|
||||
Logger().information(fmt::format("Unknown exception for {}. Connection terminated.",CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-Unknown exception for {}. Connection terminated.",CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
}
|
||||
@@ -146,16 +143,16 @@ namespace OpenWifi {
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
Logger().information(fmt::format("DISCONNECT({}): device has disconnected.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-DISCONNECT({}): device has disconnected.", CId_));
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
if (Op == Poco::Net::WebSocket::FRAME_OP_PING) {
|
||||
Logger().debug(fmt::format("WS-PING({}): received. PONG sent back.", CId_));
|
||||
Logger().debug(fmt::format("TELEMETRY-WS-PING({}): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} else if (Op == Poco::Net::WebSocket::FRAME_OP_CLOSE) {
|
||||
Logger().information(fmt::format("DISCONNECT({}): device wants to disconnect.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-DISCONNECT({}): device wants to disconnect.", CId_));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,34 +3,34 @@
|
||||
//
|
||||
#include <thread>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Array.h"
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/URI.h"
|
||||
|
||||
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int TelemetryStream::Start() {
|
||||
Running_ = true;
|
||||
Messages_->Readable_ += Poco::delegate(this,&TelemetryStream::onMessage);
|
||||
// ReactorPool_.Start("TelemetryWebSocketPool_");
|
||||
Thr_.start(Reactor_);
|
||||
Utils::SetThreadName(Thr_,"telemetry-svr");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TelemetryStream::Stop() {
|
||||
Logger().notice("Stopping reactors...");
|
||||
// ReactorPool_.Stop();
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Reactor_.stop();
|
||||
Thr_.join();
|
||||
if(Running_) {
|
||||
Running_ = false;
|
||||
Messages_->Readable_ -= Poco::delegate( this, &TelemetryStream::onMessage);
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
bool TelemetryStream::IsValidEndPoint(uint64_t SerialNumber, const std::string & UUID) {
|
||||
@@ -47,12 +47,11 @@ namespace OpenWifi {
|
||||
return (N->second.find(UUID) != N->second.end());
|
||||
}
|
||||
|
||||
bool TelemetryStream::CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, std::string &UUID) {
|
||||
bool TelemetryStream::CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, const std::string &UUID) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
Poco::URI Public(MicroService::instance().ConfigGetString("openwifi.system.uri.public"));
|
||||
Poco::URI U;
|
||||
UUID = MicroService::CreateUUID();
|
||||
U.setScheme("wss");
|
||||
U.setHost(Public.getHost());
|
||||
U.setPort(Public.getPort());
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
#include "TelemetryClient.h"
|
||||
#include "WS_ReactorPool.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
|
||||
bool IsValidEndPoint(uint64_t SerialNumber, const std::string & UUID);
|
||||
bool CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, std::string &UUID);
|
||||
bool CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, const std::string &UUID);
|
||||
void UpdateEndPoint(uint64_t SerialNumber, const std::string &PayLoad);
|
||||
bool RegisterClient(const std::string &UUID, TelemetryClient *Client);
|
||||
void DeRegisterClient(const std::string &UUID);
|
||||
@@ -52,7 +52,7 @@ namespace OpenWifi {
|
||||
void onMessage(bool& b);
|
||||
|
||||
private:
|
||||
mutable 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
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
|
||||
144
src/VenueBroadcaster.h
Normal file
144
src/VenueBroadcaster.h
Normal file
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-16.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "sdks/sdk_prov.h"
|
||||
#include "DeviceRegistry.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class VenueBroadcastNotification : public Poco::Notification {
|
||||
public:
|
||||
VenueBroadcastNotification(const std::string &SourceSerialNumber, const std::string &Data, uint64_t TimeStamp) :
|
||||
SourceSerialNumber_(SourceSerialNumber),
|
||||
Data_(Data),
|
||||
TimeStamp_(TimeStamp) {
|
||||
|
||||
}
|
||||
std::string SourceSerialNumber_;
|
||||
std::string Data_;
|
||||
uint64_t TimeStamp_=OpenWifi::Now();
|
||||
};
|
||||
|
||||
class VenueBroadcaster : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new VenueBroadcaster;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
inline int Start() override {
|
||||
Enabled_ = MicroService::instance().ConfigGetBool("venue_broadcast.enabled",true);
|
||||
if(Enabled_) {
|
||||
BroadcastManager_.start(*this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() override {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(Enabled_ && Running_) {
|
||||
BroadcastQueue_.wakeUpAll();
|
||||
BroadcastManager_.wakeUp();
|
||||
BroadcastManager_.join();
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
}
|
||||
|
||||
|
||||
struct VenueInfo {
|
||||
uint64_t timestamp=OpenWifi::Now();
|
||||
Types::StringVec serialNumbers;
|
||||
};
|
||||
|
||||
inline bool FindSerialNumberList(const std::string &Source, OpenWifi::Types::StringVec & SerialNumbers) {
|
||||
// Can we find our serial number in any of the lists so far...
|
||||
for(const auto &venue:Venues_) {
|
||||
auto entry = std::find(venue.second.serialNumbers.begin(),venue.second.serialNumbers.end(),Source);
|
||||
if(entry!=venue.second.serialNumbers.end() && (OpenWifi::Now()-venue.second.timestamp)<600) {
|
||||
SerialNumbers = venue.second.serialNumbers;
|
||||
auto entry2 = std::find(SerialNumbers.begin(),SerialNumbers.end(),Source);
|
||||
SerialNumbers.erase(entry2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// get the venue from Prov and the serial numbers.
|
||||
Types::UUID_t Venue;
|
||||
Types::StringVec TmpSerialNumbers;
|
||||
if(OpenWifi::SDK::Prov::GetSerialNumbersForVenueOfSerialNumber(Source,Venue,TmpSerialNumbers,Logger())) {
|
||||
std::sort(TmpSerialNumbers.begin(),TmpSerialNumbers.end());
|
||||
VenueInfo V{.timestamp=OpenWifi::Now(), .serialNumbers=TmpSerialNumbers};
|
||||
Venues_[Venue] = V;
|
||||
auto p = std::find(TmpSerialNumbers.begin(),TmpSerialNumbers.end(),Source);
|
||||
if(p!=TmpSerialNumbers.end()) {
|
||||
TmpSerialNumbers.erase(p);
|
||||
SerialNumbers = TmpSerialNumbers;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void SendToDevice(const std::string &SerialNumber,const std::string &Payload) {
|
||||
DeviceRegistry()->SendFrame(SerialNumber,Payload);
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("venue-bcast");
|
||||
Poco::AutoPtr<Poco::Notification> NextNotification(BroadcastQueue_.waitDequeueNotification());
|
||||
while (NextNotification && Running_) {
|
||||
auto Notification = dynamic_cast<VenueBroadcastNotification *>(NextNotification.get());
|
||||
if (Notification != nullptr) {
|
||||
Types::StringVec SerialNumbers;
|
||||
if(FindSerialNumberList(Notification->SourceSerialNumber_,SerialNumbers)) {
|
||||
Poco::JSON::Object Payload;
|
||||
Payload.set("jsonrpc","2.0");
|
||||
Payload.set("method","venue_broadcast");
|
||||
Poco::JSON::Object ParamBlock;
|
||||
ParamBlock.set("serial",Notification->SourceSerialNumber_);
|
||||
ParamBlock.set("timestamp",Notification->TimeStamp_);
|
||||
ParamBlock.set("data",Notification->Data_);
|
||||
Payload.set("params", ParamBlock);
|
||||
std::ostringstream o;
|
||||
Payload.stringify(o);
|
||||
for(const auto &Device:SerialNumbers) {
|
||||
SendToDevice(Device,o.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
NextNotification = BroadcastQueue_.waitDequeueNotification();
|
||||
}
|
||||
Running_=false;
|
||||
}
|
||||
|
||||
inline void Broadcast(const std::string &SourceSerial, const std::string &Data, uint64_t TimeStamp) {
|
||||
BroadcastQueue_.enqueueNotification(new VenueBroadcastNotification(SourceSerial,Data,TimeStamp));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::atomic_bool Running_=false;
|
||||
bool Enabled_=false;
|
||||
Poco::NotificationQueue BroadcastQueue_;
|
||||
Poco::Thread BroadcastManager_;
|
||||
|
||||
std::map<OpenWifi::Types::UUID_t,VenueInfo> Venues_;
|
||||
|
||||
VenueBroadcaster() noexcept:
|
||||
SubSystemServer("VenueBroadcaster", "VENUE-BCAST", "venue.broacast")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline auto VenueBroadcaster() { return VenueBroadcaster::instance(); }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,97 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WSConnection {
|
||||
static constexpr int BufSize = 128000;
|
||||
public:
|
||||
WSConnection(Poco::Net::StreamSocket& Socket, Poco::Net::SocketReactor& Reactor);
|
||||
~WSConnection();
|
||||
|
||||
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(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_; }
|
||||
bool SetWebSocketTelemetryReporting(uint64_t interval, uint64_t TelemetryWebSocketTimer);
|
||||
bool SetKafkaTelemetryReporting(uint64_t interval, uint64_t TelemetryKafkaTimer);
|
||||
bool StopWebSocketTelemetry();
|
||||
bool StopKafkaTelemetry();
|
||||
inline bool GetTelemetryParameters(bool & Reporting, uint64_t & Interval,
|
||||
uint64_t & WebSocketTimer, uint64_t & KafkaTimer,
|
||||
uint64_t &WebSocketCount, uint64_t & KafkaCount,
|
||||
uint64_t &WebSocketPackets,
|
||||
uint64_t &KafkaPackets ) const {
|
||||
Reporting = TelemetryReporting_;
|
||||
WebSocketTimer = TelemetryWebSocketTimer_;
|
||||
KafkaTimer = TelemetryKafkaTimer_;
|
||||
WebSocketCount = TelemetryWebSocketRefCount_;
|
||||
KafkaCount = TelemetryKafkaRefCount_;
|
||||
Interval = TelemetryInterval_;
|
||||
WebSocketPackets = TelemetryWebSocketPackets_;
|
||||
KafkaPackets = TelemetryKafkaPackets_;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::StreamSocket Socket_;
|
||||
Poco::Net::SocketReactor & Reactor_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
std::string SerialNumber_;
|
||||
uint64_t SerialNumberInt_=0;
|
||||
std::string Compatible_;
|
||||
std::shared_ptr<DeviceRegistry::ConnectionEntry> Conn_;
|
||||
mutable bool Registered_ = false ;
|
||||
std::string CId_;
|
||||
std::string CN_;
|
||||
GWObjects::CertificateValidation CertValidation_ = GWObjects::CertificateValidation::NO_CERTIFICATE;
|
||||
uint64_t Errors_=0;
|
||||
mutable 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;
|
||||
|
||||
void CompleteStartup();
|
||||
bool StartTelemetry();
|
||||
bool StopTelemetry();
|
||||
void UpdateCounts();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/JSON/Array.h"
|
||||
|
||||
#include "ConfigurationCache.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "WS_Server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
bool WebSocketServer::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
|
||||
if(IsCertOk()) {
|
||||
Logger().debug(fmt::format("CERTIFICATE({}): issuer='{}' cn='{}'", ConnectionId, Certificate.issuerName(),Certificate.commonName()));
|
||||
if(!Certificate.issuedBy(*IssuerCert_)) {
|
||||
Logger().debug(fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int WebSocketServer::Start() {
|
||||
// ReactorPool_.Start("DeviceReactorPool_");
|
||||
for(const auto & Svr : ConfigServersList_ ) {
|
||||
Logger().notice( fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}",
|
||||
Svr.Address(),
|
||||
Svr.Port(),
|
||||
Svr.KeyFile(),Svr.CertFile()));
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if(!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
|
||||
if(!IsCertOk()) {
|
||||
IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
|
||||
Logger().information( fmt::format("Certificate Issuer Name:{}",IssuerCert_->issuerName()));
|
||||
}
|
||||
auto NewSocketAcceptor = std::make_unique<ws_server_reactor_type_t>(Sock, Reactor_); // , 2 /*Poco::Environment::processorCount()*2) */ );
|
||||
Acceptors_.push_back(std::move(NewSocketAcceptor));
|
||||
}
|
||||
|
||||
auto ProvString = MicroService::instance().ConfigGetString("autoprovisioning.process","default");
|
||||
if(ProvString!="default") {
|
||||
auto Tokens = Poco::StringTokenizer(ProvString, ",");
|
||||
for (const auto &i : Tokens) {
|
||||
if (i == "prov")
|
||||
LookAtProvisioning_ = true;
|
||||
else
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
} else {
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
|
||||
SimulatorId_ = 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();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
}
|
||||
|
||||
} //namespace
|
||||
@@ -1,76 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#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"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WebSocketServer : public SubSystemServer {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new WebSocketServer;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool IsCertOk() { return IssuerCert_!= nullptr; }
|
||||
bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
|
||||
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
|
||||
|
||||
inline bool IsSimSerialNumber(const std::string & SerialNumber) const {
|
||||
return IsSim(SerialNumber) && SerialNumber == SimulatorId_;
|
||||
}
|
||||
|
||||
inline static bool IsSim(const std::string & SerialNumber) {
|
||||
return SerialNumber.substr(0,6) == "53494d";
|
||||
}
|
||||
|
||||
inline bool IsSimEnabled() const {
|
||||
return SimulatorEnabled_;
|
||||
}
|
||||
|
||||
inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
// 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_;
|
||||
std::string SimulatorId_;
|
||||
bool LookAtProvisioning_ = false;
|
||||
bool UseDefaultConfig_ = true;
|
||||
bool SimulatorEnabled_=false;
|
||||
|
||||
WebSocketServer() noexcept:
|
||||
SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
inline auto WebSocketServer() { return WebSocketServer::instance(); }
|
||||
|
||||
} //namespace
|
||||
206
src/attributes.json
Normal file
206
src/attributes.json
Normal file
@@ -0,0 +1,206 @@
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "wan",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh"
|
||||
],
|
||||
"ssids": []
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 100,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"gateway": "192.168.1.1",
|
||||
"send-hostname": true,
|
||||
"subnet": "192.168.1.1/24",
|
||||
"use-dns": []
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "lan",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"wifi-steering",
|
||||
"ssh"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "optional",
|
||||
"proto": "wpa-mixed"
|
||||
},
|
||||
"hidden-ssid": false,
|
||||
"isolate-clients": false,
|
||||
"maximum-clients": 64,
|
||||
"name": "arilia-rad",
|
||||
"pass-point": {
|
||||
"access-network-type": 0,
|
||||
"anqp-3gpp-cell-net": [],
|
||||
"anqp-domain": 8888,
|
||||
"asra": false,
|
||||
"auth-type": {
|
||||
"type": "terms-and-conditions"
|
||||
},
|
||||
"connection-capability": [
|
||||
"1:0:2",
|
||||
"6:22:1",
|
||||
"17:5060:0"
|
||||
],
|
||||
"disable-dgaf": true,
|
||||
"domain-name": [
|
||||
"main.arilia.com"
|
||||
],
|
||||
"esr": false,
|
||||
"friendly-name": [
|
||||
"eng:AriliaWifi",
|
||||
"fra:AriliaWifi"
|
||||
],
|
||||
"hessid": "11:22:33:44:55:66",
|
||||
"internet": true,
|
||||
"ipaddr-type-available": 14,
|
||||
"nai-realm": [],
|
||||
"osen": false,
|
||||
"roaming-consortium": [
|
||||
"F4F5E8F5F4"
|
||||
],
|
||||
"uesa": false,
|
||||
"venue-group": 2,
|
||||
"venue-name": [
|
||||
"eng:Bowen Development 1",
|
||||
"fra:Bowen Development 1"
|
||||
],
|
||||
"venue-type": 8,
|
||||
"venue-url": [
|
||||
"http://www.example.com/info-fra",
|
||||
"http://www.example.com/info-eng"
|
||||
]
|
||||
},
|
||||
"radius": {
|
||||
"accounting": {
|
||||
"interval" : 600,
|
||||
"host": "0.0.0.0",
|
||||
"port": 1813,
|
||||
"secret": "radsec"
|
||||
},
|
||||
"authentication": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1812,
|
||||
"secret": "radsec",
|
||||
},
|
||||
"chargeable-user-id" : true,
|
||||
"nas-identifier": "AriliaWifi",
|
||||
"realm" : [
|
||||
"c2k2q8e2pcs2udar1pa0.orion.area120.com"
|
||||
]
|
||||
},
|
||||
"services": [
|
||||
"radius-gw-proxy"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G",
|
||||
"5G"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 60
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"bandwidth": 10,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HT",
|
||||
"channel-width": 20,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 23
|
||||
},
|
||||
{
|
||||
"band": "5G",
|
||||
"bandwidth": 20,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "VHT",
|
||||
"channel-width": 80,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 23
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"ssh": {
|
||||
"password-authentication": true,
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 1661409802
|
||||
}
|
||||
@@ -44,7 +44,7 @@ static json DefaultUCentralSchema = R"(
|
||||
"switch": {
|
||||
"$ref": "#/$defs/switch"
|
||||
},
|
||||
"radios": {
|
||||
"radiosgrep": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/radio"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
169
src/framework/MicroServiceErrorHandler.h
Normal file
169
src/framework/MicroServiceErrorHandler.h
Normal file
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-09-29.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/JSON/Template.h"
|
||||
#include "Poco/Thread.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class MicroServiceErrorHandler : public Poco::ErrorHandler {
|
||||
public:
|
||||
explicit MicroServiceErrorHandler(Poco::Util::Application &App) : App_(App) {
|
||||
}
|
||||
|
||||
inline void exception(const Poco::Exception & Base) override {
|
||||
try {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
|
||||
App_.logger().log(Base);
|
||||
Base.rethrow();
|
||||
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidCertificateException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::InvalidSocketException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::WebSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::ConnectionResetException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::CertificateValidationException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLConnectionUnexpectedlyClosedException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLContextException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLContextException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::Net::InvalidAddressException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidAddressException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::NetException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::IOException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::IOException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::RuntimeException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::JSON::JSONTemplateException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONTemplateException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::ApplicationException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::ApplicationException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Exception thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (...) {
|
||||
poco_error(App_.logger(), fmt::format("Poco:Generic thr_name={}",t_name, t_id));
|
||||
}
|
||||
}
|
||||
|
||||
inline void exception(const std::exception & E) override {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
poco_warning(App_.logger(), fmt::format("std::exception in {}: {} thr_id={}",
|
||||
t_name,E.what(),
|
||||
t_id));
|
||||
}
|
||||
|
||||
inline void exception() override {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
poco_warning(App_.logger(), fmt::format("generic exception in {} thr_id={}",
|
||||
t_name, t_id));
|
||||
}
|
||||
private:
|
||||
Poco::Util::Application &App_;
|
||||
std::string t_name;
|
||||
int t_id=0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -33,7 +33,6 @@ namespace OpenWifi {
|
||||
int Start() override {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
Logger().setLevel(Poco::Message::PRIO_INFORMATION);
|
||||
Logger().notice("Starting.");
|
||||
std::string DBType = MicroService::instance().ConfigGetString("storage.type");
|
||||
|
||||
|
||||
@@ -69,6 +69,41 @@ namespace OpenWifi {
|
||||
}
|
||||
};
|
||||
|
||||
struct WebSocketClientNotificationNumberOfConnection {
|
||||
std::uint64_t numberOfDevices=0;
|
||||
std::uint64_t averageConnectedTime=0;
|
||||
std::uint64_t numberOfConnectingDevices=0;
|
||||
|
||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"numberOfDevices", numberOfDevices);
|
||||
RESTAPI_utils::field_to_json(Obj,"averageConnectedTime", averageConnectedTime);
|
||||
RESTAPI_utils::field_to_json(Obj,"numberOfConnectingDevices", numberOfConnectingDevices);
|
||||
}
|
||||
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"numberOfDevices", numberOfDevices);
|
||||
RESTAPI_utils::field_from_json(Obj,"averageConnectedTime", averageConnectedTime);
|
||||
RESTAPI_utils::field_from_json(Obj,"numberOfConnectingDevices", numberOfConnectingDevices);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
inline void WebSocketClientNotificationNumberOfConnections(std::uint64_t numberOfDevices,
|
||||
std::uint64_t averageConnectedTime,
|
||||
std::uint64_t numberOfConnectingDevices) {
|
||||
WebSocketNotification<WebSocketClientNotificationNumberOfConnection> N;
|
||||
N.content.numberOfDevices = numberOfDevices;
|
||||
N.content.averageConnectedTime = averageConnectedTime;
|
||||
N.content.numberOfConnectingDevices = numberOfConnectingDevices;
|
||||
N.type = "device_connections_statistics";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationDeviceConfigurationChange(const std::string &SerialNumber, uint64_t oldUUID, uint64_t newUUID) {
|
||||
WebSocketNotification<WebNotificationSingleDeviceConfigurationChange> N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
@@ -146,6 +181,10 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationRebootList {
|
||||
std::string title,
|
||||
details,
|
||||
@@ -189,5 +228,58 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationUpgradeList {
|
||||
std::string title,
|
||||
details,
|
||||
jobId;
|
||||
std::vector<std::string> success,
|
||||
skipped,
|
||||
no_firmware,
|
||||
not_connected;
|
||||
uint64_t timeStamp=OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
typedef WebSocketNotification<WebSocketNotificationUpgradeList> WebSocketClientNotificationVenueUpgradeList_t;
|
||||
|
||||
inline void WebSocketNotificationUpgradeList::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,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_to_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_to_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||
}
|
||||
|
||||
inline bool WebSocketNotificationUpgradeList::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,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_from_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_from_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationVenueUpgradeCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpgradeList_t &N) {
|
||||
N.type = "venue_upgrader";
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
|
||||
@@ -196,6 +196,8 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
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."};
|
||||
|
||||
static const struct msg MaximumRTTYSessionsReached{1144,"Too many RTTY sessions currently active"};
|
||||
static const struct msg DeviceIsAlreadyBusy{1145,"Device is already executing a command. Please try later."};
|
||||
}
|
||||
|
||||
|
||||
@@ -445,6 +447,7 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
static const char *RECOVERY = "recovery";
|
||||
static const char *TELEMETRY = "telemetry";
|
||||
static const char *DEVICEUPDATE = "deviceupdate";
|
||||
static const char *VENUE_BROADCAST = "venue_broadcast";
|
||||
|
||||
enum EVENT_MSG {
|
||||
ET_UNKNOWN,
|
||||
@@ -457,7 +460,8 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
ET_CFGPENDING,
|
||||
ET_RECOVERY,
|
||||
ET_DEVICEUPDATE,
|
||||
ET_TELEMETRY
|
||||
ET_TELEMETRY,
|
||||
ET_VENUEBROADCAST
|
||||
};
|
||||
|
||||
inline EVENT_MSG EventFromString(const std::string & Method) {
|
||||
@@ -481,6 +485,8 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
return ET_RECOVERY;
|
||||
else if(strcmp(TELEMETRY,Method.c_str())==0)
|
||||
return ET_TELEMETRY;
|
||||
else if(strcmp(VENUE_BROADCAST,Method.c_str())==0)
|
||||
return ET_VENUEBROADCAST;
|
||||
return ET_UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,97 +8,67 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
RTTYS_ClientConnection::RTTYS_ClientConnection(Poco::Net::WebSocket *WS,
|
||||
Poco::Logger &L,
|
||||
std::string &Id)
|
||||
RTTYS_ClientConnection::RTTYS_ClientConnection(
|
||||
Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
Poco::Net::SocketReactor &reactor,
|
||||
const std::string &Id)
|
||||
:
|
||||
WS_(WS),
|
||||
Logger_(L),
|
||||
Id_(std::move(Id))
|
||||
Reactor_(reactor),
|
||||
Id_(Id),
|
||||
Logger_(Poco::Logger::get(fmt::format("RTTY-client({})",Id_)))
|
||||
{
|
||||
|
||||
//WS_ = new Poco::Net::WebSocket(Request, Response);
|
||||
RTTYS_server()->Register(Id_, this);
|
||||
Logger().information(fmt::format("{}: Client starting connection, session: {}.",
|
||||
Id_, RTTYS_server()->DeviceSessionID(Id_)));
|
||||
RTTYS_server()->ClientReactor().addEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
RTTYS_server()->ClientReactor().addEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
|
||||
std::thread T([=]() { CompleteLogin(); });
|
||||
T.detach();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::CompleteLogin() {
|
||||
int tries = 0;
|
||||
completing_connection_ = true;
|
||||
try {
|
||||
while (!aborting_connection_ && tries < 20) {
|
||||
if (RTTYS_server()->Login(this->Id_)) {
|
||||
Logger().information(fmt::format("{}: Client connected to device, session: {}.",
|
||||
Id_, RTTYS_server()->DeviceSessionID(Id_)));
|
||||
this->Connected_ = true;
|
||||
completing_connection_ = false;
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(2000ms);
|
||||
tries++;
|
||||
Logger().information(fmt::format(
|
||||
"{}: Waiting for device to connect to start session. (try={})", Id_, tries));
|
||||
}
|
||||
Logger().information(fmt::format("{}: Client could not connect to device, session: {}.",
|
||||
Id_, RTTYS_server()->DeviceSessionID(Id_)));
|
||||
delete this;
|
||||
} catch (...) {
|
||||
completing_connection_ = false;
|
||||
delete this;
|
||||
Valid_ = true;
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request,response);
|
||||
WS_->setBlocking(false);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
Registered_ = true;
|
||||
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));
|
||||
Logger_.information("Starting connection");
|
||||
}
|
||||
}
|
||||
|
||||
RTTYS_ClientConnection::~RTTYS_ClientConnection() {
|
||||
// std::lock_guard G(Mutex_);
|
||||
try {
|
||||
aborting_connection_ = true;
|
||||
if(completing_connection_) {
|
||||
aborting_connection_ = true;
|
||||
while(completing_connection_)
|
||||
continue;
|
||||
}
|
||||
Logger().information(fmt::format("{}: Client disconnecting.", Id_));
|
||||
RTTYS_server()->DeRegister(Id_, this);
|
||||
if (Connected_) {
|
||||
RTTYS_server()->ClientReactor().removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
RTTYS_server()->ClientReactor().removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
}
|
||||
Logger().information(fmt::format("{}: Client disconnected.", Id_));
|
||||
delete WS_;
|
||||
} catch (...) {
|
||||
Logger().information(fmt::format("{}: Client disconnected (exception).", Id_));
|
||||
poco_information(Logger_,
|
||||
fmt::format("Client {} session ending", Id_)
|
||||
);
|
||||
DeRegister();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::DeRegister() {
|
||||
Valid_ = false;
|
||||
if(Registered_) {
|
||||
Registered_ = false;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::Close() {
|
||||
{
|
||||
std::lock_guard G(Mutex_);
|
||||
CloseConnection_ = true;
|
||||
}
|
||||
delete this;
|
||||
void RTTYS_ClientConnection::EndConnection() {
|
||||
DeRegister();
|
||||
RTTYS_server()->NotifyClientDisconnect(Id_, this);
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::onSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
bool MustDisconnect = false;
|
||||
|
||||
{
|
||||
std::lock_guard G(Mutex_);
|
||||
if(!Valid_ || !Registered_)
|
||||
return;
|
||||
std::shared_lock G(Mutex_);
|
||||
try {
|
||||
int flags;
|
||||
auto n = WS_->receiveFrame(Buffer_, sizeof(Buffer_), flags);
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
auto n = WS_->receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
@@ -110,10 +80,10 @@ namespace OpenWifi {
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
if (n == 0) {
|
||||
Logger().information(fmt::format("{}: Socket readable shutdown.", Id_));
|
||||
Logger_.information("Socket readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
std::string s((char *)Buffer_, n);
|
||||
std::string s((char *)IncomingFrame.begin(), IncomingFrame.size());
|
||||
try {
|
||||
auto Doc = nlohmann::json::parse(s);
|
||||
if (Doc.contains("type")) {
|
||||
@@ -122,34 +92,34 @@ namespace OpenWifi {
|
||||
auto cols = Doc["cols"];
|
||||
auto rows = Doc["rows"];
|
||||
if (!RTTYS_server()->WindowSize(Id_, cols, rows)) {
|
||||
Logger().information(
|
||||
fmt::format("{}: Winsize shutdown.", Id_));
|
||||
Logger_.information("Winsize shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
// just ignore parse errors
|
||||
Logger().information(
|
||||
fmt::format("{}: Frame text exception shutdown.", Id_));
|
||||
Logger_.information("Frame text exception shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_BINARY: {
|
||||
if (n == 0) {
|
||||
Logger().information(fmt::format("{}: Frame binary size shutdown.", Id_));
|
||||
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(fmt::format("{}: Sendkeystrokes shutdown.", Id_));
|
||||
poco_trace(Logger_, fmt::format("Sending {} key strokes to device.", n));
|
||||
if (!RTTYS_server()->SendKeyStrokes(
|
||||
Id_, (const unsigned char *)IncomingFrame.begin(),
|
||||
IncomingFrame.size())) {
|
||||
Logger_.information("Sendkeystrokes shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger().information(fmt::format("{}: Frame frame close shutdown.", Id_));
|
||||
Logger_.information("Frame frame close shutdown.");
|
||||
MustDisconnect = true;
|
||||
} break;
|
||||
|
||||
@@ -157,55 +127,45 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
Logger().information(fmt::format("{}: Frame readable shutdown.", Id_));
|
||||
Logger_.information("Frame readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(MustDisconnect)
|
||||
delete this;
|
||||
if(MustDisconnect) {
|
||||
EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::SendData( const u_char *Buf, size_t len ) {
|
||||
bool done = false;
|
||||
{
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
try {
|
||||
WS_->sendFrame(Buf, len,
|
||||
Poco::Net::WebSocket::FRAME_FLAG_FIN |
|
||||
Poco::Net::WebSocket::FRAME_OP_BINARY);
|
||||
} catch (...) {
|
||||
done = true;
|
||||
Logger().information(fmt::format("{}: SendData shutdown.", Id_));
|
||||
}
|
||||
if(!Valid_ || !Registered_)
|
||||
return;
|
||||
try {
|
||||
WS_->sendFrame(Buf, len,
|
||||
Poco::Net::WebSocket::FRAME_FLAG_FIN |
|
||||
Poco::Net::WebSocket::FRAME_OP_BINARY);
|
||||
return;
|
||||
} catch (...) {
|
||||
Logger_.information("SendData shutdown.");
|
||||
}
|
||||
if(done)
|
||||
return delete this;
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::SendData( const std::string &s , bool login) {
|
||||
bool done = false;
|
||||
{
|
||||
try {
|
||||
std::lock_guard G(Mutex_);
|
||||
if (login) {
|
||||
RTTYS_server()->LoginDone(Id_);
|
||||
}
|
||||
WS_->sendFrame(s.c_str(), s.length());
|
||||
} catch (...) {
|
||||
done = true;
|
||||
Logger().information(fmt::format("{}: Senddata shutdown.", Id_));
|
||||
return delete this;
|
||||
}
|
||||
void RTTYS_ClientConnection::SendData( const std::string &s) {
|
||||
if(!Valid_ || !Registered_)
|
||||
return;
|
||||
try {
|
||||
WS_->sendFrame(s.c_str(), s.length());
|
||||
return;
|
||||
} catch (...) {
|
||||
Logger_.information("SendData shutdown.");
|
||||
}
|
||||
if(done)
|
||||
return delete this;
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::onSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
Logger().information(fmt::format("{}: Socket shutdown.", Id_));
|
||||
delete this;
|
||||
Logger_.information("Socket shutdown.");
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,37 +11,38 @@
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/FIFOBuffer.h"
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RTTYS_ClientConnection {
|
||||
public:
|
||||
// RTTYS_ClientConnection(std::unique_ptr<Poco::Net::WebSocket> WS, std::string &Id,
|
||||
RTTYS_ClientConnection(Poco::Net::WebSocket *WS,
|
||||
Poco::Logger &L,
|
||||
std::string &Id);
|
||||
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 DeRegister();
|
||||
|
||||
void Close();
|
||||
|
||||
void CompleteLogin();
|
||||
[[nodiscard]] inline std::string ID() { return Id_; }
|
||||
[[nodiscard]] inline bool Valid() { return Valid_; }
|
||||
|
||||
private:
|
||||
Poco::Net::WebSocket *WS_= nullptr;
|
||||
Poco::Logger & Logger_;
|
||||
std::string Id_;
|
||||
std::string Sid_;
|
||||
mutable std::atomic_bool Connected_=false;
|
||||
u_char Buffer_[16000]{0};
|
||||
mutable bool CloseConnection_=false;
|
||||
std::mutex Mutex_;
|
||||
mutable std::atomic_bool aborting_connection_ = false;
|
||||
mutable std::atomic_bool completing_connection_ = false;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::string Id_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
Poco::Logger &Logger_;
|
||||
std::string Sid_;
|
||||
std::shared_mutex Mutex_;
|
||||
volatile bool Valid_=false;
|
||||
volatile bool Registered_=false;
|
||||
|
||||
void EndConnection();
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
};
|
||||
}
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
RTTY_Client_WebSocketRequestHandler::RTTY_Client_WebSocketRequestHandler(Poco::Logger & L)
|
||||
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();
|
||||
@@ -30,13 +30,9 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
try {
|
||||
Poco::Thread::current()->setName(fmt::format("WebRTTYRequest_WSHandler_{}", T[2]));
|
||||
std::cout << "Creating websocket end point for a RTTY client" << std::endl;
|
||||
auto WS = new Poco::Net::WebSocket(request, response);
|
||||
new RTTYS_ClientConnection(WS, Logger_, T[2]);
|
||||
std::cout << "Ending web server websocket creation end point for RTTY" << std::endl;
|
||||
RTTYS_server()->CreateNewClient(request,response,T[2]);
|
||||
} catch (...) {
|
||||
Logger_.warning("Exception during WS creation");
|
||||
poco_warning(Logger_,"Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,9 +104,9 @@ namespace OpenWifi {
|
||||
Poco::Net::HTTPServerResponse &response) {
|
||||
|
||||
Utils::SetThreadName("rt:webserver");
|
||||
uint64_t id = rtty_ws_id++;
|
||||
[[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();
|
||||
|
||||
@@ -132,7 +128,7 @@ 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") {
|
||||
SetCommonHeaders(request,response, false);
|
||||
@@ -141,7 +137,7 @@ namespace OpenWifi {
|
||||
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") {
|
||||
SetCommonHeaders(request,response, false);
|
||||
@@ -150,7 +146,7 @@ namespace OpenWifi {
|
||||
response.setContentType("application/json");
|
||||
std::ostream &answer = response.send();
|
||||
answer << to_string(doc);
|
||||
Logger_.information(fmt::format("{}: Finishing font size request.",id));
|
||||
poco_debug(Logger(),fmt::format("{}: Finishing font size request.",id));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -158,12 +154,12 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -173,7 +169,7 @@ namespace OpenWifi {
|
||||
// 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);
|
||||
@@ -190,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")
|
||||
@@ -204,21 +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::Logger & L)
|
||||
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) {
|
||||
Utils::SetThreadName("rtty-websvr-ws");
|
||||
Poco::Thread::current()->setName("WebRTTYRequest_WSHandler");
|
||||
return new RTTY_Client_WebSocketRequestHandler(Logger_);
|
||||
return new RTTYS_Client_WebSocketRequestHandler(Logger_);
|
||||
} else {
|
||||
Poco::Thread::current()->setName("WebRTTYRequest_PageHandler");
|
||||
Utils::SetThreadName("rtty-websvr-pg");
|
||||
return new PageRequestHandler(Logger_);
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#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::Logger &L);
|
||||
explicit RTTYS_Client_WebSocketRequestHandler(Poco::Logger &L);
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
@@ -23,7 +23,7 @@ namespace OpenWifi {
|
||||
|
||||
class PageRequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
PageRequestHandler(Poco::Logger &L)
|
||||
explicit PageRequestHandler(Poco::Logger &L)
|
||||
: Logger_(L) {
|
||||
}
|
||||
|
||||
@@ -32,11 +32,12 @@ namespace OpenWifi {
|
||||
|
||||
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::Logger &L);
|
||||
explicit RTTYS_Client_RequestHandlerFactory(Poco::Logger &L);
|
||||
|
||||
Poco::Net::HTTPRequestHandler *
|
||||
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override;
|
||||
|
||||
@@ -4,93 +4,147 @@
|
||||
|
||||
#include "RTTYS_device.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
#include "rttys/RTTYS_ClientConnection.h"
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
|
||||
|
||||
void dump(const u_char *b, uint s) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
int l=0;
|
||||
std::cout << std::endl;
|
||||
while(s) {
|
||||
std::string SS;
|
||||
SS += (hex[(*b & 0xf0) >> 4]);
|
||||
SS += (hex[(*b & 0x0f)]);
|
||||
std::cout << SS << " ";
|
||||
l++;
|
||||
if((l % 16) == 0)
|
||||
std::cout << std::endl;
|
||||
b++;
|
||||
--s;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
#define SOCKET_DEBUG(X,Y,Z) { std::cout << __func__ << ":" << __LINE__ << std::endl; (Z)=socket_.sendBytes(X,Y); dump(X,Y); }
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
inline Poco::Logger & RTTY_Device_ConnectionHandler::Logger() { return RTTYS_server()->Logger(); }
|
||||
|
||||
RTTY_Device_ConnectionHandler::RTTY_Device_ConnectionHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor & reactor):
|
||||
RTTYS_Device_ConnectionHandler::RTTYS_Device_ConnectionHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor & reactor):
|
||||
socket_(socket),
|
||||
reactor_(reactor),
|
||||
inBuf_(RTTY_DEVICE_BUFSIZE){
|
||||
std::thread T([=]() { CompleteConnection(); });
|
||||
T.detach();
|
||||
Logger_(Poco::Logger::get(fmt::format("RTTY-device({})",socket_.peerAddress().toString())))
|
||||
{
|
||||
// std::thread T([=]() { CompleteConnection(); });
|
||||
// T.detach();
|
||||
CompleteConnection();
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::CompleteConnection() {
|
||||
void RTTYS_Device_ConnectionHandler::CompleteConnection() {
|
||||
try {
|
||||
valid_=true;
|
||||
device_address_ = socket_.peerAddress();
|
||||
if (MicroService::instance().NoAPISecurity()) {
|
||||
Logger().information(
|
||||
fmt::format("{}: Unsecured connection.", device_address_.toString()));
|
||||
} else {
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl *>(socket_.impl());
|
||||
while (true) {
|
||||
auto V = SS->completeHandshake();
|
||||
if (V == 1)
|
||||
break;
|
||||
}
|
||||
if ((SS->secure()))
|
||||
Logger().information(
|
||||
fmt::format("{}: Secure connection.", device_address_.toString()));
|
||||
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl *>(socket_.impl());
|
||||
while (true) {
|
||||
auto V = SS->completeHandshake();
|
||||
if (V == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((SS->secure())) {
|
||||
poco_information(Logger(), "Secure connection.");
|
||||
}
|
||||
|
||||
socket_.setBlocking(false);
|
||||
socket_.setKeepAlive(true);
|
||||
socket_.setNoDelay(true);
|
||||
|
||||
registered_=true;
|
||||
reactor_.addEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTY_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTY_Device_ConnectionHandler::onSocketReadable));
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketReadable));
|
||||
reactor_.addEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTY_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTY_Device_ConnectionHandler::onSocketShutdown));
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketShutdown));
|
||||
} catch (...) {
|
||||
Logger().information(
|
||||
fmt::format("{}: Device cause exception while completing connection.", device_address_.toString()));
|
||||
delete this;
|
||||
poco_warning(Logger(), "Device caused exception while completing connection.");
|
||||
std::unique_lock G(M_);
|
||||
EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
RTTYS_Device_ConnectionHandler::~RTTYS_Device_ConnectionHandler() {
|
||||
poco_information(Logger_,
|
||||
fmt::format("Device {} session ending", id_)
|
||||
);
|
||||
DeRegister();
|
||||
}
|
||||
|
||||
RTTY_Device_ConnectionHandler::~RTTY_Device_ConnectionHandler() {
|
||||
try {
|
||||
void RTTYS_Device_ConnectionHandler::DeRegister() {
|
||||
if(registered_) {
|
||||
registered_ = false;
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTY_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTY_Device_ConnectionHandler::onSocketReadable));
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketReadable));
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTY_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTY_Device_ConnectionHandler::onSocketShutdown));
|
||||
|
||||
if (registered_) {
|
||||
Logger().information(fmt::format("{}: Deregistering.", device_address_.toString()));
|
||||
RTTYS_server()->DeRegisterDevice(id_, this, web_socket_active_);
|
||||
Logger().information(fmt::format("{}: Deregistered.", device_address_.toString()));
|
||||
}
|
||||
Logger().information(fmt::format("{}: Done.", device_address_.toString()));
|
||||
} catch (...) {
|
||||
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketShutdown));
|
||||
}
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::onSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
void RTTYS_Device_ConnectionHandler::EndConnection() {
|
||||
if(valid_) {
|
||||
valid_ = false;
|
||||
DeRegister();
|
||||
RTTYS_server()->NotifyDeviceDisconnect(id_, this);
|
||||
}
|
||||
}
|
||||
|
||||
[[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 ;
|
||||
}
|
||||
|
||||
void RTTYS_Device_ConnectionHandler::onSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
bool good = true;
|
||||
|
||||
if(!valid_ || !registered_)
|
||||
return;
|
||||
|
||||
std::unique_lock G(M_);
|
||||
try {
|
||||
auto received_bytes = socket_.receiveBytes(inBuf_);
|
||||
if(received_bytes==0) {
|
||||
// std::cout << "No data received" << std::endl;
|
||||
return delete this;
|
||||
if (received_bytes == 0) {
|
||||
poco_information(Logger(), fmt::format("{}: Device Closing connection - 0 bytes received.",id_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
// std::cout << "Received: " << received_bytes << std::endl;
|
||||
while (inBuf_.isReadable() && good) {
|
||||
std::size_t msg_len;
|
||||
u_char header[3]{0};
|
||||
inBuf_.read((char *)&header[0], 3);
|
||||
last_command_ = header[0];
|
||||
msg_len = header[1] * 256 + header[2];
|
||||
uint32_t msg_len = 0;
|
||||
if (waiting_for_bytes_ != 0) {
|
||||
|
||||
} else {
|
||||
if (inBuf_.used() >= RTTY_HDR_SIZE) {
|
||||
auto *head = (unsigned char *)inBuf_.begin();
|
||||
last_command_ = head[0];
|
||||
msg_len = head[1] * 256 + head[2];
|
||||
inBuf_.drain(RTTY_HDR_SIZE);
|
||||
} else {
|
||||
good = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (last_command_) {
|
||||
case msgTypeRegister: {
|
||||
@@ -126,114 +180,150 @@ namespace OpenWifi {
|
||||
case msgTypeMax: {
|
||||
good = do_msgTypeMax(msg_len);
|
||||
} break;
|
||||
default:
|
||||
Logger().warning(fmt::format("{}: ID:{} Unknown command {}", conn_id_, id_,
|
||||
(int)last_command_));
|
||||
default: {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("{}: Unknown command {} from device. GW closing connection.", id_,
|
||||
(int)last_command_));
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
} 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 delete this;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::onSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
void RTTY_Device_ConnectionHandler::Stop() {
|
||||
running_ = false;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::SendToClient(const u_char *Buf, int Len) {
|
||||
return RTTYS_server()->SendToClient(id_, Buf, Len);
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::SendToClient(const std::string &S) {
|
||||
return RTTYS_server()->SendToClient(id_, S);
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::KeyStrokes(const u_char *buf, size_t len) {
|
||||
std::lock_guard G(M_);
|
||||
|
||||
if(len>(RTTY_DEVICE_BUFSIZE-5))
|
||||
return false;
|
||||
|
||||
auto total_len = 3 + 1 + len-1;
|
||||
scratch_[0] = msgTypeTermData;
|
||||
scratch_[1] = (len & 0xff00) >> 8 ;
|
||||
scratch_[2] = (len & 0x00ff) ;
|
||||
scratch_[3] = sid_;
|
||||
memcpy( &scratch_[4], &buf[1], len-1);
|
||||
try {
|
||||
socket_.sendBytes((const void *)&scratch_[0], total_len);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
if(!good) {
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::WindowSize(int cols, int rows) {
|
||||
std::lock_guard G(M_);
|
||||
void RTTYS_Device_ConnectionHandler::onSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
poco_information(Logger(),fmt::format("{}: Connection being closed - socket shutdown.",id_));
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
u_char outBuf[8]{0};
|
||||
bool RTTYS_Device_ConnectionHandler::SendToClient(const u_char *Buf, int Len) {
|
||||
u_char bb[64000]{0};
|
||||
if(old_rtty_) {
|
||||
bb[0] = session_id_[0];
|
||||
memcpy(&bb[1],Buf,Len);
|
||||
} else {
|
||||
bb[0] = 0;
|
||||
memcpy(&bb[1],Buf,Len);
|
||||
}
|
||||
return RTTYS_server()->SendToClient(id_, Buf, Len );
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::SendToClient(const std::string &S) {
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
return RTTYS_server()->SendToClient(id_,S);
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::KeyStrokes(const u_char *buf, size_t len) {
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
if(len<=(sizeof(small_buf_)-RTTY_HDR_SIZE-session_length_)) {
|
||||
small_buf_[0] = msgTypeTermData;
|
||||
small_buf_[1] = ((len-1+session_length_) & 0xff00) >> 8;
|
||||
small_buf_[2] = ((len-1+session_length_) & 0x00ff);
|
||||
memcpy(&small_buf_[RTTY_HDR_SIZE],session_id_,session_length_);
|
||||
memcpy(&small_buf_[RTTY_HDR_SIZE+session_length_], &buf[1], len-1);
|
||||
try {
|
||||
auto Sent = socket_.sendBytes(small_buf_, RTTY_HDR_SIZE + session_length_ + len - 1);
|
||||
return (Sent==(int)(RTTY_HDR_SIZE + session_length_ + len - 1));
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
auto Msg = std::make_unique<unsigned char []>(len + RTTY_HDR_SIZE + session_length_);
|
||||
Msg.get()[0] = msgTypeTermData;
|
||||
Msg.get()[1] = ((len-1+session_length_) & 0xff00) >> 8;
|
||||
Msg.get()[2] = ((len-1+session_length_) & 0x00ff);
|
||||
memcpy((Msg.get()+RTTY_HDR_SIZE),session_id_,session_length_);
|
||||
memcpy((Msg.get()+RTTY_HDR_SIZE+session_length_), &buf[1], len-1);
|
||||
try {
|
||||
auto Sent = socket_.sendBytes(Msg.get(), RTTY_HDR_SIZE + session_length_ + len - 1);
|
||||
return (Sent==(int)( RTTY_HDR_SIZE + session_length_ + len - 1));
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::WindowSize(int cols, int rows) {
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
u_char outBuf[8+RTTY_SESSION_ID_LENGTH]{0};
|
||||
outBuf[0] = msgTypeWinsize;
|
||||
outBuf[1] = 0 ;
|
||||
outBuf[2] = 4 + 1 ;
|
||||
outBuf[3] = sid_;
|
||||
outBuf[4] = cols >> 8 ;
|
||||
outBuf[5] = cols & 0x00ff;
|
||||
outBuf[6] = rows >> 8;
|
||||
outBuf[7] = rows & 0x00ff;
|
||||
outBuf[2] = 4 + session_length_ ;
|
||||
memcpy(&outBuf[RTTY_HDR_SIZE],session_id_,session_length_);
|
||||
outBuf[RTTY_HDR_SIZE+0+session_length_] = cols >> 8 ;
|
||||
outBuf[RTTY_HDR_SIZE+1+session_length_] = cols & 0x00ff;
|
||||
outBuf[RTTY_HDR_SIZE+2+session_length_] = rows >> 8;
|
||||
outBuf[RTTY_HDR_SIZE+3+session_length_] = rows & 0x00ff;
|
||||
try {
|
||||
socket_.sendBytes(outBuf, 8);
|
||||
return true;
|
||||
auto Sent = socket_.sendBytes(outBuf, RTTY_HDR_SIZE + 4 + session_length_ );
|
||||
return (Sent==(int)(RTTY_HDR_SIZE + 4 + session_length_));
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::Login() {
|
||||
std::lock_guard G(M_);
|
||||
u_char outBuf[3]{0};
|
||||
bool RTTYS_Device_ConnectionHandler::Login() {
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
u_char outBuf[RTTY_HDR_SIZE+RTTY_SESSION_ID_LENGTH]{0};
|
||||
outBuf[0] = msgTypeLogin;
|
||||
outBuf[1] = 0;
|
||||
outBuf[2] = 0;
|
||||
if(old_rtty_) {
|
||||
outBuf[2] = 0;
|
||||
} else {
|
||||
outBuf[2] = RTTY_SESSION_ID_LENGTH;
|
||||
std::strncpy(session_id_,Utils::ComputeHash(id_,token_).substr(0,RTTY_SESSION_ID_LENGTH/2).c_str(),RTTY_SESSION_ID_LENGTH);
|
||||
memcpy(&outBuf[RTTY_HDR_SIZE],session_id_,RTTY_SESSION_ID_LENGTH);
|
||||
}
|
||||
try {
|
||||
socket_.sendBytes(outBuf, 3);
|
||||
poco_information(Logger(),fmt::format("{}: Device login", id_));
|
||||
auto Sent = socket_.sendBytes( outBuf, RTTY_HDR_SIZE + (old_rtty_ ? 0 : RTTY_SESSION_ID_LENGTH));
|
||||
return Sent==(int)(RTTY_HDR_SIZE + (old_rtty_ ? 0 : RTTY_SESSION_ID_LENGTH));
|
||||
} 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;
|
||||
}
|
||||
received_login_from_websocket_ = true;
|
||||
Logger().debug(fmt::format("{}: Device {} login", conn_id_, id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::Logout() {
|
||||
std::lock_guard G(M_);
|
||||
u_char outBuf[4]{0};
|
||||
bool RTTYS_Device_ConnectionHandler::Logout() {
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
u_char outBuf[4+RTTY_SESSION_ID_LENGTH]{0};
|
||||
outBuf[0] = msgTypeLogout;
|
||||
outBuf[1] = 0;
|
||||
outBuf[2] = 1;
|
||||
outBuf[3] = sid_;
|
||||
Logger().debug(fmt::format("{}: ID:{} Logout", conn_id_, id_));
|
||||
outBuf[2] = session_length_;
|
||||
memcpy(&outBuf[3],session_id_,session_length_);
|
||||
poco_information(Logger(),fmt::format("{}: Logout", id_));
|
||||
try {
|
||||
socket_.sendBytes(outBuf, 4);
|
||||
return true;
|
||||
auto Sent = socket_.sendBytes(outBuf, RTTY_HDR_SIZE + session_length_);
|
||||
return Sent==(int)(RTTY_HDR_SIZE+session_length_);
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string RTTY_Device_ConnectionHandler::ReadString() {
|
||||
std::string RTTYS_Device_ConnectionHandler::ReadString() {
|
||||
std::string Res;
|
||||
|
||||
while(inBuf_.used()) {
|
||||
@@ -248,37 +338,38 @@ namespace OpenWifi {
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::do_msgTypeRegister([[maybe_unused]] std::size_t msg_len) {
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeRegister([[maybe_unused]] std::size_t msg_len) {
|
||||
bool good = true;
|
||||
try {
|
||||
// establish if this is an old rtty or a new one.
|
||||
old_rtty_ = (inBuf_[0] != 0x03); // rtty_proto_ver for full session ID inclusion
|
||||
if(old_rtty_) {
|
||||
session_length_ = 1;
|
||||
} else {
|
||||
inBuf_.drain(1); // remove protocol if used.
|
||||
session_length_ = RTTY_SESSION_ID_LENGTH;
|
||||
}
|
||||
|
||||
id_ = ReadString();
|
||||
desc_ = ReadString();
|
||||
token_ = ReadString();
|
||||
serial_ = RTTYS_server()->SerialNumber(id_);
|
||||
|
||||
Logger().debug(fmt::format("{}: ID:{} Serial:{} Description:{} Device registration",
|
||||
conn_id_, id_, serial_, desc_));
|
||||
if (RTTYS_server()->Register(id_, token_, this)) {
|
||||
u_char OutBuf[8];
|
||||
OutBuf[0] = msgTypeRegister;
|
||||
OutBuf[1] = 0;
|
||||
OutBuf[2] = 4;
|
||||
OutBuf[3] = 0;
|
||||
OutBuf[4] = 'O';
|
||||
OutBuf[5] = 'K';
|
||||
OutBuf[6] = 0;
|
||||
if (socket_.sendBytes(OutBuf, 7) != 7) {
|
||||
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; // Data length
|
||||
OutBuf[2] = 4; //
|
||||
OutBuf[3] = 0; // Error
|
||||
OutBuf[4] = 'O';
|
||||
OutBuf[5] = 'K';
|
||||
OutBuf[6] = 0;
|
||||
if (socket_.sendBytes(OutBuf, 7) != 7) {
|
||||
poco_information(Logger(),
|
||||
fmt::format("{}: Description:{} Could not send data to complete registration",
|
||||
id_, desc_));
|
||||
good = false;
|
||||
Logger().debug(fmt::format(
|
||||
"{}: ID:{} Serial:{} Description:{} Could not complete registration",
|
||||
conn_id_, id_, serial_, desc_));
|
||||
} else {
|
||||
registered_ = true;
|
||||
}
|
||||
} else {
|
||||
Logger().debug(fmt::format(
|
||||
"{}: ID:{} Serial:{} Description:{} Could not complete registration", conn_id_,
|
||||
id_, serial_, desc_));
|
||||
}
|
||||
} catch (...) {
|
||||
good = false;
|
||||
@@ -286,81 +377,106 @@ namespace OpenWifi {
|
||||
return good;
|
||||
}
|
||||
|
||||
bool 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);
|
||||
inBuf_.read(&sid_, 1);
|
||||
if(old_rtty_) {
|
||||
inBuf_.read(&Error, 1);
|
||||
inBuf_.read(&session_id_[0], session_length_);
|
||||
} else {
|
||||
char session[RTTY_SESSION_ID_LENGTH+1]{0};
|
||||
inBuf_.read(&session[0], session_length_);
|
||||
inBuf_.read(&Error, 1);
|
||||
}
|
||||
doc["type"] = "login";
|
||||
doc["err"] = Error;
|
||||
const auto login_msg = to_string(doc);
|
||||
web_socket_active_ = true ;
|
||||
return SendToClient(login_msg);
|
||||
}
|
||||
|
||||
bool 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_));
|
||||
return true;
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeLogout([[maybe_unused]] std::size_t msg_len) {
|
||||
char session[RTTY_SESSION_ID_LENGTH];
|
||||
if(old_rtty_) {
|
||||
inBuf_.read(&session[0],1);
|
||||
} else {
|
||||
inBuf_.read(&session[0],RTTY_SESSION_ID_LENGTH);
|
||||
}
|
||||
poco_information(Logger(),fmt::format("{}: Logout", id_));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::do_msgTypeTermData(std::size_t msg_len) {
|
||||
bool good = false;
|
||||
if(waiting_for_bytes_!=0) {
|
||||
auto to_read = std::min(inBuf_.used(),waiting_for_bytes_);
|
||||
inBuf_.read(&scratch_[0], to_read);
|
||||
good = SendToClient((u_char *)&scratch_[0], (int) to_read);
|
||||
if(to_read<waiting_for_bytes_)
|
||||
waiting_for_bytes_ -= to_read;
|
||||
else
|
||||
waiting_for_bytes_ = 0 ;
|
||||
} else {
|
||||
if(inBuf_.used()<msg_len) {
|
||||
auto read_count = inBuf_.read(&scratch_[0], inBuf_.used());
|
||||
good = SendToClient((u_char *)&scratch_[0], read_count);
|
||||
waiting_for_bytes_ = msg_len - read_count;
|
||||
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());
|
||||
inBuf_.drain();
|
||||
} else {
|
||||
inBuf_.read(&scratch_[0], msg_len);
|
||||
good = SendToClient((u_char *)&scratch_[0], (int)msg_len);
|
||||
waiting_for_bytes_=0;
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), waiting_for_bytes_);
|
||||
inBuf_.drain(waiting_for_bytes_);
|
||||
waiting_for_bytes_ = 0 ;
|
||||
}
|
||||
} else {
|
||||
if(old_rtty_) {
|
||||
inBuf_.drain(1);
|
||||
msg_len -= 1;
|
||||
} else {
|
||||
inBuf_.drain(RTTY_SESSION_ID_LENGTH);
|
||||
msg_len -= RTTY_SESSION_ID_LENGTH;
|
||||
}
|
||||
if(inBuf_.used()<msg_len) {
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), inBuf_.used());
|
||||
waiting_for_bytes_ = msg_len - inBuf_.used();
|
||||
inBuf_.drain();
|
||||
} else {
|
||||
waiting_for_bytes_ = 0 ;
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), msg_len);
|
||||
inBuf_.drain(msg_len);
|
||||
}
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
bool RTTY_Device_ConnectionHandler::do_msgTypeHeartbeat([[maybe_unused]] std::size_t msg_len) {
|
||||
u_char MsgBuf[3]{0};
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeHeartbeat([[maybe_unused]] std::size_t msg_len) {
|
||||
u_char MsgBuf[RTTY_HDR_SIZE + 16]{0};
|
||||
if(msg_len)
|
||||
inBuf_.drain(msg_len);
|
||||
MsgBuf[0] = msgTypeHeartbeat;
|
||||
return socket_.sendBytes(MsgBuf, 3)==3;
|
||||
MsgBuf[1] = 0;
|
||||
MsgBuf[2] = 0;
|
||||
auto Sent = socket_.sendBytes(MsgBuf, RTTY_HDR_SIZE);
|
||||
return Sent == RTTY_HDR_SIZE;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <shared_mutex>
|
||||
#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;
|
||||
constexpr std::size_t RTTY_SESSION_ID_LENGTH=32;
|
||||
constexpr std::size_t RTTY_HDR_SIZE=3;
|
||||
|
||||
inline static std::atomic_uint64_t global_device_connection_id = 1;
|
||||
|
||||
class RTTY_Device_ConnectionHandler{
|
||||
class RTTYS_Device_ConnectionHandler{
|
||||
public:
|
||||
enum RTTY_MSG_TYPE {
|
||||
msgTypeRegister = 0,
|
||||
@@ -30,51 +31,48 @@ namespace OpenWifi {
|
||||
msgTypeAck,
|
||||
msgTypeMax };
|
||||
|
||||
explicit RTTY_Device_ConnectionHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor& reactor);
|
||||
|
||||
~RTTY_Device_ConnectionHandler();
|
||||
explicit RTTYS_Device_ConnectionHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor& reactor);
|
||||
~RTTYS_Device_ConnectionHandler();
|
||||
|
||||
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_; }
|
||||
// inline auto SessionID() const { return conn_id_; }
|
||||
|
||||
void onSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void onSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);
|
||||
|
||||
bool Connected() const { return received_login_from_websocket_; }
|
||||
inline Poco::Logger &Logger() { return Logger_; }
|
||||
inline bool Valid() { return valid_; }
|
||||
|
||||
private:
|
||||
Poco::Net::StreamSocket socket_;
|
||||
Poco::Net::SocketReactor &reactor_;
|
||||
Poco::FIFOBuffer inBuf_{RTTY_DEVICE_BUFSIZE};
|
||||
Poco::Logger &Logger_;
|
||||
|
||||
mutable std::atomic_bool running_=false;
|
||||
std::atomic_bool valid_=false;
|
||||
bool old_rtty_=true;
|
||||
Poco::Net::SocketAddress device_address_;
|
||||
std::recursive_mutex M_;
|
||||
std::shared_mutex M_;
|
||||
std::string id_;
|
||||
std::string token_;
|
||||
std::string desc_;
|
||||
std::string serial_;
|
||||
char sid_=0;
|
||||
mutable std::atomic_bool registered_=false;
|
||||
mutable std::atomic_bool web_socket_active_=false;
|
||||
|
||||
Poco::FIFOBuffer inBuf_;
|
||||
std::array<char,RTTY_DEVICE_BUFSIZE> scratch_{0};
|
||||
char session_id_[RTTY_SESSION_ID_LENGTH+1]{0};
|
||||
std::uint64_t session_length_=1;
|
||||
std::size_t waiting_for_bytes_{0};
|
||||
u_char last_command_=0;
|
||||
uint64_t conn_id_=0;
|
||||
mutable std::atomic_bool received_login_from_websocket_=false;
|
||||
std::atomic_bool registered_=false;
|
||||
unsigned char small_buf_[64+RTTY_SESSION_ID_LENGTH];
|
||||
|
||||
void EndConnection() ;
|
||||
void CompleteConnection();
|
||||
|
||||
Poco::Logger & Logger();
|
||||
void DeRegister();
|
||||
|
||||
[[nodiscard]] bool do_msgTypeRegister(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeLogin(std::size_t msg_len);
|
||||
|
||||
@@ -16,23 +16,19 @@ namespace OpenWifi {
|
||||
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");
|
||||
MaxConcurrentSessions_ = MicroService::instance().ConfigGetInt("rtty.maxsessions",0);
|
||||
|
||||
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 TcpServerParams = new Poco::Net::TCPServerParams();
|
||||
TcpServerParams->setMaxThreads(50);
|
||||
TcpServerParams->setMaxQueued(100);
|
||||
TcpServerParams->setThreadIdleTime(Poco::Timespan(10,0));
|
||||
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Poco::Net::ServerSocket DeviceSocket(DSport, 64);
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::SocketAcceptor<RTTY_Device_ConnectionHandler>>(DeviceSocket,DeviceReactor_);
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>>(DeviceSocket,DeviceReactor_);
|
||||
} else {
|
||||
auto DeviceSecureContext = new Poco::Net::Context(Poco::Net::Context::SERVER_USE,
|
||||
auto DeviceSecureContext = Poco::AutoPtr<Poco::Net::Context>( new Poco::Net::Context(Poco::Net::Context::SERVER_USE,
|
||||
KeyFileName, CertFileName, "",
|
||||
Poco::Net::Context::VERIFY_RELAXED);
|
||||
Poco::Net::Context::VERIFY_RELAXED));
|
||||
Poco::Crypto::X509Certificate DeviceRoot(RootCa);
|
||||
DeviceSecureContext->addCertificateAuthority(DeviceRoot);
|
||||
DeviceSecureContext->disableStatelessSessionResumption();
|
||||
@@ -44,7 +40,7 @@ namespace OpenWifi {
|
||||
SSL_CTX_dane_enable(SSLCtxDevice);
|
||||
|
||||
Poco::Net::SecureServerSocket DeviceSocket(DSport, 64, DeviceSecureContext);
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::SocketAcceptor<RTTY_Device_ConnectionHandler>>(DeviceSocket,DeviceReactor_);
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>>(DeviceSocket,DeviceReactor_);
|
||||
}
|
||||
DeviceReactorThread_.start(DeviceReactor_);
|
||||
Utils::SetThreadName(DeviceReactorThread_,"rt:devreactor");
|
||||
@@ -53,11 +49,12 @@ namespace OpenWifi {
|
||||
WebServerHttpParams->setMaxThreads(50);
|
||||
WebServerHttpParams->setMaxQueued(200);
|
||||
WebServerHttpParams->setKeepAlive(true);
|
||||
WebServerHttpParams->setName("rt:dispatch");
|
||||
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Poco::Net::ServerSocket ClientSocket(CSport, 64);
|
||||
ClientSocket.setNoDelay(true);
|
||||
WebServer_ = std::make_unique<Poco::Net::HTTPServer>(new RTTY_Client_RequestHandlerFactory(Logger()), ClientSocket, WebServerHttpParams);
|
||||
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);
|
||||
@@ -73,7 +70,7 @@ namespace OpenWifi {
|
||||
|
||||
Poco::Net::SecureServerSocket ClientSocket(CSport, 64, WebClientSecureContext);
|
||||
ClientSocket.setNoDelay(true);
|
||||
WebServer_ = std::make_unique<Poco::Net::HTTPServer>(new RTTY_Client_RequestHandlerFactory(Logger()), ClientSocket, WebServerHttpParams);
|
||||
WebServer_ = std::make_unique<Poco::Net::HTTPServer>(new RTTYS_Client_RequestHandlerFactory(Logger()), ClientSocket, WebServerHttpParams);
|
||||
};
|
||||
WebServer_->start();
|
||||
ClientReactorThread_.start(ClientReactor_);
|
||||
@@ -81,314 +78,205 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
GCCallBack_ = std::make_unique<Poco::TimerCallback<RTTYS_server>>(*this, &RTTYS_server::onTimer);
|
||||
Timer_.setStartInterval(10 * 1000); // first run in 30 seconds
|
||||
Timer_.setPeriodicInterval(1 * 60 * 1000);
|
||||
Timer_.start(*GCCallBack_);
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 30 seconds
|
||||
Timer_.setPeriodicInterval(5 * 1000);
|
||||
Timer_.start(*GCCallBack_, MicroService::instance().TimerPool() );
|
||||
NotificationManager_.start(*this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RTTYS_server::Stop() {
|
||||
Timer_.stop();
|
||||
if(Internal_) {
|
||||
Timer_.stop();
|
||||
WebServer_->stopAll();
|
||||
DeviceAcceptor_->unregisterAcceptor();
|
||||
DeviceReactor_.stop();
|
||||
DeviceReactorThread_.join();
|
||||
ResponseQueue_.wakeUpAll();
|
||||
NotificationManager_.wakeUp();
|
||||
NotificationManager_.join();
|
||||
WebServer_->stopAll(true);
|
||||
WebServer_->stop();
|
||||
ClientReactor_.stop();
|
||||
ClientReactorThread_.join();
|
||||
DeviceReactor_.stop();
|
||||
DeviceAcceptor_->unregisterAcceptor();
|
||||
DeviceReactorThread_.join();
|
||||
NotificationManagerRunning_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::onTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
Logger().debug("Removing stale connections.");
|
||||
std::lock_guard G(Mutex_);
|
||||
poco_trace(Logger(),"Removing stale connections.");
|
||||
Utils::SetThreadName("rt:janitor");
|
||||
// Logger().debug(fmt::format("Current: connections:{} threads:{}.", DeviceAcceptor_->currentConnections(), DeviceAcceptor_->currentThreads()));
|
||||
auto now = OpenWifi::Now();
|
||||
dump("GC ", std::cout);
|
||||
for(auto element=EndPoints_.begin();element!=EndPoints_.end();) {
|
||||
if( element->second.ShutdownComplete ||
|
||||
(element->second.ShuttingDown && (now-element->second.TimeStamp>600))) {
|
||||
static auto LastStats = OpenWifi::Now();
|
||||
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
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;
|
||||
}
|
||||
}
|
||||
dump("GC ", std::cout);
|
||||
FailedDevices.clear();
|
||||
FailedClients.clear();
|
||||
|
||||
if(Now()-LastStats>(60*5)) {
|
||||
LastStats = Now();
|
||||
Logger().information(fmt::format("Statistics: Total connections:{} Total Device Connection Time: {}s Total Client Connection Time: {}s Device failures: {} Client failures: {}",
|
||||
TotalEndPoints_,
|
||||
TotalConnectedDeviceTime_,
|
||||
TotalConnectedClientTime_,
|
||||
FailedNumDevices_,
|
||||
FailedNumClients_));
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::Register(const std::string &Id, RTTYS_ClientConnection *Client) {
|
||||
std::lock_guard G(Mutex_);
|
||||
dump("C REG--> ", std::cout);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end()) {
|
||||
It->second.Client = Client;
|
||||
It->second.ClientConnected = OpenWifi::Now();
|
||||
dump("C REG--> ", std::cout);
|
||||
}
|
||||
dump("C Already REG--> ", std::cout);
|
||||
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);
|
||||
}
|
||||
|
||||
bool RTTYS_server::Register(const std::string &Id, const std::string &Token, RTTY_Device_ConnectionHandler *Device) {
|
||||
std::lock_guard G(Mutex_);
|
||||
dump("D REG--> ", std::cout);
|
||||
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));
|
||||
dump("D REG--> ", std::cout);
|
||||
return true;
|
||||
void RTTYS_server::run() {
|
||||
Utils::SetThreadName("rt:manager");
|
||||
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 Lock(LocalMutex_);
|
||||
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: {
|
||||
It->second->SetDevice(Notification->device_);
|
||||
if(!It->second->Joined() && It->second->ValidClient()) {
|
||||
It->second->Join();
|
||||
It->second->Login();
|
||||
}
|
||||
} break;
|
||||
case RTTYS_Notification_type::client_registration: {
|
||||
It->second->SetClient(Notification->client_);
|
||||
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) {
|
||||
FailedNumDevices_++;
|
||||
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();
|
||||
}
|
||||
dump("D Already REG--> ", std::cout);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendToClient(const std::string &Id, const u_char *Buf, std::size_t Len) {
|
||||
std::lock_guard G(Mutex_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
try {
|
||||
auto It = EndPoints_.find(Id);
|
||||
if (It != EndPoints_.end() && It->second.Client != nullptr) {
|
||||
It->second.Client->SendData(Buf, Len);
|
||||
return true;
|
||||
if (It != EndPoints_.end() && It->second!=nullptr) {
|
||||
return It->second->SendToClient(Buf,Len);
|
||||
}
|
||||
} catch(...) {
|
||||
|
||||
} 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(Mutex_);
|
||||
try {
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Client!= nullptr) {
|
||||
It->second.Client->SendData(s);
|
||||
return true;
|
||||
}
|
||||
} catch(...) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
try {
|
||||
auto It = EndPoints_.find(Id);
|
||||
if (It != EndPoints_.end() && It->second!=nullptr) {
|
||||
return It->second->SendToClient(s);
|
||||
}
|
||||
} 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, RTTYS_ClientConnection *Client) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Logger().information("{}: Deregistering.", Client->ID());
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Client==Client) {
|
||||
if(It->second.Device!= nullptr) {
|
||||
if(!It->second.ShuttingDown) {
|
||||
It->second.ShuttingDown = true;
|
||||
if(It->second.Device!= nullptr)
|
||||
It->second.Device->Stop();
|
||||
} else {
|
||||
It->second.ShutdownComplete = true;
|
||||
}
|
||||
} else {
|
||||
if(!It->second.ShuttingDown) {
|
||||
It->second.ShuttingDown = true;
|
||||
} else {
|
||||
It->second.ShutdownComplete = true;
|
||||
}
|
||||
}
|
||||
It->second.ClientConnected=0;
|
||||
It->second.Client= nullptr;
|
||||
}
|
||||
Logger().information("{}: Deregistered.", Client->ID());
|
||||
}
|
||||
bool RTTYS_server::SendKeyStrokes(const std::string &Id, const u_char *buffer, std::size_t len) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
void RTTYS_server::DeRegisterDevice(const std::string &Id, RTTY_Device_ConnectionHandler *Device, bool remove_websocket) {
|
||||
std::lock_guard G(Mutex_);
|
||||
dump("D DEREG--> ", std::cout);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Device==Device) {
|
||||
It->second.Device = nullptr;
|
||||
It->second.DeviceConnected = 0 ;
|
||||
if(It->second.Client!=nullptr) {
|
||||
if(remove_websocket) {
|
||||
It->second.ShuttingDown = true;
|
||||
if(It->second.Client!= nullptr)
|
||||
It->second.Client->Close();
|
||||
}
|
||||
/* if(!It->second.ShuttingDown) {
|
||||
It->second.ShuttingDown = true;
|
||||
It->second.Client->Close();
|
||||
} else {
|
||||
It->second.ShutdownComplete = true;
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
if(!It->second.ShuttingDown) {
|
||||
It->second.ShuttingDown = true;
|
||||
} else {
|
||||
It->second.ShutdownComplete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger().information(fmt::format("{}: Deregistering device.", Device->SessionID()));
|
||||
if(Device!= nullptr) {
|
||||
for (auto i = EndPoints_.begin(); i != EndPoints_.end(); i++) {
|
||||
if (i->second.Device == Device) {
|
||||
EndPoints_.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
dump("D DEREG--> ", std::cout);
|
||||
}
|
||||
Logger().information(fmt::format("{}: Deregistered device.", Device->SessionID()));
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendKeyStrokes(const std::string &Id, const u_char *buffer, std::size_t s) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It=EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
if(It==EndPoints_.end() || It->second==nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (It->second.Device != nullptr)
|
||||
return It->second.Device->KeyStrokes(buffer, s);
|
||||
auto res = It->second->KeyStrokes(buffer, len);
|
||||
return res;
|
||||
} 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(Mutex_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
auto It=EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
if(It==EndPoints_.end() || It->second==nullptr) {
|
||||
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(Mutex_);
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
|
||||
EndPoint E;
|
||||
E.ShuttingDown = false;
|
||||
E.Token = Token;
|
||||
E.TimeStamp = OpenWifi::Now();
|
||||
E.SerialNumber = SerialNumber;
|
||||
E.UserName = UserName;
|
||||
EndPoints_[Id] = E;
|
||||
if(MaxConcurrentSessions_!=0 && EndPoints_.size()==MaxConcurrentSessions_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EndPoints_[Id] = std::make_unique<RTTYS_EndPoint>(Token, SerialNumber, UserName );
|
||||
++TotalEndPoints_;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string RTTYS_server::SerialNumber(const std::string & Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end())
|
||||
return "";
|
||||
return It->second.SerialNumber;
|
||||
}
|
||||
|
||||
bool RTTYS_server::ValidId(const std::string &Token) {
|
||||
std::lock_guard G(Mutex_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
return EndPoints_.find(Token) != EndPoints_.end();
|
||||
}
|
||||
|
||||
void RTTYS_server::LoginDone(const std::string & Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
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(Mutex_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
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(Mutex_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It!=EndPoints_.end() && It->second.Client==Conn) {
|
||||
It->second.ClientConnected = OpenWifi::Now();
|
||||
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(Mutex_);
|
||||
|
||||
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()) {
|
||||
return 0;
|
||||
} else {
|
||||
if(it->second.Device== nullptr) {
|
||||
return 0;
|
||||
} else {
|
||||
return it->second.Device->SessionID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RTTYS_server::Login(const std::string & Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It == 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();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::Logout(const std::string & Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
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(Mutex_);
|
||||
|
||||
auto It = EndPoints_.find(Id);
|
||||
if(It == EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(It->second.Device!= nullptr)
|
||||
It->second.Device->Stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,205 @@
|
||||
#include "Poco/Net/SocketAcceptor.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(RTTYS_ClientConnection *Client) {
|
||||
ClientConnected_ = std::chrono::high_resolution_clock::now();
|
||||
Client_ = std::unique_ptr<RTTYS_ClientConnection>(Client);
|
||||
}
|
||||
|
||||
inline void SetDevice(RTTYS_Device_ConnectionHandler* Device) {
|
||||
DeviceConnected_ = std::chrono::high_resolution_clock::now();
|
||||
Device_ = std::unique_ptr<RTTYS_Device_ConnectionHandler>(Device);
|
||||
}
|
||||
|
||||
inline bool Login() {
|
||||
if(Device_!= nullptr) {
|
||||
return Device_->Login();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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_)>5s) {
|
||||
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_)>5s) {
|
||||
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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SendToClient(const u_char *Buf, std::size_t Len) {
|
||||
if(Client_!= nullptr && Client_->Valid()) {
|
||||
Client_->SendData(Buf,Len);
|
||||
return true;
|
||||
}
|
||||
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() {
|
||||
if(DeviceDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
DeviceDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
return std::chrono::duration<double>{DeviceDisconnected_ - DeviceConnected_}.count(); }
|
||||
|
||||
[[nodiscard]] inline auto TimeClientConnected() {
|
||||
if(ClientDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
ClientDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
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() {
|
||||
@@ -28,38 +220,33 @@ 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 DeRegisterDevice(const std::string &Id, RTTY_Device_ConnectionHandler *Device, bool remove_websocket);
|
||||
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 ValidId(const std::string &Id);
|
||||
|
||||
struct EndPoint {
|
||||
std::string Token;
|
||||
mutable RTTYS_ClientConnection * Client = nullptr;
|
||||
mutable RTTY_Device_ConnectionHandler * Device = nullptr;
|
||||
uint64_t TimeStamp = OpenWifi::Now();
|
||||
mutable uint64_t DeviceConnected = 0;
|
||||
mutable uint64_t ClientConnected = 0;
|
||||
std::string UserName;
|
||||
std::string SerialNumber;
|
||||
mutable bool ShuttingDown = false;
|
||||
mutable bool ShutdownComplete = 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);
|
||||
|
||||
@@ -67,32 +254,38 @@ namespace OpenWifi {
|
||||
return Internal_;
|
||||
}
|
||||
|
||||
inline void dump([[maybe_unused]] const char *ID, [[maybe_unused]] std::ostream &s) {
|
||||
/* for(const auto &[id,point]:EndPoints_) {
|
||||
s << ID << " ID: " << id << " C:" << (point.Client == nullptr) << " D:" << (point.Device== nullptr)
|
||||
<< " Shutting down: " << point.ShuttingDown
|
||||
<< " Shutdown: " << point.ShutdownComplete << std::endl;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
inline Poco::Net::SocketReactor & ClientReactor() { return ClientReactor_; }
|
||||
inline auto Uptime() const { return OpenWifi::Now() - Started_; }
|
||||
|
||||
private:
|
||||
// std::recursive_mutex M_;
|
||||
Poco::Net::SocketReactor ClientReactor_;
|
||||
Poco::Net::SocketReactor DeviceReactor_;
|
||||
Poco::Thread ClientReactorThread_;
|
||||
std::string RTTY_UIAssets_;
|
||||
std::atomic_bool Internal_ = false;
|
||||
Poco::Net::SocketReactor ClientReactor_;
|
||||
Poco::Net::SocketReactor DeviceReactor_;
|
||||
Poco::Thread ClientReactorThread_;
|
||||
std::string RTTY_UIAssets_;
|
||||
bool Internal_ = false;
|
||||
|
||||
std::map<std::string, EndPoint> EndPoints_; // id, endpoint
|
||||
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<RTTY_Device_ConnectionHandler>> DeviceAcceptor_;
|
||||
Poco::Thread DeviceReactorThread_;
|
||||
std::unique_ptr<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>> DeviceAcceptor_;
|
||||
Poco::Thread DeviceReactorThread_;
|
||||
Poco::NotificationQueue ResponseQueue_;
|
||||
std::atomic_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;
|
||||
std::shared_mutex LocalMutex_;
|
||||
|
||||
std::atomic_uint64_t TotalEndPoints_=0;
|
||||
std::atomic_uint64_t FailedNumDevices_=0;
|
||||
std::atomic_uint64_t FailedNumClients_=0;
|
||||
double TotalConnectedDeviceTime_=0.0;
|
||||
double TotalConnectedClientTime_=0.0;
|
||||
|
||||
std::atomic_uint64_t Started_=OpenWifi::Now();
|
||||
std::atomic_uint64_t MaxConcurrentSessions_=0;
|
||||
|
||||
explicit RTTYS_server() noexcept:
|
||||
SubSystemServer("RTTY_Server", "RTTY-SVR", "rtty.server")
|
||||
|
||||
52
src/sdks/sdk_prov.h
Normal file
52
src/sdks/sdk_prov.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-16.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_ProvObjects.h"
|
||||
|
||||
namespace OpenWifi::SDK::Prov {
|
||||
|
||||
inline bool GetSerialNumbersForVenueOfSerialNumber( const std::string & SerialNumber, Types::UUID_t &Venue, Types::StringVec & AdjacentSerialNumbers , Poco::Logger &Logger ) {
|
||||
OpenAPIRequestGet GetInventoryForSerialNumber( uSERVICE_PROVISIONING, "/api/v1/inventory/" + SerialNumber , {} , 30000);
|
||||
|
||||
auto CallResponse1 = Poco::makeShared<Poco::JSON::Object>();
|
||||
if(!GetInventoryForSerialNumber.Do(CallResponse1,"")) {
|
||||
Logger.error(fmt::format("{}: Cannot find serial number in inventory.", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
ProvObjects::InventoryTag Device;
|
||||
if(!Device.from_json(CallResponse1)) {
|
||||
Logger.error(fmt::format("{}: Invalid Inventory response.", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
Venue = Device.venue;
|
||||
|
||||
OpenAPIRequestGet GetInventoryForVenue( uSERVICE_PROVISIONING, "/api/v1/inventory" ,
|
||||
{
|
||||
{"serialOnly","true"},
|
||||
{"venue", Venue}
|
||||
}, 30000);
|
||||
|
||||
auto CallResponse2 = Poco::makeShared<Poco::JSON::Object>();
|
||||
if(!GetInventoryForVenue.Do(CallResponse2,"")) {
|
||||
Logger.error(fmt::format("{}: Cannot get inventory for venue.", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
OpenWifi::RESTAPI_utils::field_from_json(CallResponse2, "serialNumbers",
|
||||
AdjacentSerialNumbers);
|
||||
} catch(...) {
|
||||
Logger.error(fmt::format("{}: Cannot parse inventory list", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return true;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -99,7 +99,7 @@ namespace OpenWifi {
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ namespace OpenWifi {
|
||||
BlackListDevices.erase(SerialNumber);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -155,7 +155,7 @@ namespace OpenWifi {
|
||||
|
||||
return Select.rowsExtracted()==1;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning( fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -128,22 +128,16 @@ typedef Poco::Tuple<
|
||||
|
||||
bool Storage::AddCommand(std::string &SerialNumber, GWObjects::CommandDetails &Command, CommandExecutionType Type) {
|
||||
try {
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
|
||||
if(Type == COMMAND_PENDING) {
|
||||
Command.Status = "pending";
|
||||
} else if(Type == COMMAND_COMPLETED) {
|
||||
Command.Status = "completed";
|
||||
Command.Status = to_string(Type);
|
||||
if( Type==CommandExecutionType::COMMAND_COMPLETED ||
|
||||
Type==CommandExecutionType::COMMAND_TIMEDOUT ||
|
||||
Type==CommandExecutionType::COMMAND_FAILED ||
|
||||
Type==CommandExecutionType::COMMAND_EXPIRED ||
|
||||
Type==CommandExecutionType::COMMAND_EXECUTED
|
||||
) {
|
||||
Command.Executed = Now;
|
||||
} else if (Type == COMMAND_TIMEDOUT) {
|
||||
Command.Executed = Now;
|
||||
Command.Status = "timedout";
|
||||
} else if (Type == COMMAND_FAILED) {
|
||||
Command.Executed = Now;
|
||||
Command.Status = "failed";
|
||||
} else {
|
||||
Command.Executed = Now;
|
||||
Command.Status = "executing";
|
||||
}
|
||||
|
||||
RemoveOldCommands(SerialNumber, Command.Command);
|
||||
@@ -271,7 +265,7 @@ typedef Poco::Tuple<
|
||||
Offset++;
|
||||
GWObjects::CommandDetails R;
|
||||
ConvertCommandRecord(i,R);
|
||||
if (DeviceRegistry()->Connected(R.SerialNumber))
|
||||
if (DeviceRegistry()->Connected(Utils::SerialNumberToInt(R.SerialNumber)))
|
||||
Commands.push_back(R);
|
||||
}
|
||||
|
||||
@@ -317,11 +311,14 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
std::string St{"UPDATE CommandList SET Executed=? WHERE UUID=?"};
|
||||
auto Now = OpenWifi::Now();
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status=? WHERE UUID=?"};
|
||||
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use( CommandUUID);
|
||||
Update.execute();
|
||||
return true;
|
||||
@@ -331,7 +328,63 @@ typedef Poco::Tuple<
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetCommand(std::string &UUID, GWObjects::CommandDetails &Command) {
|
||||
void Storage::RemovedExpiredCommands() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = OpenWifi::Now(), Window = Now-(4*60*60);
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_EXPIRED);
|
||||
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status=? WHERE submitted<? and executed=0"};
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(Window);
|
||||
Update.execute();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::RemoveTimedOutCommands() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = OpenWifi::Now(), Window = Now-(1*60*60);
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status='timedout' WHERE Executed<? and completed=0"};
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Window);
|
||||
Update.execute();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
}
|
||||
|
||||
bool Storage::SetCommandTimedOut(std::string &CommandUUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = OpenWifi::Now();
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_TIMEDOUT);
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status=? WHERE UUID=?"};
|
||||
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(CommandUUID);
|
||||
Update.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetCommand(const std::string &UUID, GWObjects::CommandDetails &Command) {
|
||||
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
@@ -341,11 +394,11 @@ typedef Poco::Tuple<
|
||||
"SELECT " +
|
||||
DB_Command_SelectFields +
|
||||
" FROM CommandList WHERE UUID=?"};
|
||||
|
||||
auto tmp_uuid = UUID;
|
||||
CommandDetailsRecordTuple R;
|
||||
Select << ConvertParams(St),
|
||||
Poco::Data::Keywords::into(R),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Poco::Data::Keywords::use(tmp_uuid);
|
||||
ConvertCommandRecord(R,Command);
|
||||
Select.execute();
|
||||
return true;
|
||||
@@ -406,12 +459,12 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
std::string St{
|
||||
"SELECT " +
|
||||
DB_Command_SelectFields
|
||||
+ " FROM CommandList "
|
||||
" WHERE ((RunAt<=?) And (Executed=0)) ORDER BY UUID ASC "};
|
||||
" WHERE ((RunAt<=?) And (Executed=0)) ORDER BY Submitted ASC "};
|
||||
CommandDetailsRecordList Records;
|
||||
|
||||
std::string SS = ConvertParams(St) + ComputeRange(Offset, HowMany);
|
||||
@@ -423,7 +476,7 @@ typedef Poco::Tuple<
|
||||
for(const auto &i : Records) {
|
||||
GWObjects::CommandDetails R;
|
||||
ConvertCommandRecord(i,R);
|
||||
if (DeviceRegistry()->Connected(R.SerialNumber))
|
||||
if (DeviceRegistry()->Connected(Utils::SerialNumberToInt(R.SerialNumber)))
|
||||
Commands.push_back(R);
|
||||
}
|
||||
return true;
|
||||
@@ -435,7 +488,7 @@ typedef Poco::Tuple<
|
||||
|
||||
bool Storage::CommandExecuted(std::string &UUID) {
|
||||
try {
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
@@ -451,7 +504,6 @@ typedef Poco::Tuple<
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -460,7 +512,7 @@ typedef Poco::Tuple<
|
||||
bool FullCommand) {
|
||||
try {
|
||||
|
||||
uint64_t Now = FullCommand ? time(nullptr) : 0;
|
||||
auto Now = FullCommand ? OpenWifi::Now() : 0;
|
||||
|
||||
// Parse the result to get the ErrorText and make sure that this is a JSON document
|
||||
uint64_t ErrorCode = 0;
|
||||
@@ -486,7 +538,7 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string StatusText{"completed"};
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
std::string St{"UPDATE CommandList SET Completed=?, ErrorCode=?, ErrorText=?, Results=?, Status=?, executionTime=? WHERE UUID=?"};
|
||||
double tET{execution_time.count()};
|
||||
Update << ConvertParams(St),
|
||||
@@ -494,23 +546,21 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Keywords::use(ErrorCode),
|
||||
Poco::Data::Keywords::use(ErrorText),
|
||||
Poco::Data::Keywords::use(ResultStr),
|
||||
Poco::Data::Keywords::use(StatusText),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(tET),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CancelWaitFile( std::string & UUID, std::string & ErrorText ) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
uint64_t Size = 0, WaitForFile = 0;
|
||||
|
||||
Poco::Data::Statement Update(Sess);
|
||||
@@ -531,79 +581,12 @@ typedef Poco::Tuple<
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/* bool Storage::AttachFileToCommand(std::string &UUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
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();
|
||||
auto Now = OpenWifi::Now();
|
||||
uint64_t WaitForFile = 0;
|
||||
|
||||
Poco::Data::Statement Update(Sess);
|
||||
@@ -639,7 +622,7 @@ typedef Poco::Tuple<
|
||||
Insert.execute();
|
||||
return true;
|
||||
} else {
|
||||
Logger().warning(fmt::format("File {} is too large.", UUID));
|
||||
poco_warning(Logger(),fmt::format("File {} is too large.", UUID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -647,48 +630,6 @@ typedef Poco::Tuple<
|
||||
return false;
|
||||
}
|
||||
|
||||
/* bool Storage::GetAttachedFile(std::string &UUID, const std::string & SerialNumber, const std::string &FileName, std::string &Type) {
|
||||
try {
|
||||
Poco::Data::BLOB L;
|
||||
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();
|
||||
|
||||
// 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;
|
||||
@@ -734,11 +675,15 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
std::string St{"UPDATE CommandList SET Completed=?, Results=? WHERE UUID=?"};
|
||||
auto Now = OpenWifi::Now();
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
std::string St{"UPDATE CommandList SET Completed=?, Results=?, Status=? WHERE UUID=?"};
|
||||
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Result), Poco::Data::Keywords::use(UUID);
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Result),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
return true;
|
||||
|
||||
@@ -763,7 +708,6 @@ typedef Poco::Tuple<
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace OpenWifi {
|
||||
std::string St{"SELECT name FROM DefaultConfigs WHERE Name=?"};
|
||||
Select << ConvertParams(St) ,
|
||||
Poco::Data::Keywords::into(TmpName) ,
|
||||
Name;
|
||||
Poco::Data::Keywords::use(Name);
|
||||
Select.execute();
|
||||
|
||||
if (!TmpName.empty())
|
||||
@@ -90,12 +90,12 @@ namespace OpenWifi {
|
||||
Insert.execute();
|
||||
return true;
|
||||
} else {
|
||||
Logger().warning("Cannot create device: invalid configuration.");
|
||||
poco_warning(Logger(),"Cannot create device: invalid configuration.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -167,7 +167,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -190,7 +190,7 @@ namespace OpenWifi {
|
||||
return Select.rowsExtracted()==1;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -215,7 +215,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -245,7 +245,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -261,7 +261,7 @@ namespace OpenWifi {
|
||||
return Count;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "Daemon.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "FindCountry.h"
|
||||
#include "OUIServer.h"
|
||||
#include "Poco/Data/RecordSet.h"
|
||||
#include "Poco/Net/IPAddress.h"
|
||||
#include "SDKcalls.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "StateUtils.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#include "FindCountry.h"
|
||||
#include "WS_Server.h"
|
||||
#include "SDKcalls.h"
|
||||
#include "StateUtils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace OpenWifi {
|
||||
|
||||
bool Found = false;
|
||||
std::string FoundConfig;
|
||||
if(WebSocketServer()->UseProvisioning()) {
|
||||
if(AP_WS_Server()->UseProvisioning()) {
|
||||
if(SDKCalls::GetProvisioningConfiguration(SerialNumber, FoundConfig)) {
|
||||
if(FoundConfig != "none") {
|
||||
Found = true;
|
||||
@@ -337,7 +337,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found && WebSocketServer()->UseDefaults() && FindDefaultConfigurationForModel(Compat, DefConfig)) {
|
||||
if (!Found && AP_WS_Server()->UseDefaults() && FindDefaultConfigurationForModel(Compat, DefConfig)) {
|
||||
Config::Config NewConfig(DefConfig.Configuration);
|
||||
NewConfig.SetUUID(Now);
|
||||
D.Configuration = NewConfig.get();
|
||||
@@ -433,7 +433,7 @@ namespace OpenWifi {
|
||||
|
||||
bool Storage::DeleteDevice(std::string &SerialNumber) {
|
||||
try {
|
||||
std::vector<std::string> DBList{"Devices", "Statistics", "CommandList", "HealthChecks", "LifetimeStats", "Capabilities", "DeviceLogs"};
|
||||
std::vector<std::string> DBList{"Devices", "Statistics", "CommandList", "HealthChecks", "Capabilities", "DeviceLogs"};
|
||||
|
||||
for(const auto &i:DBList) {
|
||||
|
||||
@@ -453,10 +453,14 @@ namespace OpenWifi {
|
||||
SerialNumberCache()->DeleteSerialNumber(SerialNumber);
|
||||
|
||||
if(KafkaManager()->Enabled()) {
|
||||
nlohmann::json Message;
|
||||
Message["command"] = "delete_device";
|
||||
Message["payload"]["serialNumber"] = SerialNumber;
|
||||
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, to_string(Message));
|
||||
Poco::JSON::Object Message;
|
||||
Message.set("command","command");
|
||||
Poco::JSON::Object Payload;
|
||||
Payload.set("serialNumber", SerialNumber);
|
||||
Message.set("payload",Payload);
|
||||
std::ostringstream StrPayload;
|
||||
Message.stringify(StrPayload);
|
||||
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, StrPayload.str());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -162,7 +162,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ namespace OpenWifi {
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user