mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-12-24 14:27:00 +00:00
Compare commits
1149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17fe350d8c | ||
|
|
73e4f0df94 | ||
|
|
702d863e6b | ||
|
|
c31ea8f632 | ||
|
|
82688aa4ca | ||
|
|
96e6ebdfa1 | ||
|
|
986cb57389 | ||
|
|
a39efd3204 | ||
|
|
350eeca6ec | ||
|
|
33d908db96 | ||
|
|
aa39497793 | ||
|
|
20cdc999f3 | ||
|
|
5cbf25260d | ||
|
|
9c9e6cb593 | ||
|
|
81fa16fb9c | ||
|
|
82e877393d | ||
|
|
02320b616a | ||
|
|
bf1137a99b | ||
|
|
5e2d3e7c81 | ||
|
|
61ab1f7904 | ||
|
|
d6a61c45ec | ||
|
|
f6e7693e39 | ||
|
|
0e605f9ada | ||
|
|
613a2adfca | ||
|
|
8955c614a8 | ||
|
|
1685aefda3 | ||
|
|
3a70f669ee | ||
|
|
57771f411a | ||
|
|
22df3fb8ef | ||
|
|
ea369afabf | ||
|
|
4a450269f5 | ||
|
|
e44bb3199c | ||
|
|
eee680686f | ||
|
|
0e9b13f2b3 | ||
|
|
117f24e0b6 | ||
|
|
f639710d38 | ||
|
|
6d59b45e6f | ||
|
|
540205763c | ||
|
|
ec450c30e5 | ||
|
|
ef9902c75a | ||
|
|
9384bed03d | ||
|
|
29e61bf432 | ||
|
|
510e56518a | ||
|
|
82004e3f2e | ||
|
|
2620baca91 | ||
|
|
f105b9386c | ||
|
|
24dffe09a4 | ||
|
|
c2c37ad0d2 | ||
|
|
5a306f1a70 | ||
|
|
629a3b390b | ||
|
|
3b5b9636f3 | ||
|
|
8e125732b3 | ||
|
|
8e0ae5f6c8 | ||
|
|
45a4211793 | ||
|
|
68e85d8c5a | ||
|
|
61deb1f589 | ||
|
|
a1df232de9 | ||
|
|
3ac0875b83 | ||
|
|
94f4930bd7 | ||
|
|
0bc515e3ab | ||
|
|
81e49026f8 | ||
|
|
1ae68019d3 | ||
|
|
2e316478d7 | ||
|
|
6c23a969d0 | ||
|
|
8e900aea69 | ||
|
|
16c32e53bd | ||
|
|
fb15504294 | ||
|
|
8357cd76ed | ||
|
|
716d3755fe | ||
|
|
3299aadf57 | ||
|
|
71ed6c90d1 | ||
|
|
f45b2baa4b | ||
|
|
e00aa23775 | ||
|
|
83c9476720 | ||
|
|
18d9947c0e | ||
|
|
3de2dd1931 | ||
|
|
847648f1ee | ||
|
|
d77a4a6bb9 | ||
|
|
05767cc1a7 | ||
|
|
0e5c7ef5c6 | ||
|
|
bc6773ac28 | ||
|
|
d39574aa22 | ||
|
|
b6795a4f04 | ||
|
|
b8fe03c74d | ||
|
|
47b182e481 | ||
|
|
f680135e53 | ||
|
|
f3aecbd034 | ||
|
|
15776c01ac | ||
|
|
8fc342770b | ||
|
|
27c1bbeb20 | ||
|
|
a4bb7a1c0e | ||
|
|
89134305e8 | ||
|
|
f7b4fe84e1 | ||
|
|
2c29200bbf | ||
|
|
1e2728423a | ||
|
|
24c9283a55 | ||
|
|
92e1afedfb | ||
|
|
b86f06b818 | ||
|
|
2f3a0cc756 | ||
|
|
713cd01b6b | ||
|
|
888cc94709 | ||
|
|
0926f57391 | ||
|
|
78396d28d7 | ||
|
|
9edcd5a330 | ||
|
|
dc9a04dbc3 | ||
|
|
1d675067fe | ||
|
|
f69bc3434a | ||
|
|
17c8d5ceaf | ||
|
|
caf133b6a2 | ||
|
|
dcfdb6d242 | ||
|
|
40535390b1 | ||
|
|
b86d7425ac | ||
|
|
907803eafa | ||
|
|
050a3e3584 | ||
|
|
1052bbee57 | ||
|
|
16a970feb3 | ||
|
|
a185377258 | ||
|
|
0871045b3c | ||
|
|
4e2b1e4ecc | ||
|
|
b3f7b16f30 | ||
|
|
2b7d96728b | ||
|
|
13e5eab8f4 | ||
|
|
fd3fbb3dbf | ||
|
|
7abd8af2e6 | ||
|
|
3d97f5a9e3 | ||
|
|
d70ed3cae2 | ||
|
|
814fe872f6 | ||
|
|
354f0057c1 | ||
|
|
390e050801 | ||
|
|
f8a157ddbe | ||
|
|
8d4abd42ec | ||
|
|
4a82af2bcd | ||
|
|
bfeb9f64e2 | ||
|
|
6678669188 | ||
|
|
afe989205f | ||
|
|
5955e2e845 | ||
|
|
2500dfdd80 | ||
|
|
cfa496653f | ||
|
|
e4b9920b56 | ||
|
|
ec156c203e | ||
|
|
13fd91b135 | ||
|
|
123a638080 | ||
|
|
c165a1d3de | ||
|
|
40d2cdf1b3 | ||
|
|
565199df70 | ||
|
|
c9599c3d86 | ||
|
|
988c90643d | ||
|
|
62951a502c | ||
|
|
05ec034f7a | ||
|
|
4e5bf7929c | ||
|
|
e39149337c | ||
|
|
d14da5612b | ||
|
|
e42852297d | ||
|
|
1501e0f037 | ||
|
|
2d3fd0b736 | ||
|
|
17a77ba02b | ||
|
|
2541e25ee6 | ||
|
|
7799b3f904 | ||
|
|
1762fdc859 | ||
|
|
339ce4734b | ||
|
|
3f6b469c3c | ||
|
|
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 | ||
|
|
02c3b2fe2e | ||
|
|
cce4a7ec93 | ||
|
|
9aef183dc2 | ||
|
|
60a3365a9e | ||
|
|
6c052d7afe | ||
|
|
88eae31b7f | ||
|
|
d59f6e3dfc | ||
|
|
c97566f625 | ||
|
|
1fb41a9460 | ||
|
|
cfec8a1cbc | ||
|
|
7a84640c71 | ||
|
|
0d2276ff5a | ||
|
|
d227f83384 | ||
|
|
acb4d91a3d | ||
|
|
72b2913cc5 | ||
|
|
746ef603e2 | ||
|
|
ab792f7239 | ||
|
|
c4bb577763 | ||
|
|
3caf67102e | ||
|
|
8a3ade14ae | ||
|
|
4199b859ad | ||
|
|
be1b571f7f | ||
|
|
3002e17fd2 | ||
|
|
0d1a794e10 | ||
|
|
2aa7d97c80 | ||
|
|
0d3a0cbf03 | ||
|
|
1d8cb5447b | ||
|
|
3526a7abd9 | ||
|
|
d7ec9a3552 | ||
|
|
9f567e0e69 | ||
|
|
b16a410f1d | ||
|
|
0955f23dfc | ||
|
|
bd10ebc19c | ||
|
|
f74c5b496f | ||
|
|
6e961be74e | ||
|
|
c92d22f3cb | ||
|
|
e1770dc6a2 | ||
|
|
eace417fd3 | ||
|
|
ec3b5ededc | ||
|
|
78a6b011f8 | ||
|
|
a5450418b3 | ||
|
|
c74aa0d89f | ||
|
|
5f5e887f91 | ||
|
|
54a9290589 | ||
|
|
24be35c974 | ||
|
|
937d2818c0 | ||
|
|
f014960b3a | ||
|
|
cc5b319141 | ||
|
|
d5e7a6661f | ||
|
|
3368782471 | ||
|
|
2f013557a9 | ||
|
|
09595abc8c | ||
|
|
5104ab1dc3 | ||
|
|
8f3b2f795f | ||
|
|
9779ee669b | ||
|
|
f7187749a1 | ||
|
|
ddec407856 | ||
|
|
4650ac592a | ||
|
|
bc5c9e30cf | ||
|
|
1b53398e1e | ||
|
|
7b59a981dd | ||
|
|
ec3cb6586f | ||
|
|
c40be95aa8 | ||
|
|
ba8edb7f74 | ||
|
|
ea14936a1d | ||
|
|
676f131ca9 | ||
|
|
2e1fc663c8 | ||
|
|
cd9ef2ed2a | ||
|
|
4a1a903656 | ||
|
|
f6409fc063 | ||
|
|
6af855f6ca | ||
|
|
bec81bc380 | ||
|
|
0e4e4156a1 | ||
|
|
2aa60a5676 | ||
|
|
8b396e51ff | ||
|
|
01f53d7b78 | ||
|
|
b3c188701f | ||
|
|
7eb4c9e38b | ||
|
|
c93c34c042 | ||
|
|
418f8d31ae | ||
|
|
77c0c191f7 | ||
|
|
f0f4cf54bb | ||
|
|
917abf1d7f | ||
|
|
b4e7e4e26b | ||
|
|
9d0a146859 | ||
|
|
7420b72b23 | ||
|
|
5fc675484c | ||
|
|
38ad11542b | ||
|
|
63f2a4085a | ||
|
|
fea70efb2d | ||
|
|
da42c9845f | ||
|
|
ed46778bd4 | ||
|
|
1f7c0b7fdf | ||
|
|
15ec31fc89 | ||
|
|
d2a0d6da8a | ||
|
|
77cae31031 | ||
|
|
6cab1caf6c | ||
|
|
eea8203869 | ||
|
|
040397aa8e | ||
|
|
bba92aa9b8 | ||
|
|
c332a3946d | ||
|
|
02e677f849 | ||
|
|
a26f7c03c1 | ||
|
|
9181ae01cc | ||
|
|
7825b00d2e | ||
|
|
8b895c2088 | ||
|
|
49d39d37a1 | ||
|
|
406d59d5d7 | ||
|
|
186d12c78a | ||
|
|
421c24c961 | ||
|
|
e00c835680 | ||
|
|
3f972ebb4a | ||
|
|
cf8d29e66f | ||
|
|
d5e11d246a | ||
|
|
6ac29199e0 | ||
|
|
2f9452d6ef | ||
|
|
caed454e1a | ||
|
|
30916cbed1 | ||
|
|
81899788a9 | ||
|
|
e1590cbe90 | ||
|
|
bcbc212436 | ||
|
|
520671684b | ||
|
|
eacf9c0450 | ||
|
|
bef4c3ed5c | ||
|
|
4fe6254bf2 | ||
|
|
63ba3d633d | ||
|
|
1255cf0a56 | ||
|
|
7a6f2a517c | ||
|
|
6c15908ed6 | ||
|
|
d0a7670fff | ||
|
|
17d6253cfe | ||
|
|
ab592305ce | ||
|
|
0da527e1d7 | ||
|
|
d3848a6f8b | ||
|
|
c522c22d31 | ||
|
|
783886662f | ||
|
|
56ab9b1409 | ||
|
|
67e86a0edf | ||
|
|
70c12a5b77 | ||
|
|
03f2e2d457 | ||
|
|
ed12331d20 | ||
|
|
ec0c295c7c | ||
|
|
2438bd7ca7 | ||
|
|
18d18f68c5 | ||
|
|
120f94a95a | ||
|
|
7b9cda8c3d | ||
|
|
0d116119ed | ||
|
|
b9a7f53a92 | ||
|
|
459029d5d7 | ||
|
|
bfe0ff4481 | ||
|
|
b70a95d12b | ||
|
|
8280ff46db | ||
|
|
59da808bcd | ||
|
|
840c22e0d1 | ||
|
|
996e410fde | ||
|
|
521dcc2eed | ||
|
|
4d73467b8a | ||
|
|
515444d223 | ||
|
|
dccda306d4 | ||
|
|
3fd5c59994 | ||
|
|
87fee4ecd2 | ||
|
|
b37e7d4c5d | ||
|
|
f8c21f0c68 | ||
|
|
f74c098b99 | ||
|
|
1619cec197 | ||
|
|
62211b6e8b | ||
|
|
1bebe0729a | ||
|
|
6a8a6aa851 | ||
|
|
4b6880a306 | ||
|
|
3d252116dd | ||
|
|
2fc5e69145 | ||
|
|
8d2e85d0ee | ||
|
|
d1efdc93a4 | ||
|
|
c27627302f | ||
|
|
ae18fead11 | ||
|
|
75a6300ffb | ||
|
|
f84a4c83d0 | ||
|
|
d5c8cb5837 | ||
|
|
a09f2ec7bd | ||
|
|
7af9be5845 | ||
|
|
bc6e7d538b | ||
|
|
59ed9df3c9 | ||
|
|
0f46a6ded0 | ||
|
|
ef09214187 | ||
|
|
aa4631b55d | ||
|
|
08b59e04ee | ||
|
|
3455297cd6 | ||
|
|
350ccd5371 | ||
|
|
b89c0773c5 | ||
|
|
d03cd6a6df | ||
|
|
142a04ffc3 | ||
|
|
2b8e496bbc | ||
|
|
776a781a87 | ||
|
|
f5d66365b8 | ||
|
|
fd8b021225 | ||
|
|
1d2b54b6cf | ||
|
|
b073246293 | ||
|
|
8205cb7336 | ||
|
|
9339ae893a | ||
|
|
ce483ba51c | ||
|
|
85a7de67fb | ||
|
|
abdabe7da3 | ||
|
|
669af7640c | ||
|
|
83c46c44aa | ||
|
|
7b2ba4fed4 | ||
|
|
ef5aa26991 | ||
|
|
92b25846d2 | ||
|
|
77663f9184 | ||
|
|
61c7ab3267 | ||
|
|
8ae0006343 | ||
|
|
64a1fa1c85 | ||
|
|
2b9c90d5e6 | ||
|
|
565cee2373 | ||
|
|
36c5c9c5b6 | ||
|
|
837c3d5570 | ||
|
|
2a71721548 | ||
|
|
055bdcf937 | ||
|
|
221ee05298 | ||
|
|
afb8252dc2 | ||
|
|
77f86d139f | ||
|
|
b2353b6a0e | ||
|
|
bf4b9b0d63 | ||
|
|
e51236f0ca | ||
|
|
5be8ad75ed | ||
|
|
054e3e1591 | ||
|
|
06366f875c | ||
|
|
64d3f8c3ee | ||
|
|
8878445e03 | ||
|
|
ea30684f0c | ||
|
|
ebf08a63f1 | ||
|
|
e9e7db9ac0 | ||
|
|
7f9d03ed34 | ||
|
|
084483b028 | ||
|
|
285dbacd12 | ||
|
|
8f79d70753 | ||
|
|
6d20481d64 | ||
|
|
7da4bbba61 | ||
|
|
ff955d8b2f | ||
|
|
29d615393f | ||
|
|
2a716e6c66 | ||
|
|
b662dcf88c | ||
|
|
253ffbf111 | ||
|
|
dfd689512b | ||
|
|
cee2705bf8 | ||
|
|
af1e293bde | ||
|
|
58266eb239 | ||
|
|
87dc357c9f | ||
|
|
02798de88a | ||
|
|
d7bd812f97 | ||
|
|
b692a7868e | ||
|
|
f57dfc62c0 | ||
|
|
21794d669e | ||
|
|
2139093a73 | ||
|
|
bc1f0670fb | ||
|
|
a0b0a169fa | ||
|
|
7feb9f3655 | ||
|
|
3878d8abe6 | ||
|
|
770b5969f8 | ||
|
|
00bca216fc | ||
|
|
64eb7748d1 | ||
|
|
d6434666b4 | ||
|
|
747c84de4a | ||
|
|
538bdb25b1 | ||
|
|
07229e7e1f | ||
|
|
a63a1785e2 | ||
|
|
14820bd9c8 | ||
|
|
aeeb333c62 | ||
|
|
caa8f8c5a5 | ||
|
|
02aada469b | ||
|
|
020f9aea16 | ||
|
|
a8d5717fd5 | ||
|
|
51dd030419 | ||
|
|
6a83895efc | ||
|
|
c5e2574ab1 | ||
|
|
5a1828eaea | ||
|
|
c62f5a16f5 | ||
|
|
b6e778ada3 | ||
|
|
1b34ec8a78 | ||
|
|
57eb7312c8 | ||
|
|
368cdb72d4 | ||
|
|
712d326560 | ||
|
|
11df029ec0 | ||
|
|
020542b751 | ||
|
|
4b19163091 | ||
|
|
852ae3fde7 | ||
|
|
1ab9729ec1 | ||
|
|
9b1711fff6 | ||
|
|
929bc79136 | ||
|
|
e8fec5075f | ||
|
|
0bae840106 | ||
|
|
bf519637aa | ||
|
|
b15dc2b517 | ||
|
|
44f2843a7f | ||
|
|
e2eda25764 | ||
|
|
b2411d97d6 | ||
|
|
4a61f57912 | ||
|
|
1cafe0b6fc | ||
|
|
20763dedf6 | ||
|
|
80c0a3c07e | ||
|
|
0138cfdede | ||
|
|
066bad7953 | ||
|
|
2ca1508be1 | ||
|
|
737e49a376 | ||
|
|
251a4c2310 | ||
|
|
4e4ad418b6 | ||
|
|
b07c381bf7 | ||
|
|
6134c37d2b | ||
|
|
5e42202264 | ||
|
|
2f389599f8 | ||
|
|
36b633fcb7 | ||
|
|
5a1d56399c | ||
|
|
8ebb92b95a | ||
|
|
69716f50c0 | ||
|
|
580e4ce052 | ||
|
|
ab663be084 | ||
|
|
d5350b4283 | ||
|
|
873d77adf0 | ||
|
|
530555ff26 | ||
|
|
3db8892e58 | ||
|
|
c1ba58be6e | ||
|
|
0750be2d81 | ||
|
|
adec21906f | ||
|
|
80b5c6f3b5 | ||
|
|
e29a7589f2 | ||
|
|
8255ff3218 | ||
|
|
5b70cdfe53 | ||
|
|
2e94733c8d | ||
|
|
3d62625cf6 | ||
|
|
eb0eae90b6 | ||
|
|
d7dc43f0de | ||
|
|
3c6ec00695 | ||
|
|
eb705dfeb1 | ||
|
|
46bd78ba15 | ||
|
|
e730c60ebc | ||
|
|
3329781bc2 | ||
|
|
dfcc59a7b8 | ||
|
|
b72fb379cd | ||
|
|
74db8cd36d | ||
|
|
1219a70da2 | ||
|
|
dc95a8632a | ||
|
|
8b0ecb464b | ||
|
|
9f863c1cc2 | ||
|
|
fda6f8b2d9 | ||
|
|
9703ed035a | ||
|
|
4117ed927a | ||
|
|
8980eaa5ba | ||
|
|
d3d1ccee81 | ||
|
|
4a0aaa8f6b | ||
|
|
85e84e0672 | ||
|
|
7d63852d94 | ||
|
|
698a2b2fcb | ||
|
|
62e1c6eb0f | ||
|
|
1a8fa724d6 | ||
|
|
b4088519cf | ||
|
|
58ce304e53 | ||
|
|
9fbc77a85a | ||
|
|
623c4c43d4 | ||
|
|
63ea97b435 | ||
|
|
d9f3d92736 | ||
|
|
7fc2239e59 | ||
|
|
badfe61d6a | ||
|
|
ab57221040 | ||
|
|
5ae62b8892 | ||
|
|
c5425fc9cf | ||
|
|
dbdc14891c | ||
|
|
f4b4627c78 | ||
|
|
35dbe47571 | ||
|
|
a97337234e | ||
|
|
a87b8de6e3 | ||
|
|
949d7a54ad | ||
|
|
5a3c97a529 | ||
|
|
0772898160 | ||
|
|
638ed3f5c8 | ||
|
|
d996e9e05e | ||
|
|
58fd622980 | ||
|
|
29113ac39c | ||
|
|
f947f472b9 | ||
|
|
393763fb9e | ||
|
|
eced94910d | ||
|
|
df000f35ee | ||
|
|
24d2de568f | ||
|
|
8508396ae6 | ||
|
|
9f6d38e6b7 | ||
|
|
b8f3b9b37a | ||
|
|
71cdcb5909 | ||
|
|
e92e852dcb | ||
|
|
0ac5b3a39d | ||
|
|
3fbf460f81 | ||
|
|
9b7db5c095 | ||
|
|
eb9e88b54a | ||
|
|
952b1c4562 | ||
|
|
cec50beecf | ||
|
|
2048107866 | ||
|
|
2d72a15ec0 | ||
|
|
d5c36aa2e9 | ||
|
|
41079d9f0b | ||
|
|
a47977b029 | ||
|
|
e20b71181f | ||
|
|
4f29e5a650 | ||
|
|
e168c7b2c7 | ||
|
|
1f6de95f16 | ||
|
|
96995730c6 | ||
|
|
9d000ca84d | ||
|
|
9af6deaec3 | ||
|
|
aaa13e1e2f | ||
|
|
bd0419fb0c | ||
|
|
656efd0d57 | ||
|
|
863ff017b0 | ||
|
|
8c26cc37d7 | ||
|
|
4e9c26cd04 | ||
|
|
d098bca86f | ||
|
|
9980c2b175 | ||
|
|
a52daae4a5 | ||
|
|
1d8af05302 | ||
|
|
2efccedfba | ||
|
|
243b615814 | ||
|
|
dc37bcb5ff | ||
|
|
edac1d6ceb | ||
|
|
64848d8fdd | ||
|
|
c874b7633d | ||
|
|
2ca85970e4 | ||
|
|
0184aa8879 | ||
|
|
ac05fe833e | ||
|
|
998a686179 | ||
|
|
288b5e207f | ||
|
|
2ec0c923c3 | ||
|
|
4c9dd0cef7 | ||
|
|
8f16abd4ff | ||
|
|
c706ea4118 | ||
|
|
9c2fef1ee4 | ||
|
|
1648acca32 | ||
|
|
c11c0281ce | ||
|
|
58ee7344bf | ||
|
|
6c9dac79d5 | ||
|
|
7aa284e92c | ||
|
|
933b41e7c1 | ||
|
|
a39e586bc1 | ||
|
|
4e81683bcd | ||
|
|
6a74297cb3 | ||
|
|
67764ec5c1 | ||
|
|
ebbcd99453 | ||
|
|
3719df39fe | ||
|
|
70670117a7 | ||
|
|
31f77b84d6 | ||
|
|
924e2f0775 | ||
|
|
cb61ce3f9e | ||
|
|
d97033d6cf | ||
|
|
c2f547da0c | ||
|
|
7cc60e6063 | ||
|
|
4f117199f0 | ||
|
|
0d444c4bc9 | ||
|
|
87646944dd | ||
|
|
13c9633964 | ||
|
|
ab77f1371d | ||
|
|
4ac71c4af2 | ||
|
|
1ca1fffa26 | ||
|
|
4e623ab182 | ||
|
|
fb27ea8528 | ||
|
|
bc20d66694 | ||
|
|
beadcd50e7 | ||
|
|
5d1c9b10da | ||
|
|
7e877b74a7 | ||
|
|
47b569aa59 | ||
|
|
2afa4b64e8 | ||
|
|
315bad5451 | ||
|
|
c8fa1d5405 | ||
|
|
40a28015bd | ||
|
|
4a25b0ba99 | ||
|
|
9ea7ab14df | ||
|
|
aa692d9f30 | ||
|
|
044d978c46 | ||
|
|
b767dd3aa4 | ||
|
|
9acbd6cef6 | ||
|
|
a20ec0587e | ||
|
|
28b72a6303 | ||
|
|
9540fc9a5f | ||
|
|
18eac29b1a | ||
|
|
76b2255716 | ||
|
|
17377aa8bc | ||
|
|
d1a50fcf22 | ||
|
|
cccd8f8fbd | ||
|
|
9c37d0760d | ||
|
|
90d56197e6 | ||
|
|
6b91065468 | ||
|
|
f851957523 | ||
|
|
ec0574bfdf | ||
|
|
6bc279ac32 | ||
|
|
1cdb5ef2e3 | ||
|
|
d85854a1f2 | ||
|
|
e0d6fb0bcc | ||
|
|
6e864c14a1 | ||
|
|
8e49ffa904 | ||
|
|
4db50c0ed2 | ||
|
|
191611bc24 | ||
|
|
d10541afb7 | ||
|
|
1887878088 | ||
|
|
de3985191a | ||
|
|
629a615f7c | ||
|
|
ec947df8a0 | ||
|
|
203095a6f7 | ||
|
|
f71ce62c5b | ||
|
|
89680d6be7 | ||
|
|
e411f4f6ac | ||
|
|
bbcb23b821 | ||
|
|
75dfd49067 | ||
|
|
39d4423a5e | ||
|
|
6238fee522 | ||
|
|
e301ea7cee | ||
|
|
42aff04610 | ||
|
|
345053bdba | ||
|
|
285fd26f99 |
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@@ -13,6 +13,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- 'release/*'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
||||
8
.github/workflows/cleanup.yml
vendored
8
.github/workflows/cleanup.yml
vendored
@@ -17,4 +17,10 @@ jobs:
|
||||
- name: Cleanup Docker image with PR branch tag
|
||||
run: |
|
||||
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
|
||||
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"
|
||||
|
||||
if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then
|
||||
echo "PR branch is $PR_BRANCH_TAG, deleting Docker image"
|
||||
curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"
|
||||
else
|
||||
echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image"
|
||||
fi
|
||||
|
||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
path: wlan-cloud-ucentralgw
|
||||
|
||||
- name: Build package
|
||||
working-directory: wlan-cloud-ucentralgw/chart
|
||||
working-directory: wlan-cloud-ucentralgw/helm
|
||||
run: |
|
||||
helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
helm package . -d dist
|
||||
|
||||
- name: Generate GitHub release body
|
||||
working-directory: wlan-cloud-ucentralgw/chart
|
||||
working-directory: wlan-cloud-ucentralgw/helm
|
||||
run: |
|
||||
pip3 install yq -q
|
||||
echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owgw:$GITHUB_REF_NAME" > release.txt
|
||||
@@ -42,5 +42,5 @@ jobs:
|
||||
- name: Create GitHub release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body_path: wlan-cloud-ucentralgw/chart/release.txt
|
||||
files: wlan-cloud-ucentralgw/chart/dist/*
|
||||
body_path: wlan-cloud-ucentralgw/helm/release.txt
|
||||
files: wlan-cloud-ucentralgw/helm/dist/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owgw VERSION 2.6.0)
|
||||
project(owgw VERSION 2.7.1)
|
||||
|
||||
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,10 +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)
|
||||
endif()
|
||||
|
||||
add_executable( owgw
|
||||
build
|
||||
@@ -97,14 +100,13 @@ add_executable( owgw
|
||||
src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h
|
||||
src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
|
||||
src/RESTAPI/RESTAPI_telemetryWebSocket.cpp src/RESTAPI/RESTAPI_telemetryWebSocket.h
|
||||
src/RESTAPI/RESTAPI_webSocketServer.cpp src/RESTAPI/RESTAPI_webSocketServer.h
|
||||
src/storage/storage_blacklist.cpp src/storage/storage_tables.cpp src/storage/storage_logs.cpp
|
||||
src/storage/storage_command.cpp src/storage/storage_healthcheck.cpp src/storage/storage_statistics.cpp
|
||||
src/storage/storage_device.cpp src/storage/storage_capabilities.cpp src/storage/storage_defconfig.cpp
|
||||
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
|
||||
@@ -117,7 +119,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/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 src/framework/MicroServiceErrorHandler.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 \
|
||||
|
||||
194
MICRO_SERVICE_PROTOCOL.md
Normal file
194
MICRO_SERVICE_PROTOCOL.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# Micro-service backbone responsibilities
|
||||
|
||||
## Bus management
|
||||
Each microservice must get onto kafka and consume/produce messages on the kafka bus. The topic to subscribe to is `service_events`.
|
||||
|
||||
## System messages
|
||||
System messages are what maintains the collection of micro-services working on the system. Each message has the format
|
||||
|
||||
```json
|
||||
{
|
||||
"event": <event-type>,
|
||||
"id": 1234567890,
|
||||
"type": "owrrm",
|
||||
"publicEndPoint": "https://myhostname.com:16020",
|
||||
"privateEndPoint": "https://localhost:17020",
|
||||
"key" : "289479847948794870749",
|
||||
"version" : "1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### 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`
|
||||
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.
|
||||
|
||||
## The `type`
|
||||
The `type` in the system message is oen of the following:
|
||||
```c++
|
||||
static const std::string uSERVICE_SECURITY{"owsec"};
|
||||
static const std::string uSERVICE_GATEWAY{"owgw"};
|
||||
static const std::string uSERVICE_FIRMWARE{ "owfms"};
|
||||
static const std::string uSERVICE_TOPOLOGY{ "owtopo"};
|
||||
static const std::string uSERVICE_PROVISIONING{ "owprov"};
|
||||
static const std::string uSERVICE_OWLS{ "owls"};
|
||||
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
|
||||
static const std::string uSERVICE_INSTALLER{ "owinst"};
|
||||
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
|
||||
static const std::string uSERVICE_OWRRM{ "owrrm"};
|
||||
```
|
||||
|
||||
The `type` is what you should use to find the `privateEndPoint` you are looking to communicate with.
|
||||
|
||||
### Example
|
||||
Assume you want to communicate with the gateway to configure a device.
|
||||
|
||||
```text
|
||||
1. Look into my list of current Micro-services for the type=owgw.
|
||||
2. Use the privateEndPoint associated with that entry
|
||||
```
|
||||
|
||||
## REST API calls on the private interface
|
||||
For inter-service REST calls, you should never use the `Authorization: Bearer token` method. Instead, the following headers should be included in all API calls
|
||||
```json
|
||||
{
|
||||
"X-API-KEY" : "289479847948794870749",
|
||||
"X-INTERNAL-NAME" : "https://myhostname.com:16020"
|
||||
}
|
||||
```
|
||||
|
||||
### `X-API-KEY`
|
||||
This is the `key` you included in your `system-messages`.
|
||||
|
||||
### `X-INTERNAL-NAME`
|
||||
This is the `publicEndPoint` you included in your `system-messages`.
|
||||
|
||||
This method can _only_ be used to any another `privateEndPoint` in the system. You can use the exact same EndPoints provided in the OpenAPI files for any of the services.
|
||||
|
||||
## OpenAPI Integration
|
||||
To appear in the UI consoles, a 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 microservice should answer:
|
||||
```yaml
|
||||
/system:
|
||||
get:
|
||||
tags:
|
||||
- System Commands
|
||||
summary: Retrieve different values from the running service.
|
||||
operationId: getSystemCommand
|
||||
parameters:
|
||||
- in: query
|
||||
description: Get a value
|
||||
name: command
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- info
|
||||
required: true
|
||||
|
||||
responses:
|
||||
200:
|
||||
description: Successful command execution
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemInfoResults'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
```
|
||||
The relevant data structures are:
|
||||
```yaml
|
||||
SystemInfoResults:
|
||||
type: object
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
uptime:
|
||||
type: integer
|
||||
format: integer64
|
||||
start:
|
||||
type: integer
|
||||
format: integer64
|
||||
os:
|
||||
type: string
|
||||
processors:
|
||||
type: integer
|
||||
hostname:
|
||||
type: string
|
||||
certificates:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
filename:
|
||||
type: string
|
||||
expires:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
```
|
||||
and
|
||||
```yaml
|
||||
responses:
|
||||
NotFound:
|
||||
description: The specified resource was not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
Unauthorized:
|
||||
description: The requested does not have sufficient rights to perform the operation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
enum:
|
||||
- 0 # Success
|
||||
- 1 # PASSWORD_CHANGE_REQUIRED,
|
||||
- 2 # INVALID_CREDENTIALS,
|
||||
- 3 # PASSWORD_ALREADY_USED,
|
||||
- 4 # USERNAME_PENDING_VERIFICATION,
|
||||
- 5 # PASSWORD_INVALID,
|
||||
- 6 # INTERNAL_ERROR,
|
||||
- 7 # ACCESS_DENIED,
|
||||
- 8 # INVALID_TOKEN
|
||||
- 9 # EXPIRED_TOKEN
|
||||
- 10 # RATE_LIMIT_EXCEEDED
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
```
|
||||
215
PROTOCOL.md
215
PROTOCOL.md
@@ -30,7 +30,7 @@ In this RPC, here are some common interpretations:
|
||||
#### Connection event
|
||||
Device Sends connection notification to the controller after establishing a connection. The controller
|
||||
my decide to send the AP a newer configuration. The controller will record the device capabilities provided.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "connect" ,
|
||||
"params" : {
|
||||
@@ -47,7 +47,7 @@ my decide to send the AP a newer configuration. The controller will record the d
|
||||
#### State event
|
||||
The device sends device state information periodically. If the controller detects that it has a newer configuration, it
|
||||
may decide to send this new configuration to the AP.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "state" ,
|
||||
"params" : {
|
||||
@@ -62,7 +62,7 @@ may decide to send this new configuration to the AP.
|
||||
#### Healthcheck event
|
||||
Device sends a `healthcheck` periodically. This message contains information about how vital subsystems are operating and
|
||||
if they need attention.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "healthcheck" ,
|
||||
"params" : {
|
||||
@@ -77,7 +77,7 @@ if they need attention.
|
||||
|
||||
#### Log event
|
||||
Device sends a log message whenever necessary. The controller will log this message to the log system for the device.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "log" ,
|
||||
"params" : {
|
||||
@@ -102,7 +102,7 @@ The `severity` matches the `syslog` levels. Here are the details:
|
||||
|
||||
#### Crash Log event
|
||||
Device may send a crash log event after rebooting after a crash. The event cannot be sent until a connection event has been sent.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "crashlog" ,
|
||||
"params" : {
|
||||
@@ -117,7 +117,7 @@ Device may send a crash log event after rebooting after a crash. The event canno
|
||||
Device sends this message to tell the controller that the device
|
||||
has received a configuration but is still running an older configuration. The controller will not
|
||||
reply to this message.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "cfgpending" ,
|
||||
"params" : {
|
||||
@@ -131,7 +131,7 @@ reply to this message.
|
||||
#### DeviceUpdate event
|
||||
Device sends this message to tell the controller it is changing something is its configuration because
|
||||
of some requirement or some changes.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "deviceupdate" ,
|
||||
"params" : {
|
||||
@@ -145,7 +145,7 @@ of some requirement or some changes.
|
||||
#### Send a keepalive to the controller event
|
||||
Device sends a keepalive whenever necessary. The device will send this message to tell the controller
|
||||
which version it is running. The Controller may decide to send the device a newer configuration.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "ping" ,
|
||||
"params" : {
|
||||
@@ -157,7 +157,7 @@ which version it is running. The Controller may decide to send the device a newe
|
||||
|
||||
#### Recovery Event
|
||||
Device may decide it has to do into recovery mode. This event should be used.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "recovery" ,
|
||||
"params" : {
|
||||
@@ -170,6 +170,34 @@ Device may decide it has to do into recovery mode. This event should be used.
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : 0 or an error number,
|
||||
"text" : <description of the error or success>
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
#### 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
|
||||
@@ -180,7 +208,7 @@ always a numeric parameter.
|
||||
#### Controller wants the device to apply a given configuration
|
||||
Controller sends this command when it believes the device should load a new configuration. The device
|
||||
should send message with `pending change` events until this version has been applied and running.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "configure" ,
|
||||
"params" : {
|
||||
@@ -194,7 +222,7 @@ should send message with `pending change` events until this version has been app
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -233,7 +261,7 @@ The rejected section is an array containing the following:
|
||||
|
||||
#### Controller wants the device to reboot
|
||||
Controller sends this command when it believes the device should reboot.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "reboot" ,
|
||||
"params" : {
|
||||
@@ -245,7 +273,7 @@ Controller sends this command when it believes the device should reboot.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -264,7 +292,7 @@ The device should answer:
|
||||
|
||||
#### Controller wants the device to upgrade its firmware
|
||||
Controller sends this command when it believes the device should upgrade its firmware.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "upgrade" ,
|
||||
"params" : {
|
||||
@@ -277,7 +305,7 @@ Controller sends this command when it believes the device should upgrade its fir
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -293,7 +321,7 @@ The device should answer:
|
||||
|
||||
#### Controller wants the device to perform a factory reset
|
||||
Controller sends this command when it believes the device should upgrade its firmware.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "factory" ,
|
||||
"params" : {
|
||||
@@ -306,7 +334,7 @@ Controller sends this command when it believes the device should upgrade its fir
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -320,9 +348,50 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller issuing RRM commands to the AP
|
||||
Controller sends this command to perform several RRM commands.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "rrm" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"actions": [
|
||||
{
|
||||
"type": "roam",
|
||||
"bss": [ "00:11:22:33:44:55", ... ],
|
||||
"params" : { action specific data }
|
||||
}, {
|
||||
"type": "tx-power",
|
||||
"bss": [ "00:11:22:33:44:55", ... ],
|
||||
“params”: { action specific data }
|
||||
}, {
|
||||
"type": "beacon-request",
|
||||
"bss": [ "00:11:22:33:44:55", ... ],
|
||||
"params": { action specific data }
|
||||
}
|
||||
]
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : 0 or an error number,
|
||||
"text" : <description of the error or success>,
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to flash its LEDs
|
||||
Controller sends this command when it wants the device to flash its LEDs.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "leds" ,
|
||||
"params" : {
|
||||
@@ -336,14 +405,13 @@ Controller sends this command when it wants the device to flash its LEDs.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : 0 or an error number,
|
||||
"text" : <description of the error or success>,
|
||||
"when" : <time when this will be performed as UTC seconds>,
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
@@ -358,7 +426,7 @@ The device should answer:
|
||||
#### Controller sends a device specific command
|
||||
Controller sends this command specific to this device. The command is proprietary and must be agreed upon by the device
|
||||
and the controller.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "perform" ,
|
||||
"params" : {
|
||||
@@ -372,7 +440,7 @@ and the controller.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -395,7 +463,7 @@ The device should answer with teh above message. The `error` value should be int
|
||||
|
||||
#### Controller wants the device to perform a trace
|
||||
Controller sends this command when it needs the device to perform a trace (i.e. tcpdump).
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "trace" ,
|
||||
"params" : {
|
||||
@@ -412,7 +480,7 @@ Controller sends this command when it needs the device to perform a trace (i.e.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -438,7 +506,7 @@ uploaded or the timeout occurs, the upload will be rejected.
|
||||
|
||||
#### Controller wants the device to perform a WiFi Scan
|
||||
Controller sends this command when it needs the device to perform a WiFi Scan.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "wifiscan" ,
|
||||
"params" : {
|
||||
@@ -446,15 +514,16 @@ Controller sends this command when it needs the device to perform a WiFi Scan.
|
||||
"bands" : [ "2","5","5l","5u",6" ], <optional this is a list of bands to scan: on or more bands >
|
||||
"channels" : [ 1,2,3...] , <optional list of discreet channels to scan >
|
||||
"verbose" : <optional boolean: true or false> (by default false),
|
||||
"bandwidth" : <optional int: 20,40,80 in MHz>
|
||||
"active" : 0 or 1 (to select passive or active scan)
|
||||
"bandwidth" : <optional int: 20,40,80 in MHz>,
|
||||
"active" : 0 or 1 (to select passive or active scan),
|
||||
"ies": <optional: array of unsigned int 8 bits: i.e. [1,4,34,58,91]>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -477,7 +546,7 @@ Controller sends this command when it needs the device to provide a message back
|
||||
supported messages are "state" and "healthcheck". More messages maybe added later. The messages will
|
||||
be returned the usual way. The RPC response to this message just says that the request has been accepted and the
|
||||
message will be returned "soon".
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "request" ,
|
||||
"params" : {
|
||||
@@ -491,7 +560,7 @@ message will be returned "soon".
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -507,7 +576,7 @@ The device should answer:
|
||||
|
||||
#### Controller requesting eventqueue buffers
|
||||
Controller sends this command when it needs the device to provide the content of ist ring buffers.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "event" ,
|
||||
"params" : {
|
||||
@@ -521,7 +590,7 @@ Controller sends this command when it needs the device to provide the content of
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -537,7 +606,7 @@ The device should answer:
|
||||
|
||||
#### Controller requesting telemetry stream information
|
||||
Controller sends this command when it needs the device to telemetry streaming.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "telemetry" ,
|
||||
"params" : {
|
||||
@@ -550,7 +619,7 @@ Controller sends this command when it needs the device to telemetry streaming.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -564,7 +633,7 @@ The device should answer:
|
||||
```
|
||||
|
||||
When the interval is greater than 0, the gateway will start to receive messages
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "telemetry" ,
|
||||
"params" : {
|
||||
@@ -579,7 +648,7 @@ The device will stop sending data after 30 minutes or if it receives a `telemetr
|
||||
|
||||
#### Controller requesting an `rtty` session
|
||||
Controller sends this command an administrator requests to start an `rtty` session with the AP.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "remote_access" ,
|
||||
"params" : {
|
||||
@@ -597,7 +666,7 @@ Controller sends this command an administrator requests to start an `rtty` sessi
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -613,7 +682,7 @@ The device should answer:
|
||||
|
||||
#### Controller wants to ping the device
|
||||
Controller sends this command when it tries to establish latency to the device.
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "ping" ,
|
||||
"params" : {
|
||||
@@ -624,7 +693,7 @@ Controller sends this command when it tries to establish latency to the device.
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
@@ -635,8 +704,41 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to perform a script
|
||||
Controller sends this command to run a predefined script. Extreme care must be taken.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "script" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"type" : <one of "shell", "ucode">,
|
||||
"script" : <text blob containing the script>,
|
||||
"timeout" : <max timeout in seconds, default is 30>,
|
||||
"when" : <time when this will be performed as UTC seconds>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
#### `rtty server`
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
one of either
|
||||
"result_64" : <gzipped base64 result of running the command>,
|
||||
"result_sz" : <size of unzipped content>
|
||||
or
|
||||
"result" : <a single text blob of the result>
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
### `rtty server`
|
||||
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.
|
||||
|
||||
### Message compression
|
||||
@@ -647,21 +749,48 @@ 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
|
||||
of the completed message. The following should how the `state` event could be compressed:
|
||||
|
||||
```
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "state" ,
|
||||
"params" : {
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk"
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk",
|
||||
"compress_sz" : 212322
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 'Radius Proxying'
|
||||
The gateway can receive RADIUS messages from the device and forward them. It can also receive messages
|
||||
on its behalf and send them to the device.
|
||||
|
||||
```json
|
||||
{
|
||||
"radius" : <type, can be auth, acct, coa> ,
|
||||
"data" : <base 64 encoded raw RADIUS payload>
|
||||
}
|
||||
```
|
||||
|
||||
The GW will include a TLV to mark the sender MAC. The RADIUS server must use the same TLV to
|
||||
identify the destination for its messages.
|
||||
|
||||
#### Incoming RADIUS messages configuration
|
||||
The GW must be configured with the following:
|
||||
|
||||
```asm
|
||||
radius.proxy.enable = true
|
||||
radius.proxy.accounting.port = 1813
|
||||
radius.proxy.authentication.port = 1812
|
||||
radius.proxy.coa.port = 3799
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
91
README.md
91
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,16 +50,7 @@ cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/nlohmann/json.git
|
||||
cd json
|
||||
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
|
||||
@@ -66,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
|
||||
@@ -80,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
|
||||
@@ -93,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
|
||||
@@ -101,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
|
||||
@@ -123,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
|
||||
@@ -142,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
|
||||
@@ -248,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.
|
||||
@@ -560,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
@@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
||||
update-ca-certificates
|
||||
fi
|
||||
|
||||
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWGW_CONFIG"/owgw.properties ]]; then
|
||||
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
|
||||
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
|
||||
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 10.9.2
|
||||
- name: mysql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 8.8.3
|
||||
- name: mariadb
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 9.4.2
|
||||
digest: sha256:1fdae7cbea906e41dccd8618ff9e2c68d0c684724ae27c79a12bb6089968df5c
|
||||
generated: "2021-08-17T12:18:40.341427893+03:00"
|
||||
digest: sha256:e9df5a5d8a0a193bfda33ea06060203aace01f0f7df9eda662a84185322c7ab5
|
||||
generated: "2022-06-03T15:38:31.063022252+03:00"
|
||||
|
||||
@@ -5,14 +5,14 @@ name: owgw
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 10.9.2
|
||||
condition: postgresql.enabled
|
||||
- name: mysql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 8.8.3
|
||||
condition: mysql.enabled
|
||||
- name: mariadb
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
version: 9.4.2
|
||||
condition: mariadb.enabled
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -215,8 +215,9 @@ configProperties:
|
||||
openwifi.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2: IOT:esp32
|
||||
oui.download.uri: https://linuxnet.ca/ieee/oui.txt
|
||||
oui.download.uri: https://standards-oui.ieee.org/oui/oui.txt
|
||||
firmware.autoupdate.policy.default: auto
|
||||
iptocountry.provider: ipinfo
|
||||
# Callback
|
||||
openwifi.callback.enable: "false"
|
||||
openwifi.callback.0.local: localhost:16001
|
||||
|
||||
@@ -31,58 +31,13 @@ components:
|
||||
|
||||
responses:
|
||||
NotFound:
|
||||
description: The specified resource was not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||
Unauthorized:
|
||||
description: The requested does not have sufficient rights to perform the operation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
enum:
|
||||
- 0 # Success
|
||||
- 1 # PASSWORD_CHANGE_REQUIRED,
|
||||
- 2 # INVALID_CREDENTIALS,
|
||||
- 3 # PASSWORD_ALREADY_USED,
|
||||
- 4 # USERNAME_PENDING_VERIFICATION,
|
||||
- 5 # PASSWORD_INVALID,
|
||||
- 6 # INTERNAL_ERROR,
|
||||
- 7 # ACCESS_DENIED,
|
||||
- 8 # INVALID_TOKEN
|
||||
- 9 # EXPIRED_TOKEN
|
||||
- 10 # RATE_LIMIT_EXCEEDED
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||
Success:
|
||||
description: The requested operation was performed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
Operation:
|
||||
type: string
|
||||
Details:
|
||||
type: string
|
||||
Code:
|
||||
type: integer
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
|
||||
BadRequest:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
|
||||
|
||||
schemas:
|
||||
DeviceType:
|
||||
@@ -235,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
|
||||
@@ -327,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:
|
||||
@@ -510,6 +488,31 @@ components:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
ScriptRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
timeout:
|
||||
type: integer
|
||||
format: int64
|
||||
default: 30
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- uci
|
||||
- ucode
|
||||
- shell
|
||||
script:
|
||||
type: string
|
||||
scriptId:
|
||||
type: string
|
||||
format: uuid
|
||||
when:
|
||||
type: integer
|
||||
format: int64
|
||||
default: 0
|
||||
|
||||
FactoryRequest:
|
||||
type: object
|
||||
properties:
|
||||
@@ -976,6 +979,12 @@ components:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/WifiBands'
|
||||
- $ref: '#/components/schemas/WifiChannels'
|
||||
ies:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 255
|
||||
required:
|
||||
- serialNumber
|
||||
|
||||
@@ -1047,6 +1056,99 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/CapabilitiesModel'
|
||||
|
||||
RadiusProxyServerEntry:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
ip:
|
||||
type: string
|
||||
format: ip-addr
|
||||
port:
|
||||
type: integer
|
||||
weight:
|
||||
type: integer
|
||||
secret:
|
||||
type: string
|
||||
certificate:
|
||||
type: string
|
||||
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
|
||||
properties:
|
||||
strategy:
|
||||
type: string
|
||||
enum:
|
||||
- random
|
||||
- round_robin
|
||||
- weighted
|
||||
monitor:
|
||||
type: boolean
|
||||
default: false
|
||||
monitorMethod:
|
||||
type: string
|
||||
enum:
|
||||
- none
|
||||
- https
|
||||
- radius
|
||||
methodParameters:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
servers:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RadiusProxyServerEntry'
|
||||
|
||||
RadiusProxyPool:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
authConfig:
|
||||
$ref: '#/components/schemas/RadiusProxyServerConfig'
|
||||
acctConfig:
|
||||
$ref: '#/components/schemas/RadiusProxyServerConfig'
|
||||
coaConfig:
|
||||
$ref: '#/components/schemas/RadiusProxyServerConfig'
|
||||
|
||||
RadiusProxyPoolList:
|
||||
type: object
|
||||
properties:
|
||||
pools:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RadiusProxyPool'
|
||||
|
||||
paths:
|
||||
/devices:
|
||||
get:
|
||||
@@ -1096,6 +1198,27 @@ paths:
|
||||
name: deviceWithStatus
|
||||
schema:
|
||||
type: boolean
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: orderBy
|
||||
schema:
|
||||
type: string
|
||||
example: serialNumber:a,created:d
|
||||
required: false
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: orderSpec
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: connectionStatistics
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List devices
|
||||
@@ -1107,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:
|
||||
@@ -1992,6 +2116,32 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/script:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Debug a device.
|
||||
operationId: debugDevice
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Command details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScriptRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/CommandInfo'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/factory:
|
||||
post:
|
||||
tags:
|
||||
@@ -2433,6 +2583,45 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/radiusProxyConfig:
|
||||
get:
|
||||
tags:
|
||||
- RADIUSProxy
|
||||
summary: Retrieve RADIUS Proxy configuration.
|
||||
operationId: getRadiusProxyConfig
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/RadiusProxyPoolList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
put:
|
||||
tags:
|
||||
- RADIUSProxy
|
||||
summary: Modify RADIUS Proxy configuration.
|
||||
operationId: modifyRadiusProxyConfig
|
||||
requestBody:
|
||||
description: Change RADIUS configuration pool config
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RadiusProxyPoolList'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/RadiusProxyPoolList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- RADIUSProxy
|
||||
summary: Delete RADIUS Proxy configuration.
|
||||
operationId: deleteRadiusProxyConfig
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/deviceDashboard:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -96,6 +96,12 @@ rtty.timeout = 60
|
||||
rtty.viewport = 5913
|
||||
rtty.assets = $OWGW_ROOT/rtty_ui
|
||||
|
||||
### RADIUS proxy config
|
||||
radius.proxy.enable = false
|
||||
radius.proxy.accounting.port = 1813
|
||||
radius.proxy.authentication.port = 1812
|
||||
radius.proxy.coa.port = 3799
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
#############################
|
||||
|
||||
41
pcap/radius
Normal file
41
pcap/radius
Normal file
@@ -0,0 +1,41 @@
|
||||
/* Frame (255 bytes) */
|
||||
static const unsigned char pkt41[255] = {
|
||||
0x14, 0x98, 0x77, 0x71, 0xc6, 0xe7, 0x34, 0xef, /* ..wq..4. */
|
||||
0xb6, 0xaf, 0x4a, 0x5c, 0x08, 0x00, 0x45, 0x00, /* ..J\..E. */
|
||||
0x00, 0xf1, 0x87, 0x50, 0x00, 0x00, 0x40, 0x11, /* ...P..@. */
|
||||
0x0c, 0xdf, 0xc0, 0xa8, 0xb2, 0x1b, 0xc0, 0xa8, /* ........ */
|
||||
0xb2, 0x60, 0xc3, 0xfe, 0x07, 0x14, 0x00, 0xdd, /* .`...... */
|
||||
0x26, 0x63, 0x01, 0x04, 0x00, 0xd5, 0xcc, 0x29, /* &c.....) */
|
||||
0x82, 0x36, 0xd6, 0x57, 0x3d, 0xa7, 0xd5, 0x62, /* .6.W=..b */
|
||||
0x70, 0x12, 0x00, 0xc0, 0xf2, 0x19, 0x01, 0x03, /* p....... */
|
||||
0x61, 0x1e, 0x1c, 0x33, 0x34, 0x2d, 0x45, 0x46, /* a..34-EF */
|
||||
0x2d, 0x42, 0x36, 0x2d, 0x41, 0x46, 0x2d, 0x34, /* -B6-AF-4 */
|
||||
0x41, 0x2d, 0x36, 0x30, 0x3a, 0x4f, 0x70, 0x65, /* A-60:Ope */
|
||||
0x6e, 0x57, 0x69, 0x66, 0x69, 0x3d, 0x06, 0x00, /* nWifi=.. */
|
||||
0x00, 0x00, 0x13, 0x06, 0x06, 0x00, 0x00, 0x00, /* ........ */
|
||||
0x02, 0x05, 0x06, 0x00, 0x00, 0x00, 0x01, 0x1f, /* ........ */
|
||||
0x13, 0x42, 0x36, 0x2d, 0x43, 0x34, 0x2d, 0x30, /* .B6-C4-0 */
|
||||
0x36, 0x2d, 0x30, 0x39, 0x2d, 0x31, 0x35, 0x2d, /* 6-09-15- */
|
||||
0x42, 0x37, 0x4d, 0x18, 0x43, 0x4f, 0x4e, 0x4e, /* B7M.CONN */
|
||||
0x45, 0x43, 0x54, 0x20, 0x35, 0x34, 0x4d, 0x62, /* ECT 54Mb */
|
||||
0x70, 0x73, 0x20, 0x38, 0x30, 0x32, 0x2e, 0x31, /* ps 802.1 */
|
||||
0x31, 0x61, 0x2c, 0x12, 0x33, 0x42, 0x45, 0x44, /* 1a,.3BED */
|
||||
0x37, 0x32, 0x39, 0x30, 0x44, 0x30, 0x43, 0x38, /* 7290D0C8 */
|
||||
0x35, 0x36, 0x44, 0x33, 0xba, 0x06, 0x00, 0x0f, /* 56D3.... */
|
||||
0xac, 0x04, 0xbb, 0x06, 0x00, 0x0f, 0xac, 0x04, /* ........ */
|
||||
0xbc, 0x06, 0x00, 0x0f, 0xac, 0x05, 0xbd, 0x06, /* ........ */
|
||||
0x00, 0x0f, 0xac, 0x06, 0x1a, 0x1b, 0x00, 0x00, /* ........ */
|
||||
0xe6, 0x08, 0x47, 0x15, 0x01, 0x13, 0x33, 0x34, /* ..G...34 */
|
||||
0x2d, 0x65, 0x66, 0x2d, 0x62, 0x36, 0x2d, 0x61, /* -ef-b6-a */
|
||||
0x66, 0x2d, 0x34, 0x61, 0x2d, 0x35, 0x63, 0x0c, /* f-4a-5c. */
|
||||
0x06, 0x00, 0x00, 0x05, 0x78, 0x4f, 0x08, 0x02, /* ....xO.. */
|
||||
0x01, 0x00, 0x06, 0x01, 0x61, 0x50, 0x12, 0x20, /* ....aP. */
|
||||
0x9c, 0xae, 0xe5, 0xe3, 0x77, 0xaf, 0x0b, 0x1b, /* ....w... */
|
||||
0xaf, 0x0e, 0xb5, 0x08, 0x82, 0x9e, 0xeb /* ....... */
|
||||
};
|
||||
|
||||
/* Reassembled EAP (6 bytes) */
|
||||
static const unsigned char pkt41_1[6] = {
|
||||
0x02, 0x01, 0x00, 0x06, 0x01, 0x61 /* .....a */
|
||||
};
|
||||
|
||||
1
pcap/radius.blob.bin
Normal file
1
pcap/radius.blob.bin
Normal file
@@ -0,0 +1 @@
|
||||
192.168.178.1
|
||||
BIN
pcap/radius.pcapng
Normal file
BIN
pcap/radius.pcapng
Normal file
Binary file not shown.
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
|
||||
}
|
||||
72
radius_config_sample.json
Normal file
72
radius_config_sample.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"pools" : [
|
||||
{
|
||||
"name" : "master" ,
|
||||
"description" : "master pool",
|
||||
"useByDefault" : true,
|
||||
"authConfig" : {
|
||||
"strategy" : "weighted",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "10.100.0.1",
|
||||
"port" : 1812,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
},
|
||||
{
|
||||
"name" : "svr2",
|
||||
"ip" : "10.100.10.1",
|
||||
"port" : 1812,
|
||||
"weight" : 20,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
},
|
||||
"acctConfig" : {
|
||||
"strategy" : "random",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "10.100.0.1",
|
||||
"port" : 1813,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
},
|
||||
{
|
||||
"name" : "svr2",
|
||||
"ip" : "10.100.10.1",
|
||||
"port" : 1813,
|
||||
"weight" : 20,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
},
|
||||
"coaConfig" : {
|
||||
"strategy" : "round_robin",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "svr1",
|
||||
"ip" : "10.100.0.1",
|
||||
"port" : 3799,
|
||||
"weight" : 10,
|
||||
"secret" : "my_secret!"
|
||||
},
|
||||
{
|
||||
"name" : "svr2",
|
||||
"ip" : "10.100.10.1",
|
||||
"port" : 3799,
|
||||
"weight" : 20,
|
||||
"secret" : "my_secret!"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
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,21 +5,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include "Poco/Environment.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ReactorPool {
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit ReactorPool(unsigned int NumberOfThreads = Poco::Environment::processorCount())
|
||||
: NumberOfThreads_(NumberOfThreads) {}
|
||||
explicit AP_WS_ReactorThreadPool() {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()*2;
|
||||
if(NumberOfThreads_==0)
|
||||
NumberOfThreads_=4;
|
||||
}
|
||||
|
||||
void Start(const std::string & ThreadNamePrefix) {
|
||||
~ AP_WS_ReactorThreadPool() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
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->start(*NewReactor);
|
||||
NewThread->setName(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));
|
||||
}
|
||||
@@ -31,17 +41,21 @@ namespace OpenWifi {
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor &NextReactor() {
|
||||
std::shared_lock Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
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_;
|
||||
};
|
||||
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,240 +8,277 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void CommandManager::run() {
|
||||
Utils::SetThreadName("cmd:mgr");
|
||||
Running_ = true;
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while(NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification*>(NextMsg.get());
|
||||
if(Resp!= nullptr) {
|
||||
const Poco::JSON::Object & Payload = Resp->Payload_;
|
||||
const std::string & SerialNumber = Resp->SerialNumber_;
|
||||
|
||||
if(!Payload.has(uCentralProtocol::ID)){
|
||||
Logger().error(fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
return;
|
||||
}
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while (NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification *>(NextMsg.get());
|
||||
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
if(ID<2) {
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
return;
|
||||
try {
|
||||
if (Resp != nullptr) {
|
||||
const Poco::JSON::Object &Payload = Resp->Payload_;
|
||||
const std::string &SerialNumber = Resp->SerialNumber_;
|
||||
|
||||
std::ostringstream SS;
|
||||
Payload.stringify(SS);
|
||||
|
||||
if (!Payload.has(uCentralProtocol::ID)) {
|
||||
poco_error(Logger(), fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
|
||||
auto RPC = OutStandingRequests_.find(Idx);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
Logger().warning(fmt::format("({}): Outdated RPC {}", SerialNumber, ID));
|
||||
return;
|
||||
}
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - RPC->second->submitted;
|
||||
StorageService()->CommandCompleted(RPC->second->uuid, Payload, rpc_execution_time, true);
|
||||
if(RPC->second->rpc_entry) {
|
||||
RPC->second->rpc_entry->set_value(Payload);
|
||||
}
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),"Exception occurred during run.");
|
||||
}
|
||||
NextMsg = ResponseQueue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger(),"RPC Command processor stopping.");
|
||||
}
|
||||
|
||||
int CommandManager::Start() {
|
||||
Logger().notice("Starting...");
|
||||
ManagerThread.start(*this);
|
||||
poco_notice(Logger(),"Starting...");
|
||||
|
||||
ManagerThread.start(*this);
|
||||
|
||||
JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onJanitorTimer);
|
||||
JanitorTimer_.setStartInterval( 10000 );
|
||||
JanitorTimer_.setPeriodicInterval(10 * 60 * 1000); // 1 hours
|
||||
JanitorTimer_.start(*JanitorCallback_);
|
||||
JanitorTimer_.start(*JanitorCallback_, 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_);
|
||||
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 > 120000ms) {
|
||||
Logger().debug(fmt::format("Timing 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) {
|
||||
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("Parsing: {}", Cmd.UUID));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
Logger().information(fmt::format("Parsed: {}", Cmd.UUID));
|
||||
auto Result = PostCommandDisk( Cmd.SerialNumber,
|
||||
Cmd.Command,
|
||||
*Params,
|
||||
Cmd.UUID,
|
||||
Sent);
|
||||
if(Sent) {
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
OutstandingUUIDs_.insert(Cmd.UUID);
|
||||
Logger().information(fmt::format("{}: Sent command '{}-{}'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
|
||||
} else {
|
||||
Logger().information(fmt::format("{}: Could not send command '{}-{}'", Cmd.SerialNumber, Cmd.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 '{}-{}'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
|
||||
Logger().log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
Logger().information(fmt::format("{}: Exception - hard fail - Failed command '{}-{}'", Cmd.SerialNumber, Cmd.Command, 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);
|
||||
Logger().information(
|
||||
fmt::format("({}): Sending command '{}', ID: {}", SerialNumber, Method, Idx.Id));
|
||||
|
||||
Object->submitted = std::chrono::high_resolution_clock::now();
|
||||
Object->uuid = UUID;
|
||||
if(disk_only) {
|
||||
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())) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* void CommandManager::onRPCAnswer(bool &b) {
|
||||
if(b) {
|
||||
RPCResponse Resp;
|
||||
auto S = RPCResponseQueue_->Read(Resp);
|
||||
const std::string & SerialNumber = Resp.serialNumber;
|
||||
std::lock_guard M(Mutex_);
|
||||
if(S) {
|
||||
if(!Resp.payload.has(uCentralProtocol::ID)){
|
||||
Logger().error(fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t ID = Resp.payload.get(uCentralProtocol::ID);
|
||||
if(ID<2) {
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
return;
|
||||
}
|
||||
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
|
||||
auto RPC = OutStandingRequests_.find(Idx);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
Logger().warning(fmt::format("({}): Outdated RPC {}", SerialNumber, ID));
|
||||
return;
|
||||
}
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - RPC->second->submitted;
|
||||
StorageService()->CommandCompleted(RPC->second->uuid, Resp.payload, rpc_execution_time, true);
|
||||
if(RPC->second->rpc_entry) {
|
||||
RPC->second->rpc_entry->set_value(Resp.payload);
|
||||
}
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
} // namespace
|
||||
@@ -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::shared_mutex LocalMutex_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
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,23 +6,28 @@
|
||||
// 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"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -36,6 +41,7 @@ namespace OpenWifi {
|
||||
StorageService(),
|
||||
SerialNumberCache(),
|
||||
ConfigurationValidator(),
|
||||
WebSocketClientServer(),
|
||||
OUIServer(),
|
||||
FindCountryFromIP(),
|
||||
DeviceRegistry(),
|
||||
@@ -44,7 +50,9 @@ namespace OpenWifi {
|
||||
StorageArchiver(),
|
||||
TelemetryStream(),
|
||||
RTTYS_server(),
|
||||
WebSocketServer()
|
||||
RADIUS_proxy_server(),
|
||||
VenueBroadcaster(),
|
||||
AP_WS_Server()
|
||||
});
|
||||
return &instance;
|
||||
}
|
||||
@@ -85,6 +93,8 @@ namespace OpenWifi {
|
||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning",false);
|
||||
DeviceTypes_ = DefaultDeviceTypes;
|
||||
|
||||
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string & Id ) const {
|
||||
@@ -98,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,8 +27,8 @@
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
|
||||
#include "Dashboard.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "GwWebSocketClient.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -56,7 +58,7 @@ namespace OpenWifi {
|
||||
bool AutoProvisioning_ = false;
|
||||
std::vector<std::pair<std::string,std::string>> DeviceTypes_;
|
||||
DeviceDashboard DB_;
|
||||
|
||||
std::unique_ptr<GwWebSocketClient> WebSocketProcessor_;
|
||||
};
|
||||
|
||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
void DeviceDashboard::Create() {
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
|
||||
if(LastRun_==0 || (Now-LastRun_)>120) {
|
||||
DB_.reset();
|
||||
|
||||
@@ -7,144 +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 = std::time(nullptr);
|
||||
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::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;
|
||||
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::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::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::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;
|
||||
}
|
||||
|
||||
} // 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,80 +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);
|
||||
bool SendFrame(std::uint64_t SerialNumber, const std::string & Payload) const ;
|
||||
|
||||
inline void SetPendingUUID(const std::string & SerialNumber, uint64_t PendingUUID) {
|
||||
return SetPendingUUID(Utils::SerialNumberToInt(SerialNumber), PendingUUID);
|
||||
}
|
||||
void SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID);
|
||||
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);
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(const std::string & SerialNumber) {
|
||||
return GetDeviceConnection(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
void SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber);
|
||||
bool EndSession(std::uint64_t connection_id, std::uint64_t serial_number);
|
||||
|
||||
[[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;
|
||||
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:
|
||||
inline static std::atomic_uint64_t Id_=1;
|
||||
std::map<uint64_t ,std::shared_ptr<ConnectionEntry>> Devices_;
|
||||
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;
|
||||
|
||||
DeviceRegistry() noexcept:
|
||||
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto DeviceRegistry() { return DeviceRegistry::instance(); }
|
||||
|
||||
@@ -7,29 +7,28 @@
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/HTTPServerParams.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/DynamicAny.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "Poco/Net/PartHandler.h"
|
||||
#include "Poco/Net/MessageHeader.h"
|
||||
#include "Poco/Net/MultipartReader.h"
|
||||
#include "Poco/CountingStream.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
#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();
|
||||
@@ -41,37 +40,68 @@ namespace OpenWifi {
|
||||
Path_ = "/tmp";
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
std::string l{"Starting: " +
|
||||
Svr.Address() + ":" + std::to_string(Svr.Port()) +
|
||||
" key:" + Svr.KeyFile() +
|
||||
" cert:" + Svr.CertFile()};
|
||||
Logger().information(l);
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
poco_notice(Logger(), fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
auto Sock{Svr.CreateSocket(Logger())};
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if(!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
MicroService::instance().ConfigGetString("openwifi.fileuploader.uri", "");
|
||||
if (TmpName.empty()) {
|
||||
FullName_ =
|
||||
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
poco_information(Logger(),fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
if(FullName_.empty()) {
|
||||
std::string TmpName = MicroService::instance().ConfigGetString("openwifi.fileuploader.uri","");
|
||||
if(TmpName.empty()) {
|
||||
FullName_ =
|
||||
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE ;
|
||||
}
|
||||
Logger().information(fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
|
||||
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()};
|
||||
poco_information(Logger(),l);
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new FileUpLoaderRequestHandlerFactory(Logger()), Pool_, Sock, Params);
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if (!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
MicroService::instance().ConfigGetString("openwifi.fileuploader.uri", "");
|
||||
if (TmpName.empty()) {
|
||||
FullName_ =
|
||||
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
poco_information(Logger(), fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
}
|
||||
}
|
||||
|
||||
MaxSize_ = 1000 * MicroService::instance().ConfigGetInt("openwifi.fileuploader.maxsize", 10000);
|
||||
@@ -81,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();
|
||||
}
|
||||
@@ -94,18 +124,18 @@ namespace OpenWifi {
|
||||
bool FileUploader::AddUUID( const std::string & UUID) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
uint64_t Now = time(nullptr) ;
|
||||
uint64_t now = OpenWifi::Now();
|
||||
|
||||
// remove old stuff...
|
||||
for(auto i=OutStandingUploads_.cbegin();i!=OutStandingUploads_.end();) {
|
||||
if ((Now-i->second) > (60 * 30))
|
||||
OutStandingUploads_.erase(i++);
|
||||
for(auto i=OutStandingUploads_.begin();i!=OutStandingUploads_.end();) {
|
||||
if ((now-i->second) > (60 * 30))
|
||||
i = OutStandingUploads_.erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
if(!UUID.empty())
|
||||
OutStandingUploads_[UUID] = Now;
|
||||
OutStandingUploads_[UUID] = now;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -121,64 +151,39 @@ namespace OpenWifi {
|
||||
OutStandingUploads_.erase(UUID);
|
||||
}
|
||||
|
||||
class FileUploaderPartHandler: public Poco::Net::PartHandler
|
||||
{
|
||||
public:
|
||||
FileUploaderPartHandler(std::string UUID, Poco::Logger & Logger):
|
||||
UUID_(std::move(UUID)),
|
||||
Logger_(Logger)
|
||||
{
|
||||
}
|
||||
|
||||
void handlePart(const Poco::Net::MessageHeader& Header, std::istream& Stream) override
|
||||
{
|
||||
try {
|
||||
Name_ = "(unnamed)";
|
||||
if (Header.has("Content-Disposition")) {
|
||||
std::string Disposition;
|
||||
Poco::Net::NameValueCollection Parameters;
|
||||
Poco::Net::MessageHeader::splitParameters(Header["Content-Disposition"],
|
||||
Disposition, Parameters);
|
||||
Name_ = Parameters.get("filename", "(unnamed)");
|
||||
}
|
||||
|
||||
std::string FinalFileName = FileUploader()->Path() + "/" + UUID_;
|
||||
|
||||
Logger().information(fmt::format("FILE-UPLOADER: uploading trace for {}", FinalFileName));
|
||||
Poco::CountingInputStream InputStream(Stream);
|
||||
std::ofstream OutputStream(FinalFileName, std::ofstream::out);
|
||||
Poco::StreamCopier::copyStream(InputStream, OutputStream);
|
||||
|
||||
Poco::File TmpFile(FinalFileName);
|
||||
Length_ = TmpFile.getSize();
|
||||
if (Length_ < FileUploader()->MaxSize()) {
|
||||
Good_=true;
|
||||
} else {
|
||||
TmpFile.remove();
|
||||
Error_ = "File is too large.";
|
||||
}
|
||||
return;
|
||||
} catch (const Poco::Exception &E ) {
|
||||
Logger().log(E);
|
||||
Error_ = std::string("Upload caused an internal error: ") + E.what() ;
|
||||
}
|
||||
class FileUploaderPartHandler2 : public Poco::Net::PartHandler {
|
||||
public:
|
||||
FileUploaderPartHandler2(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
|
||||
Id_(std::move(Id)),
|
||||
Logger_(Logger),
|
||||
OutputStream_(ofs){
|
||||
}
|
||||
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
|
||||
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
|
||||
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
|
||||
std::string Disposition;
|
||||
Poco::Net::NameValueCollection Parameters;
|
||||
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
|
||||
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
|
||||
}
|
||||
Poco::CountingInputStream InputStream(Stream);
|
||||
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
|
||||
Length_ = OutputStream_.str().size();
|
||||
}
|
||||
[[nodiscard]] uint64_t Length() const { return Length_; }
|
||||
[[nodiscard]] std::string &Name() { return Name_; }
|
||||
[[nodiscard]] std::string &ContentType() { return FileType_; }
|
||||
|
||||
[[nodiscard]] uint64_t Length() const { return Length_; }
|
||||
[[nodiscard]] const std::string& Name() const { return Name_; }
|
||||
[[nodiscard]] bool Good() const { return Good_; }
|
||||
std::string & Error() { return Error_; }
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
private:
|
||||
uint64_t Length_=0;
|
||||
bool Good_=false;
|
||||
std::string Name_;
|
||||
std::string UUID_;
|
||||
std::string Error_;
|
||||
Poco::Logger & Logger_;
|
||||
};
|
||||
private:
|
||||
uint64_t Length_ = 0;
|
||||
std::string FileType_;
|
||||
std::string Name_;
|
||||
std::string Id_;
|
||||
Poco::Logger &Logger_;
|
||||
std::stringstream &OutputStream_;
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; };
|
||||
};
|
||||
|
||||
class FormRequestHandler: public Poco::Net::HTTPRequestHandler
|
||||
{
|
||||
@@ -189,40 +194,71 @@ namespace OpenWifi {
|
||||
{
|
||||
}
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override
|
||||
{
|
||||
try {
|
||||
FileUploaderPartHandler partHandler(UUID_,Logger());
|
||||
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) final {
|
||||
|
||||
Poco::Net::HTMLForm form(Request, Request.stream(), partHandler);
|
||||
Utils::SetThreadName("FileUploader");
|
||||
const auto ContentType = Request.getContentType();
|
||||
const auto Tokens = Poco::StringTokenizer(ContentType,";",Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
Response.setContentType("application/json");
|
||||
poco_debug(Logger(),fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
if (partHandler.Good()) {
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 0);
|
||||
StorageService()->AttachFileToCommand(UUID_);
|
||||
} else {
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 13);
|
||||
Answer.set("errorText", partHandler.Error() );
|
||||
StorageService()->CancelWaitFile(UUID_, partHandler.Error() );
|
||||
try {
|
||||
if (Poco::icompare(Tokens[0], "multipart/form-data") == 0 ||
|
||||
Poco::icompare(Tokens[0], "multipart/mixed") == 0) {
|
||||
|
||||
const auto &BoundaryTokens =
|
||||
Poco::StringTokenizer(Tokens[1], "=", Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
if (BoundaryTokens[0] == "boundary") {
|
||||
const std::string &Boundary = BoundaryTokens[1];
|
||||
Poco::Net::MultipartReader Reader(Request.stream(), Boundary);
|
||||
bool Done = false;
|
||||
|
||||
while (!Done) {
|
||||
Poco::Net::MessageHeader Hdr;
|
||||
Reader.nextPart(Hdr);
|
||||
|
||||
const auto PartContentType = Hdr.get("Content-Type", "");
|
||||
if (PartContentType == "application/octet-stream") {
|
||||
std::stringstream FileContent;
|
||||
Poco::StreamCopier::copyStream(Reader.stream(), FileContent);
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 0);
|
||||
poco_debug(Logger(),fmt::format("{}: Trace file uploaded.", UUID_));
|
||||
StorageService()->AttachFileDataToCommand(UUID_, FileContent);
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
return;
|
||||
} else {
|
||||
std::stringstream OO;
|
||||
Poco::StreamCopier::copyStream(Reader.stream(), OO);
|
||||
}
|
||||
|
||||
if (!Reader.hasNextPart())
|
||||
Done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
return;
|
||||
}
|
||||
catch( const Poco::Exception & E )
|
||||
{
|
||||
Logger().warning(fmt::format("Error occurred while performing upload. Error='{}'",E.displayText()));
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),"Exception while receiving trace file.");
|
||||
}
|
||||
|
||||
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_);
|
||||
Answer.set("error", 13);
|
||||
Answer.set("errorText", "Attached file is too large");
|
||||
StorageService()->CancelWaitFile(UUID_, Error);
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
}
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
private:
|
||||
std::string UUID_;
|
||||
Poco::Logger & Logger_;
|
||||
@@ -230,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);
|
||||
@@ -246,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 {
|
||||
|
||||
@@ -37,15 +38,13 @@ namespace OpenWifi {
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
|
||||
Poco::ThreadPool Pool_;
|
||||
std::string FullName_;
|
||||
std::map<std::string,uint64_t> OutStandingUploads_;
|
||||
std::string Path_;
|
||||
uint64_t MaxSize_=10000000;
|
||||
|
||||
explicit FileUploader() noexcept:
|
||||
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader"),
|
||||
Pool_("FileUpLoaderPool")
|
||||
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 )
|
||||
|
||||
66
src/GwWebSocketClient.cpp
Normal file
66
src/GwWebSocketClient.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-04-28.
|
||||
//
|
||||
|
||||
#include "GwWebSocketClient.h"
|
||||
#include "SerialNumberCache.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
GwWebSocketClient::GwWebSocketClient(Poco::Logger &Logger):
|
||||
Logger_(Logger){
|
||||
WebSocketClientServer()->SetProcessor(this);
|
||||
}
|
||||
|
||||
GwWebSocketClient::~GwWebSocketClient() {
|
||||
WebSocketClientServer()->SetProcessor(nullptr);
|
||||
}
|
||||
|
||||
void GwWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ) {
|
||||
try {
|
||||
if (O->has("command")) {
|
||||
auto Command = O->get("command").toString();
|
||||
if (Command == "serial_number_search" && O->has("serial_prefix")) {
|
||||
ws_command_serial_number_search(O,Done,Answer);
|
||||
} else if (Command=="exit") {
|
||||
ws_command_exit(O,Done,Answer);
|
||||
} else {
|
||||
ws_command_invalid(O, Done, Answer);
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
|
||||
void GwWebSocketClient::ws_command_serial_number_search(const Poco::JSON::Object::Ptr &O,
|
||||
bool &Done, std::string &Answer) {
|
||||
Done = false;
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||
std::vector<uint64_t> Numbers;
|
||||
SerialNumberCache()->FindNumbers(Prefix, 50, Numbers);
|
||||
Poco::JSON::Array Arr;
|
||||
for (const auto &i : Numbers)
|
||||
Arr.add(Utils::int_to_hex(i));
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set("serialNumbers", Arr);
|
||||
std::ostringstream SS;
|
||||
Poco::JSON::Stringifier::stringify(RetObj, SS);
|
||||
Answer = SS.str();
|
||||
}
|
||||
}
|
||||
|
||||
void GwWebSocketClient::ws_command_exit([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
|
||||
Done = true;
|
||||
Answer = R"lit({ "closing" : "Goodbye! Aurevoir! Hasta la vista!" })lit";
|
||||
}
|
||||
|
||||
void GwWebSocketClient::ws_command_invalid([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
|
||||
Done = false;
|
||||
Answer = std::string{R"lit({ "error" : "invalid command" })lit"};
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
23
src/GwWebSocketClient.h
Normal file
23
src/GwWebSocketClient.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-04-28.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class GwWebSocketClient : public WebSocketClientProcessor {
|
||||
public:
|
||||
explicit GwWebSocketClient(Poco::Logger &Logger);
|
||||
virtual ~GwWebSocketClient();
|
||||
virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done );
|
||||
void ws_command_serial_number_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
|
||||
void ws_command_exit( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
|
||||
void ws_command_invalid( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
|
||||
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
};
|
||||
}
|
||||
@@ -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"
|
||||
@@ -21,43 +18,41 @@ namespace OpenWifi {
|
||||
|
||||
int OUIServer::Start() {
|
||||
Running_ = true;
|
||||
LatestOUIFileName_ = MicroService::instance().DataDir() + "/newOUIFile.txt";
|
||||
CurrentOUIFileName_ = MicroService::instance().DataDir() + "/current_oui.txt";
|
||||
|
||||
UpdaterCallBack_ = std::make_unique<Poco::TimerCallback<OUIServer>>(*this, &OUIServer::onTimer);
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
|
||||
Timer_.setPeriodicInterval(7 * 24 * 60 * 60 * 1000);
|
||||
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();
|
||||
}
|
||||
|
||||
bool OUIServer::GetFile(const std::string &FileName) {
|
||||
try {
|
||||
Logger().information(fmt::format("Start: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
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;
|
||||
Poco::File F(FileName);
|
||||
if(F.exists()) {
|
||||
auto LastModified = F.getLastModified();
|
||||
auto Delta = OpenWifi::Now() - LastModified.epochTime();
|
||||
if((Delta / (24*60*60)) < 1)
|
||||
return true;
|
||||
F.remove();
|
||||
}
|
||||
OS.open(FileName);
|
||||
Poco::StreamCopier::copyStream(*pStr, OS);
|
||||
OS.close();
|
||||
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);
|
||||
@@ -102,32 +97,48 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void OUIServer::onTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
Utils::SetThreadName("ouisvr-timer");
|
||||
if(Updating_)
|
||||
return;
|
||||
Updating_ = true;
|
||||
|
||||
// fetch data from server, if not available, just use the file we already have.
|
||||
std::string LatestOUIFileName{ MicroService::instance().DataDir() + "/newOUIFile.txt"};
|
||||
std::string CurrentOUIFileName{ MicroService::instance().DataDir() + "/current_oui.txt"};
|
||||
Poco::File Current(CurrentOUIFileName_);
|
||||
if(Current.exists()) {
|
||||
if((OpenWifi::Now()-Current.getLastModified().epochTime()) < (7*24*60*60)) {
|
||||
if(!Initialized_) {
|
||||
if(ProcessFile(CurrentOUIFileName_, OUIs_)) {
|
||||
Initialized_ = true;
|
||||
Updating_=false;
|
||||
poco_information(Logger(), "Using cached file.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Updating_=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OUIMap TmpOUIs;
|
||||
if(GetFile(LatestOUIFileName) && ProcessFile(LatestOUIFileName, TmpOUIs)) {
|
||||
if(GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
|
||||
std::lock_guard G(Mutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
LastUpdate_ = std::time(nullptr);
|
||||
Poco::File F1(CurrentOUIFileName);
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
Poco::File F1(CurrentOUIFileName_);
|
||||
if(F1.exists())
|
||||
F1.remove();
|
||||
Poco::File F2(LatestOUIFileName);
|
||||
F2.renameTo(CurrentOUIFileName);
|
||||
Logger().information(fmt::format("New OUI file {} downloaded.",LatestOUIFileName));
|
||||
Poco::File F2(LatestOUIFileName_);
|
||||
F2.renameTo(CurrentOUIFileName_);
|
||||
poco_information(Logger(), fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
} else if(OUIs_.empty()) {
|
||||
if(ProcessFile(CurrentOUIFileName, TmpOUIs)) {
|
||||
LastUpdate_ = std::time(nullptr);
|
||||
if(ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
std::lock_guard G(Mutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
}
|
||||
}
|
||||
Initialized_=true;
|
||||
Updating_ = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,12 +31,13 @@ namespace OpenWifi {
|
||||
|
||||
private:
|
||||
uint64_t LastUpdate_ = 0 ;
|
||||
// bool ValidFile_=false;
|
||||
bool Initialized_ = false;
|
||||
OUIMap OUIs_;
|
||||
std::atomic_bool Updating_=false;
|
||||
std::atomic_bool Running_=false;
|
||||
volatile std::atomic_bool Updating_=false;
|
||||
volatile std::atomic_bool Running_=false;
|
||||
Poco::Timer Timer_;
|
||||
std::unique_ptr<Poco::TimerCallback<OUIServer>> UpdaterCallBack_;
|
||||
std::string LatestOUIFileName_,CurrentOUIFileName_;
|
||||
|
||||
OUIServer() noexcept:
|
||||
SubSystemServer("OUIServer", "OUI-SVR", "ouiserver")
|
||||
|
||||
1856
src/ParseWifiScan.h
Normal file
1856
src/ParseWifiScan.h
Normal file
File diff suppressed because it is too large
Load Diff
672
src/RADIUS_helpers.h
Normal file
672
src/RADIUS_helpers.h
Normal file
@@ -0,0 +1,672 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-06-20.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#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};
|
||||
uint16_t pos{0};
|
||||
unsigned len{0};
|
||||
};
|
||||
struct RawRadiusPacket {
|
||||
unsigned char code{1};
|
||||
unsigned char identifier{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
|
||||
//
|
||||
static const uint32_t TIP_vendor_id = 58888;
|
||||
static const unsigned char TIP_serial = 1;
|
||||
static const unsigned char TIP_AAAipaddr = 2;
|
||||
static const unsigned char TIP_AAAipv6addr = 3;
|
||||
|
||||
using AttributeList = std::list<RadiusAttribute>;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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=(unsigned int)(Buffer[pos+1]-2)};
|
||||
if(pos+Attr.len<=Size) {
|
||||
Attrs.emplace_back(Attr);
|
||||
} else {
|
||||
std::cout << "Bad parse1: " << (uint32_t) (pos+Attr.len) << " S:" << Size << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(Buffer[pos+1]==0) {
|
||||
std::cout << "Bad parse2: " << (uint32_t) (pos+Attr.len) << " S:" << Size << std::endl;
|
||||
return false;
|
||||
}
|
||||
pos+=Buffer[pos+1];
|
||||
x--;
|
||||
}
|
||||
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_ = (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_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
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_);}
|
||||
|
||||
void Evaluate(uint16_t size) {
|
||||
Size_ = size;
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.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;
|
||||
|
||||
while(p<Size_) {
|
||||
os << std::setfill('0') << std::setw(4) << p << ": ";
|
||||
uint16_t v=0;
|
||||
while(v<16 && p+v<Size_) {
|
||||
os << std::setfill('0') << std::setw(2) << std::right << std::hex << (uint16_t )((const unsigned char *)&P_)[p+v] << " ";
|
||||
v++;
|
||||
}
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec << std::endl << std::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;
|
||||
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==26) {
|
||||
AttributeList VendorAttributes;
|
||||
uint32_t VendorId = htonl( *(const uint32_t *)&(P_.attributes[attribute.pos]));
|
||||
// std::cout << VendorId << std::endl;
|
||||
if(VendorId==TIP_vendor_id && attribute.len>(4+2)) {
|
||||
if (ParseRadius(attribute.pos + 4, &P_.attributes[attribute.pos + 4], attribute.len - 4 - 2,
|
||||
VendorAttributes)) {
|
||||
// std::cout << VendorAttributes << std::endl;
|
||||
for (const auto &vendorAttr: VendorAttributes) {
|
||||
if (vendorAttr.type == TIP_serial) {
|
||||
for (uint16_t i = 0; i < vendorAttr.len; i++) {
|
||||
if (P_.attributes[vendorAttr.pos + i] == '-')
|
||||
continue;
|
||||
R += (char) P_.attributes[vendorAttr.pos + i];
|
||||
}
|
||||
return R;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
std::string ExtractSerialNumberFromProxyState() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==33) {
|
||||
const char * SN = (const char *)&P_.attributes[attribute.pos];
|
||||
auto i=0;
|
||||
while(*SN!=':' && i<12) {
|
||||
Result+=*SN++;
|
||||
i++;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractProxyStateDestination() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==33 && attribute.len>2) {
|
||||
std::string Attr33;
|
||||
// format is serial:IP:port:interface
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
|
||||
auto Parts = Poco::StringTokenizer(Attr33,":");
|
||||
if(Parts.count()==4)
|
||||
return Parts[1]+":"+Parts[2];
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractCallingStationID() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==31 && attribute.len>2) {
|
||||
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractCalledStationID() {
|
||||
std::string Result;
|
||||
for(const auto &attribute:Attrs_) {
|
||||
if(attribute.type==30 && attribute.len>2) {
|
||||
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
[[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};
|
||||
AttributeList Attrs_;
|
||||
bool Valid_=false;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
os << P.Attrs_ ;
|
||||
return os;
|
||||
}
|
||||
}
|
||||
592
src/RADIUS_proxy_server.cpp
Normal file
592
src/RADIUS_proxy_server.cpp
Normal file
@@ -0,0 +1,592 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-18.
|
||||
//
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RADIUS_helpers.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
const int SMALLEST_RADIUS_PACKET = 20+19+4;
|
||||
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
|
||||
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
|
||||
const int DEFAULT_RADIUS_CoA_PORT = 3799;
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
ConfigFilename_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
|
||||
Poco::File Config(ConfigFilename_);
|
||||
|
||||
enabled_ = MicroService::instance().ConfigGetBool("radius.proxy.enable",false);
|
||||
if(!enabled_ && !Config.exists())
|
||||
return 0;
|
||||
|
||||
enabled_ = true;
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4,true);
|
||||
Poco::Net::SocketAddress AuthSockAddrV6(Poco::Net::AddressFamily::IPv6,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6,true);
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.accounting.port",DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4,true);
|
||||
Poco::Net::SocketAddress AcctSockAddrV6(Poco::Net::AddressFamily::IPv6,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.accounting.port",DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6,true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4,true);
|
||||
Poco::Net::SocketAddress CoASockAddrV6(Poco::Net::AddressFamily::IPv6,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6,true);
|
||||
|
||||
RadiusReactor_.addEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
RadiusReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
RadiusReactor_.addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
RadiusReactor_.addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
|
||||
RadiusReactor_.addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_.addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
ParseConfig();
|
||||
|
||||
// start RADSEC servers...
|
||||
StartRADSECServers();
|
||||
RadiusReactorThread_.start(RadiusReactor_);
|
||||
|
||||
Utils::SetThreadName(RadiusReactorThread_,"rad:reactor");
|
||||
|
||||
running_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(enabled_ && running_) {
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
for(auto &[_,radsec_server]:RADSECservers_)
|
||||
radsec_server->Stop();
|
||||
|
||||
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) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger(),"Accounting: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
poco_warning(Logger(),"Accounting: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_information(Logger(), fmt::format("Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAccountingData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger(),"Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
poco_warning(Logger(),"Authentication: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_information(Logger(), fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAuthenticationData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger(),"CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if(SerialNumber.empty()) {
|
||||
poco_warning(Logger(),"CoA/DM: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_information(Logger(), fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusCoAData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size) {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
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) {
|
||||
return Sock.sendTo(buf, size, S)==(int)size;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber, const char *buffer, std::size_t size) {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
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();
|
||||
|
||||
if(Destination.empty()) {
|
||||
Destination = "0.0.0.0:0";
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
uint64_t TotalV4=0, TotalV6=0;
|
||||
|
||||
for(const auto &server:Config.servers) {
|
||||
Poco::Net::IPAddress a;
|
||||
if(!Poco::Net::IPAddress::tryParse(server.ip,a)) {
|
||||
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));
|
||||
Destination D{
|
||||
.Addr = S,
|
||||
.state = 0,
|
||||
.step = 0,
|
||||
.weight = server.weight,
|
||||
.available = true,
|
||||
.strategy = Config.strategy,
|
||||
.monitor = Config. monitor,
|
||||
.monitorMethod = Config.monitorMethod,
|
||||
.methodParameters = Config.methodParameters,
|
||||
.useAsDefault = setAsDefault,
|
||||
.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);
|
||||
} else {
|
||||
TotalV6 += server.weight;
|
||||
V6.push_back(D);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &i:V4) {
|
||||
if(TotalV4==0) {
|
||||
i.step = 1000;
|
||||
} else {
|
||||
i.step = 1000 - ((1000 * i.weight) / TotalV4);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &i:V6) {
|
||||
if(TotalV6==0) {
|
||||
i.step = 1000;
|
||||
} else {
|
||||
i.step = 1000 - ((1000 * i.weight) / TotalV6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ParseConfig() {
|
||||
|
||||
try {
|
||||
Poco::File F(ConfigFilename_);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if(F.exists()) {
|
||||
std::ifstream ifs(ConfigFilename_,std::ios_base::binary);
|
||||
Poco::JSON::Parser P;
|
||||
auto RawConfig = P.parse(ifs).extract<Poco::JSON::Object::Ptr>();
|
||||
GWObjects::RadiusProxyPoolList RPC;
|
||||
if(RPC.from_json(RawConfig)) {
|
||||
ResetConfig();
|
||||
PoolList_ = RPC;
|
||||
for(const auto &pool:RPC.pools) {
|
||||
RadiusPool NewPool;
|
||||
ParseServerList(pool.authConfig, NewPool.AuthV4, NewPool.AuthV6, pool.useByDefault);
|
||||
ParseServerList(pool.acctConfig, NewPool.AcctV4, NewPool.AcctV6, pool.useByDefault);
|
||||
ParseServerList(pool.coaConfig, NewPool.CoaV4, NewPool.CoaV6, pool.useByDefault);
|
||||
Pools_.push_back(NewPool);
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger(),fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger(),fmt::format("No configuration file '{}' exists.",ConfigFilename_));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger(),fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
|
||||
}
|
||||
}
|
||||
|
||||
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::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, 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;
|
||||
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, P, UseRADSEC);
|
||||
}
|
||||
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D, bool &UseRADSEC) -> bool {
|
||||
for(const auto &entry:D)
|
||||
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), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::auth: {
|
||||
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), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress) {
|
||||
|
||||
if(Pool.size()==1) {
|
||||
return Pool[0].Addr;
|
||||
}
|
||||
|
||||
if (Pool[0].strategy == "weighted") {
|
||||
bool found = false;
|
||||
uint64_t cur_state = std::numeric_limits<uint64_t>::max();
|
||||
std::size_t pos = 0, index = 0;
|
||||
for (auto &i : Pool) {
|
||||
if (!i.available) {
|
||||
i.state += i.step;
|
||||
continue;
|
||||
}
|
||||
if (i.state < cur_state) {
|
||||
index = pos;
|
||||
cur_state = i.state;
|
||||
found = true;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
Pool[index].state += Pool[index].step;
|
||||
return Pool[index].Addr;
|
||||
} else if (Pool[0].strategy == "round_robin") {
|
||||
bool found = false;
|
||||
uint64_t cur_state = std::numeric_limits<uint64_t>::max();
|
||||
std::size_t pos = 0, index = 0;
|
||||
for (auto &i : Pool) {
|
||||
if (!i.available) {
|
||||
i.state += 1;
|
||||
continue;
|
||||
}
|
||||
if (i.state < cur_state) {
|
||||
index = pos;
|
||||
cur_state = i.state;
|
||||
found = true;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
Pool[index].state += 1;
|
||||
return Pool[index].Addr;
|
||||
} else if (Pool[0].strategy == "random") {
|
||||
if (Pool.size() > 1) {
|
||||
return Pool[std::rand() % Pool.size()].Addr;
|
||||
} else {
|
||||
return OriginalAddress;
|
||||
}
|
||||
}
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
|
||||
std::lock_guard G(Mutex_);
|
||||
PoolList_ = C;
|
||||
|
||||
Poco::JSON::Object Disk;
|
||||
C.to_json(Disk);
|
||||
|
||||
std::ofstream ofs(ConfigFilename_, std::ios_base::trunc | std::ios_base::binary );
|
||||
Disk.stringify(ofs);
|
||||
ofs.close();
|
||||
|
||||
if(!running_) {
|
||||
Start();
|
||||
}
|
||||
|
||||
ParseConfig();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ResetConfig() {
|
||||
PoolList_.pools.clear();
|
||||
Pools_.clear();
|
||||
defaultPoolIndex_=0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::DeleteConfig() {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
try {
|
||||
Poco::File F(ConfigFilename_);
|
||||
if (F.exists())
|
||||
F.remove();
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
ResetConfig();
|
||||
Stop();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::GetConfig(GWObjects::RadiusProxyPoolList &C) {
|
||||
std::lock_guard G(Mutex_);
|
||||
C = PoolList_;
|
||||
}
|
||||
|
||||
}
|
||||
111
src/RADIUS_proxy_server.h
Normal file
111
src/RADIUS_proxy_server.h
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-18.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Net/DatagramSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
|
||||
#include "RADSECserver.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
enum class radius_type {
|
||||
auth, acct, coa
|
||||
};
|
||||
|
||||
|
||||
class RADIUS_proxy_server : public SubSystemServer {
|
||||
public:
|
||||
inline static auto instance() {
|
||||
static auto instance_= new RADIUS_proxy_server;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
inline bool Enabled() const { return enabled_; }
|
||||
|
||||
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
|
||||
void SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
void SendAuthenticationData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
|
||||
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
|
||||
void DeleteConfig();
|
||||
void GetConfig(GWObjects::RadiusProxyPoolList &C);
|
||||
|
||||
void StartRADSECServers();
|
||||
void StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E);
|
||||
|
||||
struct Destination {
|
||||
Poco::Net::SocketAddress Addr;
|
||||
uint64_t state = 0;
|
||||
uint64_t step = 0;
|
||||
uint64_t weight=0;
|
||||
bool available = true;
|
||||
std::string strategy;
|
||||
bool monitor=false;
|
||||
std::string monitorMethod;
|
||||
std::vector<std::string> methodParameters;
|
||||
bool useAsDefault=false;
|
||||
bool useRADSEC=false;
|
||||
std::vector<std::string> realms;
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
|
||||
Poco::Net::SocketReactor 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;
|
||||
std::vector<Destination> AcctV4;
|
||||
std::vector<Destination> AcctV6;
|
||||
std::vector<Destination> CoaV4;
|
||||
std::vector<Destination> CoaV6;
|
||||
};
|
||||
|
||||
std::vector<RadiusPool> Pools_;
|
||||
uint defaultPoolIndex_=0;
|
||||
bool enabled_=false;
|
||||
bool defaultIsRADSEC_=false;
|
||||
std::atomic_bool running_=false;
|
||||
|
||||
RADIUS_proxy_server() noexcept:
|
||||
SubSystemServer("RADIUS-PROXY", "RADIUS-PROXY", "radius.proxy")
|
||||
{
|
||||
}
|
||||
|
||||
static bool SendData( Poco::Net::DatagramSocket & Sock, const unsigned char *buf , std::size_t size, const Poco::Net::SocketAddress &S);
|
||||
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A, 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, 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_;
|
||||
};
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "DeviceRegistry.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "ParseWifiScan.h"
|
||||
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
void SetCommandStatus(GWObjects::CommandDetails &Cmd,
|
||||
@@ -22,12 +23,17 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if (StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Status)) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Cmd.to_json(RetObj);
|
||||
return Handler->ReturnObject(RetObj);
|
||||
if(Handler!= nullptr)
|
||||
return Handler->ReturnObject(RetObj);
|
||||
return;
|
||||
}
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
if(Handler!= nullptr)
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
void WaitForCommand(GWObjects::CommandDetails &Cmd,
|
||||
void WaitForCommand(uint64_t RPCID,
|
||||
bool RetryLater,
|
||||
GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
@@ -36,12 +42,19 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger) {
|
||||
|
||||
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)) {
|
||||
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();
|
||||
@@ -49,83 +62,98 @@ 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);
|
||||
|
||||
Poco::JSON::Object L;
|
||||
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);
|
||||
}
|
||||
|
||||
if (Sent && rpc_endpoint!= nullptr) {
|
||||
std::future<CommandManager::objtype_t> rpc_future(rpc_endpoint->get_future());
|
||||
auto rpc_result = rpc_future.wait_for(WaitTimeInMs);
|
||||
if (rpc_result == std::future_status::ready) {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - rpc_submitted;
|
||||
auto rpc_answer = rpc_future.get();
|
||||
if (rpc_answer.has(uCentralProtocol::RESULT) && rpc_answer.isObject(uCentralProtocol::RESULT)) {
|
||||
auto ResultFields =
|
||||
rpc_answer.get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
if (ResultFields->has(uCentralProtocol::STATUS) && ResultFields->isObject(uCentralProtocol::STATUS)) {
|
||||
auto StatusInnerObj =
|
||||
ResultFields->get(uCentralProtocol::STATUS).extract<Poco::JSON::Object::Ptr>();
|
||||
if (StatusInnerObj->has(uCentralProtocol::ERROR))
|
||||
Cmd.ErrorCode = StatusInnerObj->get(uCentralProtocol::ERROR);
|
||||
if (StatusInnerObj->has(uCentralProtocol::TEXT))
|
||||
Cmd.ErrorText = StatusInnerObj->get(uCentralProtocol::TEXT).toString();
|
||||
std::stringstream ResultText;
|
||||
Poco::JSON::Stringifier::stringify(rpc_answer.get(uCentralProtocol::RESULT),
|
||||
ResultText);
|
||||
Cmd.Results = ResultText.str();
|
||||
Cmd.Status = "completed";
|
||||
Cmd.Completed = std::time(nullptr);
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
if(!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);
|
||||
}
|
||||
|
||||
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
|
||||
Cmd.WaitingForFile = 0;
|
||||
Cmd.AttachDate = Cmd.AttachSize = 0;
|
||||
Cmd.AttachType = "";
|
||||
}
|
||||
|
||||
// Add the completed command to the database...
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::COMMAND_COMPLETED);
|
||||
|
||||
if (ObjectToReturn) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
} else {
|
||||
Poco::JSON::Object O;
|
||||
Cmd.to_json(O);
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
Logger.information( fmt::format("Command({}): completed in {:.3f}ms.", Cmd.UUID, Cmd.executionTime));
|
||||
return;
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler,
|
||||
Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format(
|
||||
"Invalid response for command '{}'. Missing status.", Cmd.UUID));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED,
|
||||
Logger);
|
||||
Logger.information(fmt::format(
|
||||
"Invalid response for command '{}'. Missing status.", Cmd.UUID));
|
||||
return;
|
||||
}
|
||||
} else if (rpc_result == std::future_status::timeout) {
|
||||
Logger.information(fmt::format(
|
||||
"Timeout2 for command '{}'.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_TIMEDOUT,
|
||||
Logger);
|
||||
return;
|
||||
} else {
|
||||
Logger.information(fmt::format(
|
||||
"Pending completion for command '{}'.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
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::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response. Missing result.", Cmd.UUID, RPCID));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Logger.information(fmt::format(
|
||||
"Pending completion for command '{}'.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
|
||||
auto ResultFields = rpc_answer.get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
if (!ResultFields->has(uCentralProtocol::STATUS) || !ResultFields->isObject(uCentralProtocol::STATUS)) {
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
if(Cmd.Command=="ping") {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::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::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response from device. Missing status.", Cmd.UUID,RPCID));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto StatusInnerObj = ResultFields->get(uCentralProtocol::STATUS).extract<Poco::JSON::Object::Ptr>();
|
||||
if (StatusInnerObj->has(uCentralProtocol::ERROR))
|
||||
Cmd.ErrorCode = StatusInnerObj->get(uCentralProtocol::ERROR);
|
||||
if (StatusInnerObj->has(uCentralProtocol::TEXT))
|
||||
Cmd.ErrorText = StatusInnerObj->get(uCentralProtocol::TEXT).toString();
|
||||
std::stringstream ResultText;
|
||||
if(rpc_answer.has(uCentralProtocol::RESULT)) {
|
||||
if(Cmd.Command==uCentralProtocol::WIFISCAN) {
|
||||
auto ScanObj = rpc_answer.get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
|
||||
ParseWifiScan(ScanObj, ResultText, Logger);
|
||||
} else {
|
||||
Poco::JSON::Stringifier::stringify(
|
||||
rpc_answer.get(uCentralProtocol::RESULT), ResultText);
|
||||
}
|
||||
} if (rpc_answer.has(uCentralProtocol::RESULT_64)) {
|
||||
uint64_t sz=0;
|
||||
if(rpc_answer.has(uCentralProtocol::RESULT_SZ))
|
||||
sz=rpc_answer.get(uCentralProtocol::RESULT_SZ);
|
||||
std::string UnCompressedData;
|
||||
Utils::ExtractBase64CompressedData(rpc_answer.get(uCentralProtocol::RESULT_64).toString(),
|
||||
UnCompressedData,sz);
|
||||
Poco::JSON::Stringifier::stringify(UnCompressedData, ResultText);
|
||||
}
|
||||
Cmd.Results = ResultText.str();
|
||||
Cmd.Status = "completed";
|
||||
Cmd.Completed = OpenWifi::Now();
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
|
||||
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
|
||||
Cmd.WaitingForFile = 0;
|
||||
Cmd.AttachDate = Cmd.AttachSize = 0;
|
||||
Cmd.AttachType = "";
|
||||
}
|
||||
|
||||
// Add the completed command to the database...
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
|
||||
if (ObjectToReturn && Handler) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
} else {
|
||||
Poco::JSON::Object O;
|
||||
Cmd.to_json(O);
|
||||
if(Handler)
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
Logger.information( fmt::format("{},{}: Completed in {:.3f}ms.", Cmd.UUID, RPCID, Cmd.executionTime));
|
||||
return;
|
||||
}
|
||||
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,14 +51,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RESTAPI_blacklist::DoPost() {
|
||||
auto Obj = ParseStream();
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!D.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(D.serialNumber.empty()) {
|
||||
if(D.serialNumber.empty() || !Utils::NormalizeMac(D.serialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
D.author = UserInfo_.userinfo.email;
|
||||
D.created = std::time(nullptr);
|
||||
D.created = OpenWifi::Now();
|
||||
|
||||
if(StorageService()->AddBlackListDevice(D)) {
|
||||
GWObjects::BlackListedDevice CreatedDevice;
|
||||
@@ -84,12 +84,11 @@ 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);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::BlackListedDevice Existing;
|
||||
if(!StorageService()->GetBlackListDevice(SerialNumber, Existing)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
|
||||
@@ -45,6 +45,6 @@ namespace OpenWifi {
|
||||
if (StorageService()->DeleteCommand(CommandUUID)) {
|
||||
return OK();
|
||||
}
|
||||
return InternalError();
|
||||
return InternalError(RESTAPI::Errors::NoRecordsDeleted);
|
||||
}
|
||||
}
|
||||
@@ -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,13 +37,13 @@ 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();
|
||||
}
|
||||
InternalError();
|
||||
InternalError(RESTAPI::Errors::NoRecordsDeleted);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -47,17 +48,17 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if(StorageService()->DefaultConfigurationAlreadyExists(Name)) {
|
||||
return BadRequest("Configuration name already exists.");
|
||||
return BadRequest(RESTAPI::Errors::DefConfigNameExists);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (!DefConfig.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(DefConfig.Models.empty()) {
|
||||
return BadRequest("modelIds cannot be empty");
|
||||
return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty);
|
||||
}
|
||||
|
||||
std::string Error;
|
||||
@@ -65,7 +66,7 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
|
||||
DefConfig.Created = DefConfig.LastModified = std::time(nullptr);
|
||||
DefConfig.Created = DefConfig.LastModified = OpenWifi::Now();
|
||||
if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) {
|
||||
return OK();
|
||||
}
|
||||
@@ -76,7 +77,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_default_configuration::DoPut() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
|
||||
auto Obj = ParseStream();
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::DefaultConfiguration NewConfig;
|
||||
if (!NewConfig.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
@@ -95,7 +96,7 @@ namespace OpenWifi {
|
||||
Existing.Configuration = NewConfig.Configuration;
|
||||
}
|
||||
|
||||
Existing.LastModified = std::time(nullptr);
|
||||
Existing.LastModified = OpenWifi::Now();
|
||||
AssignIfPresent(Obj,"description",Existing.Description);
|
||||
if(Obj->has("modelIds"))
|
||||
Existing.Models = NewConfig.Models;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_device_commandHandler : public RESTAPIHandler {
|
||||
@@ -30,21 +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 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;
|
||||
@@ -52,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()) {
|
||||
@@ -65,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,17 +86,17 @@ 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);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
std::string Arg;
|
||||
if(HasParameter("validateOnly",Arg) && Arg=="true") {
|
||||
auto Body = ParseStream();
|
||||
if(!Body->has("configuration")) {
|
||||
return BadRequest("Must have 'configuration' element.");
|
||||
if(!Obj->has("configuration")) {
|
||||
return BadRequest(RESTAPI::Errors::MustHaveConfigElement);
|
||||
}
|
||||
auto Config=Body->get("configuration").toString();
|
||||
auto Config=Obj->get("configuration").toString();
|
||||
Poco::JSON::Object Answer;
|
||||
std::string Error;
|
||||
auto Res = ValidateUCentralConfiguration(Config, Error);
|
||||
@@ -111,12 +111,15 @@ namespace OpenWifi {
|
||||
return BadRequest( RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
GWObjects::Device Device;
|
||||
if (!Device.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(!Utils::NormalizeMac(Device.SerialNumber)) {
|
||||
return BadRequest( RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
if(SerialNumber!=Device.SerialNumber) {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
}
|
||||
@@ -126,11 +129,13 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
|
||||
for(auto &i:Device.Notes)
|
||||
for(auto &i:Device.Notes) {
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
i.created = OpenWifi::Now();
|
||||
}
|
||||
|
||||
Config::Config NewConfig(Device.Configuration);
|
||||
Device.UUID = std::time(nullptr);
|
||||
Device.UUID = OpenWifi::Now();
|
||||
NewConfig.SetUUID(Device.UUID);
|
||||
Device.Configuration = NewConfig.get();
|
||||
|
||||
@@ -148,11 +153,11 @@ 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);
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::Device NewDevice;
|
||||
if (!NewDevice.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
@@ -169,7 +174,7 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
Config::Config NewConfig(NewDevice.Configuration);
|
||||
uint64_t NewConfigUUID = std::time(nullptr);
|
||||
uint64_t NewConfigUUID = OpenWifi::Now();
|
||||
NewConfig.SetUUID(NewConfigUUID);
|
||||
Existing.Configuration = NewConfig.get();
|
||||
Existing.UUID = NewConfigUUID;
|
||||
@@ -183,10 +188,11 @@ namespace OpenWifi {
|
||||
|
||||
for(auto &i:NewDevice.Notes) {
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
i.created = OpenWifi::Now();
|
||||
Existing.Notes.push_back(i);
|
||||
}
|
||||
|
||||
Existing.LastConfigurationChange = std::time(nullptr);
|
||||
Existing.LastConfigurationChange = OpenWifi::Now();
|
||||
if (StorageService()->UpdateDevice(Existing)) {
|
||||
SetCurrentConfigurationID(SerialNumber, Existing.UUID);
|
||||
Poco::JSON::Object DevObj;
|
||||
|
||||
@@ -15,10 +15,73 @@
|
||||
#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 &OrderByListRaw, std::string &OrderByString) {
|
||||
auto OrderByList = ORM::Escape(OrderByListRaw);
|
||||
auto items = Poco::StringTokenizer(OrderByList,",");
|
||||
std::string ItemList;
|
||||
|
||||
Types::StringVec Fields;
|
||||
StorageService()->GetDeviceDbFieldList(Fields);
|
||||
|
||||
std::set<std::string> FieldNames;
|
||||
for(const auto &field:Fields)
|
||||
FieldNames.insert(Poco::toLower(field));
|
||||
|
||||
for(const auto &i:items) {
|
||||
auto T = Poco::StringTokenizer(i,":");
|
||||
if(T.count()!=2) {
|
||||
return false;
|
||||
}
|
||||
if(T[1]!="a" && T[1]!="d") {
|
||||
return false;
|
||||
}
|
||||
if(!ItemList.empty())
|
||||
ItemList += " , ";
|
||||
auto hint = FieldNames.find(Poco::toLower(T[0]));
|
||||
if(hint==FieldNames.end()) {
|
||||
return false;
|
||||
}
|
||||
ItemList += T[0] + (T[1]=="a" ? " ASC" : " DESC");
|
||||
}
|
||||
|
||||
if(!ItemList.empty()) {
|
||||
OrderByString = " ORDER BY " + ItemList;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RESTAPI_devices_handler::DoGet() {
|
||||
|
||||
if(GetBoolParameter("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);
|
||||
std::sort(Fields.begin(),Fields.end());
|
||||
Poco::JSON::Object Answer;
|
||||
RESTAPI_utils::field_to_json(Answer,"list",Fields);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
std::string OrderBy{" ORDER BY serialNumber ASC "}, Arg;
|
||||
if(HasParameter("orderBy",Arg)) {
|
||||
if(!PrepareOrderBy(Arg,OrderBy)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidLOrderBy);
|
||||
}
|
||||
}
|
||||
|
||||
auto serialOnly = GetBoolParameter(RESTAPI::Protocol::SERIALONLY, false);
|
||||
auto deviceWithStatus = GetBoolParameter(RESTAPI::Protocol::DEVICEWITHSTATUS, false);
|
||||
auto completeInfo = GetBoolParameter("completeInfo",false);
|
||||
@@ -28,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) {
|
||||
@@ -59,7 +124,7 @@ namespace OpenWifi {
|
||||
}
|
||||
} else if (serialOnly) {
|
||||
std::vector<std::string> SerialNumbers;
|
||||
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers);
|
||||
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers, OrderBy);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : SerialNumbers) {
|
||||
Objects.add(i);
|
||||
@@ -67,7 +132,7 @@ namespace OpenWifi {
|
||||
RetObj.set(RESTAPI::Protocol::SERIALNUMBERS, Objects);
|
||||
} else {
|
||||
std::vector<GWObjects::Device> Devices;
|
||||
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices);
|
||||
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices, OrderBy);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : Devices) {
|
||||
Poco::JSON::Object Obj;
|
||||
|
||||
@@ -20,15 +20,12 @@ namespace OpenWifi {
|
||||
auto UUID = GetBinding(RESTAPI::Protocol::FILEUUID, "");
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
// does the file exist
|
||||
Poco::File DownloadFile(FileUploader()->Path() + "/" + UUID);
|
||||
|
||||
std::string FileType;
|
||||
if (!StorageService()->GetAttachedFile(UUID, SerialNumber, DownloadFile.path(), FileType)) {
|
||||
std::string FileContent;
|
||||
if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType)) {
|
||||
return NotFound();
|
||||
}
|
||||
SendFile(DownloadFile, UUID);
|
||||
DownloadFile.remove();
|
||||
SendFileContent(FileContent,"pcap",UUID+".pcap");
|
||||
}
|
||||
|
||||
void RESTAPI_file::DoDelete() {
|
||||
|
||||
70
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp
Normal file
70
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-20.
|
||||
//
|
||||
|
||||
#include "RESTAPI_radiusProxyConfig_handler.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_radiusProxyConfig_handler::DoGet() {
|
||||
GWObjects::RadiusProxyPoolList C;
|
||||
RADIUS_proxy_server()->GetConfig(C);
|
||||
Poco::JSON::Object Answer;
|
||||
C.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
void RESTAPI_radiusProxyConfig_handler::DoDelete() {
|
||||
if(!Internal_ && (UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
RADIUS_proxy_server()->DeleteConfig();
|
||||
return OK();
|
||||
}
|
||||
|
||||
void RESTAPI_radiusProxyConfig_handler::DoPut() {
|
||||
|
||||
if(!Internal_ && (UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
GWObjects::RadiusProxyPoolList C;
|
||||
if(!C.from_json(ParsedBody_) || C.pools.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
// Logically validate the config.
|
||||
for(const auto &pool:C.pools) {
|
||||
if(pool.name.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::PoolNameInvalid);
|
||||
}
|
||||
for(const auto &config:{pool.acctConfig,pool.authConfig,pool.coaConfig}) {
|
||||
if(config.strategy!="random" && config.strategy!="round_robin" && config.strategy!="weighted") {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusProxyStrategy);
|
||||
}
|
||||
if(config.monitorMethod!="none" && config.monitorMethod!="https" && config.monitorMethod!="radius") {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusProxyMonitorMethod);
|
||||
}
|
||||
if(config.servers.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MustHaveAtLeastOneRadiusServer);
|
||||
}
|
||||
|
||||
for(auto &server:config.servers) {
|
||||
Poco::Net::IPAddress Addr;
|
||||
if(!Poco::Net::IPAddress::tryParse(server.ip,Addr) || server.port==0) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusServerEntry);
|
||||
}
|
||||
if(config.strategy=="weighted" && server.weight==0) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRadiusServerWeigth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RADIUS_proxy_server()->SetConfig(C);
|
||||
return ReturnObject(*ParsedBody_);
|
||||
}
|
||||
|
||||
}
|
||||
27
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h
Normal file
27
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-05-20.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_radiusProxyConfig_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_radiusProxyConfig_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServer &Server, uint64_t TransactionId,
|
||||
bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/radiusProxyConfig"}; }
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final{};
|
||||
void DoPut() final;
|
||||
};
|
||||
}
|
||||
@@ -16,18 +16,16 @@
|
||||
#include "RESTAPI/RESTAPI_devices_handler.h"
|
||||
#include "RESTAPI/RESTAPI_file.h"
|
||||
#include "RESTAPI/RESTAPI_ouis.h"
|
||||
|
||||
#include "RESTAPI/RESTAPI_capabilities_handler.h"
|
||||
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
|
||||
#include "RESTAPI/RESTAPI_webSocketServer.h"
|
||||
#include "RESTAPI/RESTAPI_iptocountry_handler.h"
|
||||
#include "RESTAPI/RESTAPI_radiusProxyConfig_handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
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,
|
||||
@@ -44,13 +42,13 @@ namespace OpenWifi {
|
||||
RESTAPI_blacklist,
|
||||
RESTAPI_blacklist_list,
|
||||
RESTAPI_iptocountry_handler,
|
||||
RESTAPI_radiusProxyConfig_handler,
|
||||
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket>(Path,Bindings,L, S, TransactionId);
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -63,6 +61,7 @@ namespace OpenWifi {
|
||||
RESTAPI_file,
|
||||
RESTAPI_blacklist,
|
||||
RESTAPI_iptocountry_handler,
|
||||
RESTAPI_radiusProxyConfig_handler,
|
||||
RESTAPI_blacklist_list>(Path,Bindings,L, S, TransactionId);
|
||||
}
|
||||
}
|
||||
@@ -25,14 +25,23 @@ void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
}
|
||||
}
|
||||
|
||||
if(!Utils::NormalizeMac(SNum)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
auto SerialNumber = Utils::SerialNumberToInt(SNum);
|
||||
|
||||
if(!TelemetryStream()->IsValidEndPoint(SerialNumber,UUID)) {
|
||||
Logger_.warning(fmt::format("Illegal telemetry request for S: {}, UUID: {}", SerialNumber, UUID));
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
return;
|
||||
}
|
||||
auto WS = Poco::SharedPtr<Poco::Net::WebSocket>( new Poco::Net::WebSocket(*Request, *Response));
|
||||
new TelemetryClient(UUID, SerialNumber, WS, TelemetryStream()->NextReactor(), Logger_);
|
||||
|
||||
auto WS = std::make_unique<Poco::Net::WebSocket>(*Request, *Response);
|
||||
new TelemetryClient(UUID, SerialNumber, std::move(WS), TelemetryStream()->NextReactor(), Logger_);
|
||||
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
Logger_.log(E);
|
||||
switch (E.code()) {
|
||||
@@ -49,7 +58,21 @@ void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
return;
|
||||
} catch (...) {
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SetCommonHeaders(true);
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTP_METHOD_NOT_ALLOWED);
|
||||
Response->send();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-08-12.
|
||||
//
|
||||
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/JSON/Stringifier.h"
|
||||
#include "RESTAPI_webSocketServer.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_webSocketServer::DoGet() {
|
||||
|
||||
// try and upgrade this session to websocket...
|
||||
if(Request->find("Upgrade") != Request->end() && Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
|
||||
try
|
||||
{
|
||||
Poco::Net::WebSocket WS(*Request, *Response);
|
||||
int flags;
|
||||
int n;
|
||||
bool Authenticated=false;
|
||||
bool Done=false;
|
||||
do
|
||||
{
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
n = WS.receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
switch(Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS.sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
IncomingFrame.append(0);
|
||||
if(!Authenticated) {
|
||||
std::string Frame{IncomingFrame.begin()};
|
||||
auto Tokens = Utils::Split(Frame,':');
|
||||
bool Expired=false, Contacted = false;
|
||||
if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||
Authenticated=true;
|
||||
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||
WS.sendFrame(S.c_str(),S.size());
|
||||
} else {
|
||||
std::string S{"Invalid token. Closing connection."};
|
||||
WS.sendFrame(S.c_str(),S.size());
|
||||
Done=true;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Obj = P.parse(IncomingFrame.begin())
|
||||
.extract<Poco::JSON::Object::Ptr>();
|
||||
std::string Answer;
|
||||
if(Process(Obj, Answer)) {
|
||||
if (!Answer.empty())
|
||||
WS.sendFrame(Answer.c_str(), Answer.size());
|
||||
else {
|
||||
WS.sendFrame("{}", 2);
|
||||
}
|
||||
} else {
|
||||
Done=true;
|
||||
}
|
||||
} catch (const Poco::JSON::JSONException & E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Done=true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!Done && (n > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE));
|
||||
}
|
||||
catch (const Poco::Net::WebSocketException & E)
|
||||
{
|
||||
Logger_.log(E);
|
||||
switch (E.code())
|
||||
{
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION:
|
||||
Response->set("Sec-WebSocket-Version", Poco::Net::WebSocket::WEBSOCKET_VERSION);
|
||||
// fallthrough
|
||||
case Poco::Net::WebSocket::WS_ERR_NO_HANDSHAKE:
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_VERSION:
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_KEY:
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
catch (...) {
|
||||
|
||||
}
|
||||
} else {
|
||||
return BadRequest("Client does not support a websocket connection.");
|
||||
}
|
||||
}
|
||||
|
||||
bool RESTAPI_webSocketServer::Process(const Poco::JSON::Object::Ptr &O, std::string &Answer ) {
|
||||
try {
|
||||
if (O->has("command")) {
|
||||
auto Command = O->get("command").toString();
|
||||
if (Command == "serial_number_search" && O->has("serial_prefix")) {
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
uint64_t HowMany = 50;
|
||||
if (O->has("howMany"))
|
||||
HowMany = O->get("howMany");
|
||||
Logger_.information(fmt::format("serial_number_search: {}", Prefix));
|
||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||
std::vector<uint64_t> Numbers;
|
||||
SerialNumberCache()->FindNumbers(Prefix, HowMany, Numbers);
|
||||
Poco::JSON::Array A;
|
||||
for (const auto &i : Numbers)
|
||||
A.add(Utils::IntToSerialNumber(i));
|
||||
Poco::JSON::Object AO;
|
||||
AO.set("serialNumbers", A);
|
||||
AO.set("command","serial_number_search");
|
||||
std::ostringstream SS;
|
||||
Poco::JSON::Stringifier::stringify(AO, SS);
|
||||
Answer = SS.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-08-12.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_webSocketServer : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_webSocketServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{ Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal,false) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/ws"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final {};
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
private:
|
||||
bool Process(const Poco::JSON::Object::Ptr &O, std::string &Answer);
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
void Report::reset() {
|
||||
}
|
||||
|
||||
void Report::to_json(Poco::JSON::Object &Obj) const {
|
||||
void Report::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
|
||||
}
|
||||
|
||||
void VenueInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
@@ -167,6 +167,23 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"inactive",inactive);
|
||||
field_to_json(Obj,"tx_rate",tx_rate);
|
||||
field_to_json(Obj,"rx_rate",rx_rate);
|
||||
// field_to_json(Obj, "tidstats", tidstats);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_to_json(Obj,"tx_failed_delta",tx_failed_delta);
|
||||
field_to_json(Obj,"tx_retries_delta",tx_retries_delta);
|
||||
field_to_json(Obj,"tx_duration_delta",tx_duration_delta);
|
||||
}
|
||||
|
||||
bool UETimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -184,6 +201,21 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"inactive",inactive);
|
||||
field_from_json(Obj,"tx_rate",tx_rate);
|
||||
field_from_json(Obj,"rx_rate",rx_rate);
|
||||
// field_from_json(Obj,"tidstats",tidstats);
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_from_json(Obj,"tx_failed_delta",tx_failed_delta);
|
||||
field_from_json(Obj,"tx_retries_delta",tx_retries_delta);
|
||||
field_from_json(Obj,"tx_duration_delta",tx_duration_delta);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -203,6 +235,24 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"tx_dropped",tx_dropped);
|
||||
field_to_json(Obj,"tx_errors",tx_errors);
|
||||
field_to_json(Obj,"tx_packets",tx_packets);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
|
||||
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_to_json(Obj,"rx_dropped_delta",rx_dropped_delta);
|
||||
field_to_json(Obj,"tx_dropped_delta",tx_dropped_delta);
|
||||
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_to_json(Obj,"rx_errors_delta",rx_errors_delta);
|
||||
field_to_json(Obj,"tx_errors_delta",tx_errors_delta);
|
||||
}
|
||||
|
||||
bool APTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -218,6 +268,25 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"tx_dropped",tx_dropped);
|
||||
field_from_json(Obj,"tx_errors",tx_errors);
|
||||
field_from_json(Obj,"tx_packets",tx_packets);
|
||||
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
|
||||
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
|
||||
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
|
||||
field_from_json(Obj,"rx_dropped_delta",rx_dropped_delta);
|
||||
field_from_json(Obj,"tx_dropped_delta",tx_dropped_delta);
|
||||
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
|
||||
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
|
||||
field_from_json(Obj,"rx_errors_delta",rx_errors_delta);
|
||||
field_from_json(Obj,"tx_errors_delta",tx_errors_delta);
|
||||
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -247,7 +316,7 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
|
||||
void RadioTimePoint::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"band",band);
|
||||
field_to_json(Obj,"radio_channel",radio_channel);
|
||||
field_to_json(Obj,"channel_width",channel_width);
|
||||
field_to_json(Obj,"active_ms",active_ms);
|
||||
field_to_json(Obj,"busy_ms",busy_ms);
|
||||
field_to_json(Obj,"receive_ms",receive_ms);
|
||||
@@ -256,12 +325,16 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"channel",channel);
|
||||
field_to_json(Obj,"temperature",temperature);
|
||||
field_to_json(Obj,"noise",noise);
|
||||
field_to_json(Obj,"active_pct",active_pct);
|
||||
field_to_json(Obj,"busy_pct",busy_pct);
|
||||
field_to_json(Obj,"receive_pct",receive_pct);
|
||||
field_to_json(Obj,"transmit_pct",transmit_pct);
|
||||
}
|
||||
|
||||
bool RadioTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"band",band);
|
||||
field_from_json(Obj,"radio_channel",radio_channel);
|
||||
field_from_json(Obj,"channel_width",channel_width);
|
||||
field_from_json(Obj,"active_ms",active_ms);
|
||||
field_from_json(Obj,"busy_ms",busy_ms);
|
||||
field_from_json(Obj,"receive_ms",receive_ms);
|
||||
@@ -270,6 +343,28 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"channel",channel);
|
||||
field_from_json(Obj,"temperature",temperature);
|
||||
field_from_json(Obj,"noise",noise);
|
||||
field_from_json(Obj,"active_pct",active_pct);
|
||||
field_from_json(Obj,"busy_pct",busy_pct);
|
||||
field_from_json(Obj,"receive_pct",receive_pct);
|
||||
field_from_json(Obj,"transmit_pct",transmit_pct);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AveragePoint::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"min",min);
|
||||
field_to_json(Obj,"max",max);
|
||||
field_to_json(Obj,"avg",avg);
|
||||
}
|
||||
|
||||
bool AveragePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"min",min);
|
||||
field_from_json(Obj,"max",max);
|
||||
field_from_json(Obj,"avg",avg);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -282,7 +377,15 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"mode",mode);
|
||||
field_to_json(Obj,"ssid",ssid);
|
||||
field_to_json(Obj,"band",band);
|
||||
field_to_json(Obj,"channel",channel);
|
||||
field_to_json(Obj,"associations",associations);
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
}
|
||||
|
||||
bool SSIDTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -291,7 +394,15 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"mode",mode);
|
||||
field_from_json(Obj,"ssid",ssid);
|
||||
field_from_json(Obj,"band",band);
|
||||
field_from_json(Obj,"channel",channel);
|
||||
field_from_json(Obj,"associations",associations);
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
|
||||
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
|
||||
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -307,6 +418,7 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_to_json(Obj,"ssid_data",ssid_data);
|
||||
field_to_json(Obj,"radio_data",radio_data);
|
||||
field_to_json(Obj,"device_info",device_info);
|
||||
field_to_json(Obj,"serialNumber",serialNumber);
|
||||
}
|
||||
|
||||
bool DeviceTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -318,6 +430,49 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
field_from_json(Obj,"ssid_data",ssid_data);
|
||||
field_from_json(Obj,"radio_data",radio_data);
|
||||
field_from_json(Obj,"device_info",device_info);
|
||||
field_from_json(Obj,"serialNumber",serialNumber);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceTimePointAnalysis::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"noise",noise);
|
||||
field_to_json(Obj,"temperature",temperature);
|
||||
field_to_json(Obj,"active_pct",active_pct);
|
||||
field_to_json(Obj,"busy_pct",busy_pct);
|
||||
field_to_json(Obj,"receive_pct",receive_pct);
|
||||
field_to_json(Obj,"transmit_pct",transmit_pct);
|
||||
field_to_json(Obj,"tx_power",tx_power);
|
||||
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
}
|
||||
|
||||
bool DeviceTimePointAnalysis::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"noise",noise);
|
||||
field_from_json(Obj,"temperature",temperature);
|
||||
field_from_json(Obj,"active_pct",active_pct);
|
||||
field_from_json(Obj,"busy_pct",busy_pct);
|
||||
field_from_json(Obj,"receive_pct",receive_pct);
|
||||
field_from_json(Obj,"transmit_pct",transmit_pct);
|
||||
field_from_json(Obj,"tx_power",tx_power);
|
||||
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
|
||||
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
|
||||
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
|
||||
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
|
||||
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
|
||||
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
|
||||
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
|
||||
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -327,11 +482,13 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
|
||||
void DeviceTimePointList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"points",points);
|
||||
field_to_json(Obj,"stats",stats);
|
||||
}
|
||||
|
||||
bool DeviceTimePointList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"points",points);
|
||||
field_from_json(Obj,"stats",stats);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -357,4 +514,111 @@ namespace OpenWifi::AnalyticsObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WifiClientRate::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"bitrate",bitrate);
|
||||
field_to_json(Obj,"chwidth",chwidth);
|
||||
field_to_json(Obj,"mcs",mcs);
|
||||
field_to_json(Obj,"nss",nss);
|
||||
field_to_json(Obj,"vht",vht);
|
||||
}
|
||||
|
||||
bool WifiClientRate::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"bitrate",bitrate);
|
||||
field_from_json(Obj,"chwidth",chwidth);
|
||||
field_from_json(Obj,"mcs",mcs);
|
||||
field_from_json(Obj,"nss",nss);
|
||||
field_from_json(Obj,"vht",vht);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"timestamp",timestamp);
|
||||
field_to_json(Obj,"station_id",station_id);
|
||||
field_to_json(Obj,"bssid",bssid);
|
||||
field_to_json(Obj,"ssid",ssid);
|
||||
field_to_json(Obj,"rssi",rssi);
|
||||
field_to_json(Obj,"rx_bitrate",rx_bitrate);
|
||||
field_to_json(Obj,"rx_chwidth",rx_chwidth);
|
||||
field_to_json(Obj,"rx_mcs",rx_mcs);
|
||||
field_to_json(Obj,"rx_nss",rx_nss);
|
||||
field_to_json(Obj,"rx_vht",rx_vht);
|
||||
field_to_json(Obj,"tx_bitrate",tx_bitrate);
|
||||
field_to_json(Obj,"tx_chwidth",tx_chwidth);
|
||||
field_to_json(Obj,"tx_mcs",tx_mcs);
|
||||
field_to_json(Obj,"tx_nss",tx_nss);
|
||||
field_to_json(Obj,"tx_vht",tx_vht);
|
||||
field_to_json(Obj,"rx_bytes",rx_bytes);
|
||||
field_to_json(Obj,"tx_bytes",tx_bytes);
|
||||
field_to_json(Obj,"rx_duration",rx_duration);
|
||||
field_to_json(Obj,"tx_duration",tx_duration);
|
||||
field_to_json(Obj,"rx_packets",rx_packets);
|
||||
field_to_json(Obj,"tx_packets",tx_packets);
|
||||
field_to_json(Obj,"ipv4",ipv4);
|
||||
field_to_json(Obj,"ipv6",ipv6);
|
||||
field_to_json(Obj,"channel_width",channel_width);
|
||||
field_to_json(Obj,"noise",noise);
|
||||
field_to_json(Obj,"tx_power",tx_power);
|
||||
field_to_json(Obj,"channel",channel);
|
||||
field_to_json(Obj,"active_ms",active_ms);
|
||||
field_to_json(Obj,"busy_ms",busy_ms);
|
||||
field_to_json(Obj,"receive_ms",receive_ms);
|
||||
field_to_json(Obj,"mode",mode);
|
||||
field_to_json(Obj,"ack_signal",ack_signal);
|
||||
field_to_json(Obj,"ack_signal_avg",ack_signal_avg);
|
||||
field_to_json(Obj,"connected",connected);
|
||||
field_to_json(Obj,"inactive",inactive);
|
||||
field_to_json(Obj,"tx_retries",tx_retries);
|
||||
field_to_json(Obj,"venue_id",venue_id);
|
||||
}
|
||||
|
||||
bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"timestamp",timestamp);
|
||||
field_from_json(Obj,"station_id",station_id);
|
||||
field_from_json(Obj,"bssid",bssid);
|
||||
field_from_json(Obj,"ssid",ssid);
|
||||
field_from_json(Obj,"rssi",rssi);
|
||||
field_from_json(Obj,"rx_bitrate",rx_bitrate);
|
||||
field_from_json(Obj,"rx_chwidth",rx_chwidth);
|
||||
field_from_json(Obj,"rx_mcs",rx_mcs);
|
||||
field_from_json(Obj,"rx_nss",rx_nss);
|
||||
field_from_json(Obj,"rx_vht",rx_vht);
|
||||
field_from_json(Obj,"tx_bitrate",tx_bitrate);
|
||||
field_from_json(Obj,"tx_chwidth",tx_chwidth);
|
||||
field_from_json(Obj,"tx_mcs",tx_mcs);
|
||||
field_from_json(Obj,"tx_nss",tx_nss);
|
||||
field_from_json(Obj,"tx_vht",tx_vht);
|
||||
field_from_json(Obj,"rx_bytes",rx_bytes);
|
||||
field_from_json(Obj,"tx_bytes",tx_bytes);
|
||||
field_from_json(Obj,"rx_duration",rx_duration);
|
||||
field_from_json(Obj,"tx_duration",tx_duration);
|
||||
field_from_json(Obj,"rx_packets",rx_packets);
|
||||
field_from_json(Obj,"tx_packets",tx_packets);
|
||||
field_from_json(Obj,"ipv4",ipv4);
|
||||
field_from_json(Obj,"ipv6",ipv6);
|
||||
field_from_json(Obj,"channel_width",channel_width);
|
||||
field_from_json(Obj,"noise",noise);
|
||||
field_from_json(Obj,"tx_power",tx_power);
|
||||
field_from_json(Obj,"channel",channel);
|
||||
field_from_json(Obj,"active_ms",active_ms);
|
||||
field_from_json(Obj,"busy_ms",busy_ms);
|
||||
field_from_json(Obj,"receive_ms",receive_ms);
|
||||
field_from_json(Obj,"mode",mode);
|
||||
field_from_json(Obj,"ack_signal",ack_signal);
|
||||
field_from_json(Obj,"ack_signal_avg",ack_signal_avg);
|
||||
field_from_json(Obj,"connected",connected);
|
||||
field_from_json(Obj,"inactive",inactive);
|
||||
field_from_json(Obj,"tx_retries",tx_retries);
|
||||
field_from_json(Obj,"venue_id",venue_id);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,14 @@ namespace OpenWifi {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct AveragePoint {
|
||||
double min = 0.0,
|
||||
max = 0.0,
|
||||
avg = 0.0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct UETimePoint {
|
||||
std::string station;
|
||||
int64_t rssi = 0;
|
||||
@@ -121,9 +129,26 @@ namespace OpenWifi {
|
||||
tx_failed = 0,
|
||||
connected = 0,
|
||||
inactive = 0;
|
||||
|
||||
double tx_bytes_bw = 0.0 ,
|
||||
rx_bytes_bw = 0.0 ,
|
||||
tx_packets_bw = 0.0 ,
|
||||
rx_packets_bw = 0.0 ,
|
||||
tx_failed_pct = 0.0 ,
|
||||
tx_retries_pct = 0.0 ,
|
||||
tx_duration_pct = 0.0;
|
||||
|
||||
uint64_t tx_bytes_delta = 0,
|
||||
rx_bytes_delta = 0,
|
||||
tx_duration_delta = 0,
|
||||
rx_packets_delta = 0,
|
||||
tx_packets_delta = 0,
|
||||
tx_retries_delta = 0,
|
||||
tx_failed_delta = 0;
|
||||
|
||||
UE_rate tx_rate,
|
||||
rx_rate;
|
||||
std::vector<TIDstat_entry> tidstat;
|
||||
std::vector<TIDstat_entry> tidstats;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -159,9 +184,18 @@ namespace OpenWifi {
|
||||
std::string bssid,
|
||||
mode,
|
||||
ssid;
|
||||
uint64_t band=0;
|
||||
uint64_t band=0,
|
||||
channel=0;
|
||||
std::vector<UETimePoint> associations;
|
||||
|
||||
AveragePoint tx_bytes_bw,
|
||||
rx_bytes_bw,
|
||||
tx_packets_bw,
|
||||
rx_packets_bw,
|
||||
tx_failed_pct,
|
||||
tx_retries_pct,
|
||||
tx_duration_pct;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
@@ -184,7 +218,18 @@ namespace OpenWifi {
|
||||
rx_dropped_pct = 0.0,
|
||||
tx_dropped_pct = 0.0,
|
||||
rx_packets_bw = 0.0,
|
||||
tx_packets_bw = 0.0;
|
||||
tx_packets_bw = 0.0,
|
||||
rx_errors_pct = 0.0 ,
|
||||
tx_errors_pct = 0.0;
|
||||
|
||||
uint64_t tx_bytes_delta = 0,
|
||||
rx_bytes_delta = 0 ,
|
||||
rx_dropped_delta = 0,
|
||||
tx_dropped_delta = 0,
|
||||
rx_packets_delta = 0,
|
||||
tx_packets_delta = 0,
|
||||
rx_errors_delta = 0,
|
||||
tx_errors_delta = 0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -192,15 +237,20 @@ namespace OpenWifi {
|
||||
|
||||
struct RadioTimePoint {
|
||||
uint64_t band = 0,
|
||||
radio_channel = 0;
|
||||
uint64_t active_ms = 0,
|
||||
busy_ms = 0,
|
||||
receive_ms = 0,
|
||||
transmit_ms = 0,
|
||||
tx_power = 0,
|
||||
channel = 0;
|
||||
int64_t temperature = 0,
|
||||
noise = 0;
|
||||
channel_width = 0;
|
||||
uint64_t active_ms = 0,
|
||||
busy_ms = 0,
|
||||
receive_ms = 0,
|
||||
transmit_ms = 0,
|
||||
tx_power = 0,
|
||||
channel = 0;
|
||||
int64_t temperature = 0,
|
||||
noise = 0;
|
||||
|
||||
double active_pct = 0.0 ,
|
||||
busy_pct = 0.0,
|
||||
receive_pct = 0.0,
|
||||
transmit_pct = 0.0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -208,13 +258,14 @@ namespace OpenWifi {
|
||||
|
||||
|
||||
struct DeviceTimePoint {
|
||||
std::string id;
|
||||
std::string boardId;
|
||||
uint64_t timestamp = 0;
|
||||
APTimePoint ap_data;
|
||||
std::vector<SSIDTimePoint> ssid_data;
|
||||
std::vector<RadioTimePoint> radio_data;
|
||||
AnalyticsObjects::DeviceInfo device_info;
|
||||
std::string id;
|
||||
std::string boardId;
|
||||
uint64_t timestamp = 0;
|
||||
APTimePoint ap_data;
|
||||
std::vector<SSIDTimePoint> ssid_data;
|
||||
std::vector<RadioTimePoint> radio_data;
|
||||
AnalyticsObjects::DeviceInfo device_info;
|
||||
std::string serialNumber;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -245,9 +296,34 @@ namespace OpenWifi {
|
||||
|
||||
};
|
||||
|
||||
struct DeviceTimePointList {
|
||||
std::vector<DeviceTimePoint> points;
|
||||
struct DeviceTimePointAnalysis {
|
||||
uint64_t timestamp;
|
||||
|
||||
AveragePoint noise;
|
||||
AveragePoint temperature;
|
||||
AveragePoint active_pct;
|
||||
AveragePoint busy_pct;
|
||||
AveragePoint receive_pct;
|
||||
AveragePoint transmit_pct;
|
||||
AveragePoint tx_power;
|
||||
|
||||
AveragePoint tx_bytes_bw;
|
||||
AveragePoint rx_bytes_bw;
|
||||
AveragePoint rx_dropped_pct;
|
||||
AveragePoint tx_dropped_pct;
|
||||
AveragePoint rx_packets_bw;
|
||||
AveragePoint tx_packets_bw;
|
||||
AveragePoint rx_errors_pct;
|
||||
AveragePoint tx_errors_pct;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
|
||||
};
|
||||
|
||||
struct DeviceTimePointList {
|
||||
std::vector<DeviceTimePoint> points;
|
||||
std::vector<DeviceTimePointAnalysis> stats;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
@@ -286,5 +362,61 @@ namespace OpenWifi {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WifiClientRate {
|
||||
uint32_t bitrate=0;
|
||||
uint32_t chwidth=0;
|
||||
uint16_t mcs=0;
|
||||
uint16_t nss=0;
|
||||
bool vht=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WifiClientHistory {
|
||||
uint64_t timestamp=OpenWifi::Now();
|
||||
std::string station_id;
|
||||
std::string bssid;
|
||||
std::string ssid;
|
||||
int64_t rssi=0;
|
||||
uint32_t rx_bitrate=0;
|
||||
uint32_t rx_chwidth=0;
|
||||
uint16_t rx_mcs=0;
|
||||
uint16_t rx_nss=0;
|
||||
bool rx_vht=false;
|
||||
uint32_t tx_bitrate=0;
|
||||
uint32_t tx_chwidth=0;
|
||||
uint16_t tx_mcs=0;
|
||||
uint16_t tx_nss=0;
|
||||
bool tx_vht=false;
|
||||
uint64_t rx_bytes=0;
|
||||
uint64_t tx_bytes=0;
|
||||
uint64_t rx_duration=0;
|
||||
uint64_t tx_duration=0;
|
||||
uint64_t rx_packets=0;
|
||||
uint64_t tx_packets=0;
|
||||
std::string ipv4;
|
||||
std::string ipv6;
|
||||
uint64_t channel_width=0;
|
||||
int64_t noise=0;
|
||||
uint64_t tx_power=0;
|
||||
uint64_t channel=0;
|
||||
uint64_t active_ms=0;
|
||||
uint64_t busy_ms=0;
|
||||
uint64_t receive_ms=0;
|
||||
std::string mode;
|
||||
int64_t ack_signal=0;
|
||||
int64_t ack_signal_avg=0;
|
||||
uint64_t connected=0;
|
||||
uint64_t inactive=0;
|
||||
uint64_t tx_retries=0;
|
||||
std::string venue_id;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,176 +3,206 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_CertObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
|
||||
namespace OpenWifi {
|
||||
namespace CertObjects {
|
||||
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"type", type);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"certificate", certificate);
|
||||
field_to_json(Obj,"key", key);
|
||||
field_to_json(Obj,"devid", devid);
|
||||
field_to_json(Obj,"cas", cas);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonName", commonName);
|
||||
field_to_json(Obj,"certificateId", certificateId);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"revoked", revoked);
|
||||
field_to_json(Obj,"revokeCount", revokeCount);
|
||||
}
|
||||
namespace OpenWifi::CertObjects {
|
||||
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"type", type);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"certificate", certificate);
|
||||
field_to_json(Obj,"key", key);
|
||||
field_to_json(Obj,"devid", devid);
|
||||
field_to_json(Obj,"cas", cas);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonName", commonName);
|
||||
field_to_json(Obj,"certificateId", certificateId);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"revoked", revoked);
|
||||
field_to_json(Obj,"revokeCount", revokeCount);
|
||||
field_to_json(Obj,"synched", synched);
|
||||
}
|
||||
|
||||
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"type", type);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"certificate", certificate);
|
||||
field_from_json(Obj,"key", key);
|
||||
field_from_json(Obj,"devid", devid);
|
||||
field_from_json(Obj,"cas", cas);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonName", commonName);
|
||||
field_from_json(Obj,"certificateId", certificateId);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"revoked", revoked);
|
||||
field_from_json(Obj,"revokeCount", revokeCount);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"type", type);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"certificate", certificate);
|
||||
field_from_json(Obj,"key", key);
|
||||
field_from_json(Obj,"devid", devid);
|
||||
field_from_json(Obj,"cas", cas);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonName", commonName);
|
||||
field_from_json(Obj,"certificateId", certificateId);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"revoked", revoked);
|
||||
field_from_json(Obj,"revokeCount", revokeCount);
|
||||
field_from_json(Obj,"synched", synched);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_to_json(Obj,"apiKey", apiKey);
|
||||
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_to_json(Obj,"organization", organization);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"suspended", suspended);
|
||||
field_to_json(Obj,"deleted", deleted);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
}
|
||||
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_to_json(Obj,"apiKey", apiKey);
|
||||
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_to_json(Obj,"organization", organization);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"suspended", suspended);
|
||||
field_to_json(Obj,"deleted", deleted);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
}
|
||||
|
||||
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_from_json(Obj,"apiKey", apiKey);
|
||||
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_from_json(Obj,"organization", organization);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"suspended", suspended);
|
||||
field_from_json(Obj,"deleted", deleted);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"defaultRedirector", defaultRedirector);
|
||||
field_from_json(Obj,"apiKey", apiKey);
|
||||
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
|
||||
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
|
||||
field_from_json(Obj,"organization", organization);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"suspended", suspended);
|
||||
field_from_json(Obj,"deleted", deleted);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"jobHistory", jobHistory);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
}
|
||||
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"manufacturer", manufacturer);
|
||||
field_to_json(Obj,"model", model);
|
||||
field_to_json(Obj,"redirector", redirector);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"jobHistory", jobHistory);
|
||||
field_to_json(Obj,"notes", notes);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
}
|
||||
|
||||
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"jobHistory", jobHistory);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"name", name);
|
||||
field_from_json(Obj,"description", description);
|
||||
field_from_json(Obj,"manufacturer", manufacturer);
|
||||
field_from_json(Obj,"model", model);
|
||||
field_from_json(Obj,"redirector", redirector);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"jobHistory", jobHistory);
|
||||
field_from_json(Obj,"notes", notes);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"completedNames", completedNames);
|
||||
field_to_json(Obj,"errorNames", errorNames);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"command", command);
|
||||
field_to_json(Obj,"parameters", parameters);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
}
|
||||
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"creator", creator);
|
||||
field_to_json(Obj,"batch", batch);
|
||||
field_to_json(Obj,"commonNames", commonNames);
|
||||
field_to_json(Obj,"completedNames", completedNames);
|
||||
field_to_json(Obj,"errorNames", errorNames);
|
||||
field_to_json(Obj,"status", status);
|
||||
field_to_json(Obj,"command", command);
|
||||
field_to_json(Obj,"parameters", parameters);
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
}
|
||||
|
||||
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"completedNames", completedNames);
|
||||
field_from_json(Obj,"errorNames", errorNames);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"command", command);
|
||||
field_from_json(Obj,"parameters", parameters);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"id", id);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"creator", creator);
|
||||
field_from_json(Obj,"batch", batch);
|
||||
field_from_json(Obj,"commonNames", commonNames);
|
||||
field_from_json(Obj,"completedNames", completedNames);
|
||||
field_from_json(Obj,"errorNames", errorNames);
|
||||
field_from_json(Obj,"status", status);
|
||||
field_from_json(Obj,"command", command);
|
||||
field_from_json(Obj,"parameters", parameters);
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "year", year);
|
||||
field_to_json(Obj, "activeCerts", activeCerts);
|
||||
field_to_json(Obj, "revokedCerts", revokedCerts);
|
||||
}
|
||||
|
||||
void Dashboard::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"snapshot", snapshot);
|
||||
field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts);
|
||||
field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts);
|
||||
field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization);
|
||||
field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization);
|
||||
field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors);
|
||||
field_to_json(Obj,"deviceTypes", deviceTypes);
|
||||
field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts);
|
||||
field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear);
|
||||
}
|
||||
|
||||
void Dashboard::reset() {
|
||||
snapshot=0;
|
||||
numberOfRevokedCerts = numberOfIssuedCerts = 0;
|
||||
activeCertsPerOrganization.clear();
|
||||
revokedCertsPerOrganization.clear();
|
||||
numberOfRedirectors.clear();
|
||||
deviceTypes.clear();
|
||||
monthlyNumberOfCerts.clear();
|
||||
monthlyNumberOfCertsPerOrgPerYear.clear();
|
||||
}
|
||||
}
|
||||
@@ -5,97 +5,118 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
namespace OpenWifi::CertObjects {
|
||||
|
||||
namespace CertObjects {
|
||||
struct CertificateEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string type;
|
||||
std::string status;
|
||||
std::string certificate;
|
||||
std::string key;
|
||||
std::string devid;
|
||||
std::string cas;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::string commonName;
|
||||
std::string certificateId;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
uint64_t created = 0;
|
||||
uint64_t modified = 0;
|
||||
uint64_t revoked = 0;
|
||||
uint64_t revokeCount = 0;
|
||||
uint64_t synched = 0;
|
||||
|
||||
struct CertificateEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string type;
|
||||
std::string status;
|
||||
std::string certificate;
|
||||
std::string key;
|
||||
std::string devid;
|
||||
std::string cas;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::string commonName;
|
||||
std::string certificateId;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
uint64_t created = 0;
|
||||
uint64_t modified = 0;
|
||||
uint64_t revoked = 0;
|
||||
uint64_t revokeCount = 0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct EntityEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string defaultRedirector;
|
||||
std::string apiKey;
|
||||
std::string serverEnrollmentProfile;
|
||||
std::string clientEnrollmentProfile;
|
||||
std::string organization;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
bool suspended=false;
|
||||
bool deleted=false;
|
||||
uint64_t created = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
|
||||
struct EntityEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string defaultRedirector;
|
||||
std::string apiKey;
|
||||
std::string serverEnrollmentProfile;
|
||||
std::string clientEnrollmentProfile;
|
||||
std::string organization;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
bool suspended=false;
|
||||
bool deleted=false;
|
||||
uint64_t created = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct BatchEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::vector<std::string> commonNames;
|
||||
std::vector<std::string> jobHistory;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t submitted = 0 ;
|
||||
uint64_t started = 0 ;
|
||||
uint64_t completed = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
|
||||
struct BatchEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string manufacturer;
|
||||
std::string model;
|
||||
std::string redirector;
|
||||
std::vector<std::string> commonNames;
|
||||
std::vector<std::string> jobHistory;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t submitted = 0 ;
|
||||
uint64_t started = 0 ;
|
||||
uint64_t completed = 0 ;
|
||||
uint64_t modified = 0 ;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct JobEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
std::string command;
|
||||
OpenWifi::Types::StringVec commonNames;
|
||||
OpenWifi::Types::StringVec completedNames;
|
||||
OpenWifi::Types::StringVec errorNames;
|
||||
Types::StringPairVec parameters;
|
||||
std::string status;
|
||||
uint64_t submitted=0;
|
||||
uint64_t started=0;
|
||||
uint64_t completed=0;
|
||||
|
||||
struct JobEntry {
|
||||
OpenWifi::Types::UUID_t id;
|
||||
OpenWifi::Types::UUID_t entity;
|
||||
OpenWifi::Types::UUID_t creator;
|
||||
OpenWifi::Types::UUID_t batch;
|
||||
std::string command;
|
||||
OpenWifi::Types::StringVec commonNames;
|
||||
OpenWifi::Types::StringVec completedNames;
|
||||
OpenWifi::Types::StringVec errorNames;
|
||||
Types::StringPairVec parameters;
|
||||
std::string status;
|
||||
uint64_t submitted=0;
|
||||
uint64_t started=0;
|
||||
uint64_t completed=0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DashBoardYearlyStats {
|
||||
uint64_t year=0;
|
||||
OpenWifi::Types::Counted3DMapSII activeCerts;
|
||||
OpenWifi::Types::Counted3DMapSII revokedCerts;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct Dashboard {
|
||||
uint64_t snapshot=0;
|
||||
uint64_t numberOfIssuedCerts=0;
|
||||
uint64_t numberOfRevokedCerts=0;
|
||||
OpenWifi::Types::CountedMap activeCertsPerOrganization;
|
||||
OpenWifi::Types::CountedMap revokedCertsPerOrganization;
|
||||
OpenWifi::Types::CountedMap numberOfRedirectors;
|
||||
OpenWifi::Types::CountedMap deviceTypes;
|
||||
OpenWifi::Types::CountedMap monthlyNumberOfCerts;
|
||||
std::vector<DashBoardYearlyStats> monthlyNumberOfCertsPerOrgPerYear;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void reset();
|
||||
};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,7 @@ namespace OpenWifi::FMSObjects {
|
||||
UnknownFirmwares_.clear();
|
||||
totalSecondsOld_.clear();
|
||||
numberOfDevices = 0 ;
|
||||
snapshot = std::time(nullptr);
|
||||
snapshot = OpenWifi::Now();
|
||||
}
|
||||
|
||||
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -273,4 +273,37 @@ namespace OpenWifi::FMSObjects {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "serialNumber",serialNumber);
|
||||
field_to_json(Obj, "revision", revision);
|
||||
field_to_json(Obj, "upgraded", upgraded);
|
||||
}
|
||||
|
||||
bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serialNumber",serialNumber);
|
||||
field_from_json(Obj, "revision", revision);
|
||||
field_from_json(Obj, "upgraded", upgraded);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "devices",devices);
|
||||
}
|
||||
|
||||
bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "devices",devices);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
#define UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
@@ -29,7 +27,7 @@ namespace OpenWifi::FMSObjects {
|
||||
std::string location;
|
||||
std::string uploader;
|
||||
std::string digest;
|
||||
bool latest=0;
|
||||
bool latest=false;
|
||||
SecurityObjects::NoteInfoVec notes;
|
||||
uint64_t created=0;
|
||||
|
||||
@@ -141,7 +139,21 @@ namespace OpenWifi::FMSObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceCurrentInfo {
|
||||
std::string serialNumber;
|
||||
std::string revision;
|
||||
uint64_t upgraded=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceCurrentInfoList {
|
||||
std::vector<DeviceCurrentInfo> devices;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H
|
||||
|
||||
@@ -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);
|
||||
@@ -264,7 +285,7 @@ namespace OpenWifi::GWObjects {
|
||||
lastContact.clear();
|
||||
associations.clear();
|
||||
numberOfDevices = 0 ;
|
||||
snapshot = std::time(nullptr);
|
||||
snapshot = OpenWifi::Now();
|
||||
}
|
||||
|
||||
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
|
||||
@@ -272,5 +293,123 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"capabilities", capabilities);
|
||||
};
|
||||
|
||||
void ScriptRequest::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber",serialNumber);
|
||||
field_to_json(Obj,"timeout",timeout);
|
||||
field_to_json(Obj,"type",type);
|
||||
field_to_json(Obj,"script",script);
|
||||
field_to_json(Obj,"scriptId",scriptId);
|
||||
field_to_json(Obj,"when",when);
|
||||
}
|
||||
|
||||
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"serialNumber",serialNumber);
|
||||
field_from_json(Obj,"timeout",timeout);
|
||||
field_from_json(Obj,"type",type);
|
||||
field_from_json(Obj,"script",script);
|
||||
field_from_json(Obj,"scriptId",scriptId);
|
||||
field_from_json(Obj,"when",when);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"pools",pools);
|
||||
}
|
||||
|
||||
bool RadiusProxyPoolList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"pools",pools);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadiusProxyPool::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"name",name);
|
||||
field_to_json(Obj,"description",description);
|
||||
field_to_json(Obj,"authConfig",authConfig);
|
||||
field_to_json(Obj,"acctConfig",acctConfig);
|
||||
field_to_json(Obj,"coaConfig",coaConfig);
|
||||
field_to_json(Obj,"useByDefault",useByDefault);
|
||||
}
|
||||
|
||||
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"name",name);
|
||||
field_from_json(Obj,"description",description);
|
||||
field_from_json(Obj,"authConfig",authConfig);
|
||||
field_from_json(Obj,"acctConfig",acctConfig);
|
||||
field_from_json(Obj,"coaConfig",coaConfig);
|
||||
field_from_json(Obj,"useByDefault",useByDefault);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"strategy",strategy);
|
||||
field_to_json(Obj,"monitor",monitor);
|
||||
field_to_json(Obj,"monitorMethod",monitorMethod);
|
||||
field_to_json(Obj,"methodParameters",methodParameters);
|
||||
field_to_json(Obj,"servers",servers);
|
||||
}
|
||||
|
||||
bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"strategy",strategy);
|
||||
field_from_json(Obj,"monitor",monitor);
|
||||
field_from_json(Obj,"monitorMethod",monitorMethod);
|
||||
field_from_json(Obj,"methodParameters",methodParameters);
|
||||
field_from_json(Obj,"servers",servers);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadiusProxyServerEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"name",name);
|
||||
field_to_json(Obj,"ip",ip);
|
||||
field_to_json(Obj,"port",port);
|
||||
field_to_json(Obj,"weight",weight);
|
||||
field_to_json(Obj,"secret",secret);
|
||||
field_to_json(Obj,"certificate",certificate);
|
||||
field_to_json(Obj,"radsec",radsec);
|
||||
field_to_json(Obj,"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) {
|
||||
try {
|
||||
field_from_json(Obj,"name",name);
|
||||
field_from_json(Obj,"ip",ip);
|
||||
field_from_json(Obj,"port",port);
|
||||
field_from_json(Obj,"weight",weight);
|
||||
field_from_json(Obj,"secret",secret);
|
||||
field_from_json(Obj,"certificate",certificate);
|
||||
field_from_json(Obj,"radsec",radsec);
|
||||
field_from_json(Obj,"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) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
@@ -199,4 +212,65 @@ namespace OpenWifi::GWObjects {
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct ScriptRequest {
|
||||
uint64_t timeout=30;
|
||||
std::string serialNumber;
|
||||
std::string type;
|
||||
std::string script;
|
||||
std::string scriptId;
|
||||
uint64_t when=0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RadiusProxyServerEntry {
|
||||
std::string name;
|
||||
std::string ip;
|
||||
uint16_t port=0;
|
||||
uint64_t weight=0;
|
||||
std::string secret;
|
||||
std::string certificate;
|
||||
bool radsec=false;
|
||||
uint16_t 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);
|
||||
};
|
||||
|
||||
struct RadiusProxyServerConfig {
|
||||
std::string strategy;
|
||||
bool monitor=false;
|
||||
std::string monitorMethod;
|
||||
std::vector<std::string> methodParameters;
|
||||
std::vector<RadiusProxyServerEntry> servers;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RadiusProxyPool {
|
||||
std::string name;
|
||||
std::string description;
|
||||
RadiusProxyServerConfig authConfig;
|
||||
RadiusProxyServerConfig acctConfig;
|
||||
RadiusProxyServerConfig coaConfig;
|
||||
bool useByDefault=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RadiusProxyPoolList {
|
||||
std::vector<RadiusProxyPool> pools;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_to_json( Obj,"devices",devices);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"sourceIP",sourceIP);
|
||||
field_to_json( Obj,"variables", variables);
|
||||
field_to_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -111,7 +111,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_from_json( Obj,"devices",devices);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"sourceIP",sourceIP);
|
||||
field_from_json( Obj,"variables", variables);
|
||||
field_from_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -154,7 +154,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_to_json( Obj,"contacts",contacts);
|
||||
field_to_json( Obj,"location",location);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"sourceIP",sourceIP);
|
||||
field_to_json( Obj,"variables", variables);
|
||||
field_to_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -178,7 +178,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_from_json( Obj,"contacts",contacts);
|
||||
field_from_json( Obj,"location",location);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"sourceIP",sourceIP);
|
||||
field_from_json( Obj,"variables", variables);
|
||||
field_from_json( Obj,"managementPolicies", managementPolicies);
|
||||
@@ -197,9 +197,7 @@ namespace OpenWifi::ProvObjects {
|
||||
info.to_json(Obj);
|
||||
field_to_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_to_json( Obj,"managementRoles",managementRoles);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"variables",variables);
|
||||
field_to_json( Obj,"defaultOperator",defaultOperator);
|
||||
field_to_json( Obj,"sourceIP",sourceIP);
|
||||
@@ -211,9 +209,7 @@ namespace OpenWifi::ProvObjects {
|
||||
info.from_json(Obj);
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"managementRoles",managementRoles);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"variables",variables);
|
||||
field_from_json( Obj,"defaultOperator",defaultOperator);
|
||||
field_from_json( Obj,"sourceIP",sourceIP);
|
||||
@@ -598,7 +594,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj, "location", location);
|
||||
field_to_json( Obj, "contact", contact);
|
||||
field_to_json( Obj, "deviceConfiguration",deviceConfiguration);
|
||||
field_to_json( Obj, "rrm",rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj, "managementPolicy",managementPolicy);
|
||||
field_to_json( Obj, "state",state);
|
||||
field_to_json( Obj, "devClass",devClass);
|
||||
@@ -619,7 +615,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"location",location);
|
||||
field_from_json( Obj,"contact",contact);
|
||||
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"state",state);
|
||||
field_from_json( Obj,"devClass",devClass);
|
||||
@@ -690,16 +686,14 @@ namespace OpenWifi::ProvObjects {
|
||||
info.to_json(Obj);
|
||||
field_to_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_to_json( Obj,"deviceTypes",deviceTypes);
|
||||
field_to_json( Obj,"configuration",configuration);
|
||||
field_to_json( Obj,"inUse",inUse);
|
||||
field_to_json( Obj,"variables",variables);
|
||||
field_to_json( Obj,"rrm",rrm);
|
||||
field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_to_json( Obj,"subscriberOnly",subscriberOnly);
|
||||
field_to_json( Obj,"entity", entity);
|
||||
field_to_json( Obj,"venue", venue);
|
||||
field_to_json( Obj,"subscriber", subscriber);
|
||||
field_to_json( Obj,"configuration",configuration);
|
||||
field_to_json( Obj,"inUse",inUse);
|
||||
field_to_json( Obj,"variables",variables);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
}
|
||||
|
||||
bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -707,16 +701,14 @@ namespace OpenWifi::ProvObjects {
|
||||
info.from_json(Obj);
|
||||
field_from_json( Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json( Obj,"deviceTypes",deviceTypes);
|
||||
field_from_json( Obj,"configuration",configuration);
|
||||
field_from_json( Obj,"inUse",inUse);
|
||||
field_from_json( Obj,"variables",variables);
|
||||
field_from_json( Obj,"rrm",rrm);
|
||||
field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
|
||||
field_from_json( Obj,"subscriberOnly",subscriberOnly);
|
||||
field_from_json( Obj,"entity", entity);
|
||||
field_from_json( Obj,"venue", venue);
|
||||
field_from_json( Obj,"subscriber", subscriber);
|
||||
field_from_json( Obj,"configuration",configuration);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -896,6 +888,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"statusCode", statusCode);
|
||||
field_to_json( Obj,"deviceID", deviceID);
|
||||
field_to_json( Obj,"registrationId",registrationId);
|
||||
field_to_json( Obj,"operatorId",operatorId);
|
||||
}
|
||||
|
||||
bool SignupEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -912,6 +905,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"statusCode", statusCode);
|
||||
field_from_json( Obj,"deviceID", deviceID);
|
||||
field_from_json( Obj,"registrationId",registrationId);
|
||||
field_from_json( Obj,"operatorId",operatorId);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -994,6 +988,26 @@ namespace OpenWifi::ProvObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConfigurationDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json( Obj,"configuration", configuration);
|
||||
field_to_json( Obj,"rrm", rrm);
|
||||
field_to_json( Obj,"firmwareRCOnly", firmwareRCOnly);
|
||||
field_to_json( Obj,"firmwareUpgrade", firmwareUpgrade);
|
||||
}
|
||||
|
||||
bool ConfigurationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json( Obj,"configuration", configuration);
|
||||
field_from_json( Obj,"rrm", rrm);
|
||||
field_from_json( Obj,"firmwareRCOnly", firmwareRCOnly);
|
||||
field_from_json( Obj,"firmwareUpgrade", firmwareUpgrade);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json( Obj,"serialNumber", serialNumber);
|
||||
@@ -1006,7 +1020,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj,"serviceClass", serviceClass);
|
||||
field_to_json( Obj,"qrCode", qrCode);
|
||||
field_to_json( Obj,"geoCode", geoCode);
|
||||
field_to_json( Obj,"rrm", rrm);
|
||||
field_to_json( Obj,"deviceRules",deviceRules);
|
||||
field_to_json( Obj,"state", state);
|
||||
field_to_json( Obj,"locale", locale);
|
||||
field_to_json( Obj,"billingCode", billingCode);
|
||||
@@ -1028,7 +1042,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"serviceClass", serviceClass);
|
||||
field_from_json( Obj,"qrCode", qrCode);
|
||||
field_from_json( Obj,"geoCode", geoCode);
|
||||
field_from_json( Obj,"rrm", rrm);
|
||||
field_from_json( Obj,"deviceRules",deviceRules);
|
||||
field_from_json( Obj,"state", state);
|
||||
field_from_json( Obj,"locale", locale);
|
||||
field_from_json( Obj,"billingCode", billingCode);
|
||||
@@ -1077,7 +1091,7 @@ namespace OpenWifi::ProvObjects {
|
||||
}
|
||||
|
||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
if(O->has("name"))
|
||||
I.name = O->get("name").toString();
|
||||
|
||||
@@ -1127,41 +1141,17 @@ namespace OpenWifi::ProvObjects {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketNotificationContent::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"title",title);
|
||||
field_to_json(Obj,"type",type);
|
||||
field_to_json(Obj,"success",success);
|
||||
field_to_json(Obj,"errors",errors);
|
||||
field_to_json(Obj,"warnings",warnings);
|
||||
field_to_json(Obj,"timeStamp",timeStamp);
|
||||
field_to_json(Obj,"details",details);
|
||||
void DeviceRules::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"rcOnly",rcOnly);
|
||||
field_to_json(Obj,"rrm",rrm);
|
||||
field_to_json(Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
}
|
||||
|
||||
bool WebSocketNotificationContent::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
bool DeviceRules::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"title",title);
|
||||
field_from_json(Obj,"type",type);
|
||||
field_from_json(Obj,"success",success);
|
||||
field_from_json(Obj,"errors",errors);
|
||||
field_from_json(Obj,"warnings",warnings);
|
||||
field_from_json(Obj,"timeStamp",timeStamp);
|
||||
field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebSocketNotification::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"notification_id",notification_id);
|
||||
field_to_json(Obj,"content",content);
|
||||
}
|
||||
|
||||
bool WebSocketNotification::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"notification_id",notification_id);
|
||||
field_from_json(Obj,"content",content);
|
||||
field_from_json(Obj,"rcOnly",rcOnly);
|
||||
field_from_json(Obj,"rrm",rrm);
|
||||
field_from_json(Obj,"firmwareUpgrade",firmwareUpgrade);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
|
||||
@@ -62,6 +62,15 @@ namespace OpenWifi::ProvObjects {
|
||||
};
|
||||
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
|
||||
|
||||
struct DeviceRules {
|
||||
std::string rcOnly{"inherit"};
|
||||
std::string rrm{"inherit"};
|
||||
std::string firmwareUpgrade{"inherit"};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Entity {
|
||||
ObjectInfo info;
|
||||
Types::UUID_t parent;
|
||||
@@ -72,7 +81,7 @@ namespace OpenWifi::ProvObjects {
|
||||
Types::UUID_t managementPolicy;
|
||||
Types::UUIDvec_t deviceConfiguration;
|
||||
Types::UUIDvec_t devices;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
Types::StringVec sourceIP;
|
||||
Types::UUIDvec_t variables;
|
||||
Types::UUIDvec_t managementPolicies;
|
||||
@@ -107,7 +116,7 @@ namespace OpenWifi::ProvObjects {
|
||||
Types::UUIDvec_t deviceConfiguration;
|
||||
Types::UUIDvec_t contacts;
|
||||
std::string location;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
Types::StringVec sourceIP;
|
||||
Types::UUIDvec_t variables;
|
||||
Types::UUIDvec_t configurations;
|
||||
@@ -375,9 +384,7 @@ namespace OpenWifi::ProvObjects {
|
||||
DeviceConfigurationElementVec configuration;
|
||||
Types::StringVec inUse;
|
||||
Types::UUIDvec_t variables;
|
||||
std::string rrm;
|
||||
std::string firmwareUpgrade;
|
||||
bool firmwareRCOnly=false;
|
||||
DeviceRules deviceRules;
|
||||
bool subscriberOnly=false;
|
||||
std::string venue;
|
||||
std::string entity;
|
||||
@@ -401,7 +408,7 @@ namespace OpenWifi::ProvObjects {
|
||||
std::string location;
|
||||
std::string contact;
|
||||
std::string deviceConfiguration;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
Types::UUID_t managementPolicy;
|
||||
std::string state;
|
||||
std::string devClass;
|
||||
@@ -534,6 +541,7 @@ namespace OpenWifi::ProvObjects {
|
||||
uint64_t statusCode=0;
|
||||
std::string deviceID;
|
||||
std::string registrationId;
|
||||
std::string operatorId;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -581,9 +589,7 @@ namespace OpenWifi::ProvObjects {
|
||||
ObjectInfo info;
|
||||
Types::UUID_t managementPolicy;
|
||||
Types::UUIDvec_t managementRoles;
|
||||
std::string rrm;
|
||||
std::string firmwareUpgrade;
|
||||
bool firmwareRCOnly=true;
|
||||
DeviceRules deviceRules;
|
||||
std::vector<Variable> variables;
|
||||
bool defaultOperator=false;
|
||||
Types::StringVec sourceIP;
|
||||
@@ -632,6 +638,16 @@ namespace OpenWifi::ProvObjects {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ConfigurationDetails {
|
||||
DeviceConfigurationElementVec configuration;
|
||||
std::string rrm{"inherit"};
|
||||
std::string firmwareUpgrade{"inherit"};
|
||||
std::string firmwareRCOnly{"inherit"};
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SubscriberDevice {
|
||||
ObjectInfo info;
|
||||
std::string serialNumber;
|
||||
@@ -644,7 +660,7 @@ namespace OpenWifi::ProvObjects {
|
||||
Types::UUID_t serviceClass;
|
||||
std::string qrCode;
|
||||
std::string geoCode;
|
||||
std::string rrm;
|
||||
DeviceRules deviceRules;
|
||||
std::string state;
|
||||
std::string locale;
|
||||
std::string billingCode;
|
||||
@@ -663,28 +679,6 @@ namespace OpenWifi::ProvObjects {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WebSocketNotificationContent {
|
||||
std::string title,
|
||||
type,
|
||||
details;
|
||||
std::vector<std::string> success,
|
||||
errors,
|
||||
warnings;
|
||||
uint64_t timeStamp=std::time(nullptr);
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct WebSocketNotification {
|
||||
inline static uint64_t xid=1;
|
||||
uint64_t notification_id=++xid;
|
||||
WebSocketNotificationContent content;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
|
||||
@@ -113,6 +113,8 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"userMustChangePassword",userMustChangePassword);
|
||||
field_to_json(Obj,"errorCode", errorCode);
|
||||
Obj.set("aclTemplate",AclTemplateObj);
|
||||
field_to_json(Obj,"errorCode", errorCode);
|
||||
field_to_json(Obj,"lastRefresh", lastRefresh_);
|
||||
}
|
||||
|
||||
bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -129,6 +131,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_from_json(Obj, "created", created_);
|
||||
field_from_json(Obj, "username", username_);
|
||||
field_from_json(Obj, "userMustChangePassword",userMustChangePassword);
|
||||
field_from_json(Obj,"lastRefresh", lastRefresh_);
|
||||
return true;
|
||||
} catch (...) {
|
||||
std::cout << "Cannot parse: WebToken" << std::endl;
|
||||
@@ -430,7 +433,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
SecurityObjects::NoteInfoVec NIV;
|
||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
|
||||
for(auto const &i:NIV) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note};
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
Notes.push_back(ii);
|
||||
}
|
||||
}
|
||||
@@ -443,7 +446,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
|
||||
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
|
||||
for(auto const &i:NewNotes) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note};
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
ExistingNotes.push_back(ii);
|
||||
}
|
||||
return true;
|
||||
@@ -588,6 +591,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"expires",expires);
|
||||
field_to_json(Obj,"idleTimeout",idleTimeout);
|
||||
field_to_json(Obj,"revocationDate",revocationDate);
|
||||
field_to_json(Obj,"lastRefresh", lastRefresh);
|
||||
}
|
||||
|
||||
bool Token::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -600,6 +604,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_from_json(Obj,"expires",expires);
|
||||
field_from_json(Obj,"idleTimeout",idleTimeout);
|
||||
field_from_json(Obj,"revocationDate",revocationDate);
|
||||
field_from_json(Obj,"lastRefresh", lastRefresh);
|
||||
return true;
|
||||
} catch(...) {
|
||||
std::cout << "Cannot parse: Token" << std::endl;
|
||||
|
||||
@@ -9,14 +9,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Data/LOB.h"
|
||||
#include "Poco/Data/LOBStream.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
uint64_t Now();
|
||||
namespace SecurityObjects {
|
||||
|
||||
|
||||
typedef std::string USER_ID_TYPE;
|
||||
|
||||
struct AclTemplate {
|
||||
@@ -26,8 +28,13 @@ namespace OpenWifi {
|
||||
bool Delete_ = true;
|
||||
bool PortalLogin_ = true;
|
||||
|
||||
AclTemplate() noexcept = default;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj); };
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
static_assert( std::is_nothrow_move_constructible_v<AclTemplate> );
|
||||
|
||||
struct WebToken {
|
||||
std::string access_token_;
|
||||
@@ -41,6 +48,7 @@ namespace OpenWifi {
|
||||
uint64_t idle_timeout_=0;
|
||||
AclTemplate acl_template_;
|
||||
uint64_t created_=0;
|
||||
uint64_t lastRefresh_=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -54,7 +62,7 @@ namespace OpenWifi {
|
||||
std::string UserTypeToString(USER_ROLE U);
|
||||
|
||||
struct NoteInfo {
|
||||
uint64_t created=0; // = std::time(nullptr);
|
||||
uint64_t created=0; // = OpenWifi::Now();
|
||||
std::string createdBy;
|
||||
std::string note;
|
||||
|
||||
@@ -93,7 +101,7 @@ namespace OpenWifi {
|
||||
std::string uuid;
|
||||
std::string question;
|
||||
std::string method;
|
||||
uint64_t created = std::time(nullptr);
|
||||
uint64_t created = OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -255,7 +263,7 @@ namespace OpenWifi {
|
||||
std::string locale;
|
||||
std::string message;
|
||||
uint64_t sent=0;
|
||||
uint64_t created=std::time(nullptr);
|
||||
uint64_t created=OpenWifi::Now();
|
||||
uint64_t expires=0;
|
||||
uint64_t completed=0;
|
||||
uint64_t canceled=0;
|
||||
@@ -292,6 +300,7 @@ namespace OpenWifi {
|
||||
uint64_t expires=0;
|
||||
uint64_t idleTimeout=0;
|
||||
uint64_t revocationDate=0;
|
||||
uint64_t lastRefresh=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -302,7 +311,6 @@ namespace OpenWifi {
|
||||
std::string type;
|
||||
uint64_t created=0;
|
||||
std::string name;
|
||||
// Poco::Data::LOB<char> avatar;
|
||||
Poco::Data::BLOB avatar;
|
||||
};
|
||||
|
||||
|
||||
@@ -280,6 +280,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_to_json(Obj, "ipv6", ipv6);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "manufacturer", manufacturer);
|
||||
}
|
||||
|
||||
bool Association::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -293,6 +294,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_from_json(Obj, "ipv6", ipv6);
|
||||
field_from_json(Obj, "tx", tx);
|
||||
field_from_json(Obj, "rx", rx);
|
||||
field_from_json(Obj, "manufacturer", manufacturer);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
@@ -324,6 +326,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_to_json(Obj, "ipv6", ipv6);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "manufacturer", manufacturer);
|
||||
}
|
||||
|
||||
bool Client::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -335,6 +338,7 @@ namespace OpenWifi::SubObjects {
|
||||
field_from_json(Obj, "ipv6", ipv6);
|
||||
field_from_json(Obj, "tx", tx);
|
||||
field_from_json(Obj, "rx", rx);
|
||||
field_from_json(Obj, "manufacturer", manufacturer);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
@@ -562,4 +566,38 @@ namespace OpenWifi::SubObjects {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StatsEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "timestamp", timestamp);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
}
|
||||
|
||||
bool StatsEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "timestamp", timestamp);
|
||||
field_from_json(Obj, "tx", tx);
|
||||
field_from_json(Obj, "rx", rx);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StatsBlock::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "modified", modified);
|
||||
field_to_json(Obj, "external", external);
|
||||
field_to_json(Obj, "internal", internal);
|
||||
}
|
||||
|
||||
bool StatsBlock::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "modified", modified);
|
||||
field_from_json(Obj, "external", external);
|
||||
field_from_json(Obj, "internal", internal);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,7 @@ namespace OpenWifi::SubObjects {
|
||||
std::string ipv6;
|
||||
uint64_t tx=0;
|
||||
uint64_t rx=0;
|
||||
std::string manufacturer;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -179,6 +180,7 @@ namespace OpenWifi::SubObjects {
|
||||
std::string ipv6;
|
||||
uint64_t tx=0;
|
||||
uint64_t rx=0;
|
||||
std::string manufacturer;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -298,6 +300,23 @@ namespace OpenWifi::SubObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct StatsEntry {
|
||||
uint64_t timestamp=0;
|
||||
uint64_t tx=0;
|
||||
uint64_t rx=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct StatsBlock {
|
||||
uint64_t modified=0;
|
||||
std::vector<StatsEntry> external, internal;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OWSUB_RESTAPI_SUBOBJECTS_H
|
||||
|
||||
@@ -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,33 +4,35 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "StorageArchiver.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void Archiver::onTimer([[maybe_unused]] Poco::Timer &timer){
|
||||
Utils::SetThreadName("strg-archiver");
|
||||
auto now = OpenWifi::Now();
|
||||
for(const auto &i:DBs_) {
|
||||
if (!Poco::icompare(i.DBName, "healthchecks")) {
|
||||
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);
|
||||
@@ -53,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,":");
|
||||
@@ -79,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
|
||||
});
|
||||
@@ -90,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) + " ";
|
||||
@@ -85,17 +101,18 @@ namespace OpenWifi {
|
||||
bool CreateDefaultDevice(std::string & SerialNumber, std::string & Capabilities, std::string & Firmware, std::string &Compatible,const Poco::Net::IPAddress & IPAddress);
|
||||
|
||||
bool GetDevice(std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select, std::vector<GWObjects::Device> &Devices);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices, const std::string & orderBy="");
|
||||
// bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select, std::vector<GWObjects::Device> &Devices, const std::string & orderBy="");
|
||||
bool DeleteDevice(std::string &SerialNumber);
|
||||
bool UpdateDevice(GWObjects::Device &);
|
||||
bool DeviceExists(std::string & SerialNumber);
|
||||
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
|
||||
bool GetDeviceCount(uint64_t & Count);
|
||||
bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany, std::vector<std::string> & SerialNumbers);
|
||||
bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany, std::vector<std::string> & SerialNumbers, const std::string & orderBy="");
|
||||
bool GetDeviceFWUpdatePolicy(std::string & SerialNumber, std::string & Policy);
|
||||
bool SetDevicePassword(std::string & SerialNumber, std::string & Password);
|
||||
bool UpdateSerialNumberCache();
|
||||
void GetDeviceDbFieldList( Types::StringVec & Fields);
|
||||
|
||||
bool ExistingConfiguration(std::string &SerialNumber, uint64_t CurrentConfig, std::string &NewConfig, uint64_t &);
|
||||
|
||||
@@ -124,18 +141,24 @@ 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);
|
||||
bool CommandCompleted(std::string & UUID, const Poco::JSON::Object & ReturnVars, const std::chrono::duration<double, std::milli> & execution_time, bool FullCommand);
|
||||
bool AttachFileToCommand(std::string & UUID);
|
||||
// bool AttachFileToCommand(std::string & UUID);
|
||||
bool AttachFileDataToCommand(std::string & UUID, const std::stringstream &s);
|
||||
bool CancelWaitFile( std::string & UUID, std::string & ErrorText );
|
||||
bool GetAttachedFile(std::string & UUID, const std::string & SerialNumber, const std::string & FileName, std::string &Type);
|
||||
// bool GetAttachedFile(std::string & UUID, const std::string & SerialNumber, const std::string & FileName, std::string &Type);
|
||||
bool GetAttachedFileContent(std::string & UUID, const std::string & SerialNumber, std::string & FileContent, std::string &Type);
|
||||
bool RemoveAttachedFile(std::string & UUID);
|
||||
bool SetCommandResult(std::string & UUID, std::string & Result);
|
||||
bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands);
|
||||
bool SetCommandExecuted(std::string & CommandUUID);
|
||||
bool SetCommandTimedOut(std::string &CommandUUID);
|
||||
|
||||
void RemovedExpiredCommands();
|
||||
void RemoveTimedOutCommands();
|
||||
|
||||
bool RemoveOldCommands(std::string & SerilNumber, std::string & Command);
|
||||
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
//
|
||||
|
||||
#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 {
|
||||
|
||||
TelemetryClient::TelemetryClient(
|
||||
std::string UUID,
|
||||
uint64_t SerialNumber,
|
||||
Poco::SharedPtr<Poco::Net::WebSocket> WSock,
|
||||
std::unique_ptr<Poco::Net::WebSocket> WSock,
|
||||
Poco::Net::SocketReactor& Reactor,
|
||||
Poco::Logger &Logger):
|
||||
UUID_(std::move(UUID)),
|
||||
@@ -24,7 +24,6 @@ namespace OpenWifi {
|
||||
Reactor_(Reactor),
|
||||
Logger_(Logger),
|
||||
WS_(std::move(WSock)) {
|
||||
std::cout << "Telemetry client creation" << std::endl;
|
||||
try {
|
||||
std::thread T([this]() { this->CompleteStartup(); });
|
||||
T.detach();
|
||||
@@ -35,14 +34,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void TelemetryClient::CompleteStartup() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
try {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Socket_ = *WS_;
|
||||
CId_ = Utils::FormatIPv6(Socket_.peerAddress().toString());
|
||||
|
||||
// auto SS = static_cast<Poco::Net::SecureStreamSocketImpl*>((WS_->impl()));
|
||||
// SS->havePeerCertificate();
|
||||
|
||||
if (TelemetryStream()->RegisterClient(UUID_, this)) {
|
||||
auto TS = Poco::Timespan(240, 0);
|
||||
|
||||
@@ -50,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));
|
||||
@@ -60,7 +57,7 @@ namespace OpenWifi {
|
||||
*WS_, Poco::NObserver<TelemetryClient, Poco::Net::ErrorNotification>(
|
||||
*this, &TelemetryClient::OnSocketError));
|
||||
Registered_ = true;
|
||||
Logger().information(fmt::format("CONNECTION({}): completed.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-CONNECTION({}): Connection completed.", CId_));
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
@@ -73,7 +70,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
TelemetryClient::~TelemetryClient() {
|
||||
Logger().information("Closing telemetry session.");
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-CONNECTION({}): Closing connection.", CId_));
|
||||
if(Registered_ && WS_)
|
||||
{
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
@@ -85,13 +82,8 @@ namespace OpenWifi {
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
Poco::NObserver<TelemetryClient,
|
||||
Poco::Net::ErrorNotification>(*this,&TelemetryClient::OnSocketError));
|
||||
(*WS_).close();
|
||||
Socket_.shutdown();
|
||||
} else {
|
||||
if(WS_)
|
||||
(*WS_).close();
|
||||
Socket_.shutdown();
|
||||
}
|
||||
WS_->close();
|
||||
}
|
||||
|
||||
bool TelemetryClient::Send(const std::string &Payload) {
|
||||
@@ -101,32 +93,26 @@ 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) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
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) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().information(fmt::format("SOCKET-ERROR({}): Closing.",CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-SOCKET-ERROR({}): Closing.",CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
try
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
ProcessIncomingFrame();
|
||||
}
|
||||
catch (const Poco::Exception & E)
|
||||
@@ -136,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();
|
||||
}
|
||||
}
|
||||
@@ -157,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 ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenWifi {
|
||||
TelemetryClient(
|
||||
std::string UUID,
|
||||
uint64_t SerialNumber,
|
||||
Poco::SharedPtr<Poco::Net::WebSocket> WSock,
|
||||
std::unique_ptr<Poco::Net::WebSocket> WSock,
|
||||
Poco::Net::SocketReactor& Reactor,
|
||||
Poco::Logger &Logger);
|
||||
~TelemetryClient();
|
||||
@@ -40,7 +40,7 @@ namespace OpenWifi {
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::StreamSocket Socket_;
|
||||
std::string CId_;
|
||||
Poco::SharedPtr<Poco::Net::WebSocket> WS_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
bool Registered_=false;
|
||||
void SendTelemetryShutdown();
|
||||
void CompleteStartup();
|
||||
|
||||
@@ -3,30 +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) {
|
||||
@@ -43,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());
|
||||
@@ -129,7 +132,4 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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,20 +43,21 @@ 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);
|
||||
Poco::Net::SocketReactor & NextReactor() { return ReactorPool_.NextReactor(); }
|
||||
Poco::Net::SocketReactor & NextReactor() { return Reactor_; }
|
||||
|
||||
void onMessage(bool& b);
|
||||
|
||||
private:
|
||||
std::atomic_bool Running_=false;
|
||||
volatile std::atomic_bool Running_=false;
|
||||
std::map<std::string, TelemetryClient *> Clients_; // uuid -> client
|
||||
std::map<uint64_t, std::set<std::string>> SerialNumbers_; // serialNumber -> uuid
|
||||
ReactorPool ReactorPool_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
std::unique_ptr<FIFO<QueueUpdate>> Messages_=std::make_unique<FIFO<QueueUpdate>>(100);
|
||||
Poco::Thread Thr_;
|
||||
|
||||
TelemetryStream() noexcept:
|
||||
SubSystemServer("TelemetryServer", "TELEMETRY-SVR", "openwifi.telemetry") {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user