Compare commits

...

188 Commits

Author SHA1 Message Date
TIP Automation User
67aef046ac Chg: update image tag in helm values to v2.10.0 2023-06-30 15:30:31 +00:00
TIP Automation User
ed47e1d7e9 Chg: update image tag in helm values to v2.10.0-RC2 2023-06-21 16:24:21 +00:00
Stephane Bourque
abfe38b6fc Merge pull request #330 from Telecominfraproject/master
https://telecominfraproject.atlassian.net/browse/WIFI-12689
2023-06-20 08:59:27 -07:00
stephb9959
b8673c2dcc https://telecominfraproject.atlassian.net/browse/WIFI-12689
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-06-20 08:40:29 -07:00
TIP Automation User
1974622104 Chg: update image tag in helm values to v2.10.0-RC1 2023-06-09 13:34:11 +00:00
stephb9959
13e8ceb7e3 https://telecominfraproject.atlassian.net/browse/WIFI-12634
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-30 23:08:44 -07:00
stephb9959
6c112c21a7 https://telecominfraproject.atlassian.net/browse/WIFI-12630
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-25 07:54:28 -07:00
stephb9959
1ca76459fe https://telecominfraproject.atlassian.net/browse/WIFI-12630
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 14:32:23 -07:00
stephb9959
52ebfd30b9 https://telecominfraproject.atlassian.net/browse/WIFI-12630
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 14:05:06 -07:00
stephb9959
44822e5a63 https://telecominfraproject.atlassian.net/browse/WIFI-12630
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 13:58:56 -07:00
stephb9959
2561fb5cd4 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 13:37:24 -07:00
stephb9959
96f25fd949 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 13:36:11 -07:00
stephb9959
ccbc6307e6 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 13:35:28 -07:00
stephb9959
39e625bb34 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 13:33:15 -07:00
stephb9959
8fd4e57fe8 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 12:23:36 -07:00
stephb9959
192b2d50b4 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 12:20:37 -07:00
stephb9959
6dd67a8218 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 12:17:17 -07:00
stephb9959
3edfb11c33 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 12:12:02 -07:00
stephb9959
fd607bf963 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-22 08:51:35 -07:00
stephb9959
c68cd6aad8 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-18 08:51:29 -07:00
stephb9959
f4674e93c7 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-18 08:50:08 -07:00
stephb9959
21a4eb2a71 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-18 08:46:04 -07:00
stephb9959
ed336bec0c https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 14:17:25 -07:00
stephb9959
b5f8063ab7 https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 14:12:18 -07:00
stephb9959
69dc1b8056 https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 10:24:59 -07:00
stephb9959
a933376bf6 https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 10:14:04 -07:00
stephb9959
21a4245204 https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 10:08:28 -07:00
stephb9959
bcfbc0d2c0 https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 09:48:48 -07:00
stephb9959
f453205a5d https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 09:09:43 -07:00
stephb9959
a8d3ed0dba https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 08:56:57 -07:00
stephb9959
42ab4717d5 https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 08:52:00 -07:00
stephb9959
a36796ab4e https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-17 08:11:16 -07:00
stephb9959
cd9a4f9902 https://telecominfraproject.atlassian.net/browse/WIFI-12590
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-16 09:38:13 -07:00
stephb9959
806f39bc88 https://telecominfraproject.atlassian.net/browse/WIFI-12610
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-16 09:07:41 -07:00
stephb9959
6afeb470d9 https://telecominfraproject.atlassian.net/browse/WIFI-12572
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-15 09:49:57 -07:00
stephb9959
991d60e019 https://telecominfraproject.atlassian.net/browse/WIFI-12572
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-15 09:33:30 -07:00
stephb9959
5cebcdd675 Merge remote-tracking branch 'origin/master' 2023-05-02 09:05:57 -07:00
stephb9959
fdb09654c2 https://telecominfraproject.atlassian.net/browse/WIFI-12572
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-02 09:05:44 -07:00
jaspreetsachdev
a657ce2f52 Update values.yaml 2023-05-02 10:44:14 -04:00
stephb9959
7b17af5575 https://telecominfraproject.atlassian.net/browse/WIFI-12567
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-05-01 07:59:57 -07:00
stephb9959
cc2b9e536f https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-27 07:47:33 -07:00
stephb9959
1a8a0b2ebc https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-21 09:51:40 -07:00
stephb9959
c808d0146c https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-21 09:40:17 -07:00
stephb9959
0bb107b48d https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-21 09:30:03 -07:00
stephb9959
a4f2b8fd5e https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-21 09:27:27 -07:00
stephb9959
4fd9b4f540 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-20 06:40:58 -07:00
stephb9959
d51980e0e5 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-19 22:19:45 -07:00
stephb9959
5ece25ebac https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-19 22:04:22 -07:00
stephb9959
d578174b23 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-19 22:00:00 -07:00
stephb9959
08689107da https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-19 14:27:46 -07:00
stephb9959
0d680934f8 https://telecominfraproject.atlassian.net/browse/WIFI-12525
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-19 13:28:30 -07:00
stephb9959
907d739943 https://telecominfraproject.atlassian.net/browse/WIFI-12378
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-18 16:29:18 -07:00
stephb9959
e5665769ef https://telecominfraproject.atlassian.net/browse/WIFI-12378
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-18 16:23:52 -07:00
stephb9959
8abbc73546 https://telecominfraproject.atlassian.net/browse/WIFI-12378
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-18 15:57:31 -07:00
stephb9959
0c86ffdfff https://telecominfraproject.atlassian.net/browse/WIFI-12378
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-18 15:09:14 -07:00
stephb9959
c0f59756ae https://telecominfraproject.atlassian.net/browse/WIFI-12378
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-18 15:05:15 -07:00
stephb9959
41dd567630 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-17 07:57:10 -07:00
stephb9959
6d87fafbc0 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-17 07:40:47 -07:00
stephb9959
dddc4f34ac https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-06 10:27:49 -07:00
stephb9959
9a99bcd2c2 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-06 10:23:24 -07:00
stephb9959
e849a3eba0 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-06 09:23:11 -07:00
stephb9959
decb2bf8c2 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-06 09:07:37 -07:00
stephb9959
0ae5dc5cf9 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-06 08:59:15 -07:00
stephb9959
9160497b28 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 23:36:19 -07:00
stephb9959
9a4e19c651 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 23:33:59 -07:00
stephb9959
62bfb10ca3 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 22:59:44 -07:00
stephb9959
9e3d80f1ea https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 14:30:13 -07:00
stephb9959
fc3b516c76 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 09:45:50 -07:00
stephb9959
ac183fcde6 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 09:21:13 -07:00
stephb9959
7ebc977601 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 09:18:12 -07:00
stephb9959
ec94cdb2df https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-04 09:04:29 -07:00
stephb9959
9c61451f0f https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 22:50:00 -07:00
stephb9959
d08afb6d75 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 22:18:29 -07:00
stephb9959
087ea5372b https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 21:53:30 -07:00
stephb9959
b882796c90 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 21:49:18 -07:00
stephb9959
91c6a8fba1 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 21:27:29 -07:00
stephb9959
2e69ca7444 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 21:19:23 -07:00
stephb9959
58c08c3ff7 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 21:15:18 -07:00
stephb9959
737f1146a1 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 21:05:12 -07:00
stephb9959
0f85f2453b https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 20:47:13 -07:00
stephb9959
a8c4cf1940 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 20:44:38 -07:00
stephb9959
cf320e63ee https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 15:34:07 -07:00
stephb9959
95a11e8f96 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 15:28:23 -07:00
stephb9959
bf611d36cc https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 15:22:03 -07:00
stephb9959
b543e03660 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 15:03:30 -07:00
stephb9959
c1e101366e https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 14:28:29 -07:00
stephb9959
47f21ae17e https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 13:01:32 -07:00
stephb9959
c1dd0151f9 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:54:56 -07:00
stephb9959
80efb654d5 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:49:47 -07:00
stephb9959
2ef9a9220f https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:42:42 -07:00
stephb9959
c27edec0f7 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:29:41 -07:00
stephb9959
c8a65d6137 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:26:22 -07:00
stephb9959
f408a44898 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:15:51 -07:00
stephb9959
4f289427ca https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:11:42 -07:00
stephb9959
2b89cc187b https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 12:04:54 -07:00
stephb9959
59dc2ad032 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-03 11:45:47 -07:00
stephb9959
0d6e2c0e33 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-02 23:32:09 -07:00
stephb9959
37a02b699d https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-02 20:56:58 -07:00
stephb9959
9772e95238 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-02 17:27:20 -07:00
stephb9959
f4d86120c4 https://telecominfraproject.atlassian.net/browse/WIFI-12423
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-04-02 16:21:19 -07:00
Stephane Bourque
384d11d998 Merge pull request #329 from Telecominfraproject/WIFI-12334
https://telecominfraproject.atlassian.net/browse/WIFI-12334
2023-04-02 15:43:35 -07:00
stephb9959
5f8ea6a474 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-30 08:59:32 -07:00
Stephane Bourque
9769a9fa24 Merge pull request #328 from Telecominfraproject/WIFI-12334
https://telecominfraproject.atlassian.net/browse/WIFI-12334
2023-03-28 10:39:00 -07:00
stephb9959
4d16155aec https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-28 10:36:31 -07:00
stephb9959
00ca2a6d92 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-28 10:25:10 -07:00
stephb9959
ecddb5ba63 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-28 10:21:13 -07:00
stephb9959
6fe5298602 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-28 10:18:09 -07:00
stephb9959
1c3c7ec842 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-28 09:59:55 -07:00
stephb9959
e547ee40b0 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-28 08:49:13 -07:00
stephb9959
81806df5cb https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-28 08:42:01 -07:00
stephb9959
3b9c574149 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 23:44:10 -07:00
stephb9959
4159ba4dca https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 23:39:22 -07:00
stephb9959
a1eb8ab3d0 https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 23:31:58 -07:00
stephb9959
2fb316b79e https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 23:23:28 -07:00
stephb9959
ad3319496d https://telecominfraproject.atlassian.net/browse/WIFI-12334
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 23:18:10 -07:00
stephb9959
38a7d35c4b https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 23:00:05 -07:00
stephb9959
3c6e24e50f https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 22:56:59 -07:00
stephb9959
b127f38081 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 22:56:36 -07:00
Stephane Bourque
82cdc4cc03 Merge pull request #327 from Telecominfraproject/WIFI-12428
https://telecominfraproject.atlassian.net/browse/WIFI-12428
2023-03-27 22:46:47 -07:00
Stephane Bourque
2566237c91 Merge branch 'master' into WIFI-12428 2023-03-27 22:46:37 -07:00
stephb9959
562c952d52 https://telecominfraproject.atlassian.net/browse/WIFI-12428
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 14:35:19 -07:00
stephb9959
23d160cba1 https://telecominfraproject.atlassian.net/browse/WIFI-12428
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 14:33:14 -07:00
stephb9959
8cbe0b7c4f https://telecominfraproject.atlassian.net/browse/WIFI-12428
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 14:17:58 -07:00
stephb9959
d804dad1f0 https://telecominfraproject.atlassian.net/browse/WIFI-12428
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-27 11:25:26 -07:00
Stephane Bourque
72595922eb Merge pull request #326 from Telecominfraproject/WIFI-12337
https://telecominfraproject.atlassian.net/browse/WIFI-12337
2023-03-23 21:36:54 -07:00
Stephane Bourque
f1c330eac7 Merge branch 'master' into WIFI-12337 2023-03-23 21:36:30 -07:00
stephb9959
f143471723 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:31:29 -07:00
stephb9959
957e6acf03 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:27:54 -07:00
stephb9959
a6bc509c3d https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:26:17 -07:00
stephb9959
5fd145c7d6 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:21:20 -07:00
stephb9959
f9b431e566 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:16:34 -07:00
stephb9959
a35acfeb88 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:10:52 -07:00
stephb9959
e028b2dd41 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:09:24 -07:00
stephb9959
69e539ffbe https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 21:03:40 -07:00
stephb9959
4a8506f4fe https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 19:26:46 -07:00
stephb9959
2621e2fdde https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 19:25:44 -07:00
stephb9959
8425632453 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 19:20:17 -07:00
stephb9959
bce03ee024 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 19:19:03 -07:00
stephb9959
b6f76b70ab https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 18:54:03 -07:00
stephb9959
30e62dd203 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 17:56:46 -07:00
stephb9959
ae9179eb0e https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 17:36:56 -07:00
stephb9959
0d59e8b0c2 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 17:33:45 -07:00
stephb9959
545f787a4e https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 15:25:28 -07:00
stephb9959
64199bbb62 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 15:04:21 -07:00
stephb9959
1ac4625947 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 14:47:38 -07:00
stephb9959
b45c16f2c0 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 14:35:27 -07:00
stephb9959
86a33ed818 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 11:21:52 -07:00
stephb9959
65c4a96f41 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 11:04:36 -07:00
stephb9959
b7908816a9 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 10:54:25 -07:00
stephb9959
dc55a3a180 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 10:49:50 -07:00
stephb9959
4b953d968b https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 10:40:15 -07:00
stephb9959
81324da9e8 https://telecominfraproject.atlassian.net/browse/WIFI-12337
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-23 10:26:03 -07:00
Stephane Bourque
54d94eef84 Merge pull request #323 from Telecominfraproject/WIFI-12337
https://telecominfraproject.atlassian.net/browse/WIFI-12337
2023-03-23 09:15:43 -07:00
Stephane Bourque
397799278c Merge branch 'master' into WIFI-12337 2023-03-23 09:14:57 -07:00
stephb9959
d8d0eed1fb https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-22 10:24:32 -07:00
stephb9959
d1eb584430 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-22 10:23:33 -07:00
stephb9959
c76e10299d https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-22 09:27:28 -07:00
stephb9959
2949231f67 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-22 09:08:43 -07:00
stephb9959
d6731e4e5b https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-22 08:22:08 -07:00
stephb9959
d92b064561 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-22 07:35:59 -07:00
stephb9959
ec4a7f64de https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-21 16:44:31 -07:00
stephb9959
14877301e4 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-21 16:24:09 -07:00
stephb9959
d92cba15bb https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-21 16:14:12 -07:00
stephb9959
33d92c9240 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-21 15:56:23 -07:00
stephb9959
737ed24d91 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-21 15:10:51 -07:00
stephb9959
670f497af4 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-21 11:01:25 -07:00
stephb9959
11ba1cc6e4 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-21 10:40:40 -07:00
Stephane Bourque
c69c4754cf Merge pull request #321 from Telecominfraproject/WIFI-12407
https://telecominfraproject.atlassian.net/browse/WIFI-12407
2023-03-20 09:51:59 -07:00
Stephane Bourque
8478d761db Merge branch 'master' into WIFI-12407 2023-03-20 09:51:36 -07:00
stephb9959
500a4dc130 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-20 08:58:36 -07:00
stephb9959
c420d9c572 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-20 08:15:19 -07:00
stephb9959
c94d90911f https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-20 07:47:19 -07:00
stephb9959
04fd524b52 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 22:44:39 -07:00
stephb9959
b49744779e https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 22:38:52 -07:00
stephb9959
60de792147 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 22:37:17 -07:00
stephb9959
e6d6da53c7 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 22:28:58 -07:00
stephb9959
cd62cb8b84 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 21:51:49 -07:00
stephb9959
85eb8546c3 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 21:47:17 -07:00
stephb9959
bc5a8bbe5b https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 21:04:51 -07:00
stephb9959
d92a93a872 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 16:32:39 -07:00
stephb9959
0def242b40 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 16:21:48 -07:00
stephb9959
eeb5e2d3be https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 16:14:56 -07:00
stephb9959
e76132f464 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 15:54:27 -07:00
stephb9959
ac41327bf8 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 15:45:12 -07:00
stephb9959
0084b5d21c https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 15:06:54 -07:00
stephb9959
69b4de1b74 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 15:02:26 -07:00
stephb9959
0c3e8d4630 https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 14:55:29 -07:00
stephb9959
af739bc32b https://telecominfraproject.atlassian.net/browse/WIFI-12407
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2023-03-19 14:19:22 -07:00
73 changed files with 30685 additions and 1015 deletions

1
.idea/vcs.xml generated
View File

@@ -2,5 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-debug/rapidjson-test" vcs="Git" />
</component>
</project>

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 2.9.0)
project(owgw VERSION 2.10.0)
set(CMAKE_CXX_STANDARD 17)
@@ -144,9 +144,14 @@ 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_scripts_handler.cpp src/RESTAPI/RESTAPI_scripts_handler.h
src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h
src/RESTAPI/RESTAPI_regulatory.cpp src/RESTAPI/RESTAPI_regulatory.h
src/RESTAPI/RESTAPI_radiussessions_handler.cpp src/RESTAPI/RESTAPI_radiussessions_handler.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_scripts.cpp src/storage/storage_scripts.h
src/storage/storage_tables.cpp
src/RESTAPI/RESTAPI_routers.cpp
src/Daemon.cpp src/Daemon.h
@@ -195,7 +200,18 @@ add_executable( owgw
src/AP_WS_Process_telemetry.cpp
src/AP_WS_Process_venuebroadcast.cpp
src/RADSEC_server.h
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h src/framework/RESTAPI_SystemConfiguration.h src/ScriptManager.cpp src/ScriptManager.h src/RESTAPI/RESTAPI_scripts_handler.cpp src/RESTAPI/RESTAPI_scripts_handler.h src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h src/storage/storage_scripts.cpp src/storage/storage_scripts.h src/SignatureMgr.h src/AP_WS_Process_event.cpp src/AP_WS_Process_wifiscan.cpp src/AP_WS_Process_alarm.cpp src/GWKafkaEvents.cpp src/GWKafkaEvents.h src/RegulatoryInfo.cpp src/RegulatoryInfo.h src/RESTAPI/RESTAPI_regulatory.cpp src/RESTAPI/RESTAPI_regulatory.h)
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h
src/framework/RESTAPI_SystemConfiguration.h
src/ScriptManager.cpp src/ScriptManager.h
src/SignatureMgr.h
src/AP_WS_Process_event.cpp
src/AP_WS_Process_wifiscan.cpp
src/AP_WS_Process_alarm.cpp
src/GWKafkaEvents.cpp src/GWKafkaEvents.h
src/RegulatoryInfo.cpp src/RegulatoryInfo.h
src/RADIUSSessionTracker.cpp src/RADIUSSessionTracker.h
src/libs/Scheduler.h src/libs/InterruptableSleep.h src/libs/ctpl_stl.h src/libs/Cron.h
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h)
if(NOT SMALL_BUILD)

View File

@@ -149,18 +149,35 @@ The `severity` matches the `syslog` levels. Here are the details:
- 7 : LOG_DEBUG 7 /* debug-level messages */
#### 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.
Device may send a `crash log event` during rebooting after a crash. The event cannot be sent until a connection event has been established.
```json
{ "jsonrpc" : "2.0" ,
"method" : "crashlog" ,
"params" : {
"serial" : <serial number> ,
"uuid" : <the UUID of the configuration that generated the crash log>,
"loglines" : [ an array of strings representing the logs from the log file ]
"serial" : <serial number> ,
"uuid" : <the UUID of the configuration that generated the crash log>,
"loglines" : [ an array of strings representing the logs from the log file ]
}
}
```
#### Reboot Log event
The device may send a `reboot log event` after a reboot. This maybe a scheduled reboot or caused in some other way.
```json
{ "jsonrpc" : "2.0" ,
"method" : "rebootLog" ,
"params" : {
"serial" : <serial number> ,
"uuid" : <the UUID of the configuration that generated the reboot log>,
"date" : <Unix time when this reboot occurred>,
"type" : <string>,
"info" : [ "info 1", "info 2"]
}
}
```
Here is a possible list of reboot reasons:
#### Config change pending event
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

2
build
View File

@@ -1 +1 @@
103
64

View File

@@ -74,6 +74,8 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
fi

View File

@@ -9,7 +9,7 @@ fullnameOverride: ""
images:
owgw:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
tag: v2.9.0-RC2
tag: v2.10.0
pullPolicy: Always
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io

22213
issues/OWGW Logs.txt Normal file

File diff suppressed because it is too large Load Diff

2158
issues/OWLS Logs.rtf Normal file

File diff suppressed because it is too large Load Diff

2154
issues/OWLS Logs.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ openapi: 3.0.1
info:
title: uCentral gateway API
description: A process to manage configuration for devices.
version: 2.5.0
version: 2.10.0
license:
name: BSD3
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
@@ -152,6 +152,11 @@ components:
format: uuid
restrictionDetails:
$ref: '#/components/schemas/DeviceRestrictions'
simulated:
type: boolean
lastRecordedContact:
type: integer
format: int64
DeviceWithStatus:
type: object
@@ -260,6 +265,22 @@ components:
format: uuid
restrictionDetails:
$ref: '#/components/schemas/DeviceRestrictions'
hasGPS:
type: boolean
sanity:
type: integer
format: int64
memoryUsed:
type: number
format: float
load:
type: number
format: float
temperature:
type: number
format: float
connectReason:
type: string
DeviceList:
type: object
@@ -329,6 +350,9 @@ components:
associations_5G:
type: integer
format: int64
associations_6G:
type: integer
format: int64
verifiedCertificate:
type: string
enum:
@@ -336,6 +360,7 @@ components:
- VALID_CERTIFICATE,
- MISMATCH_SERIAL,
- VERIFIED
- SIMULATED
DeviceCapabilities:
type: object
@@ -420,7 +445,7 @@ components:
type: string
CommandSubmitSuccess:
description: The command was submitted succesfully.
description: The command was submitted successfully.
properties:
serialNumber:
type: string
@@ -458,6 +483,10 @@ components:
logType:
type: integer
format: int64
example:
- 0 normal logs
- 1 crash logs
- 2 reboot logs
UUID:
type: integer
format: int64
@@ -1269,6 +1298,67 @@ components:
items:
$ref: '#/components/schemas/RadiusProxyPool'
RadiusSession:
type: object
properties:
started:
type: integer
format: int64
lastTransaction:
type: integer
format: int64
inputPackets:
type: integer
format: int64
outputPackets:
type: integer
format: int64
inputOctets:
type: integer
format: int64
outputOctets:
type: integer
format: int64
inputGigaWords:
type: integer
format: int64
outputGigaWords:
type: integer
format: int64
sessionTime:
type: integer
format: int64
destination:
type: string
userName:
type: string
accountingSessionId:
type: string
accountingMultiSessionId:
type: string
callingStationId:
type: string
RadiusSessionList:
type: object
properties:
sessions:
type: array
items:
$ref: '#/components/schemas/RadiusSession'
RadiusCoADMParameters:
type: object
properties:
accountingSessionId:
type: string
accountingMultiSessionId:
type: string
callingStationId:
type: string
chargeableUserIdentity:
type: string
paths:
/devices:
get:
@@ -1377,6 +1467,54 @@ paths:
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- Devices
summary: Delete a list of devices matching a criteria
description: Delete a list of devices matching a criteria
operationId: deleteDeviceList
parameters:
- in: query
description: Supply a list of devices comma separated
name: select
schema:
type: string
example: serial1,serial2,serial3
required: false
- in: query
description: Only simulated devices
name: simulatedOnly
schema:
type: boolean
default: false
required: false
- in: query
description: MAC address must match this pattern. Mutually exclusive with oldestContact
name: macPattern
schema:
type: string
example:
- "aabbcc*"
- "*aabbcc*"
- "*cccddee"
required: false
- in: query
description: lastRecordedContact older than this value. Mutually exclusive with macPattern
name: oldestContact
schema:
type: integer
format: int64
required: false
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/commands:
get:
tags:
@@ -1775,7 +1913,7 @@ paths:
format: int64
- in: query
name: logType
description: 0=any kind of logs (default) 0=normal logs only 1=crash logs only
description: 0=any kind of logs (default) 0=normal logs, 1=crash logs, 2=reboot logs only
schema:
type: integer
format: int64
@@ -2113,32 +2251,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/command:
post:
tags:
- Commands
summary: Post a command to a device
operationId: executeCommand
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Command details
content:
application/json:
schema:
$ref: '#/components/schemas/CommandDetails'
responses:
200:
$ref: '#/components/schemas/CommandInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/configure:
post:
tags:
@@ -2723,9 +2835,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/blacklist:
get:
tags:
@@ -2918,6 +3027,82 @@ paths:
403:
$ref: '#/components/responses/Unauthorized'
/radiusSessions/{serialNumber}:
get:
tags:
- Radius Sessions
summary: Retrieve the RADIUS sessions for a given AP
operationId: getAPRadiusSessions
parameters:
- in: path
name: serialNumber
schema:
type: string
example: for searches or listing only serial number, set the serialNumber to 0
required: true
- in: query
name: serialNumberOnly
schema:
type: boolean
required: false
- in: query
name: userName
schema:
type: string
required: false
- in: query
name: mac
schema:
type: string
required: false
example: aa:bb:cc:dd:ee:ff
responses:
200:
description: AP List
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/RadiusSessionList'
- $ref: '#/components/schemas/SerialNumberList'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- Radius Sessions
summary: Retrieve the RADIUS sessions for a given AP
operationId: putAPRadiusSessions
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
- in: query
name: operation
schema:
type: string
enum:
- coadm
requestBody:
description: operationParameters
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/RadiusCoADMParameters'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/deviceDashboard:
get:
tags:

View File

@@ -85,6 +85,7 @@ iptocountry.ipdata.apikey = ${IPTOCOUNTRY_IPDATA_APIKEY}
autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
openwifi.session.timeout = ${DEVICE_SESSION_TIMEOUT}
#
# rtty
#
@@ -103,6 +104,12 @@ radius.proxy.accounting.port = ${RADIUS_PROXY_ACCOUNTING_PORT}
radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
radius.proxy.coa.port = ${RADIUS_PROXY_COA_PORT}
iptocountry.default = ${IPINFO_DEFAULT_COUNTRY}
#iptocountry.provider = ipinfo
#iptocountry.provider = ipdata
#iptocountry.ipinfo.token =
#iptocountry.ipdata.apikey =
#############################
# Generic information for all micro services
#############################

View File

@@ -0,0 +1,59 @@
//
// Created by stephane bourque on 2023-05-23.
//
#include "AP_WS_ConfigAutoUpgrader.h"
#include <framework/utils.h>
#include <RESTObjects/RESTAPI_GWobjects.h>
#include <StorageService.h>
namespace OpenWifi {
int AP_WS_ConfigAutoUpgrader::Start() {
poco_notice(Logger(), "Starting...");
QueueManager_.start(*this);
return 0;
}
void AP_WS_ConfigAutoUpgrader::Stop() {
poco_notice(Logger(), "Stopping...");
Running_ = false;
Queue_.wakeUpAll();
QueueManager_.join();
poco_notice(Logger(), "Stopped...");
}
void AP_WS_ConfigAutoUpgrader::run() {
Utils::SetThreadName("auto:cfgmgr");
Running_ = true;
while (Running_) {
Poco::AutoPtr<Poco::Notification> NextMsg(Queue_.waitDequeueNotification());
try {
auto Entry = dynamic_cast<CheckConfiguration *>(NextMsg.get());
if (Entry != nullptr) {
GWObjects::Device DeviceInfo;
std::string SerialNumber = Utils::IntToSerialNumber(Entry->serial_);
if (StorageService()->GetDevice(SerialNumber, DeviceInfo)) {
if(DeviceInfo.pendingUUID!=0 && Entry->uuid_==DeviceInfo.pendingUUID) {
StorageService()->CompleteDeviceConfigurationChange(SerialNumber);
SetDeviceCacheEntry(Entry->serial_, Utils::Now(), Entry->uuid_, 0);
continue;
}
if(DeviceInfo.UUID==Entry->uuid_) {
SetDeviceCacheEntry(Entry->serial_, Utils::Now(), Entry->uuid_, 0);
continue;
}
}
}
return;
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(), "Exception occurred during run.");
}
}
}
} // namespace OpenWifi

View File

@@ -0,0 +1,137 @@
//
// Created by stephane bourque on 2023-05-23.
//
#pragma once
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
#include "Poco/Timer.h"
#include <framework/SubSystemServer.h>
#include <framework/utils.h>
namespace OpenWifi {
class CheckConfiguration : public Poco::Notification {
public:
explicit CheckConfiguration(std::uint64_t s, std::uint64_t c) :
serial_(s), uuid_(c) {
}
std::uint64_t serial_;
std::uint64_t uuid_;
};
struct ConfigurationCacheEntry {
std::uint64_t last_check_=0;
std::uint64_t current_config_=0;
std::uint64_t pending_config_=0;
};
class AP_WS_ConfigAutoUpgrader : public SubSystemServer, Poco::Runnable {
public:
int Start() final;
void Stop() final;
void run() final;
static auto instance() {
static auto instance = new AP_WS_ConfigAutoUpgrader;
return instance;
}
inline void AddConfiguration(std::uint64_t serial, std::uint64_t config_uuid) {
std::lock_guard Guard(CacheMutex_);
auto hint = Cache_.find(serial);
if(hint==end(Cache_)) {
Cache_[serial] = { Utils::Now(),config_uuid , 0 };
return;
}
if(hint->second.pending_config_==0) {
hint->second.last_check_ = Utils::Now();
hint->second.current_config_ = config_uuid;
return;
}
}
inline void AddConfiguration(std::uint64_t serial, std::uint64_t config_uuid, std::uint64_t pending_config_uuid) {
std::lock_guard Guard(CacheMutex_);
auto hint = Cache_.find(serial);
if(hint==end(Cache_)) {
Cache_[serial] = { Utils::Now(), config_uuid , pending_config_uuid };
return;
}
if(hint->second.pending_config_==0) {
hint->second.last_check_ = Utils::Now();
hint->second.current_config_ = config_uuid;
hint->second.pending_config_ = pending_config_uuid;
return;
}
}
[[nodiscard]] inline ConfigurationCacheEntry GetSerialInfo(std::uint64_t serial) const {
std::lock_guard Guard(CacheMutex_);
auto hint = Cache_.find(serial);
if(hint==end(Cache_)) {
return {0,0,0};
}
return hint->second;
}
inline bool UpdateConfiguration(std::uint64_t serial, std::uint64_t config) {
if(serial==0)
return false;
std::lock_guard Guard(CacheMutex_);
auto hint = Cache_.find(serial);
if(hint!=end(Cache_)) {
if(hint->second.current_config_==config) {
return false;
}
if(config==hint->second.pending_config_) {
Queue_.enqueueNotification(new CheckConfiguration(serial,config));
return true;
}
if(config!=hint->second.current_config_ && hint->second.pending_config_==0) {
Queue_.enqueueNotification(new CheckConfiguration(serial,config));
return true;
}
if((Utils::Now()-hint->second.last_check_)<60*5) {
return false;
}
if(hint->second.pending_config_!=0) {
return false;
}
}
return true;
}
inline void SetDeviceCacheEntry(std::uint64_t serial, std::uint64_t t, std::uint64_t uuid, std::uint64_t pending_uuid) {
std::lock_guard Guard(CacheMutex_);
Cache_[serial] = { t, uuid, pending_uuid };
}
private:
Poco::NotificationQueue Queue_;
Poco::Thread QueueManager_;
std::atomic_bool Running_=false;
mutable std::mutex CacheMutex_;
std::map<std::uint64_t, ConfigurationCacheEntry> Cache_;
AP_WS_ConfigAutoUpgrader() noexcept
: SubSystemServer("AutoConfigUpgrade", "AUTO-CFG-MGR", "auto.config.updater") {
}
};
inline auto AP_WS_ConfigAutoUpgrader() { return AP_WS_ConfigAutoUpgrader::instance(); }
} // namespace OpenWifi

View File

@@ -31,6 +31,7 @@
#include "framework/ow_constants.h"
#include "RADIUSSessionTracker.h"
#include "RADIUS_proxy_server.h"
namespace OpenWifi {
@@ -126,7 +127,7 @@ namespace OpenWifi {
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
poco_information(Logger_,
poco_trace(Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_,
State_.sessionId, CN_));
@@ -138,10 +139,14 @@ namespace OpenWifi {
return false;
}
if(AP_WS_Server::IsSim(CN_)) {
State_.VerifiedCertificate = GWObjects::SIMULATED;
}
std::string reason, author;
std::uint64_t created;
if (!CN_.empty() && StorageService()->IsBlackListed(CN_, reason, author, created)) {
DeviceBlacklistedKafkaEvent KE(CN_, Utils::Now(), reason, author, created, CId_);
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
poco_warning(
Logger_,
fmt::format(
@@ -227,7 +232,7 @@ namespace OpenWifi {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(Disconnect, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, std::make_shared<std::string>(OS.str()));
} catch (...) {
}
}
@@ -237,10 +242,21 @@ namespace OpenWifi {
EndConnection();
}
void AP_WS_Connection::EndConnection() {
Valid_ = false;
void DeviceDisconnectionCleanup(const std::string &SerialNumber) {
if (KafkaManager()->Enabled()) {
NotifyKafkaDisconnect(SerialNumber);
}
RADIUSSessionTracker()->DeviceDisconnect(SerialNumber);
}
void AP_WS_Connection::EndConnection(bool DeleteSession) {
Valid_ = false;
if (!Dead_.test_and_set()) {
if(!SerialNumber_.empty() && State_.LastContact!=0) {
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
}
if (Registered_) {
Registered_ = false;
Reactor_.removeEventHandler(
@@ -255,14 +271,16 @@ namespace OpenWifi {
}
WS_->close();
if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
std::string s(SerialNumber_);
std::thread t([s]() { NotifyKafkaDisconnect(s); });
t.detach();
if(!SerialNumber_.empty()) {
std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_);
Cleanup.detach();
}
auto SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
if (SessionDeleted) {
bool SessionDeleted = false;
if(DeleteSession)
SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
if (SessionDeleted || !DeleteSession) {
GWWebSocketNotifications::SingleDevice_t N;
N.content.serialNumber = SerialNumber_;
GWWebSocketNotifications::DeviceDisconnected(N);
@@ -430,7 +448,7 @@ namespace OpenWifi {
std::string reason, author;
std::uint64_t created;
if (StorageService()->IsBlackListed(Serial, reason, author, created)) {
DeviceBlacklistedKafkaEvent KE(CN_, Utils::Now(), reason, author, created, CId_);
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
Poco::Exception E(
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
Serial),
@@ -495,6 +513,10 @@ namespace OpenWifi {
Process_wifiscan(ParamsObj);
} break;
case uCentralProtocol::Events::ET_REBOOTLOG: {
Process_rebootLog(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: {
@@ -703,7 +725,7 @@ namespace OpenWifi {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(PingObject, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, std::make_shared<std::string>(OS.str()));
}
return;
} break;
@@ -932,22 +954,23 @@ namespace OpenWifi {
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
if (Doc->has(uCentralProtocol::RADIUSDATA)) {
std::string secret;
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());
DecodedData.size(),secret);
} 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());
DecodedData.size(), secret);
} 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());
DecodedData.size(), secret);
}
}
}

View File

@@ -8,6 +8,7 @@
#include <string>
#include "Poco/JSON/Object.h"
#include <Poco/JSON/Parser.h>
#include "Poco/Logger.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/SocketReactor.h"
@@ -27,7 +28,7 @@ namespace OpenWifi {
Poco::Logger &L, Poco::Net::SocketReactor &R);
~AP_WS_Connection();
void EndConnection();
void EndConnection(bool DeleteSession=true);
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
void ProcessIncomingFrame();
@@ -57,7 +58,7 @@ namespace OpenWifi {
bool StopWebSocketTelemetry(uint64_t RPCID);
bool StopKafkaTelemetry(uint64_t RPCID);
inline void GetLastStats(std::string &LastStats) const {
inline void GetLastStats(std::string &LastStats) {
std::shared_lock G(ConnectionMutex_);
LastStats = RawLastStats_;
}
@@ -65,6 +66,33 @@ namespace OpenWifi {
inline void SetLastStats(const std::string &LastStats) {
std::unique_lock G(ConnectionMutex_);
RawLastStats_ = LastStats;
try {
Poco::JSON::Parser P;
auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
hasGPS = Stats->isObject("gps");
auto Unit = Stats->getObject("unit");
auto Memory = Unit->getObject("memory");
std::uint64_t TotalMemory = Memory->get("total");
std::uint64_t FreeMemory = Memory->get("free");
if(TotalMemory>0) {
memory_used_ =
(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
}
if(Unit->isArray("load")) {
Poco::JSON::Array::Ptr Load = Unit->getArray("load");
if(Load->size()>1) {
cpu_load_ = Load->get(1);
}
}
if(Unit->isArray("temperature")) {
Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
if(Temperature->size()>1) {
temperature_ = Temperature->get(0);
}
}
} catch (...) {
}
}
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
@@ -82,6 +110,8 @@ namespace OpenWifi {
State = State_;
}
inline bool HasGPS() { return hasGPS; }
inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
std::shared_lock G(ConnectionMutex_);
R = Restrictions_;
@@ -101,6 +131,7 @@ namespace OpenWifi {
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
bool ValidatedDevice();
@@ -168,6 +199,8 @@ namespace OpenWifi {
bool StartTelemetry(uint64_t RPCID, const std::vector<std::string> &TelemetryTypes);
bool StopTelemetry(uint64_t RPCID);
void UpdateCounts();
bool hasGPS=false;
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
};
} // namespace OpenWifi

View File

@@ -25,7 +25,7 @@ namespace OpenWifi {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, OS.str());
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, std::make_shared<std::string>(OS.str()));
}
}
}

View File

@@ -32,7 +32,7 @@ namespace OpenWifi {
Event.set("payload", EventDetails);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, OS.str());
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, std::make_shared<std::string>(OS.str()));
}
}
@@ -51,7 +51,7 @@ namespace OpenWifi {
Event.set("payload", EventDetails);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, OS.str());
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, std::make_shared<std::string>(OS.str()));
}
}
@@ -81,6 +81,10 @@ namespace OpenWifi {
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
CId_ = SerialNumber_ + "@" + CId_;
if(ParamsObj->has("reason")) {
State_.connectReason = ParamsObj->get("reason").toString();
}
auto IP = PeerAddress_.toString();
if (IP.substr(0, 7) == "::ffff:") {
IP = IP.substr(7);
@@ -105,7 +109,7 @@ namespace OpenWifi {
GWObjects::Device DeviceInfo;
auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
if (Daemon()->AutoProvisioning() && !DeviceExists) {
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_);
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_, State_.VerifiedCertificate==GWObjects::SIMULATED );
} else if (!Daemon()->AutoProvisioning() && !DeviceExists) {
SendKafkaDeviceNotProvisioned(SerialNumber_, Firmware, Compatible_, CId_);
poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_));
@@ -115,7 +119,7 @@ namespace OpenWifi {
int Updated{0};
if (!Firmware.empty()) {
if (Firmware != DeviceInfo.Firmware) {
DeviceFirmwareChangeKafkaEvent KEvent(SerialNumber_, Utils::Now(),
DeviceFirmwareChangeKafkaEvent KEvent(SerialNumberInt_, Utils::Now(),
DeviceInfo.Firmware, Firmware);
DeviceInfo.Firmware = Firmware;
DeviceInfo.LastFWUpdate = Utils::Now();
@@ -131,6 +135,21 @@ namespace OpenWifi {
}
}
if (DeviceInfo.lastRecordedContact==0) {
DeviceInfo.lastRecordedContact = Utils::Now();
++Updated;
}
if (DeviceInfo.simulated && (State_.VerifiedCertificate!=GWObjects::SIMULATED)) {
DeviceInfo.simulated = false;
++Updated;
}
if (!DeviceInfo.simulated && (State_.VerifiedCertificate==GWObjects::SIMULATED)) {
DeviceInfo.simulated = true;
++Updated;
}
if (DeviceInfo.locale != State_.locale) {
DeviceInfo.locale = State_.locale;
++Updated;
@@ -193,6 +212,12 @@ namespace OpenWifi {
return EndConnection();
}
}
} else {
poco_information(Logger_,
fmt::format("CONNECT({}): Simulator device. "
"Session={} ConnectionCompletion Time={}",
CId_, State_.sessionId,
State_.connectionCompletionTime));
}
GWWebSocketNotifications::SingleDevice_t Notification;
@@ -207,7 +232,7 @@ namespace OpenWifi {
ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, std::make_shared<std::string>(OS.str()));
}
} else {
poco_warning(

View File

@@ -7,10 +7,12 @@
#include "fmt/format.h"
#include "framework/ow_constants.h"
#include <GWKafkaEvents.h>
namespace OpenWifi {
void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
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;
@@ -24,11 +26,11 @@ namespace OpenWifi {
.Log = LogText,
.Data = "",
.Severity = GWObjects::DeviceLog::LOG_EMERG,
.Recorded = (uint64_t)time(nullptr),
.Recorded = Utils::Now(),
.LogType = 1,
.UUID = 0};
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
StorageService()->AddLog(DeviceLog);
DeviceLogKafkaEvent E(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
return;

View File

@@ -38,7 +38,7 @@ namespace OpenWifi {
std::ostringstream OS;
FullEvent.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
OS.str());
std::make_shared<std::string>(OS.str()));
}
}
} catch (const Poco::Exception &E) {

View File

@@ -19,8 +19,10 @@ namespace OpenWifi {
Errors_++;
return;
}
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
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();
@@ -62,7 +64,7 @@ namespace OpenWifi {
std::ostringstream OS;
ParamsObj->set("timestamp", Utils::Now());
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, std::make_shared<std::string>(OS.str()));
}
} else {
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));

View File

@@ -7,6 +7,7 @@
#include "fmt/format.h"
#include "framework/ow_constants.h"
#include <GWKafkaEvents.h>
namespace OpenWifi {
void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
@@ -36,6 +37,7 @@ namespace OpenWifi {
.LogType = 0,
.UUID = State_.UUID};
StorageService()->AddLog(DeviceLog);
DeviceLogKafkaEvent E(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
return;

View File

@@ -0,0 +1,44 @@
//
// Created by stephane bourque on 2023-05-16.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "fmt/format.h"
#include "framework/ow_constants.h"
#include <GWKafkaEvents.h>
namespace OpenWifi {
void StripNulls(std::string &S) {
for(std::size_t i=0;i<S.size();++i) {
if(S[i]==0)
S[i]=' ';
}
}
void AP_WS_Connection::Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj) {
if (ParamsObj->has(uCentralProtocol::UUID)
&& ParamsObj->isArray(uCentralProtocol::INFO)
&& ParamsObj->has(uCentralProtocol::TYPE)
&& ParamsObj->has(uCentralProtocol::DATE) ) {
poco_warning(Logger_, fmt::format("REBOOT-LOG({}): new entry.", CId_));
auto InfoLines = ParamsObj->getArray(uCentralProtocol::INFO);
std::ostringstream os;
InfoLines->stringify(os);
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
.Log = ParamsObj->get(uCentralProtocol::TYPE).toString(),
.Data = "{ \"info\" : " + os.str() + "}",
.Severity = GWObjects::DeviceLog::LOG_INFO,
.Recorded = ParamsObj->get(uCentralProtocol::DATE),
.LogType = 2,
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
StorageService()->AddLog(DeviceLog);
DeviceLogKafkaEvent E(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("REBOOT-LOG({}): Missing parameters.", CId_));
}
}
} // namespace OpenWifi

View File

@@ -59,7 +59,7 @@ namespace OpenWifi {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, std::make_shared<std::string>(OS.str()));
}
GWWebSocketNotifications::SingleDevice_t N;

View File

@@ -27,9 +27,10 @@ namespace OpenWifi {
std::ostringstream SS;
Payload->stringify(SS);
auto now = Utils::Now();
auto KafkaPayload = std::make_shared<std::string>(SS.str());
if (ParamsObj->has("adhoc")) {
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
SS.str());
KafkaPayload);
return;
}
if (TelemetryWebSocketRefCount_) {
@@ -38,7 +39,7 @@ namespace OpenWifi {
// std::endl;
TelemetryWebSocketPackets_++;
State_.websocketPackets = TelemetryWebSocketPackets_;
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, SS.str());
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, *KafkaPayload);
} else {
StopWebSocketTelemetry(CommandManager()->Next_RPC_ID());
}
@@ -49,7 +50,7 @@ namespace OpenWifi {
TelemetryKafkaPackets_++;
State_.kafkaPackets = TelemetryKafkaPackets_;
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
SS.str());
KafkaPayload);
} else {
StopKafkaTelemetry(CommandManager()->Next_RPC_ID());
}

View File

@@ -25,7 +25,7 @@ namespace OpenWifi {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, OS.str());
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, std::make_shared<std::string>(OS.str()));
}
}
}

View File

@@ -19,6 +19,7 @@
#include "fmt/format.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
#include <framework/KafkaManager.h>
namespace OpenWifi {
@@ -54,6 +55,8 @@ namespace OpenWifi {
MicroServiceConfigGetBool("openwifi.certificates.allowmismatch", true);
MismatchDepth_ = MicroServiceConfigGetInt("openwifi.certificates.mismatchdepth", 2);
SessionTimeOut_ = MicroServiceConfigGetInt("openwifi.session.timeout", 10*60);
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
Reactor_pool_->Start();
@@ -161,7 +164,7 @@ namespace OpenWifi {
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(
*this, &AP_WS_Server::onGarbageCollecting);
Timer_.setStartInterval(10 * 1000);
Timer_.setPeriodicInterval(5 * 1000); // every minute
Timer_.setPeriodicInterval(10 * 1000); // every minute
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
Running_ = true;
@@ -169,41 +172,50 @@ namespace OpenWifi {
}
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
std::lock_guard Lock(WSServerMutex_);
if (!Garbage_.empty()) {
Garbage_.clear();
}
static uint64_t last_log = Utils::Now();
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
uint64_t total_connected_time = 0;
auto now = Utils::Now();
for (const auto &connection : SerialNumbers_) {
if (connection.second.second == nullptr) {
continue;
}
if (connection.second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - connection.second.second->State_.started);
} else {
NumberOfConnectingDevices_++;
}
}
AverageDeviceConnectionTime_ =
(NumberOfConnectedDevices_ != 0) ? total_connected_time / NumberOfConnectedDevices_ : 0;
if ((now - last_log) > 120) {
last_log = now;
poco_information(
Logger(),
fmt::format(
"Active AP connections: {} Connecting: {} Average connection time: {} seconds",
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
AverageDeviceConnectionTime_));
{
std::lock_guard Lock(WSServerMutex_);
if (!Garbage_.empty()) {
Garbage_.clear();
}
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
uint64_t total_connected_time = 0;
auto hint = SerialNumbers_.begin();
while (hint != end(SerialNumbers_)) {
if (hint->second.second == nullptr) {
hint = SerialNumbers_.erase(hint);
} else if ((now - hint->second.second->State_.LastContact) > SessionTimeOut_) {
hint->second.second->EndConnection(false);
poco_information(Logger(),fmt::format("{}: Session seems idle. Controller disconnecting device.", hint->second.second->SerialNumber_));
Sessions_.erase(hint->second.second->State_.sessionId);
Garbage_.push_back(hint->second.second);
hint = SerialNumbers_.erase(hint);
} else if (hint->second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - hint->second.second->State_.started);
hint++;
} else {
NumberOfConnectingDevices_++;
hint++;
}
}
AverageDeviceConnectionTime_ = NumberOfConnectedDevices_ > 0
? total_connected_time / NumberOfConnectedDevices_
: 0;
if ((now - last_log) > 120) {
last_log = now;
poco_information(Logger(),
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
AverageDeviceConnectionTime_));
}
}
GWWebSocketNotifications::NumberOfConnection_t Notification;
@@ -212,6 +224,19 @@ namespace OpenWifi {
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
GetTotalDataStatistics(Notification.content.tx,Notification.content.rx);
GWWebSocketNotifications::NumberOfConnections(Notification);
Poco::JSON::Object KafkaNotification;
Notification.to_json(KafkaNotification);
Poco::JSON::Object FullEvent;
FullEvent.set("type", "load-update");
FullEvent.set("timestamp", now);
FullEvent.set("payload", KafkaNotification);
std::ostringstream OS;
FullEvent.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system",
std::make_shared<std::string>(OS.str()));
}
void AP_WS_Server::Stop() {
@@ -309,6 +334,32 @@ namespace OpenWifi {
}
Sessions_.erase(Session);
return false;
}
bool AP_WS_Server::EndSessionUnSafe(uint64_t session_id, uint64_t serial_number) {
auto Session = Sessions_.find(session_id);
if (Session == end(Sessions_))
return false;
Garbage_.push_back(Session->second);
auto Device = SerialNumbers_.find(serial_number);
if (Device == end(SerialNumbers_)) {
Sessions_.erase(Session);
return false;
}
if (Device->second.first == session_id) {
Sessions_.erase(Session);
SerialNumbers_.erase(Device);
return true;
}
Sessions_.erase(Session);
return false;
}

View File

@@ -159,7 +159,7 @@ namespace OpenWifi {
void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
bool EndSession(uint64_t connection_id, uint64_t serial_number);
bool EndSessionUnSafe(uint64_t session_id, uint64_t serial_number);
void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes);
@@ -212,6 +212,27 @@ namespace OpenWifi {
}
return true;
}
inline bool ExtendedAttributes(const std::string &serialNumber,
bool & hasGPS,
std::uint64_t &Sanity,
std::double_t &MemoryUsed,
std::double_t &Load,
std::double_t &Temperature
) {
std::lock_guard G(WSServerMutex_);
auto session_hint = SerialNumbers_.find(Utils::SerialNumberToInt(serialNumber));
if(session_hint==end(SerialNumbers_)) {
return false;
}
hasGPS = session_hint->second.second->hasGPS;
Sanity = session_hint->second.second->RawLastHealthcheck_.Sanity;
MemoryUsed = session_hint->second.second->memory_used_;
Load = session_hint->second.second->cpu_load_;
Temperature = session_hint->second.second->temperature_;
return true;
}
private:
mutable std::recursive_mutex WSServerMutex_;
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
@@ -230,10 +251,10 @@ namespace OpenWifi {
std::atomic_bool AllowSerialNumberMismatch_ = true;
std::atomic_uint64_t MismatchDepth_ = 2;
std::atomic_uint64_t NumberOfConnectedDevices_ = 0;
std::atomic_uint64_t AverageDeviceConnectionTime_ = 0;
std::atomic_uint64_t NumberOfConnectingDevices_ = 0;
std::uint64_t NumberOfConnectedDevices_ = 0;
std::uint64_t AverageDeviceConnectionTime_ = 0;
std::uint64_t NumberOfConnectingDevices_ = 0;
std::uint64_t SessionTimeOut_ = 10*60;
mutable std::mutex StatsMutex_;
std::atomic_uint64_t TX_=0,RX_=0;

View File

@@ -302,97 +302,116 @@ namespace OpenWifi {
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;
std::uint64_t offset = 0;
bool Done = false;
while (!Done) {
std::vector<GWObjects::CommandDetails> Commands;
if (StorageService()->GetReadyToExecuteCommands(offset, 200, Commands)) {
if(Commands.empty()) {
Done=true;
continue;
}
poco_trace(MyLogger,
fmt::format("{}: Serial={} Command={} Starting processing.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
try {
// Skip an already running command
if (IsCommandRunning(Cmd.UUID)) {
continue;
poco_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 {
auto now = Utils::Now();
// 2 hour timeout for commands
if ((now - Cmd.Submitted) > commandTimeOut_) {
poco_information(MyLogger,
fmt::format("{}: Serial={} Command={} has expired.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandTimedOut(Cmd.UUID);
continue;
}
// Skip an already running command
if (IsCommandRunning(Cmd.UUID)) {
continue;
}
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
if (!AP_WS_Server()->Connected(SerialNumberInt)) {
poco_trace(
auto now = Utils::Now();
// 2 hour timeout for commands
if ((now - Cmd.Submitted) > commandTimeOut_) {
poco_information(
MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandTimedOut(Cmd.UUID);
continue;
}
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
if (!AP_WS_Server()->Connected(SerialNumberInt)) {
poco_trace(
MyLogger,
fmt::format("{}: Serial={} Command={} Device is not connected.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandLastTry(Cmd.UUID);
continue;
}
std::string ExecutingUUID;
APCommands::Commands ExecutingCommand = APCommands::Commands::unknown;
if (CommandRunningForDevice(SerialNumberInt, ExecutingUUID,
ExecutingCommand)) {
poco_trace(
MyLogger,
fmt::format("{}: Serial={} Command={} Device is already busy "
"with command {} (Command={}).",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command,
ExecutingUUID,
APCommands::to_string(ExecutingCommand)));
continue;
}
Poco::JSON::Parser P;
bool Sent;
poco_information(
MyLogger,
fmt::format("{}: Serial={} Command={} Device is not connected.",
fmt::format("{}: Serial={} Command={} Preparing execution.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandLastTry(Cmd.UUID);
continue;
}
std::string ExecutingUUID;
APCommands::Commands ExecutingCommand = APCommands::Commands::unknown;
if (CommandRunningForDevice(SerialNumberInt, ExecutingUUID,
ExecutingCommand)) {
poco_trace(
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
auto Result = PostCommandDisk(
Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
Cmd.SerialNumber, Cmd.Command, *Params, Cmd.UUID, Sent);
if (Sent) {
StorageService()->SetCommandExecuted(Cmd.UUID);
poco_debug(MyLogger,
fmt::format("{}: Serial={} Command={} Sent.", Cmd.UUID,
Cmd.SerialNumber, Cmd.Command));
} else {
poco_debug(
MyLogger,
fmt::format("{}: Serial={} Command={} Re-queued command.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandLastTry(Cmd.UUID);
}
} catch (const Poco::Exception &E) {
poco_debug(
MyLogger,
fmt::format("{}: Serial={} Command={} Device is already busy "
"with command {} (Command={}).",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command, ExecutingUUID,
APCommands::to_string(ExecutingCommand)));
continue;
}
Poco::JSON::Parser P;
bool Sent;
poco_information(
MyLogger, fmt::format("{}: Serial={} Command={} Preparing execution.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
auto Result = PostCommandDisk(
Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
Cmd.SerialNumber, Cmd.Command, *Params, Cmd.UUID, Sent);
if (Sent) {
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={} Sent.", Cmd.UUID,
Cmd.SerialNumber, Cmd.Command));
} else {
poco_debug(MyLogger,
fmt::format("{}: Serial={} Command={} Re-queued command.",
fmt::format("{}: Serial={} Command={} Hard failure. "
"Command marked as completed.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandLastTry(Cmd.UUID);
StorageService()->SetCommandExecuted(Cmd.UUID);
}
} 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);
}
offset += Commands.size();
} else {
Done=true;
continue;
}
}
} catch (Poco::Exception &E) {
}
catch (Poco::Exception &E) {
MyLogger.log(E);
} catch (...) {
}
catch (...) {
poco_warning(MyLogger, "Exception during command processing.");
}
poco_trace(MyLogger, "Scheduler done.");

View File

@@ -11,12 +11,17 @@
#include "Poco/Util/Application.h"
#include "Poco/Util/Option.h"
#include <framework/ConfigurationValidator.h>
#include <framework/UI_WebSocketClientServer.h>
#include <framework/default_device_types.h>
#include "AP_WS_Server.h"
#include "CommandManager.h"
#include "Daemon.h"
#include "FileUploader.h"
#include "FindCountry.h"
#include "OUIServer.h"
#include "RADIUSSessionTracker.h"
#include "RADIUS_proxy_server.h"
#include "RegulatoryInfo.h"
#include "ScriptManager.h"
@@ -25,10 +30,10 @@
#include "StorageArchiver.h"
#include "StorageService.h"
#include "TelemetryStream.h"
#include "GenericScheduler.h"
#include "UI_GW_WebSocketNotifications.h"
#include "VenueBroadcaster.h"
#include "framework/ConfigurationValidator.h"
#include "framework/UI_WebSocketClientServer.h"
#include "AP_WS_ConfigAutoUpgrader.h"
#include "rttys/RTTYS_server.h"
namespace OpenWifi {
@@ -36,52 +41,21 @@ namespace OpenWifi {
static Daemon instance(
vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, vDAEMON_CONFIG_ENV_VAR,
vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
SubSystemVec{StorageService(), SerialNumberCache(), ConfigurationValidator(),
SubSystemVec{GenericScheduler(), StorageService(), SerialNumberCache(), ConfigurationValidator(),
UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(),
CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(),
RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(),
SignatureManager(), AP_WS_Server(),
RegulatoryInfo()
RegulatoryInfo(),
RADIUSSessionTracker(),
AP_WS_ConfigAutoUpgrader()
});
return &instance;
}
static const std::vector<std::pair<std::string, std::string>> DefaultDeviceTypes{
{"cig_wf160d", "AP"},
{"cig_wf188", "AP"},
{"cig_wf188n", "AP"},
{"cig_wf194c", "AP"},
{"cig_wf194c4", "AP"},
{"edgecore_eap101", "AP"},
{"edgecore_eap102", "AP"},
{"edgecore_ecs4100-12ph", "AP"},
{"edgecore_ecw5211", "AP"},
{"edgecore_ecw5410", "AP"},
{"edgecore_oap100", "AP"},
{"edgecore_spw2ac1200", "SWITCH"},
{"edgecore_spw2ac1200-lan-poe", "SWITCH"},
{"edgecore_ssw2ac2600", "SWITCH"},
{"hfcl_ion4", "AP"},
{"indio_um-305ac", "AP"},
{"linksys_e8450-ubi", "AP"},
{"linksys_ea6350", "AP"},
{"linksys_ea6350-v4", "AP"},
{"linksys_ea8300", "AP"},
{"mikrotik_nand", "AP"},
{"tp-link_ec420-g1", "AP"},
{"tplink_cpe210_v3", "AP"},
{"tplink_cpe510_v3", "AP"},
{"tplink_eap225_outdoor_v1", "AP"},
{"tplink_ec420", "AP"},
{"tplink_ex227", "AP"},
{"tplink_ex228", "AP"},
{"tplink_ex447", "AP"},
{"wallys_dr40x9", "AP"}};
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning", false);
DeviceTypes_ = DefaultDeviceTypes;
DeviceTypes_ = DefaultDeviceTypeList;
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
}

View File

@@ -14,7 +14,8 @@ namespace OpenWifi {
Event.set("payload", payload_);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, serialNumber_, OS.str());
auto payload = std::make_shared<std::string>(OS.str());
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, Utils::IntToSerialNumber(serialNumber_), payload);
}
}

View File

@@ -4,23 +4,26 @@
#pragma once
#include <Poco/JSON/Object.h>
#include <framework/KafkaManager.h>
#include <string>
#include <Poco/JSON/Object.h>
#include <RESTObjects/RESTAPI_GWobjects.h>
#include <framework/KafkaManager.h>
namespace OpenWifi {
class GWKafkaEvents {
public:
GWKafkaEvents(const std::string &serialNumber, const std::string &type,
GWKafkaEvents(std::uint64_t serialNumber, const std::string &type,
std::uint64_t timestamp)
: serialNumber_(serialNumber), type_(type), timestamp_(timestamp) {}
inline void SetPayload(Poco::JSON::Object::Ptr payload) { payload_ = std::move(payload); }
: serialNumber_(serialNumber), type_(type), timestamp_(timestamp) {
payload_ = Poco::SharedPtr<Poco::JSON::Object>(new Poco::JSON::Object);
}
void Send();
[[nodiscard]] inline std::uint64_t Serial() const { return serialNumber_;};
private:
std::string serialNumber_;
protected:
std::uint64_t serialNumber_;
std::string type_;
std::uint64_t timestamp_ = 0;
Poco::JSON::Object::Ptr payload_;
@@ -28,17 +31,15 @@ namespace OpenWifi {
class DeviceFirmwareChangeKafkaEvent : public GWKafkaEvents {
public:
DeviceFirmwareChangeKafkaEvent(const std::string &serialNumber, std::uint64_t timestamp,
DeviceFirmwareChangeKafkaEvent(std::uint64_t serialNumber, std::uint64_t timestamp,
const std::string &oldFirmware,
const std::string &newFirmware)
: GWKafkaEvents(serialNumber, "unit.firmware_change", timestamp),
oldFirmware_(oldFirmware), newFirmware_(newFirmware) {}
~DeviceFirmwareChangeKafkaEvent() {
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
payload->set("oldFirmware", oldFirmware_);
payload->set("newFirmware", newFirmware_);
SetPayload(payload);
payload_->set("oldFirmware", oldFirmware_);
payload_->set("newFirmware", newFirmware_);
Send();
}
@@ -48,15 +49,13 @@ namespace OpenWifi {
class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
public:
DeviceConfigurationChangeKafkaEvent(const std::string &serialNumber,
DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber,
std::uint64_t timestamp, const std::string config)
: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
}
~DeviceConfigurationChangeKafkaEvent() {
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
payload->set("configuration", config_);
SetPayload(payload);
payload_->set("configuration", config_);
Send();
}
@@ -66,7 +65,7 @@ namespace OpenWifi {
class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {
public:
explicit DeviceBlacklistedKafkaEvent(const std::string &serialNumber,
explicit DeviceBlacklistedKafkaEvent(std::uint64_t serialNumber,
std::uint64_t timestamp, const std::string &reason,
const std::string &author, std::uint64_t created,
std::string &IP)
@@ -74,12 +73,10 @@ namespace OpenWifi {
author_(author), created_(created), IP_(IP) {}
~DeviceBlacklistedKafkaEvent() {
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
payload->set("reason", reason_);
payload->set("author", author_);
payload->set("created", created_);
payload->set("ipaddress", IP_);
SetPayload(payload);
payload_->set("reason", reason_);
payload_->set("author", author_);
payload_->set("created", created_);
payload_->set("ipaddress", IP_);
Send();
}
@@ -89,4 +86,21 @@ namespace OpenWifi {
std::string IP_;
};
class DeviceLogKafkaEvent : public GWKafkaEvents {
public:
explicit DeviceLogKafkaEvent( const GWObjects::DeviceLog &L)
: GWKafkaEvents(Utils::MACToInt(L.SerialNumber), "device_log", L.Recorded),
DL_(L)
{
}
~DeviceLogKafkaEvent() {
DL_.to_json(*payload_);
Send();
}
private:
GWObjects::DeviceLog DL_;
};
} // namespace OpenWifi

19
src/GenericScheduler.cpp Normal file
View File

@@ -0,0 +1,19 @@
//
// Created by stephane bourque on 2023-04-19.
//
#include "GenericScheduler.h"
namespace OpenWifi {
int GenericScheduler::Start() {
poco_information(Logger(),"Starting...");
return 0;
}
void GenericScheduler::Stop() {
poco_information(Logger(),"Stopping...");
poco_information(Logger(),"Stopped...");
}
} // namespace OpenWifi

37
src/GenericScheduler.h Normal file
View File

@@ -0,0 +1,37 @@
//
// Created by stephane bourque on 2023-04-19.
//
#pragma once
#include <framework/SubSystemServer.h>
#include <libs/Scheduler.h>
#include <Poco/Environment.h>
namespace OpenWifi {
class GenericScheduler : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new GenericScheduler;
return instance_;
}
int Start() override;
void Stop() override;
auto & Scheduler() { return Scheduler_; }
private:
GenericScheduler() noexcept
: SubSystemServer("Scheduler", "SCHEDULER", "scheduler"),
Scheduler_(Poco::Environment::processorCount()*2) {
}
Bosma::Scheduler Scheduler_;
};
inline auto GenericScheduler() { return GenericScheduler::instance(); }
} // namespace OpenWifi

View File

@@ -0,0 +1,407 @@
//
// Created by stephane bourque on 2023-03-19.
//
#include "RADIUSSessionTracker.h"
#include <fmt/format.h>
#include <framework/utils.h>
#include "RADIUS_proxy_server.h"
#include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_from_json;
using OpenWifi::RESTAPI_utils::field_to_json;
namespace OpenWifi {
int RADIUSSessionTracker::Start() {
poco_information(Logger(),"Starting...");
QueueManager_.start(*this);
GarbageCollectionCallback_ = std::make_unique<Poco::TimerCallback<RADIUSSessionTracker>>(
*this, &RADIUSSessionTracker::GarbageCollection);
GarbageCollectionTimer_.setStartInterval(10000);
GarbageCollectionTimer_.setPeriodicInterval(2*60*1000); // every 2 minutes
GarbageCollectionTimer_.start(*GarbageCollectionCallback_, MicroServiceTimerPool());
return 0;
}
void RADIUSSessionTracker::Stop() {
poco_information(Logger(),"Stopping...");
Running_ = false;
GarbageCollectionTimer_.stop();
SessionMessageQueue_.wakeUpAll();
QueueManager_.join();
poco_information(Logger(),"Stopped...");
}
void RADIUSSessionTracker::GarbageCollection([[maybe_unused]] Poco::Timer &timer) {
std::lock_guard G(Mutex_);
auto Now = Utils::Now();
std::uint64_t active_sessions=0, active_devices=0;
for(auto device_it = AccountingSessions_.begin(); device_it != end(AccountingSessions_); ) {
auto & serialNumber = device_it->first;
auto & session_list = device_it->second;
for(auto session_it=session_list.begin();session_it!=end(session_list);) {
auto & session_name = session_it->first;
auto & session = session_it->second;
if((Now-session->lastTransaction)>SessionTimeout_) {
poco_debug(Logger(),fmt::format("{}: Session {} timeout for {}", serialNumber, session_name, session->userName));
session_it = session_list.erase(session_it);
} else {
++active_sessions;
++session_it;
}
}
if(session_list.empty()) {
device_it = AccountingSessions_.erase(device_it);
} else {
++active_devices;
++device_it;
}
}
poco_information(Logger(),fmt::format("{} active sessions on {} devices",active_sessions, active_devices));
}
void RADIUSSessionTracker::run() {
Utils::SetThreadName("rad:sessmgr");
Running_ = true;
Poco::AutoPtr<Poco::Notification> NextSession(SessionMessageQueue_.waitDequeueNotification());
while (NextSession && Running_) {
auto Session = dynamic_cast<SessionNotification *>(NextSession.get());
try {
if (Session != nullptr) {
switch(Session->Type_) {
case SessionNotification::NotificationType::accounting_session_message: {
ProcessAccountingSession(*Session);
} break;
case SessionNotification::NotificationType::authentication_session_message: {
ProcessAuthenticationSession(*Session);
} break;
case SessionNotification::NotificationType::ap_disconnect: {
DisconnectSession(Session->SerialNumber_);
} break;
}
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(), "Exception occurred during run.");
}
NextSession = SessionMessageQueue_.waitDequeueNotification();
}
poco_information(Logger(), "RADIUS session manager stopping.");
}
void RADIUSSessionTracker::ProcessAuthenticationSession([[maybe_unused]] OpenWifi::SessionNotification &Notification) {
std::lock_guard Guard(Mutex_);
std::string CallingStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface, nasId;
for (const auto &attribute : Notification.Packet_.Attrs_) {
switch (attribute.type) {
case RADIUS::Attributes::AUTH_USERNAME: {
UserName.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::CALLING_STATION_ID: {
CallingStationId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::ACCT_SESSION_ID: {
AccountingSessionId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::ACCT_MULTI_SESSION_ID: {
AccountingMultiSessionId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::CHARGEABLE_USER_IDENTITY:{
ChargeableUserIdentity.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::NAS_IDENTIFIER:{
nasId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::PROXY_STATE: {
std::string Tmp;
Tmp.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
auto ProxyParts = Poco::StringTokenizer(Tmp,":");
if(ProxyParts.count()==4)
Interface=ProxyParts[3];
} break;
default: {
} break;
}
}
auto ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
if(ap_hint==end(AccountingSessions_)) {
SessionMap M;
AccountingSessions_[Notification.SerialNumber_ ] = M;
ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
}
auto Index = CallingStationId; // + AccountingSessionId; // +AccountingMultiSessionId;
auto session_hint = ap_hint->second.find(Index);
if(session_hint==end(ap_hint->second)) {
auto NewSession = std::make_shared<GWObjects::RADIUSSession>();
NewSession->serialNumber = Notification.SerialNumber_;
NewSession->started = NewSession->lastTransaction = Utils::Now();
NewSession->userName = UserName;
NewSession->callingStationId = CallingStationId;
NewSession->accountingSessionId = AccountingSessionId;
NewSession->accountingMultiSessionId = AccountingMultiSessionId;
NewSession->chargeableUserIdentity = ChargeableUserIdentity;
NewSession->interface = Interface;
NewSession->nasId = nasId;
NewSession->secret = Notification.Secret_;
ap_hint->second[Index] = NewSession;
} else {
session_hint->second->lastTransaction = Utils::Now();
}
}
std::uint32_t GetUiInt32(const std::uint8_t *buf) {
return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0);
}
/*
std::string RADIUSSessionTracker::ComputeSessionIndex(OpenWifi::RADIUSSessionPtr S) {
return "";
}
*/
void
RADIUSSessionTracker::ProcessAccountingSession(OpenWifi::SessionNotification &Notification) {
std::lock_guard Guard(Mutex_);
std::string CallingStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface;
std::uint8_t AccountingPacketType = 0;
std::uint32_t InputOctets=0, OutputOctets=0, InputPackets=0, OutputPackets=0, InputGigaWords=0, OutputGigaWords=0,
SessionTime = 0;
for (const auto &attribute : Notification.Packet_.Attrs_) {
switch (attribute.type) {
case RADIUS::Attributes::AUTH_USERNAME: {
UserName.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::CALLING_STATION_ID: {
CallingStationId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::ACCT_SESSION_ID: {
AccountingSessionId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::ACCT_MULTI_SESSION_ID: {
AccountingMultiSessionId.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::CHARGEABLE_USER_IDENTITY:{
ChargeableUserIdentity.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
} break;
case RADIUS::Attributes::ACCT_STATUS_TYPE: {
AccountingPacketType = Notification.Packet_.P_.attributes[attribute.pos + 3];
} break;
case RADIUS::Attributes::ACCT_INPUT_OCTETS: {
InputOctets = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
} break;
case RADIUS::Attributes::ACCT_INPUT_PACKETS: {
InputPackets = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
} break;
case RADIUS::Attributes::ACCT_INPUT_GIGAWORDS: {
InputGigaWords = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
} break;
case RADIUS::Attributes::ACCT_OUTPUT_OCTETS: {
OutputOctets = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
} break;
case RADIUS::Attributes::ACCT_OUTPUT_PACKETS: {
OutputPackets= GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
} break;
case RADIUS::Attributes::ACCT_OUTPUT_GIGAWORDS: {
OutputGigaWords = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
} break;
case RADIUS::Attributes::ACCT_SESSION_TIME: {
SessionTime = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
} break;
case RADIUS::Attributes::PROXY_STATE: {
std::string Tmp;
Tmp.assign(
&Notification.Packet_.P_.attributes[attribute.pos],
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
auto ProxyParts = Poco::StringTokenizer(Tmp,":");
if(ProxyParts.count()==4)
Interface=ProxyParts[3];
} break;
default: {
} break;
}
}
auto Index = CallingStationId; // + AccountingSessionId; // +AccountingMultiSessionId;
auto ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
if(ap_hint==end(AccountingSessions_)) {
SessionMap M;
AccountingSessions_[Notification.SerialNumber_ ] = M;
ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
}
auto session_hint = ap_hint->second.find(Index);
if(session_hint==end(ap_hint->second)) {
// find the calling_station_id
// if we are getting a stop for something we do not know, nothing to do...
if( AccountingPacketType!=OpenWifi::RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_START &&
AccountingPacketType!=OpenWifi::RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_INTERIM_UPDATE) {
return;
}
auto NewSession = std::make_shared<GWObjects::RADIUSSession>();
NewSession->serialNumber = Notification.SerialNumber_;
NewSession->destination = Notification.Destination_;
NewSession->started = NewSession->lastTransaction = Utils::Now();
NewSession->userName = UserName;
NewSession->callingStationId = CallingStationId;
NewSession->accountingSessionId = AccountingSessionId;
NewSession->accountingMultiSessionId = AccountingMultiSessionId;
NewSession->accountingPacket = Notification.Packet_;
NewSession->destination = Notification.Destination_;
NewSession->inputOctets = InputOctets;
NewSession->inputPackets = InputPackets;
NewSession->inputGigaWords = InputGigaWords;
NewSession->outputOctets = OutputOctets;
NewSession->outputOctets = OutputPackets;
NewSession->outputGigaWords = OutputGigaWords;
NewSession->sessionTime = SessionTime;
NewSession->chargeableUserIdentity = ChargeableUserIdentity;
NewSession->interface = Interface;
NewSession->secret = Notification.Secret_;
poco_debug(Logger(),fmt::format("{}: Creating session", CallingStationId));
ap_hint->second[Index] = NewSession;
} else {
// If we receive a stop, just remove that session
if(AccountingPacketType==OpenWifi::RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_STOP) {
poco_debug(Logger(),fmt::format("{}: Deleting session", CallingStationId));
ap_hint->second.erase(Index);
} else {
poco_debug(Logger(),fmt::format("{}: Updating session", CallingStationId));
session_hint->second->accountingPacket = Notification.Packet_;
session_hint->second->destination = Notification.Destination_;
session_hint->second->lastTransaction = Utils::Now();
session_hint->second->inputOctets = InputOctets;
session_hint->second->inputPackets = InputPackets;
session_hint->second->inputGigaWords = InputGigaWords;
session_hint->second->outputOctets = OutputOctets;
session_hint->second->outputOctets = OutputPackets;
session_hint->second->outputGigaWords = OutputGigaWords;
session_hint->second->sessionTime = SessionTime;
}
}
}
[[maybe_unused]] static void store_packet(const std::string &serialNumber, const char *buffer, std::size_t size, int i) {
static std::uint64_t pkt=0;
std::string filename = MicroServiceDataDirectory() + "/radius." + serialNumber + ".stop." +
std::to_string(pkt++) + "." + std::to_string(i) + ".bin";
std::ofstream ofs(filename,std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);
ofs.write(buffer,size);
ofs.close();
}
bool RADIUSSessionTracker::SendCoADM(const RADIUSSessionPtr &session) {
RADIUS::RadiusPacket P;
P.PacketType(RADIUS::Disconnect_Request);
P.Identifier(std::rand() & 0x00ff);
P.AppendAttribute(RADIUS::Attributes::AUTH_USERNAME, session->userName);
P.AppendAttribute(RADIUS::Attributes::NAS_IP, (std::uint32_t)(0x7f000001));
P.AppendAttribute(RADIUS::Attributes::CALLING_STATION_ID, session->callingStationId);
if(!session->accountingSessionId.empty())
P.AppendAttribute(RADIUS::Attributes::ACCT_SESSION_ID, session->accountingSessionId);
if(!session->accountingMultiSessionId.empty())
P.AppendAttribute(RADIUS::Attributes::ACCT_MULTI_SESSION_ID, session->accountingMultiSessionId);
if(!session->chargeableUserIdentity.empty())
P.AppendAttribute(RADIUS::Attributes::CHARGEABLE_USER_IDENTITY, session->chargeableUserIdentity);
if(!session->nasId.empty())
P.AppendAttribute(RADIUS::Attributes::NAS_IDENTIFIER, session->nasId);
auto ProxyState = session->serialNumber + ":" + "0.0.0.0" + ":" + "3799" + ":" + session->interface;
std::cout << "Proxy state: " << ProxyState << " Secret: " << session->secret << std::endl;
// P.AppendAttribute(RADIUS::PROXY_STATE, ProxyState);
P.RecomputeAuthenticator(session->secret);
P.Log(std::cout);
AP_WS_Server()->SendRadiusCoAData(session->serialNumber, P.Buffer(), P.Size_);
return true;
}
bool RADIUSSessionTracker::SendCoADM(const std::string &serialNumber, const std::string &sessionId) {
poco_information(Logger(),fmt::format("{}: SendCoADM for {}.", serialNumber, sessionId));
std::lock_guard Guard(Mutex_);
auto ap_hint = AccountingSessions_.find(serialNumber);
if(ap_hint==end(AccountingSessions_)) {
return false;
}
for(const auto &[_,session]:ap_hint->second) {
if(session->accountingSessionId==sessionId) {
SendCoADM(session);
}
}
return true;
}
void RADIUSSessionTracker::DisconnectSession(const std::string &SerialNumber) {
poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber));
std::lock_guard Guard(Mutex_);
auto hint = AccountingSessions_.find(SerialNumber);
if(hint==end(AccountingSessions_)) {
return;
}
// we need to go through all sessions and send an accounting stop
for(const auto &session:hint->second) {
poco_debug(Logger(), fmt::format("Stopping accounting for {}:{}", SerialNumber, session.first ));
RADIUS::RadiusPacket P(session.second->accountingPacket);
P.P_.identifier++;
P.ReplaceAttribute(RADIUS::Attributes::ACCT_STATUS_TYPE, (std::uint32_t) RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_STOP);
P.ReplaceOrAdd(RADIUS::Attributes::EVENT_TIMESTAMP, (std::uint32_t) std::time(nullptr));
P.AppendAttribute(RADIUS::Attributes::ACCT_TERMINATE_CAUSE, (std::uint32_t) RADIUS::AccountingTerminationReasons::ACCT_TERMINATE_LOST_CARRIER);
RADIUS_proxy_server()->RouteAndSendAccountingPacket(session.second->destination, SerialNumber, P, true, session.second->secret);
}
AccountingSessions_.erase(hint);
}
} // namespace OpenWifi

207
src/RADIUSSessionTracker.h Normal file
View File

@@ -0,0 +1,207 @@
//
// Created by stephane bourque on 2023-03-19.
//
#pragma once
#include <framework/SubSystemServer.h>
#include <Poco/Runnable.h>
#include <Poco/Notification.h>
#include <Poco/NotificationQueue.h>
#include <Poco/JSON/Object.h>
#include <Poco/Timer.h>
#include "RADIUS_helpers.h"
#include <RESTObjects/RESTAPI_GWobjects.h>
namespace OpenWifi {
class SessionNotification : public Poco::Notification {
public:
enum class NotificationType {
accounting_session_message,
authentication_session_message,
ap_disconnect
};
explicit SessionNotification(NotificationType T, const std::string &Destination, const std::string &SerialNumber, const RADIUS::RadiusPacket &P, const std::string &secret)
: Type_(T), Destination_(Destination), SerialNumber_(SerialNumber), Packet_(P), Secret_(secret) {
}
explicit SessionNotification(const std::string &SerialNumber)
: Type_(NotificationType::ap_disconnect), SerialNumber_(SerialNumber) {
}
NotificationType Type_;
std::string Destination_;
std::string SerialNumber_;
RADIUS::RadiusPacket Packet_;
std::string Secret_;
};
class TrackerFutureCompletion {
public:
virtual bool Completed(const RADIUS::RadiusPacket &P) = 0;
virtual bool StillValid() = 0;
private:
};
class CoADisconnectResponse : public TrackerFutureCompletion {
public:
CoADisconnectResponse(const std::string &serialNumber, std::uint8_t id, const std::vector<std::uint8_t> &types, const std::string &callingStationId):
SerialNumber_(serialNumber),
Id_(id),
PacketTypes_(types),
CallingStationId_(callingStationId) {
Created_ = Utils::Now();
}
bool Completed(const RADIUS::RadiusPacket &P) final {
if(P.Identifier()==Id_) {
if(P.P_.code == RADIUS::Disconnect_ACK) {
} else if (P.P_.code == RADIUS::Disconnect_NAK) {
}
}
return true;
}
bool StillValid() final {
return (Utils::Now()-Created_) < 20;
}
private:
std::string SerialNumber_;
std::uint8_t Id_;
std::vector<std::uint8_t> PacketTypes_;
std::uint64_t Created_;
std::string CallingStationId_;
};
using RADIUSSessionPtr = std::shared_ptr<GWObjects::RADIUSSession>;
class RADIUSSessionTracker : public SubSystemServer, Poco::Runnable {
public:
static auto instance() {
static auto instance_ = new RADIUSSessionTracker;
return instance_;
}
int Start() override;
void Stop() override;
void run() final;
inline void AddAccountingSession(const std::string &Destination, const std::string &SerialNumber,
const RADIUS::RadiusPacket &P, const std::string &secret) {
SessionMessageQueue_.enqueueNotification(new SessionNotification(SessionNotification::NotificationType::accounting_session_message, Destination, SerialNumber, P, secret));
}
inline void AddAuthenticationSession(const std::string &Destination, const std::string &SerialNumber,
const RADIUS::RadiusPacket &P, const std::string &secret) {
std::lock_guard G(Mutex_);
auto ap_hint = AccountingSessions_.find(SerialNumber);
if(AccountingSessions_.find(SerialNumber)!=end(AccountingSessions_)) {
// if we have already added the info, do not need to add it again
auto CallingStationId = P.ExtractCallingStationID();
auto AccountingSessionId = P.ExtractAccountingSessionID();
if(ap_hint->second.find(CallingStationId+AccountingSessionId)!=end(ap_hint->second)) {
return;
}
}
SessionMessageQueue_.enqueueNotification(new SessionNotification(SessionNotification::NotificationType::authentication_session_message, Destination, SerialNumber, P, secret));
}
inline void DeviceDisconnect(const std::string &serialNumber) {
SessionMessageQueue_.enqueueNotification(new SessionNotification(serialNumber));
}
inline void GetAPList(std::vector<std::string> &SerialNumbers) {
std::lock_guard G(Mutex_);
for(const auto &[serialNumber,_]:AccountingSessions_) {
SerialNumbers.emplace_back(serialNumber);
}
}
inline void GetAPSessions(const std::string &SerialNumber, GWObjects::RADIUSSessionList & list) {
std::lock_guard G(Mutex_);
auto ap_hint = AccountingSessions_.find(SerialNumber);
if(ap_hint!=end(AccountingSessions_)) {
for(const auto &[index,session]:ap_hint->second) {
list.sessions.emplace_back(*session);
}
}
}
inline void GetUserNameAPSessions(const std::string &userName, GWObjects::RADIUSSessionList & list) {
std::lock_guard G(Mutex_);
for(const auto &[_,sessions]:AccountingSessions_) {
for(const auto &[_,session]:sessions) {
if(Utils::match(userName.c_str(),session->userName.c_str())) {
list.sessions.emplace_back(*session);
}
}
}
}
inline void GetMACAPSessions(const std::string &mac, GWObjects::RADIUSSessionList & list) {
std::lock_guard G(Mutex_);
for(const auto &[_,sessions]:AccountingSessions_) {
for(const auto &[_,session]:sessions) {
if(Utils::match(mac.c_str(),session->callingStationId.c_str())) {
list.sessions.emplace_back(*session);
}
}
}
}
bool SendCoADM(const std::string &serialNumber, const std::string &sessionId);
bool SendCoADM(const RADIUSSessionPtr &session);
inline std::uint32_t HasSessions(const std::string & serialNumber) {
std::lock_guard G(Mutex_);
auto ap_hint = AccountingSessions_.find(serialNumber);
if(ap_hint==end(AccountingSessions_)) {
return 0;
}
return ap_hint->second.size();
}
void GarbageCollection(Poco::Timer &timer);
private:
std::atomic_bool Running_=false;
Poco::NotificationQueue SessionMessageQueue_;
Poco::Thread QueueManager_;
using SessionMap = std::map<std::string,RADIUSSessionPtr>; // calling-station-id + accounting-session-id
std::map<std::string,SessionMap> AccountingSessions_; // serial-number -> session< accounting-session -> session>
Poco::Timer GarbageCollectionTimer_;
std::unique_ptr<Poco::TimerCallback<RADIUSSessionTracker>> GarbageCollectionCallback_;
std::uint64_t SessionTimeout_=10*60;
void ProcessAccountingSession(SessionNotification &Notification);
void ProcessAuthenticationSession(SessionNotification &Notification);
void DisconnectSession(const std::string &SerialNumber);
RADIUSSessionTracker() noexcept
: SubSystemServer("RADIUSSessionTracker", "RADIUS-SESSION", "radius.session") {}
std::string ComputeSessionIndex(RADIUSSessionPtr S);
};
inline auto RADIUSSessionTracker() { return RADIUSSessionTracker::instance(); }
} // namespace OpenWifi

View File

@@ -16,246 +16,224 @@
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] */
// Packet types
constexpr std::uint8_t Access_Request = 1;
constexpr std::uint8_t Access_Accept = 2;
constexpr std::uint8_t Access_Reject = 3;
constexpr std::uint8_t Accounting_Request = 4;
constexpr std::uint8_t Accounting_Response = 5;
constexpr std::uint8_t Accounting_Status = 6;
constexpr std::uint8_t Password_Request = 7;
constexpr std::uint8_t Password_Ack = 8;
constexpr std::uint8_t Password_Reject = 9;
constexpr std::uint8_t Accounting_Message = 10;
constexpr std::uint8_t Access_Challenge = 11;
constexpr std::uint8_t Status_Server = 12; /* Status-Server */
constexpr std::uint8_t Status_Client = 13; /* Status-Client */
constexpr std::uint8_t Disconnect_Request = 40;
constexpr std::uint8_t Disconnect_ACK = 41;
constexpr std::uint8_t Disconnect_NAK = 42;
constexpr std::uint8_t CoA_Request = 43;
constexpr std::uint8_t CoA_ACK = 44;
constexpr std::uint8_t CoA_NAK = 45;
constexpr std::uint8_t Resource_Free_Request = 21;
constexpr std::uint8_t Resource_Free_Response = 22;
constexpr std::uint8_t Resource_Query_Request = 23;
constexpr std::uint8_t Resource_Query_Response = 24;
constexpr std::uint8_t Alternate_Resource_Reclaim_Request = 25 ;
constexpr std::uint8_t Reserved_Cmd = 255; /* Reserved */
#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] */
// Some attribute values
namespace Attributes {
constexpr std::uint8_t AUTH_USERNAME = 1;
constexpr std::uint8_t USER_PASSWORD = 2;
constexpr std::uint8_t CHAP_PASSWORD = 3;
constexpr std::uint8_t NAS_IP = 4;
constexpr std::uint8_t CALLED_STATION_ID = 30;
constexpr std::uint8_t CALLING_STATION_ID = 31;
constexpr std::uint8_t NAS_IDENTIFIER = 32;
constexpr std::uint8_t PROXY_STATE = 33;
constexpr std::uint8_t ACCT_STATUS_TYPE = 40;
constexpr std::uint8_t ACCT_INPUT_OCTETS = 42;
constexpr std::uint8_t ACCT_OUTPUT_OCTETS = 43;
constexpr std::uint8_t ACCT_SESSION_ID = 44;
constexpr std::uint8_t ACCT_AUTHENTIC = 45;
constexpr std::uint8_t ACCT_SESSION_TIME = 46;
constexpr std::uint8_t ACCT_INPUT_PACKETS = 47;
constexpr std::uint8_t ACCT_OUTPUT_PACKETS = 48;
constexpr std::uint8_t ACCT_TERMINATE_CAUSE = 49;
constexpr std::uint8_t ACCT_MULTI_SESSION_ID = 50;
constexpr std::uint8_t ACCT_INPUT_GIGAWORDS = 52;
constexpr std::uint8_t ACCT_OUTPUT_GIGAWORDS = 53;
constexpr std::uint8_t EVENT_TIMESTAMP = 55;
constexpr std::uint8_t MESSAGE_AUTHENTICATOR = 80;
constexpr std::uint8_t CHARGEABLE_USER_IDENTITY = 89;
};
#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 */
namespace AccountingPacketTypes {
constexpr std::uint8_t ACCT_STATUS_TYPE_START = 1;
constexpr std::uint8_t ACCT_STATUS_TYPE_STOP = 2;
constexpr std::uint8_t ACCT_STATUS_TYPE_INTERIM_UPDATE = 3;
constexpr std::uint8_t ACCT_STATUS_TYPE_ACCOUNTING_ON = 7;
constexpr std::uint8_t ACCT_STATUS_TYPE_ACCOUNTING_OFF = 8;
constexpr std::uint8_t ACCT_STATUS_TYPE_FAILED = 15;
}
/*
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]
namespace AccountingTerminationReasons {
constexpr std::uint8_t ACCT_TERMINATE_USER_REQUEST = 1;
constexpr std::uint8_t ACCT_TERMINATE_LOST_CARRIER = 2;
constexpr std::uint8_t ACCT_TERMINATE_LOST_SERVICE = 3;
constexpr std::uint8_t ACCT_TERMINATE_IDLE_TIMEOUT = 4;
constexpr std::uint8_t ACCT_TERMINATE_SESSION_TIMEOUT = 5;
constexpr std::uint8_t ACCT_TERMINATE_ADMIN_RESET = 6;
constexpr std::uint8_t ACCT_TERMINATE_ADMIN_REBOOT = 7;
constexpr std::uint8_t ACCT_TERMINATE_PORT_ERROR = 8;
constexpr std::uint8_t ACCT_TERMINATE_NAS_ERROR = 9;
constexpr std::uint8_t ACCT_TERMINATE_NAS_REQUEST = 10;
constexpr std::uint8_t ACCT_TERMINATE_PORT_REBOOT = 11;
constexpr std::uint8_t ACCT_TERMINATE_PORT_UNNEEDED = 12;
constexpr std::uint8_t ACCT_TERMINATE_PORT_PREEMPTED = 13;
constexpr std::uint8_t ACCT_TERMINATE_PORT_SUSPEND = 14;
constexpr std::uint8_t ACCT_TERMINATE_SERVICE_UNAVAILABLE = 15;
constexpr std::uint8_t ACCT_TERMINATE_CALLBACK = 16;
constexpr std::uint8_t ACCT_TERMINATE_USER_ERROR = 17;
constexpr std::uint8_t ACCT_TERMINATE_HOST_REQUEST = 18;
};
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]
*/
namespace AuthenticationTypes {
constexpr std::uint8_t ACCT_AUTHENTIC_RADIUS = 1;
constexpr std::uint8_t ACCT_AUTHENTIC_LOCAL = 2;
constexpr std::uint8_t ACCT_AUTHENTIC_REMOTE = 3;
};
constexpr std::uint32_t TIP_vendor_id = 58888;
constexpr std::uint8_t TIP_serial = 1;
constexpr std::uint8_t TIP_AAAipaddr = 2;
constexpr std::uint8_t TIP_AAAipv6addr = 3;
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[] = {
{Access_Request, "Access-Request"},
{Access_Accept, "Access-Accept"},
{Access_Reject, "Access-Reject"},
{Accounting_Request, "Accounting-Request"},
{Accounting_Response, "Accounting-Response"},
{Access_Challenge, "Access-Challenge"},
{Status_Server, "Status-Server"},
{Status_Client, "Status-Client"},
{Disconnect_Request, "Disconnect-Request"},
{Disconnect_ACK, "Disconnect-ACK"},
{Disconnect_NAK, "Disconnect-NAK"},
{CoA_Request, "CoA-Request"},
{CoA_ACK, "CoA-ACK"},
{CoA_NAK, "CoA-NAK"},
{Reserved_Cmd, "Reserved"},
{Accounting_Status, "Accounting-Status"},
{Password_Request, "Password-Request"},
{Password_Ack, "Password-Ack"},
{Password_Reject, "Password-Reject"},
{Accounting_Message, "Accounting-Message"},
{Resource_Free_Request, "Resource-Free-Request"},
{Resource_Free_Response, "Resource-Free-Response"},
{Resource_Query_Request, "Resource-Query-Request"},
{Resource_Query_Response, "Resource-Query-Response"},
{Alternate_Resource_Reclaim_Request, "Alternate-Resource-Reclaim-Request"},
{0, nullptr}
};
static const struct tok radius_attribute_names[] = {
{ Attributes::AUTH_USERNAME, "User-Name"},
{ Attributes::USER_PASSWORD, "User-Password"},
{ Attributes::CHAP_PASSWORD, "CHAP-Password"},
{ Attributes::NAS_IP, "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"},
{ Attributes::CALLED_STATION_ID, "Called-Station-Id"},
{ Attributes::CALLING_STATION_ID, "Calling-Station-Id"},
{ Attributes::NAS_IDENTIFIER, "NAS-Identifier"},
{ Attributes::PROXY_STATE, "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"},
{ Attributes::ACCT_STATUS_TYPE, "Acct-Status-Type"},
{41, "Acct-Delay-Time"},
{ Attributes::ACCT_INPUT_OCTETS, "Acct-Input-Octets"},
{ Attributes::ACCT_OUTPUT_OCTETS, "Acct-Output-Octets"},
{ Attributes::ACCT_SESSION_ID, "Acct-Session-Id"},
{ Attributes::ACCT_AUTHENTIC, "Acct-Authentic"},
{ Attributes::ACCT_SESSION_TIME, "Acct-Session-Time"},
{ Attributes::ACCT_INPUT_PACKETS, "Acct-Input-Packets"},
{ Attributes::ACCT_OUTPUT_PACKETS, "Acct-Output-Packets"},
{ Attributes::ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause"},
{ Attributes::ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id"},
{51, "Acct-Link-Count"},
{ Attributes::ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords"},
{ Attributes::ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords"},
{ Attributes::EVENT_TIMESTAMP, "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"},
{ Attributes::MESSAGE_AUTHENTICATOR, "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"},
{ Attributes::CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity"},
{90, "Tunnel-Client-Auth-ID"},
{91, "Tunnel-Server-Auth-ID"},
{0, nullptr}
};
*/
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}};
constexpr std::uint32_t AttributeOffset = 20;
#pragma pack(push, 1)
struct RadiusAttribute {
@@ -272,25 +250,6 @@ namespace OpenWifi::RADIUS {
};
#pragma pack(pop)
constexpr unsigned char Access_Request = 1;
constexpr unsigned char Access_Accept = 2;
constexpr unsigned char Access_Reject = 3;
constexpr unsigned char Access_Challenge = 11;
constexpr unsigned char Accounting_Request = 4;
constexpr unsigned char Accounting_Response = 5;
constexpr unsigned char Accounting_Status = 6;
constexpr unsigned char Accounting_Message = 10;
constexpr unsigned char Disconnect_Request = 40;
constexpr unsigned char Disconnect_ACK = 41;
constexpr unsigned char Disconnect_NAK = 42;
constexpr unsigned char CoA_Request = 43;
constexpr unsigned char CoA_ACK = 44;
constexpr unsigned char CoA_NAK = 45;
constexpr unsigned char ATTR_MessageAuthenticator = 80;
inline bool IsAuthentication(unsigned char t) {
return (t == RADIUS::Access_Request || t == RADIUS::Access_Accept ||
t == RADIUS::Access_Challenge || t == RADIUS::Access_Reject);
@@ -333,10 +292,6 @@ namespace OpenWifi::RADIUS {
//
// 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>;
@@ -384,7 +339,7 @@ namespace OpenWifi::RADIUS {
}
memcpy((void *)&P_, Buf.begin(), Buf.size());
Size_ = Buf.size();
Valid_ = (Size_ == htons(P_.rawlen));
Valid_ = (Size_ == ntohs(P_.rawlen));
if (Valid_)
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
}
@@ -396,7 +351,7 @@ namespace OpenWifi::RADIUS {
}
memcpy((void *)&P_, buffer, size);
Size_ = size;
Valid_ = (Size_ == htons(P_.rawlen));
Valid_ = (Size_ == ntohs(P_.rawlen));
if (Valid_)
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
}
@@ -408,19 +363,35 @@ namespace OpenWifi::RADIUS {
}
memcpy((void *)&P_, (const unsigned char *)p.c_str(), p.size());
Size_ = p.size();
Valid_ = (Size_ == htons(P_.rawlen));
Valid_ = (Size_ == ntohs(P_.rawlen));
if (Valid_)
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
}
explicit RadiusPacket(const RadiusPacket &P) {
RadiusPacket(const RadiusPacket &P) {
Valid_ = P.Valid_;
Size_ = P.Size_;
P_ = P.P_;
Attrs_ = P.Attrs_;
}
explicit RadiusPacket() = default;
void ReParse() {
P_.rawlen = htons(Size_);
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
}
inline RadiusPacket& operator=(const RadiusPacket& other) {
Valid_ = other.Valid_;
Size_ = other.Size_;
P_ = other.P_;
Attrs_ = other.Attrs_;
return *this;
}
explicit RadiusPacket() :
P_{0}, Size_(AttributeOffset)
{
};
unsigned char *Buffer() { return (unsigned char *)&P_; }
[[nodiscard]] uint16_t BufferLen() const { return sizeof(P_); }
@@ -430,7 +401,7 @@ namespace OpenWifi::RADIUS {
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
}
[[nodiscard]] uint16_t Len() const { return htons(P_.rawlen); }
[[nodiscard]] uint16_t Len() const { return ntohs(P_.rawlen); }
[[nodiscard]] uint16_t Size() const { return Size_; }
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
@@ -438,9 +409,9 @@ namespace OpenWifi::RADIUS {
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);
P_.code == RADIUS::Resource_Free_Request || P_.code == RADIUS::Resource_Free_Response ||
P_.code == RADIUS::Resource_Query_Request || P_.code == RADIUS::Resource_Query_Response ||
P_.code == RADIUS::Alternate_Resource_Reclaim_Request);
}
inline bool IsAccounting() {
@@ -475,7 +446,8 @@ namespace OpenWifi::RADIUS {
inline const char *PacketType() { return CommandName(P_.code); }
inline int PacketTypeInt() { return (int)(P_.code); }
inline std::uint8_t PacketTypeInt() { return P_.code; }
inline void PacketType(std::uint8_t T) { P_.code = T; }
void ComputeMessageAuthenticator(const std::string &secret) {
RawRadiusPacket P = P_;
@@ -498,9 +470,9 @@ namespace OpenWifi::RADIUS {
NewAuthenticator[p++] = i;
if (memcmp(OldAuthenticator, NewAuthenticator, 16) == 0) {
std::cout << "Authenticator match..." << std::endl;
// std::cout << "Authenticator match..." << std::endl;
} else {
std::cout << "Authenticator MIS-match..." << std::endl;
// std::cout << "Authenticator MIS-match..." << std::endl;
for (const auto &attr : Attrs_) {
if (attr.type == 80) {
memcpy(&P_.attributes[attr.pos], NewAuthenticator, 16);
@@ -510,6 +482,21 @@ namespace OpenWifi::RADIUS {
}
}
inline std::uint8_t Identifier(std::uint8_t id) { P_.identifier = id; return id; }
inline std::uint8_t Identifier() const { return P_.identifier; }
void RecomputeAuthenticator(const std::string &secret) {
memset(P_.authenticator,0,sizeof(P_.authenticator));
Poco::MD5Engine md5;
P_.rawlen = htons(Size_);
md5.update((const unsigned char *)&P_, Size_);
md5.update(secret.c_str(), secret.size());
auto digest = md5.digest();
int p = 0;
for (const auto &i : digest)
P_.authenticator[p++] = i;
}
bool VerifyMessageAuthenticator(const std::string &secret) {
RawRadiusPacket P = P_;
if (P_.code == 1) {
@@ -548,6 +535,36 @@ namespace OpenWifi::RADIUS {
os << std::dec;
}
void PrintAccount_StatusType(std::ostream &os, const std::string &spaces, const unsigned char *buf, std::uint8_t len) {
os << spaces ;
if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_START)
os << "Start" << std::endl;
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_STOP)
os << "Stop" << std::endl;
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_INTERIM_UPDATE)
os << "Interim-Update" << std::endl;
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_ACCOUNTING_ON)
os << "Accounting-On" << std::endl;
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_ACCOUNTING_OFF)
os << "Accounting-Off" << std::endl;
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_FAILED)
os << "Failed" << std::endl;
else
BufLog(os,"",buf,len);
}
void PrintAccount_AcctAuthentic(std::ostream &os, const std::string &spaces, const unsigned char *buf, std::uint8_t len) {
os << spaces ;
if (buf[3]==AuthenticationTypes::ACCT_AUTHENTIC_RADIUS)
os << "RADIUS" << std::endl;
else if (buf[3]==AuthenticationTypes::ACCT_AUTHENTIC_LOCAL)
os << "Local" << std::endl;
else if (buf[3]==AuthenticationTypes::ACCT_AUTHENTIC_REMOTE)
os << "Remote" << std::endl;
else
BufLog(os,"",buf,len);
}
inline void Print(std::ostream &os) {
os << "Packet type: (" << (uint)P_.code << ") " << CommandName(P_.code) << std::endl;
os << " Identifier: " << (uint)P_.identifier << std::endl;
@@ -558,7 +575,13 @@ namespace OpenWifi::RADIUS {
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);
std::string attr_offset = " ";
switch(attr.type) {
case Attributes::ACCT_STATUS_TYPE: PrintAccount_StatusType(os, attr_offset, &P_.attributes[attr.pos], attr.len); break;
case Attributes::ACCT_AUTHENTIC: PrintAccount_AcctAuthentic(os, attr_offset, &P_.attributes[attr.pos], attr.len); break;
default:
BufLog(os, attr_offset.c_str(), &P_.attributes[attr.pos], attr.len);
}
}
os << std::dec << std::endl << std::endl;
}
@@ -592,10 +615,10 @@ namespace OpenWifi::RADIUS {
return R;
}
std::string ExtractSerialNumberFromProxyState() {
std::string ExtractSerialNumberFromProxyState() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == 33) {
if (attribute.type == RADIUS::Attributes::PROXY_STATE) {
std::string Attr33;
// format is serial:IP:port:interface
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
@@ -614,12 +637,13 @@ namespace OpenWifi::RADIUS {
return Result;
}
std::string ExtractProxyStateDestination() {
std::string ExtractProxyStateDestination() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == 33 && attribute.len > 2) {
if (attribute.type == RADIUS::Attributes::PROXY_STATE && attribute.len > 2) {
std::string Attr33;
// format is serial:IP:port:interface
// format is
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
auto Parts = Poco::StringTokenizer(Attr33, "|");
@@ -638,10 +662,10 @@ namespace OpenWifi::RADIUS {
return Result;
}
std::string ExtractCallingStationID() {
std::string ExtractCallingStationID() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == 31 && attribute.len > 2) {
if (attribute.type == RADIUS::Attributes::CALLING_STATION_ID && attribute.len > 2) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
return Result;
@@ -650,10 +674,22 @@ namespace OpenWifi::RADIUS {
return Result;
}
std::string ExtractCalledStationID() {
std::string ExtractAccountingSessionID() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == 30 && attribute.len > 2) {
if (attribute.type == RADIUS::Attributes::ACCT_SESSION_ID && attribute.len > 2) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
return Result;
}
}
return Result;
}
std::string ExtractCalledStationID() const {
std::string Result;
for (const auto &attribute : Attrs_) {
if (attribute.type == RADIUS::Attributes::CALLED_STATION_ID && attribute.len > 2) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
attribute.len - 2);
return Result;
@@ -664,7 +700,7 @@ namespace OpenWifi::RADIUS {
[[nodiscard]] std::string UserName() const {
for (const auto &attr : Attrs_) {
if (attr.type == 1) {
if (attr.type == RADIUS::Attributes::AUTH_USERNAME) {
std::string user_name{(const char *)&P_.attributes[attr.pos], attr.len};
return user_name;
}
@@ -672,10 +708,240 @@ namespace OpenWifi::RADIUS {
return "";
}
private:
void ReplaceAttribute(std::uint8_t attribute, std::uint8_t value) {
for (const auto &attr : Attrs_) {
if(attr.type==attribute) {
P_.attributes[attr.pos] = value;
return;
}
}
}
void ReplaceAttribute(std::uint8_t attribute, std::uint16_t value) {
for (const auto &attr : Attrs_) {
if(attr.type==attribute) {
P_.attributes[attr.pos+0] = value >> 8;
P_.attributes[attr.pos+1] = value & 0x00ff;
return;
}
}
}
void ReplaceAttribute(std::uint8_t attribute, std::uint32_t value) {
for (const auto &attr : Attrs_) {
if(attr.type==attribute) {
P_.attributes[attr.pos+0] = (std::uint8_t ) ((value & 0xff000000) >> 24);
P_.attributes[attr.pos+1] = (std::uint8_t ) ((value & 0x00ff0000) >> 16);
P_.attributes[attr.pos+2] = (std::uint8_t ) ((value & 0x0000ff00) >> 8);
P_.attributes[attr.pos+3] = (std::uint8_t ) ((value & 0x000000ff) >> 0);
return;
}
}
}
void ReplaceAttribute(std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
for (const auto &attr : Attrs_) {
if(attr.type==attribute) {
if(attr.len==attribute_len) {
memcpy(&P_.attributes[attr.pos], attribute_value, attribute_len);
} else if(attribute_len<attr.len){
memcpy(&P_.attributes[attr.pos], attribute_value, attribute_len);
P_.attributes[attr.pos-1] = attribute_len + 2;
auto Shrink = attr.len - attribute_len;
memmove(&P_.attributes[attr.pos+attribute_len], &P_.attributes[attr.pos+attr.len], Size_ - Shrink);
Size_ -= Shrink;
ReParse();
} else {
auto Augment = (attribute_len - attr.len);
memmove(&P_.attributes[attr.pos+attribute_len], &P_.attributes[attr.pos+attr.len], Size_ + Augment);
memcpy(&P_.attributes[attr.pos], attribute_value, attribute_len);
P_.attributes[attr.pos-1] = attribute_len+2;
Size_ += Augment;
ReParse();
}
return;
}
}
}
void ReplaceAttribute(std::uint8_t attribute, const std::string &attribute_value) {
ReplaceAttribute(attribute,attribute_value.c_str(),attribute_value.size());
}
void RemoveAttribute(std::uint8_t attribute) {
for (const auto &attr : Attrs_) {
if(attr.type==attribute) {
auto Shrink = attr.len+2;
memmove(&P_.attributes[attr.pos-2], &P_.attributes[attr.pos+attr.len], Size_ - Shrink);
Size_ -= Shrink;
ReParse();
return;
}
}
}
void AppendAttribute(std::uint8_t attribute, std::uint8_t value) {
if(Size_<AttributeOffset) Size_ = AttributeOffset;
auto Pos = Size_ - AttributeOffset;
P_.attributes[Pos+0] = attribute;
P_.attributes[Pos+1] = 1+2;
P_.attributes[Pos+2] = value;
Size_+= 3;
ReParse();
}
void AppendAttribute(std::uint8_t attribute, std::uint16_t value) {
if(Size_<AttributeOffset) Size_ = AttributeOffset;
auto Pos = Size_ - AttributeOffset;
P_.attributes[Pos+0] = attribute;
P_.attributes[Pos+1] = 2+2;
P_.attributes[Pos+2] = (value & 0xff00) >> 8;
P_.attributes[Pos+3] = (value & 0x00ff) >> 0;
Size_+= 4;
ReParse();
}
void AppendAttribute(std::uint8_t attribute, std::uint32_t value) {
if(Size_<AttributeOffset) Size_ = AttributeOffset;
auto Pos = Size_ - AttributeOffset;
P_.attributes[Pos+0] = attribute;
P_.attributes[Pos+1] = 4+2;
P_.attributes[Pos+2] = (value & 0xff000000) >> 24;
P_.attributes[Pos+3] = (value & 0x00ff0000) >> 16;
P_.attributes[Pos+4] = (value & 0x0000ff00) >> 8;
P_.attributes[Pos+5] = (value & 0x000000ff) >> 0;
Size_+= 6;
ReParse();
}
void AppendAttribute(std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
if(Size_<AttributeOffset) Size_ = AttributeOffset;
auto Pos = Size_ - AttributeOffset;
P_.attributes[Pos+0] = attribute;
P_.attributes[Pos+1] = attribute_len+2;
memcpy(&P_.attributes[Pos+2],attribute_value,attribute_len);
Size_+= 2 + attribute_len;
ReParse();
}
void AppendAttribute(std::uint8_t attribute, const std::string &attribute_value) {
AppendAttribute(attribute, attribute_value.c_str(), attribute_value.size());
}
void AddAttribute(std::uint8_t location, std::uint8_t attribute, std::uint8_t value) {
for (const auto &attr : Attrs_) {
if(attr.type==location) {
int Augment = 1;
memmove(&P_.attributes[attr.pos+attr.len+1+1+Augment], &P_.attributes[attr.pos+attr.len], Size_-(attr.pos+attr.len));
P_.attributes[attr.pos+attr.len+0] = attribute;
P_.attributes[attr.pos+attr.len+1] = Augment+2;
P_.attributes[attr.pos+attr.len+2] = value;
Size_+=2+Augment;
ReParse();
return;
}
}
}
void AddAttribute(std::uint8_t location, std::uint8_t attribute, std::uint16_t value) {
for (const auto &attr : Attrs_) {
if(attr.type==location) {
int Augment = 2;
memmove(&P_.attributes[attr.pos+attr.len+1+1+Augment], &P_.attributes[attr.pos+attr.len], Size_-(attr.pos+attr.len));
P_.attributes[attr.pos+attr.len+0] = attribute;
P_.attributes[attr.pos+attr.len+1] = Augment+2;
P_.attributes[attr.pos+attr.len+2] = (value & 0xff00) >> 8;
P_.attributes[attr.pos+attr.len+3] = (value & 0x00ff) >> 0;
Size_+=2+Augment;
ReParse();
return;
}
}
}
void AddAttribute(std::uint8_t location, std::uint8_t attribute, std::uint32_t value) {
for (const auto &attr: Attrs_) {
if (attr.type == location) {
int Augment = 4;
memmove(&P_.attributes[attr.pos + attr.len + 1 + 1 + Augment], &P_.attributes[attr.pos + attr.len],
Size_ - (attr.pos + attr.len));
P_.attributes[attr.pos + attr.len + 0] = attribute;
P_.attributes[attr.pos + attr.len + 1] = Augment+2;
P_.attributes[attr.pos + attr.len + 2] = (value & 0xff000000) >> 24;
P_.attributes[attr.pos + attr.len + 3] = (value & 0x00ff0000) >> 16;
P_.attributes[attr.pos + attr.len + 4] = (value & 0x0000ff00) >> 8;
P_.attributes[attr.pos + attr.len + 5] = (value & 0x000000ff) >> 0;
Size_ += 2 + Augment;
ReParse();
return;
}
}
}
void AddAttribute(std::uint8_t location, std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
for (const auto &attr: Attrs_) {
if (attr.type == location) {
int Augment = attribute_len;
memmove(&P_.attributes[attr.pos + attr.len + 1 + 1 + Augment], &P_.attributes[attr.pos + attr.len],
Size_ - (attr.pos + attr.len));
P_.attributes[attr.pos + attr.len + 0] = attribute;
P_.attributes[attr.pos + attr.len + 1] = Augment+2;
memcpy(&P_.attributes[attr.pos + attr.len + 2], attribute_value, attribute_len);
Size_ += 2 + Augment;
ReParse();
return;
}
}
}
void AddAttribute(std::uint8_t location, std::uint8_t attribute, const std::string &attribute_value) {
AddAttribute(location, attribute, attribute_value.c_str(), attribute_value.size());
}
bool HasAttribute(std::uint8_t attribute) const {
return std::any_of(Attrs_.begin(),Attrs_.end(),[attribute](const RadiusAttribute &Attr) { return Attr.type ==attribute; });
}
void ReplaceOrAdd(std::uint8_t attribute, std::uint8_t attribute_value) {
if(HasAttribute(attribute))
ReplaceAttribute(attribute, attribute_value);
else
AppendAttribute(attribute, attribute_value);
}
void ReplaceOrAdd(std::uint8_t attribute, std::uint16_t attribute_value) {
if(HasAttribute(attribute))
ReplaceAttribute(attribute, attribute_value);
else
AppendAttribute(attribute, attribute_value);
}
void ReplaceOrAdd(std::uint8_t attribute, std::uint32_t attribute_value) {
if(HasAttribute(attribute))
ReplaceAttribute(attribute, attribute_value);
else
AppendAttribute(attribute, attribute_value);
}
void ReplaceOrAdd(std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
if(HasAttribute(attribute))
ReplaceAttribute(attribute, attribute_value, attribute_len);
else
AppendAttribute(attribute, attribute_value, attribute_len);
}
void ReplaceOrAdd(std::uint8_t attribute, const std::string & attribute_value) {
if(HasAttribute(attribute))
ReplaceAttribute(attribute, attribute_value.c_str(), attribute_value.size());
else
AppendAttribute(attribute, attribute_value.c_str(), attribute_value.size());
}
AttributeList Attrs_;
RawRadiusPacket P_;
uint16_t Size_{0};
AttributeList Attrs_;
bool Valid_ = false;
};
@@ -684,16 +950,17 @@ namespace OpenWifi::RADIUS {
explicit RadiusOutputPacket(const std::string &Secret) : Secret_(Secret) {}
inline void MakeStatusMessage() {
P_.code = RADCMD_STATUS_SER;
P_.code = RADIUS::Status_Server;
P_.identifier = std::rand() & 0x00ff;
MakeRadiusAuthenticator(P_.authenticator);
unsigned char MessageAuthenticator[16]{0};
AddAttribute(ATTR_MessageAuthenticator, sizeof(MessageAuthenticator),
AddAttribute(RADIUS::Attributes::MESSAGE_AUTHENTICATOR, sizeof(MessageAuthenticator),
MessageAuthenticator);
P_.rawlen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
P_.rawlen = htons(PktLen);
Poco::HMACEngine<Poco::MD5Engine> H(Secret_);
H.update((const unsigned char *)&P_, P_.rawlen);
H.update((const unsigned char *)&P_, PktLen);
auto digest = H.digest();
int p = 0;
for (const auto &i : digest)
@@ -710,7 +977,7 @@ namespace OpenWifi::RADIUS {
[[nodiscard]] inline const unsigned char *Data() const {
return (const unsigned char *)&P_;
}
[[nodiscard]] inline std::uint16_t Len() const { return P_.rawlen; }
[[nodiscard]] inline std::uint16_t Len() const { return ntohs(P_.rawlen); }
private:
RawRadiusPacket P_;

View File

@@ -8,6 +8,7 @@
#include "RADIUS_helpers.h"
#include "RADIUS_proxy_server.h"
#include "RADIUSSessionTracker.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
@@ -17,6 +18,8 @@ namespace OpenWifi {
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799;
int RADIUS_proxy_server::Start() {
ConfigFilename_ = MicroServiceDataDirectory() + "/radius_pool_config.json";
@@ -183,6 +186,7 @@ namespace OpenWifi {
return;
}
P.Evaluate(ReceiveSize);
// P.Log(std::cout);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger(), "Accounting: missing serial number.");
@@ -210,6 +214,7 @@ namespace OpenWifi {
return;
}
P.Evaluate(ReceiveSize);
// P.Log(std::cout);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger(), "Authentication: missing serial number.");
@@ -236,6 +241,8 @@ namespace OpenWifi {
poco_warning(Logger(), "CoA/DM: bad packet received.");
return;
}
// P.Log(std::cout);
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberTIP();
if (SerialNumber.empty()) {
@@ -252,28 +259,23 @@ namespace OpenWifi {
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
}
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
const char *buffer, std::size_t size) {
if (!Continue())
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto Destination = P.ExtractProxyStateDestination();
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string & secret) {
try{
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);
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC, secret);
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);
if(RecomputeAuthenticator) {
P.RecomputeAuthenticator("radsec");
}
DestinationServer->second->SendData(serialNumber, P.Buffer(), P.Size());
}
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
@@ -287,10 +289,15 @@ namespace OpenWifi {
serialNumber));
return;
}
if(RecomputeAuthenticator) {
P.RecomputeAuthenticator(secret);
}
auto AllSent =
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
: *AccountingSocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
: *AccountingSocketV6_
, P.Buffer(), P.Size(), FinalDestination);
if (!AllSent)
poco_error(Logger(),
fmt::format("{}: Could not send Accounting packet packet to {}.",
@@ -309,13 +316,47 @@ namespace OpenWifi {
}
}
void store_packet(const std::string &serialNumber, const char *buffer, std::size_t size) {
static std::uint64_t pkt=0;
std::string filename = MicroServiceDataDirectory() + "/radius." + serialNumber + "." + std::to_string(pkt++) + ".bin";
std::ofstream ofs(filename,std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);
ofs.write(buffer,size);
ofs.close();
}
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
const char *buffer, std::size_t size, std::string & secret) {
if (!Continue())
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
// P.Log(std::cout);
auto Destination = P.ExtractProxyStateDestination();
// store_packet(serialNumber, buffer, size);
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, secret);
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, secret);
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),
fmt::format("Bad RADIUS ACCT Packet from {}. Dropped.", serialNumber));
}
}
bool RADIUS_proxy_server::SendData(Poco::Net::DatagramSocket &Sock, const unsigned char *buf,
std::size_t size, const Poco::Net::SocketAddress &S) {
return Sock.sendTo(buf, size, S) == (int)size;
}
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber,
const char *buffer, std::size_t size) {
const char *buffer, std::size_t size, std::string & secret) {
if (!Continue())
return;
@@ -327,9 +368,14 @@ namespace OpenWifi {
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
// P.Log(std::cout);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC, secret);
RADIUSSessionTracker()->AddAuthenticationSession(Destination, serialNumber, P, secret);
// std::cout << "Authentication secret: " << secret << std::endl;
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
@@ -372,7 +418,7 @@ namespace OpenWifi {
}
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer,
std::size_t size) {
std::size_t size, std::string & secret) {
if (!Continue())
return;
@@ -385,10 +431,13 @@ namespace OpenWifi {
Destination = "0.0.0.0:0";
}
P.Log(std::cout);
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC, secret);
std::cout << "CoA secret: " << secret << std::endl;
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
@@ -449,7 +498,8 @@ namespace OpenWifi {
.methodParameters = Config.methodParameters,
.useAsDefault = setAsDefault,
.useRADSEC = server.radsec,
.realms = server.radsecRealms};
.realms = server.radsecRealms,
.secret = server.secret };
if (setAsDefault && D.useRADSEC)
DefaultIsRADSEC_ = true;
@@ -530,7 +580,8 @@ namespace OpenWifi {
Poco::Net::SocketAddress
RADIUS_proxy_server::DefaultRoute(radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret) {
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
// find the realm...
@@ -545,7 +596,7 @@ namespace OpenWifi {
if (!server.realms.empty()) {
for (const auto &realm : server.realms) {
if (RealmMatch(UserRealm, realm)) {
std::cout << "Realm match..." << std::endl;
// std::cout << "Realm match..." << std::endl;
UseRADSEC = true;
return server.Addr;
}
@@ -565,18 +616,18 @@ namespace OpenWifi {
case radius_type::auth: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AuthV4
: Pools_[DefaultPoolIndex_].AuthV6,
RequestedAddress);
RequestedAddress, Secret);
}
case radius_type::acct:
default: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AcctV4
: Pools_[DefaultPoolIndex_].AcctV6,
RequestedAddress);
RequestedAddress, Secret);
}
case radius_type::coa: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
: Pools_[DefaultPoolIndex_].CoaV6,
RequestedAddress);
RequestedAddress, Secret);
}
}
}
@@ -584,7 +635,8 @@ namespace OpenWifi {
Poco::Net::SocketAddress
RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret) {
std::lock_guard G(Mutex_);
if (Pools_.empty()) {
@@ -600,7 +652,7 @@ namespace OpenWifi {
Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6);
if (useDefault) {
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC, Secret);
}
auto isAddressInPool = [&](const std::vector<Destination> &D, bool &UseRADSEC) -> bool {
@@ -616,17 +668,17 @@ namespace OpenWifi {
switch (rtype) {
case radius_type::coa: {
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress, Secret);
}
} break;
case radius_type::auth: {
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress, Secret);
}
} break;
case radius_type::acct: {
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress, Secret);
}
} break;
}
@@ -638,9 +690,11 @@ namespace OpenWifi {
Poco::Net::SocketAddress
RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool,
const Poco::Net::SocketAddress &OriginalAddress) {
const Poco::Net::SocketAddress &OriginalAddress,
std::string &Secret) {
if (Pool.size() == 1) {
Secret = Pool[0].secret;
return Pool[0].Addr;
}
@@ -657,6 +711,7 @@ namespace OpenWifi {
index = pos;
cur_state = i.state;
found = true;
Secret = i.secret ;
}
pos++;
}
@@ -664,9 +719,9 @@ namespace OpenWifi {
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();
@@ -679,6 +734,7 @@ namespace OpenWifi {
if (i.state < cur_state) {
index = pos;
cur_state = i.state;
Secret = i.secret;
found = true;
}
pos++;
@@ -692,7 +748,9 @@ namespace OpenWifi {
return Pool[index].Addr;
} else if (Pool[0].strategy == "random") {
if (Pool.size() > 1) {
return Pool[std::rand() % Pool.size()].Addr;
auto index = std::rand() % Pool.size();
Secret = Pool[index].secret;
return Pool[index].Addr;
} else {
return OriginalAddress;
}

View File

@@ -34,10 +34,12 @@ namespace OpenWifi {
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void SendAccountingData(const std::string &serialNumber, const char *buffer,
std::size_t size);
std::size_t size, std::string & secret);
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);
std::size_t size, std::string & secret);
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size, std::string & secret);
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string & secret);
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
void DeleteConfig();
@@ -59,6 +61,7 @@ namespace OpenWifi {
bool useAsDefault = false;
bool useRADSEC = false;
std::vector<std::string> realms;
std::string secret;
};
inline bool Continue() const { return Running_ && Enabled_ && !Pools_.empty(); }
@@ -102,16 +105,17 @@ namespace OpenWifi {
void ParseConfig();
void ResetConfig();
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
const RADIUS::RadiusPacket &P, bool &UseRADSEC);
const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
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);
const Poco::Net::SocketAddress &OriginalAddress, std::string &Secret);
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC);
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret);
};
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }

View File

@@ -171,7 +171,7 @@ namespace OpenWifi::RESTAPI_RPC {
// we need to post a kafka event for this.
if (Params.has(uCentralProtocol::CONFIG)) {
DeviceConfigurationChangeKafkaEvent KEvent(
Cmd.SerialNumber, Utils::Now(),
Utils::SerialNumberToInt(Cmd.SerialNumber), Utils::Now(),
Params.get(uCentralProtocol::CONFIG).toString());
}
}

View File

@@ -309,7 +309,7 @@ namespace OpenWifi {
if (AP_WS_Server()->GetState(SerialNumber_, State)) {
Poco::JSON::Object RetObject;
State.to_json(RetObject);
State.to_json(SerialNumber_, RetObject);
return ReturnObject(RetObject);
} else {
Poco::JSON::Object RetObject;
@@ -406,6 +406,7 @@ namespace OpenWifi {
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("PING({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
TransactionId_, Requester(), SerialNumber_));
const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER)) {
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
@@ -459,6 +460,14 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
bool RESTAPI_device_commandHandler::IsDeviceSimulated(std::string &Serial) {
GWObjects::Device Device;
if(StorageService()->GetDevice(Serial,Device)) {
return Device.simulated;
}
return false;
}
void RESTAPI_device_commandHandler::CallCanceled(const char *Cmd, const std::string &UUID,
uint64_t RPC,
const OpenWifi::RESTAPI::Errors::msg &Err) {
@@ -474,6 +483,10 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("SCRIPT({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
GWObjects::ScriptRequest SCR;
if (!SCR.from_json(Obj)) {
@@ -899,6 +912,10 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("TRACE({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) &&
@@ -956,6 +973,12 @@ namespace OpenWifi {
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("WIFISCAN({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
@@ -1001,7 +1024,7 @@ namespace OpenWifi {
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::wifiscan, false, Cmd, Params,
*Request, *Response, timeout, nullptr, this, Logger_);
if (Cmd.ErrorCode == 0) {
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, Cmd.Results);
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, std::make_shared<std::string>(Cmd.Results));
}
}
@@ -1011,6 +1034,10 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("EVENT-QUEUE({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->isArray(RESTAPI::Protocol::TYPES)) {
@@ -1042,7 +1069,7 @@ namespace OpenWifi {
Logger_);
if (Cmd.ErrorCode == 0) {
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
Cmd.Results);
std::make_shared<std::string>(Cmd.Results));
}
return;
}
@@ -1055,6 +1082,10 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("FORCE-REQUEST({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(uCentralProtocol::MESSAGE)) {
@@ -1104,6 +1135,10 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("RTTY({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
if (!Restrictions.developer && Restrictions.rtty) {
return BadRequest(RESTAPI::Errors::DeviceIsRestricted);
}
@@ -1112,6 +1147,11 @@ namespace OpenWifi {
GWObjects::Device Device;
if (StorageService()->GetDevice(SerialNumber_, Device)) {
if(Device.simulated) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
static std::uint64_t rtty_sid = 0;
rtty_sid += std::rand();
GWObjects::RttySessionDetails Rtty{
@@ -1185,6 +1225,10 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("TELEMETRY({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(RESTAPI::Protocol::INTERVAL) &&

View File

@@ -34,6 +34,8 @@ namespace OpenWifi {
void GetChecks();
void DeleteChecks();
bool IsDeviceSimulated(std::string &Serial);
void Configure(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void Upgrade(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,

View File

@@ -41,6 +41,10 @@ namespace OpenWifi {
void RESTAPI_device_handler::DoDelete() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!RESTAPI_utils::IsRootOrAdmin(UserInfo_.userinfo)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if (!Utils::NormalizeMac(SerialNumber)) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}

View File

@@ -23,7 +23,7 @@ namespace OpenWifi {
Device.to_json(DeviceInfo);
Answer.set("deviceInfo", DeviceInfo);
Poco::JSON::Object CSInfo;
CS.to_json(CSInfo);
CS.to_json(Device.SerialNumber, CSInfo);
Answer.set("connectionInfo", CSInfo);
Poco::JSON::Object HCInfo;
HC.to_json(HCInfo);

View File

@@ -158,4 +158,54 @@ namespace OpenWifi {
}
ReturnObject(RetObj);
}
static bool ValidMacPatternOnlyChars(const std::string &s) {
return std::for_each(s.begin(),s.end(),[](const char c) {
if(c=='%') return true;
if(c>='0' && c<='9') return true;
if(c>='a' && c<='f') return true;
return false;
});
}
void RESTAPI_devices_handler::DoDelete() {
if(!RESTAPI_utils::IsRootOrAdmin(UserInfo_.userinfo)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if(!QB_.Select.empty()) {
for(auto &serialNumber:QB_.Select) {
StorageService()->DeleteDevice(serialNumber);
}
return OK();
}
auto SimulatedOnly = GetBoolParameter("simulatedOnly",false);
auto oldestContact = GetParameter("oldestContact",0);
if(oldestContact!=0) {
StorageService()->DeleteDevices(oldestContact,SimulatedOnly);
return OK();
}
auto macPattern = GetParameter("macPattern","");
if(macPattern.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
// rules out wrong values.
Poco::toLowerInPlace(macPattern);
Poco::replaceInPlace(macPattern,"*","%");
if(!ValidMacPatternOnlyChars(macPattern)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
StorageService()->DeleteDevices(macPattern, SimulatedOnly);
return OK();
}
} // namespace OpenWifi

View File

@@ -18,11 +18,12 @@ namespace OpenWifi {
bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal){};
static auto PathName() { return std::list<std::string>{"/api/v1/devices"}; };
void DoGet() final;
void DoDelete() final{};
void DoDelete() final;
void DoPost() final{};
void DoPut() final{};
};

View File

@@ -0,0 +1,129 @@
//
// Created by stephane bourque on 2023-04-02.
//
#include "RESTAPI_radiussessions_handler.h"
#include <RESTObjects/RESTAPI_GWobjects.h>
#include <RADIUSSessionTracker.h>
namespace OpenWifi {
bool MayBeAMAC(const std::string &mac) {
return std::all_of(mac.begin(),mac.end(),[](char c)->bool {
if ((c>='0' && c<='9') ||
(c>='a' && c<='f') ||
(c>='A' && c<='F') ||
(c==':') ||
(c=='-') ||
(c=='*')) return true;
return false;
});
}
std::string InsertDelimiters(const std::string &mac, int first=1, char delimiter=':') {
std::string res;
std::size_t index=0;
for(auto c:mac) {
res += c;
index++;
if(index<mac.size()) {
if (!first)
res += delimiter;
}
first = 1-first;
}
return res;
}
std::string StripDelimiters(const std::string &V) {
std::string Res;
std::for_each(V.begin(),V.end(),[&](char c){ if(c!=':' && c!='-') { Res += c; }});
return Res;
}
static std::string ConvertToMac(const std::string & V) {
auto res = V;
Poco::toUpperInPlace(res);
res = StripDelimiters(res);
if(res.size()==12) {
res = InsertDelimiters(res);
} else {
if(res.find_first_of('*')==std::string::npos) {
return "";
}
if(res[0]=='*') {
res = InsertDelimiters(res, 1 - (res.size() % 2) );
} else {
res = InsertDelimiters(res);
}
}
return res;
}
void RESTAPI_radiussessions_handler::DoGet() {
if(GetBoolParameter("serialNumberOnly")) {
std::vector<std::string> L;
RADIUSSessionTracker()->GetAPList(L);
return ReturnObject("serialNumbers",L);
}
auto mac = GetParameter("mac","");
auto userName = GetParameter("userName","");
if(!userName.empty()) {
GWObjects::RADIUSSessionList L;
Poco::toLowerInPlace(userName);
RADIUSSessionTracker()->GetUserNameAPSessions(userName,L);
if(L.sessions.empty() && MayBeAMAC(userName)) {
mac = ConvertToMac(userName);
} else {
return ReturnObject("sessions", L.sessions);
}
}
if(!mac.empty()) {
Poco::toUpperInPlace(mac);
Poco::replaceInPlace(mac,":","-");
GWObjects::RADIUSSessionList L;
RADIUSSessionTracker()->GetMACAPSessions(mac,L);
return ReturnObject("sessions",L.sessions);
}
auto SerialNumber = GetBinding("serialNumber","");
if(SerialNumber.empty() || !Utils::ValidSerialNumber(SerialNumber)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::RADIUSSessionList L;
RADIUSSessionTracker()->GetAPSessions(SerialNumber,L);
return ReturnObject("sessions",L.sessions);
}
void RESTAPI_radiussessions_handler::DoPut() {
auto SerialNumber = GetBinding("serialNumber","");
if(SerialNumber.empty() || !Utils::ValidSerialNumber(SerialNumber)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::RadiusCoADMParameters Parameters;
if(!Parameters.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(Parameters.callingStationId.empty() || Parameters.accountingSessionId.empty() || Parameters.accountingMultiSessionId.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto Command = GetParameter("operation","");
if(Command=="coadm") {
if(RADIUSSessionTracker()->SendCoADM(SerialNumber, Parameters.accountingSessionId)) {
return OK();
}
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
}
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
} // namespace OpenWifi

View File

@@ -0,0 +1,28 @@
//
// Created by stephane bourque on 2023-04-02.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
class RESTAPI_radiussessions_handler : public RESTAPIHandler {
public:
RESTAPI_radiussessions_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal){};
static auto PathName() { return std::list<std::string>{"/api/v1/radiusSessions/{serialNumber}"}; };
void DoGet() final;
void DoDelete() final{};
void DoPost() final{};
void DoPut();
};
} // namespace OpenWifi

View File

@@ -21,6 +21,7 @@
#include "RESTAPI/RESTAPI_script_handler.h"
#include "RESTAPI/RESTAPI_scripts_handler.h"
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
#include "RESTAPI/RESTAPI_radiussessions_handler.h"
#include "framework/RESTAPI_SystemCommand.h"
#include "framework/RESTAPI_SystemConfiguration.h"
@@ -39,7 +40,7 @@ namespace OpenWifi {
RESTAPI_system_configuration, RESTAPI_deviceDashboardHandler, RESTAPI_webSocketServer,
RESTAPI_blacklist, RESTAPI_blacklist_list, RESTAPI_iptocountry_handler,
RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler, RESTAPI_script_handler,
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket,
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket, RESTAPI_radiussessions_handler,
RESTAPI_regulatory>(Path, Bindings, L, S,
TransactionId);
}
@@ -53,7 +54,7 @@ namespace OpenWifi {
RESTAPI_default_configurations, RESTAPI_default_configuration, RESTAPI_command,
RESTAPI_commands, RESTAPI_ouis, RESTAPI_file, RESTAPI_blacklist,
RESTAPI_iptocountry_handler, RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler,
RESTAPI_script_handler, RESTAPI_blacklist_list,
RESTAPI_script_handler, RESTAPI_blacklist_list, RESTAPI_radiussessions_handler,
RESTAPI_regulatory>(Path, Bindings, L, S, TransactionId);
}
} // namespace OpenWifi

View File

@@ -13,6 +13,7 @@
#ifdef TIP_GATEWAY_SERVICE
#include "AP_WS_Server.h"
#include "CapabilitiesCache.h"
#include "RADIUSSessionTracker.h"
#endif
#include "RESTAPI_GWobjects.h"
@@ -29,6 +30,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "serialNumber", SerialNumber);
#ifdef TIP_GATEWAY_SERVICE
field_to_json(Obj, "deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible));
field_to_json(Obj, "hasRADIUSSessions", RADIUSSessionTracker()->HasSessions(SerialNumber));
#endif
field_to_json(Obj, "macAddress", MACAddress);
field_to_json(Obj, "manufacturer", Manufacturer);
@@ -55,6 +57,8 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd);
field_to_json(Obj, "restrictionDetails", restrictionDetails);
field_to_json(Obj, "pendingUUID", pendingUUID);
field_to_json(Obj, "simulated", simulated);
field_to_json(Obj, "lastRecordedContact", lastRecordedContact);
}
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
@@ -64,7 +68,7 @@ namespace OpenWifi::GWObjects {
ConnectionState ConState;
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
ConState.to_json(Obj);
ConState.to_json(SerialNumber,Obj);
} else {
field_to_json(Obj, "ipAddress", "");
field_to_json(Obj, "txBytes", (uint64_t)0);
@@ -76,6 +80,13 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "associations_2G", (uint64_t)0);
field_to_json(Obj, "associations_5G", (uint64_t)0);
field_to_json(Obj, "associations_6G", (uint64_t)0);
field_to_json(Obj, "hasRADIUSSessions", false);
field_to_json(Obj, "hasGPS", ConState.hasGPS);
field_to_json(Obj, "sanity", ConState.sanity);
field_to_json(Obj, "memoryUsed", ConState.memoryUsed);
field_to_json(Obj, "sanity", ConState.sanity);
field_to_json(Obj, "load", ConState.load);
field_to_json(Obj, "temperature", ConState.temperature);
}
#endif
}
@@ -109,6 +120,8 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd);
field_from_json(Obj, "restrictionDetails", restrictionDetails);
field_from_json(Obj, "pendingUUID", pendingUUID);
field_from_json(Obj, "simulated", simulated);
field_from_json(Obj, "lastRecordedContact", lastRecordedContact);
return true;
} catch (const Poco::Exception &E) {
}
@@ -211,7 +224,7 @@ namespace OpenWifi::GWObjects {
return false;
}
void ConnectionState::to_json(Poco::JSON::Object &Obj) const {
void ConnectionState::to_json([[maybe_unused]] const std::string &SerialNumber, Poco::JSON::Object &Obj) {
field_to_json(Obj, "ipAddress", Address);
field_to_json(Obj, "txBytes", TX);
field_to_json(Obj, "rxBytes", RX);
@@ -233,6 +246,22 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_to_json(Obj, "connectReason", connectReason);
#ifdef TIP_GATEWAY_SERVICE
hasRADIUSSessions = RADIUSSessionTracker()->HasSessions(SerialNumber);
AP_WS_Server()->ExtendedAttributes(SerialNumber, hasGPS, sanity,
memoryUsed,
load,
temperature);
#endif
field_to_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
field_to_json(Obj, "hasGPS", hasGPS);
field_to_json(Obj, "sanity", sanity);
field_to_json(Obj, "memoryUsed", memoryUsed);
field_to_json(Obj, "sanity", sanity);
field_to_json(Obj, "load", load);
field_to_json(Obj, "temperature", temperature);
switch (VerifiedCertificate) {
case NO_CERTIFICATE:
@@ -247,6 +276,9 @@ namespace OpenWifi::GWObjects {
case VERIFIED:
field_to_json(Obj, "verifiedCertificate", "VERIFIED");
break;
case SIMULATED:
field_to_json(Obj, "verifiedCertificate", "SIMULATED");
break;
default:
field_to_json(Obj, "verifiedCertificate", "NO_CERTIFICATE");
break;
@@ -580,4 +612,43 @@ namespace OpenWifi::GWObjects {
(T.commands != commands) || (T.developer != developer) || (T.ssh != ssh) ||
(T.key_info != key_info) || (T.country != country));
}
void RADIUSSession::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "started", started);
field_to_json(Obj, "lastTransaction", lastTransaction);
field_to_json(Obj, "destination", destination);
field_to_json(Obj, "serialNumber", serialNumber);
field_to_json(Obj, "userName", userName);
field_to_json(Obj, "accountingSessionId", accountingSessionId);
field_to_json(Obj, "accountingMultiSessionId", accountingMultiSessionId);
field_to_json(Obj, "inputPackets", inputPackets);
field_to_json(Obj, "outputPackets", outputPackets);
field_to_json(Obj, "inputOctets", inputOctets);
field_to_json(Obj, "outputOctets", outputOctets);
field_to_json(Obj, "inputGigaWords", inputGigaWords);
field_to_json(Obj, "outputGigaWords", outputGigaWords);
field_to_json(Obj, "sessionTime", sessionTime);
field_to_json(Obj, "callingStationId", callingStationId);
field_to_json(Obj, "chargeableUserIdentity", chargeableUserIdentity);
field_to_json(Obj, "interface", interface);
field_to_json(Obj, "secret", secret);
field_to_json(Obj, "nasId", nasId);
}
void RADIUSSessionList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "sessions", sessions);
}
bool RadiusCoADMParameters::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "accountingSessionId", accountingSessionId);
field_from_json(Obj, "accountingMultiSessionId", accountingMultiSessionId);
field_from_json(Obj, "callingStationId", callingStationId);
field_from_json(Obj, "chargeableUserIdentity", chargeableUserIdentity);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
} // namespace OpenWifi::GWObjects

View File

@@ -11,9 +11,13 @@
#include "Poco/JSON/Object.h"
#include "RESTAPI_SecurityObjects.h"
#ifdef TIP_GATEWAY_SERVICE
#include <RADIUS_helpers.h>
#endif
namespace OpenWifi::GWObjects {
enum CertificateValidation { NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED };
enum CertificateValidation { NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED, SIMULATED };
struct ConnectionState {
uint64_t MessageCount = 0;
@@ -38,8 +42,15 @@ namespace OpenWifi::GWObjects {
uint64_t sessionId = 0;
double connectionCompletionTime = 0.0;
std::uint64_t certificateExpiryDate = 0;
std::uint64_t hasRADIUSSessions = 0;
bool hasGPS = false;
std::uint64_t sanity=0;
std::double_t memoryUsed=0.0;
std::double_t load=0.0;
std::double_t temperature=0.0;
std::string connectReason;
void to_json(Poco::JSON::Object &Obj) const;
void to_json(const std::string &SerialNumber, Poco::JSON::Object &Obj) ;
};
struct DeviceRestrictionsKeyInfo {
@@ -97,6 +108,8 @@ namespace OpenWifi::GWObjects {
std::string pendingConfigurationCmd;
DeviceRestrictions restrictionDetails;
std::uint64_t pendingUUID = 0;
bool simulated=false;
std::uint64_t lastRecordedContact=0;
void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const;
@@ -370,5 +383,46 @@ namespace OpenWifi::GWObjects {
using RegulatoryInfoCountryMap = std::map<std::string,RegulatoryCountryInfo>;
struct RADIUSSession {
std::uint64_t started=0,
lastTransaction=0;
std::string serialNumber,
destination,
userName,
accountingSessionId,
accountingMultiSessionId,
callingStationId,
chargeableUserIdentity,
secret,
interface,
nasId;
std::uint64_t inputPackets = 0,
outputPackets = 0,
inputOctets = 0,
outputOctets = 0,
inputGigaWords = 0,
outputGigaWords = 0;
std::uint32_t sessionTime = 0;
#ifdef TIP_GATEWAY_SERVICE
RADIUS::RadiusPacket accountingPacket;
#endif
void to_json(Poco::JSON::Object &Obj) const;
};
struct RADIUSSessionList {
std::vector<RADIUSSession> sessions;
void to_json(Poco::JSON::Object &Obj) const;
};
struct RadiusCoADMParameters {
std::string accountingSessionId,
accountingMultiSessionId,
callingStationId,
chargeableUserIdentity;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
} // namespace OpenWifi::GWObjects

View File

@@ -119,7 +119,8 @@ namespace OpenWifi {
bool CreateDevice(GWObjects::Device &);
bool CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
std::string &Firmware, const Poco::Net::IPAddress &IPAddress);
std::string &Firmware, const Poco::Net::IPAddress &IPAddress,
bool simulated);
bool GetDevice(std::string &SerialNumber, GWObjects::Device &);
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices,
@@ -127,6 +128,9 @@ namespace OpenWifi {
// 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 DeleteDevices(std::string &SerialPattern, bool SimulatedOnly);
bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly);
bool UpdateDevice(GWObjects::Device &);
bool DeviceExists(std::string &SerialNumber);
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
@@ -226,6 +230,8 @@ namespace OpenWifi {
bool RemoveCommandListRecordsOlderThan(uint64_t Date);
bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date);
bool SetDeviceLastRecordedContact(std::string & SeialNumber, std::uint64_t lastRecordedContact);
int Create_Tables();
int Create_Statistics();
int Create_Devices();

View File

@@ -11,8 +11,8 @@ namespace OpenWifi::GWWebSocketNotifications {
struct SingleDevice {
std::string serialNumber;
inline void to_json(Poco::JSON::Object &Obj) const;
inline 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 SingleDeviceConfigurationChange {
@@ -20,15 +20,15 @@ namespace OpenWifi::GWWebSocketNotifications {
uint64_t oldUUID;
uint64_t newUUID;
inline void to_json(Poco::JSON::Object &Obj) const;
inline 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 SingleDeviceFirmwareChange {
std::string serialNumber;
std::string newFirmware;
inline void to_json(Poco::JSON::Object &Obj) const;
inline 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 NumberOfConnection {
@@ -38,8 +38,8 @@ namespace OpenWifi::GWWebSocketNotifications {
std::uint64_t rx = 0;
std::uint64_t tx = 0;
inline void to_json(Poco::JSON::Object &Obj) const;
inline 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);
};
void Register();

View File

@@ -37,6 +37,10 @@ static std::string DefaultUCentralSchema = R"foo(
"uuid": {
"type": "integer"
},
"public_ip_lookup": {
"type": "string",
"format": "uc-fqdn"
},
"unit": {
"$ref": "#/$defs/unit"
},
@@ -634,26 +638,6 @@ static std::string DefaultUCentralSchema = R"foo(
"type": "string",
"format": "uc-timeout",
"default": "6h"
},
"relay-server": {
"type": "string",
"format": "ipv4",
"example": "192.168.2.1"
},
"circuit-id-format": {
"type": "string",
"example": [
"\\{Interface\\}:\\{VLAN-Id\\}:\\{SSID\\}:\\{Model\\}:\\{Name\\}:\\{AP-MAC\\}:\\{Location\\}",
"\\{AP-MAC\\};\\{SSID\\};\\{Crypto\\}",
"\\{Name\\} \\{ESSID\\}"
]
},
"remote-id-format": {
"type": "string",
"example": [
"\\{Client-MAC-hex\\} \\{SSID\\}",
"\\{AP-MAC-hex\\} \\{SSID\\}"
]
}
}
},
@@ -1232,6 +1216,32 @@ static std::string DefaultUCentralSchema = R"foo(
"secret"
]
},
"secondary": {
"type": "object",
"properties": {
"host": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"examples": [
1812
]
},
"secret": {
"type": "string",
"examples": [
"secret"
]
}
}
},
"request-attribute": {
"type": "array",
"items": {
@@ -1309,6 +1319,25 @@ static std::string DefaultUCentralSchema = R"foo(
"value": "Example Operator"
}
]
},
{
"type": "object",
"properties": {
"id": {
"type": "integer",
"maximum": 255,
"minimum": 1
},
"hex-value": {
"type": "string"
}
},
"examples": [
{
"id": 32,
"value": "0a0b0c0d"
}
]
}
]
}
@@ -1658,6 +1687,236 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"service.captive.click": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "click-to-continue"
}
}
},
"service.captive.radius": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "radius"
},
"auth-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"auth-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"auth-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"acct-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"acct-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-interval": {
"type": "integer",
"default": 600
}
}
},
"service.captive.credentials": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "credentials"
},
"credentials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string"
}
}
}
}
}
},
"service.captive.uam": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "uam"
},
"uam-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 3990
},
"uam-secret": {
"type": "string"
},
"uam-server": {
"type": "string"
},
"nasid": {
"type": "string"
},
"nasmac": {
"type": "string"
},
"auth-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"auth-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"auth-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"acct-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"acct-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-interval": {
"type": "integer",
"default": 600
},
"ssid": {
"type": "string"
},
"mac-format": {
"type": "string",
"enum": [
"aabbccddeeff",
"aa-bb-cc-dd-ee-ff",
"aa:bb:cc:dd:ee:ff",
"AABBCCDDEEFF",
"AA:BB:CC:DD:EE:FF",
"AA-BB-CC-DD-EE-FF"
]
},
"final-redirect-url": {
"type": "string",
"enum": [
"default",
"uam"
]
},
"mac-auth": {
"type": "boolean",
"default": "default"
},
"radius-gw-proxy": {
"type": "boolean",
"default": false
}
}
},
"service.captive": {
"allOf": [
{
"oneOf": [
{
"$ref": "#/$defs/service.captive.click"
},
{
"$ref": "#/$defs/service.captive.radius"
},
{
"$ref": "#/$defs/service.captive.credentials"
},
{
"$ref": "#/$defs/service.captive.uam"
}
]
},
{
"type": "object",
"properties": {
"walled-garden-fqdn": {
"type": "array",
"items": {
"type": "string"
}
},
"walled-garden-ipaddr": {
"type": "array",
"items": {
"type": "string",
"format": "uc-ip"
}
},
"web-root": {
"type": "string",
"format": "uc-base64"
},
"idle-timeout": {
"type": "integer",
"default": 600
},
"session-timeout": {
"type": "integer"
}
}
}
]
},
"interface.ssid": {
"type": "object",
"properties": {
@@ -1710,6 +1969,10 @@ static std::string DefaultUCentralSchema = R"foo(
"isolate-clients": {
"type": "boolean"
},
"strict-forwarding": {
"type": "boolean",
"default": false
},
"power-save": {
"type": "boolean"
},
@@ -1778,7 +2041,14 @@ static std::string DefaultUCentralSchema = R"foo(
"$ref": "#/$defs/interface.ssid.rate-limit"
},
"roaming": {
"$ref": "#/$defs/interface.ssid.roaming"
"anyOf": [
{
"$ref": "#/$defs/interface.ssid.roaming"
},
{
"type": "boolean"
}
]
},
"radius": {
"$ref": "#/$defs/interface.ssid.radius"
@@ -1795,6 +2065,9 @@ static std::string DefaultUCentralSchema = R"foo(
"access-control-list": {
"$ref": "#/$defs/interface.ssid.acl"
},
"captive": {
"$ref": "#/$defs/service.captive"
},
"hostapd-bss-raw": {
"type": "array",
"items": {
@@ -2084,6 +2357,10 @@ static std::string DefaultUCentralSchema = R"foo(
"examples": [
"01234567890123456789012345678901"
]
},
"mutual-tls": {
"type": "boolean",
"default": true
}
}
},
@@ -2693,236 +2970,6 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"service.captive.click": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "click-to-continue"
}
}
},
"service.captive.radius": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "radius"
},
"auth-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"auth-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"auth-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"acct-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"acct-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-interval": {
"type": "integer",
"default": 600
}
}
},
"service.captive.credentials": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "credentials"
},
"credentials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string"
}
}
}
}
}
},
"service.captive.uam": {
"type": "object",
"properties": {
"auth-mode": {
"type": "string",
"const": "uam"
},
"uam-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 3990
},
"uam-secret": {
"type": "string"
},
"uam-server": {
"type": "string"
},
"nasid": {
"type": "string"
},
"nasmac": {
"type": "string"
},
"auth-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"auth-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"auth-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-server": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"acct-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"default": 1812
},
"acct-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-interval": {
"type": "integer",
"default": 600
},
"ssid": {
"type": "string"
},
"mac-format": {
"type": "string",
"enum": [
"aabbccddeeff",
"aa-bb-cc-dd-ee-ff",
"aa:bb:cc:dd:ee:ff",
"AABBCCDDEEFF",
"AA:BB:CC:DD:EE:FF",
"AA-BB-CC-DD-EE-FF"
]
},
"final-redirect-url": {
"type": "string",
"enum": [
"default",
"uam"
]
},
"mac-auth": {
"type": "boolean",
"default": "default"
},
"radius-gw-proxy": {
"type": "boolean",
"default": false
}
}
},
"service.captive": {
"allOf": [
{
"oneOf": [
{
"$ref": "#/$defs/service.captive.click"
},
{
"$ref": "#/$defs/service.captive.radius"
},
{
"$ref": "#/$defs/service.captive.credentials"
},
{
"$ref": "#/$defs/service.captive.uam"
}
]
},
{
"type": "object",
"properties": {
"walled-garden-fqdn": {
"type": "array",
"items": {
"type": "string"
}
},
"walled-garden-ipaddr": {
"type": "array",
"items": {
"type": "string",
"format": "uc-ip"
}
},
"web-root": {
"type": "string",
"format": "uc-base64"
},
"idle-timeout": {
"type": "integer",
"default": 600
},
"session-timeout": {
"type": "integer"
}
}
}
]
},
"service.gps": {
"type": "object",
"properties": {
@@ -2941,6 +2988,32 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"service.dhcp-relay": {
"type": "object",
"properties": {
"select-ports": {
"type": "array",
"items": {
"type": "string"
}
},
"vlans": {
"type": "array",
"items": {
"type": "object",
"properties": {
"vlan": {
"type": "number"
},
"relay-server": {
"type": "string",
"format": "uc-ip"
}
}
}
}
}
},
"service": {
"type": "object",
"properties": {
@@ -3000,6 +3073,9 @@ static std::string DefaultUCentralSchema = R"foo(
},
"gps": {
"$ref": "#/$defs/service.gps"
},
"dhcp-relay": {
"$ref": "#/$defs/service.dhcp-relay"
}
}
},

View File

@@ -14,18 +14,18 @@ namespace OpenWifi {
void EventBusManager::run() {
Running_ = true;
Utils::SetThreadName("fmwk:EventMgr");
auto Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
auto Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN));
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
false);
while (Running_) {
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
if (!Running_)
break;
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE));
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(),
Msg, false);
}
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE);
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE));
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
false);
};

View File

@@ -180,7 +180,7 @@ namespace OpenWifi {
Consumer.async_commit(Msg);
continue;
}
KafkaManager()->Dispatch(Msg.get_topic(), Msg.get_key(), Msg.get_payload());
KafkaManager()->Dispatch(Msg.get_topic().c_str(), Msg.get_key(), std::make_shared<std::string>(Msg.get_payload()));
if (!AutoCommit)
Consumer.async_commit(Msg);
}
@@ -212,8 +212,8 @@ namespace OpenWifi {
}
}
void KafkaProducer::Produce(const std::string &Topic, const std::string &Key,
const std::string &Payload) {
void KafkaProducer::Produce(const char *Topic, const std::string &Key,
const std::shared_ptr<std::string> Payload) {
std::lock_guard G(Mutex_);
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
}
@@ -275,8 +275,8 @@ namespace OpenWifi {
}
}
void KafkaDispatcher::Dispatch(const std::string &Topic, const std::string &Key,
const std::string &Payload) {
void KafkaDispatcher::Dispatch(const char *Topic, const std::string &Key,
const std::shared_ptr<std::string> Payload) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if (It != Notifiers_.end()) {
@@ -332,20 +332,21 @@ namespace OpenWifi {
}
}
void KafkaManager::PostMessage(const std::string &topic, const std::string &key,
const std::string &PayLoad, bool WrapMessage) {
void KafkaManager::PostMessage(const char *topic, const std::string &key,
const std::shared_ptr<std::string> PayLoad, bool WrapMessage) {
if (KafkaEnabled_) {
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
}
}
void KafkaManager::Dispatch(const std::string &Topic, const std::string &Key,
const std::string &Payload) {
void KafkaManager::Dispatch(const char *Topic, const std::string &Key,
const std::shared_ptr<std::string> Payload) {
Dispatcher_.Dispatch(Topic, Key, Payload);
}
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string &PayLoad) {
return SystemInfoWrapper_ + PayLoad + "}";
[[nodiscard]] const std::shared_ptr<std::string> KafkaManager::WrapSystemId(const std::shared_ptr<std::string> PayLoad) {
*PayLoad = SystemInfoWrapper_ + *PayLoad + "}";
return PayLoad;
}
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic,

View File

@@ -18,17 +18,17 @@ namespace OpenWifi {
class KafkaMessage : public Poco::Notification {
public:
KafkaMessage(const std::string &Topic, const std::string &Key, const std::string &Payload)
: Topic_(Topic), Key_(Key), Payload_(Payload) {}
KafkaMessage(const char * Topic, const std::string &Key, const std::shared_ptr<std::string> Payload)
: Topic_(Topic), Key_(Key), Payload_(std::move(Payload)) {}
inline const std::string &Topic() { return Topic_; }
inline const char * Topic() { return Topic_; }
inline const std::string &Key() { return Key_; }
inline const std::string &Payload() { return Payload_; }
inline const std::string &Payload() { return *Payload_; }
private:
std::string Topic_;
const char *Topic_;
std::string Key_;
std::string Payload_;
std::shared_ptr<std::string> Payload_;
};
class KafkaProducer : public Poco::Runnable {
@@ -36,7 +36,7 @@ namespace OpenWifi {
void run() override;
void Start();
void Stop();
void Produce(const std::string &Topic, const std::string &Key, const std::string &Payload);
void Produce(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
private:
std::recursive_mutex Mutex_;
@@ -63,7 +63,7 @@ namespace OpenWifi {
void Stop();
auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, int Id);
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
void run() override;
void Topics(std::vector<std::string> &T);
@@ -91,10 +91,10 @@ namespace OpenWifi {
int Start() override;
void Stop() override;
void PostMessage(const std::string &topic, const std::string &key,
const std::string &PayLoad, bool WrapMessage = true);
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
[[nodiscard]] std::string WrapSystemId(const std::string &PayLoad);
void PostMessage(const char *topic, const std::string &key,
const std::shared_ptr<std::string> PayLoad, bool WrapMessage = true);
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
[[nodiscard]] const std::shared_ptr<std::string> WrapSystemId(const std::shared_ptr<std::string> PayLoad);
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);

View File

@@ -10,32 +10,32 @@
#include <string>
namespace OpenWifi::KafkaTopics {
static const std::string HEALTHCHECK{"healthcheck"};
static const std::string STATE{"state"};
static const std::string CONNECTION{"connection"};
static const std::string WIFISCAN{"wifiscan"};
static const std::string ALERTS{"alerts"};
static const std::string COMMAND{"command"};
static const std::string SERVICE_EVENTS{"service_events"};
static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"};
static const std::string DEVICE_TELEMETRY{"device_telemetry"};
static const std::string PROVISIONING_CHANGE{"provisioning_change"};
inline const char * HEALTHCHECK = "healthcheck";
inline const char * STATE = "state";
inline const char * CONNECTION = "connection";
inline const char * WIFISCAN = "wifiscan";
inline const char * ALERTS = "alerts";
inline const char * COMMAND = "command";
inline const char * SERVICE_EVENTS = "service_events";
inline const char * DEVICE_EVENT_QUEUE = "device_event_queue";
inline const char * DEVICE_TELEMETRY = "device_telemetry";
inline const char * PROVISIONING_CHANGE = "provisioning_change";
namespace ServiceEvents {
static const std::string EVENT_JOIN{"join"};
static const std::string EVENT_LEAVE{"leave"};
static const std::string EVENT_KEEP_ALIVE{"keep-alive"};
static const std::string EVENT_REMOVE_TOKEN{"remove-token"};
inline const char * EVENT_JOIN = "join";
inline const char * EVENT_LEAVE = "leave";
inline const char * EVENT_KEEP_ALIVE = "keep-alive";
inline const char * EVENT_REMOVE_TOKEN = "remove-token";
namespace Fields {
static const std::string EVENT{"event"};
static const std::string ID{"id"};
static const std::string TYPE{"type"};
static const std::string PUBLIC{"publicEndPoint"};
static const std::string PRIVATE{"privateEndPoint"};
static const std::string KEY{"key"};
static const std::string VRSN{"version"};
static const std::string TOKEN{"token"};
inline const char * EVENT = "event";
inline const char * ID = "id";
inline const char * TYPE = "type";
inline const char * PUBLIC = "publicEndPoint";
inline const char * PRIVATE = "privateEndPoint";
inline const char * KEY = "key";
inline const char * VRSN = "version";
inline const char * TOKEN = "token";
} // namespace Fields
} // namespace ServiceEvents
} // namespace OpenWifi::KafkaTopics

View File

@@ -47,11 +47,11 @@ namespace OpenWifi {
void MicroServiceReload(const std::string &Type) { MicroService::instance().Reload(Type); }
const Types::StringVec MicroServiceGetLogLevelNames() {
Types::StringVec MicroServiceGetLogLevelNames() {
return MicroService::instance().GetLogLevelNames();
}
const Types::StringVec MicroServiceGetSubSystems() {
Types::StringVec MicroServiceGetSubSystems() {
return MicroService::instance().GetSubSystems();
}
@@ -79,7 +79,7 @@ namespace OpenWifi {
std::string MicroServiceGetUIURI() { return MicroService::instance().GetUIURI(); }
const SubSystemVec MicroServiceGetFullSubSystems() {
SubSystemVec MicroServiceGetFullSubSystems() {
return MicroService::instance().GetFullSubSystems();
}
@@ -87,7 +87,7 @@ namespace OpenWifi {
std::uint64_t MicroServiceDaemonBusTimer() { return MicroService::instance().DaemonBusTimer(); }
std::string MicroServiceMakeSystemEventMessage(const std::string &Type) {
std::string MicroServiceMakeSystemEventMessage(const char *Type) {
return MicroService::instance().MakeSystemEventMessage(Type);
}

View File

@@ -31,8 +31,8 @@ namespace OpenWifi {
void MicroServiceLoadConfigurationFile();
void MicroServiceReload();
void MicroServiceReload(const std::string &Type);
const Types::StringVec MicroServiceGetLogLevelNames();
const Types::StringVec MicroServiceGetSubSystems();
Types::StringVec MicroServiceGetLogLevelNames();
Types::StringVec MicroServiceGetSubSystems();
Types::StringPairVec MicroServiceGetLogLevels();
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer);
@@ -40,10 +40,10 @@ namespace OpenWifi {
std::uint64_t MicroServiceUptimeTotalSeconds();
std::uint64_t MicroServiceStartTimeEpochTime();
std::string MicroServiceGetUIURI();
const SubSystemVec MicroServiceGetFullSubSystems();
SubSystemVec MicroServiceGetFullSubSystems();
std::string MicroServiceCreateUUID();
std::uint64_t MicroServiceDaemonBusTimer();
std::string MicroServiceMakeSystemEventMessage(const std::string &Type);
std::string MicroServiceMakeSystemEventMessage(const char *Type);
Poco::ThreadPool &MicroServiceTimerPool();
std::string MicroServiceConfigPath(const std::string &Key, const std::string &DefaultValue);
std::string MicroServiceWWWAssetsDir();

View File

@@ -14,8 +14,15 @@
#include "framework/OpenWifiTypes.h"
#include "framework/utils.h"
#include <RESTObjects/RESTAPI_SecurityObjects.h>
namespace OpenWifi::RESTAPI_utils {
inline bool IsRootOrAdmin(const SecurityObjects::UserInfo &UI) {
return UI.userRole==SecurityObjects::ROOT ||
UI.userRole==SecurityObjects::ADMIN;
}
inline void EmbedDocument(const std::string &ObjName, Poco::JSON::Object &Obj,
const std::string &ObjStr) {
std::string D = ObjStr.empty() ? "{}" : ObjStr;

View File

@@ -0,0 +1,63 @@
//
// Created by stephane bourque on 2023-04-19.
//
#pragma once
#include <vector>
#include <string>
namespace OpenWifi {
inline const std::vector<std::pair<std::string, std::string>> DefaultDeviceTypeList{
{"actiontec_web7200", "AP"},
{"cig_wf186w", "AP"},
{"cig_wf188n", "AP"},
{"cig_wf194c4", "AP"},
{"cig_wf196", "AP"},
{"cig_wf196-ca", "AP"},
{"cig_wf196-ca-ath12", "AP"},
{"cig_wf196-us", "AP"},
{"cig_wf610d", "AP"},
{"cig_wf660a", "AP"},
{"cig_wf808", "AP"},
{"cybertan_eww622-a1", "AP"},
{"edgecore_eap101", "AP"},
{"edgecore_eap101-ath12", "AP"},
{"edgecore_eap102", "AP"},
{"edgecore_eap104", "AP"},
{"edgecore_eap104-ath12", "AP"},
{"edgecore_ecs4100-12ph", "AP"},
{"edgecore_ecw5211", "AP"},
{"edgecore_ecw5410", "AP"},
{"edgecore_oap100", "AP"},
{"edgecore_spw2ac1200", "SWITCH"},
{"edgecore_spw2ac1200-lan-poe", "SWITCH"},
{"edgecore_ssw2ac2600", "SWITCH"},
{"hfcl_ion4", "AP"},
{"hfcl_ion4x", "AP"},
{"hfcl_ion4x_2", "AP"},
{"hfcl_ion4xe", "AP"},
{"hfcl_ion4xi", "AP"},
{"indio_um-305ac", "AP"},
{"indio_um-305ax", "AP"},
{"indio_um-310ax-v1", "AP"},
{"indio_um-325ac", "AP"},
{"indio_um-510ac-v3", "AP"},
{"indio_um-510axm-v1", "AP"},
{"indio_um-510axp-v1", "AP"},
{"indio_um-550ac", "AP"},
{"linksys_e8450-ubi", "AP"},
{"linksys_ea6350-v4", "AP"},
{"linksys_ea8300", "AP"},
{"liteon_wpx8324", "AP"},
{"meshpp_s618_cp01", "AP"},
{"meshpp_s618_cp03", "AP"},
{"udaya_a5-id2", "AP"},
{"wallys_dr40x9", "AP"},
{"wallys_dr6018", "AP"},
{"wallys_dr6018_v4", "AP"},
{"x64_vm", "AP"},
{"yuncore_ax840", "AP"},
{"yuncore_fap640", "AP"},
{"yuncore_fap650", "AP"}};
}

View File

@@ -397,6 +397,18 @@ namespace OpenWifi::RESTAPI::Errors {
static const struct msg FirmwareBDInProgress {
1170, "Firmware DB update already in progress."
};
static const struct msg SimulatedDeviceNotSupported {
1171, "Command not supported on simulated device."
};
static const struct msg SimulationDoesNotExist {
7000, "Simulation Instance ID does not exist."
};
static const struct msg SimulationIsAlreadyRunning {
7001, "There is an instance of this simulation already running.."
};
} // namespace OpenWifi::RESTAPI::Errors
@@ -554,6 +566,7 @@ namespace OpenWifi::uCentralProtocol {
static const char *HEALTHCHECK = "healthcheck";
static const char *LOG = "log";
static const char *CRASHLOG = "crashlog";
static const char *REBOOTLOG = "rebootLog";
static const char *PING = "ping";
static const char *CFGPENDING = "cfgpending";
static const char *RECOVERY = "recovery";
@@ -612,6 +625,8 @@ namespace OpenWifi::uCentralProtocol {
static const char *DEVICEUPDATE = "deviceupdate";
static const char *FWSIGNATURE = "FWsignature";
static const char *SIGNATURE = "signature";
static const char *INFO = "info";
static const char *DATE = "date";
static const char *SERIALNUMBER = "serialNumber";
static const char *COMPATIBLE = "compatible";
@@ -642,6 +657,7 @@ namespace OpenWifi::uCentralProtocol::Events {
static const char *HEALTHCHECK = "healthcheck";
static const char *LOG = "log";
static const char *CRASHLOG = "crashlog";
static const char *REBOOTLOG = "rebootLog";
static const char *PING = "ping";
static const char *CFGPENDING = "cfgpending";
static const char *RECOVERY = "recovery";
@@ -665,7 +681,8 @@ namespace OpenWifi::uCentralProtocol::Events {
ET_VENUEBROADCAST,
ET_EVENT,
ET_WIFISCAN,
ET_ALARM
ET_ALARM,
ET_REBOOTLOG
};
inline EVENT_MSG EventFromString(const std::string &Method) {
@@ -696,8 +713,10 @@ namespace OpenWifi::uCentralProtocol::Events {
else if (strcmp(WIFISCAN, Method.c_str()) == 0)
return ET_WIFISCAN;
else if (strcmp(ALARM, Method.c_str()) == 0)
return ET_WIFISCAN;
return ET_ALARM;
return ET_ALARM;
else if (strcmp(REBOOTLOG, Method.c_str()) == 0)
return ET_REBOOTLOG;
return ET_UNKNOWN;
};
} // namespace OpenWifi::uCentralProtocol::Events

View File

@@ -27,6 +27,10 @@ namespace OpenWifi::Utils {
std::all_of(Serial.begin(), Serial.end(), [](auto i) { return std::isxdigit(i); }));
}
[[nodiscard]] bool ValidSerialNumbers(const std::vector<std::string> &numbers) {
return std::all_of(numbers.begin(),numbers.end(),[](auto &number) {return ValidSerialNumber(number);});
}
[[nodiscard]] bool ValidUUID(const std::string &UUID) {
if (UUID.size() > 36)
return false;

View File

@@ -68,6 +68,7 @@ namespace OpenWifi::Utils {
};
[[nodiscard]] bool ValidSerialNumber(const std::string &Serial);
[[nodiscard]] bool ValidSerialNumbers(const std::vector<std::string> &Serial);
[[nodiscard]] bool ValidUUID(const std::string &UUID);
[[nodiscard]] bool ValidHostname(const std::string &hostname);
@@ -146,4 +147,38 @@ namespace OpenWifi::Utils {
bool ExtractBase64CompressedData(const std::string &CompressedData,
std::string &UnCompressedData, uint64_t compress_sz);
inline bool match(const char* first, const char* second)
{
// If we reach at the end of both strings, we are done
if (*first == '\0' && *second == '\0')
return true;
// Make sure to eliminate consecutive '*'
if (*first == '*') {
while (*(first + 1) == '*')
first++;
}
// Make sure that the characters after '*' are present
// in second string. This function assumes that the
// first string will not contain two consecutive '*'
if (*first == '*' && *(first + 1) != '\0'
&& *second == '\0')
return false;
// If the first string contains '?', or current
// characters of both strings match
if (*first == '?' || *first == *second)
return match(first + 1, second + 1);
// If there is *, then there are two possibilities
// a) We consider current character of second string
// b) We ignore current character of second string.
if (*first == '*')
return match(first + 1, second)
|| match(first, second + 1);
return false;
}
} // namespace OpenWifi::Utils

127
src/libs/Cron.h Normal file
View File

@@ -0,0 +1,127 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include <chrono>
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
namespace Bosma {
using Clock = std::chrono::system_clock;
inline void add(std::tm &tm, Clock::duration time) {
auto tp = Clock::from_time_t(std::mktime(&tm));
auto tp_adjusted = tp + time;
auto tm_adjusted = Clock::to_time_t(tp_adjusted);
tm = *std::localtime(&tm_adjusted);
}
class BadCronExpression : public std::exception {
public:
explicit BadCronExpression(std::string msg) : msg_(std::move(msg)) {}
const char *what() const noexcept override { return (msg_.c_str()); }
private:
std::string msg_;
};
inline void
verify_and_set(const std::string &token, const std::string &expression, int &field, const int lower_bound,
const int upper_bound, const bool adjust = false) {
if (token == "*")
field = -1;
else {
try {
field = std::stoi(token);
} catch (const std::invalid_argument &) {
throw BadCronExpression("malformed cron string (`" + token + "` not an integer or *): " + expression);
} catch (const std::out_of_range &) {
throw BadCronExpression("malformed cron string (`" + token + "` not convertable to int): " + expression);
}
if (field < lower_bound || field > upper_bound) {
std::ostringstream oss;
oss << "malformed cron string ('" << token << "' must be <= " << upper_bound << " and >= " << lower_bound
<< "): " << expression;
throw BadCronExpression(oss.str());
}
if (adjust)
field--;
}
}
class Cron {
public:
explicit Cron(const std::string &expression) {
std::istringstream iss(expression);
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
std::istream_iterator<std::string>{}};
if (tokens.size() != 5) throw BadCronExpression("malformed cron string (must be 5 fields): " + expression);
verify_and_set(tokens[0], expression, minute, 0, 59);
verify_and_set(tokens[1], expression, hour, 0, 23);
verify_and_set(tokens[2], expression, day, 1, 31);
verify_and_set(tokens[3], expression, month, 1, 12, true);
verify_and_set(tokens[4], expression, day_of_week, 0, 6);
}
// http://stackoverflow.com/a/322058/1284550
Clock::time_point cron_to_next(const Clock::time_point from = Clock::now()) const {
// get current time as a tm object
auto now = Clock::to_time_t(from);
std::tm next(*std::localtime(&now));
// it will always at least run the next minute
next.tm_sec = 0;
add(next, std::chrono::minutes(1));
while (true) {
if (month != -1 && next.tm_mon != month) {
// add a month
// if this will bring us over a year, increment the year instead and reset the month
if (next.tm_mon + 1 > 11) {
next.tm_mon = 0;
next.tm_year++;
} else
next.tm_mon++;
next.tm_mday = 1;
next.tm_hour = 0;
next.tm_min = 0;
continue;
}
if (day != -1 && next.tm_mday != day) {
add(next, std::chrono::hours(24));
next.tm_hour = 0;
next.tm_min = 0;
continue;
}
if (day_of_week != -1 && next.tm_wday != day_of_week) {
add(next, std::chrono::hours(24));
next.tm_hour = 0;
next.tm_min = 0;
continue;
}
if (hour != -1 && next.tm_hour != hour) {
add(next, std::chrono::hours(1));
next.tm_min = 0;
continue;
}
if (minute != -1 && next.tm_min != minute) {
add(next, std::chrono::minutes(1));
continue;
}
break;
}
// telling mktime to figure out dst
next.tm_isdst = -1;
return Clock::from_time_t(std::mktime(&next));
}
int minute, hour, day, month, day_of_week;
};
}

View File

@@ -0,0 +1,67 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include <chrono>
#include <thread>
#include <future>
#include <mutex>
#include <sstream>
namespace Bosma {
class InterruptableSleep {
using Clock = std::chrono::system_clock;
// InterruptableSleep offers a sleep that can be interrupted by any thread.
// It can be interrupted multiple times
// and be interrupted before any sleep is called (the sleep will immediately complete)
// Has same interface as condition_variables and futures, except with sleep instead of wait.
// For a given object, sleep can be called on multiple threads safely, but is not recommended as behaviour is undefined.
public:
InterruptableSleep() : interrupted(false) {
}
InterruptableSleep(const InterruptableSleep &) = delete;
InterruptableSleep(InterruptableSleep &&) noexcept = delete;
~InterruptableSleep() noexcept = default;
InterruptableSleep &operator=(const InterruptableSleep &) noexcept = delete;
InterruptableSleep &operator=(InterruptableSleep &&) noexcept = delete;
void sleep_for(Clock::duration duration) {
std::unique_lock<std::mutex> ul(m);
cv.wait_for(ul, duration, [this] { return interrupted; });
interrupted = false;
}
void sleep_until(Clock::time_point time) {
std::unique_lock<std::mutex> ul(m);
cv.wait_until(ul, time, [this] { return interrupted; });
interrupted = false;
}
void sleep() {
std::unique_lock<std::mutex> ul(m);
cv.wait(ul, [this] { return interrupted; });
interrupted = false;
}
void interrupt() {
std::lock_guard<std::mutex> lg(m);
interrupted = true;
cv.notify_one();
}
private:
bool interrupted;
std::mutex m;
std::condition_variable cv;
};
}

237
src/libs/Scheduler.h Normal file
View File

@@ -0,0 +1,237 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#pragma once
#include <iomanip>
#include <map>
#include "ctpl_stl.h"
#include "InterruptableSleep.h"
#include "Cron.h"
namespace Bosma {
using Clock = std::chrono::system_clock;
class Task {
public:
explicit Task(std::function<void()> &&f, bool recur = false, bool interval = false) :
f(std::move(f)), recur(recur), interval(interval) {}
virtual Clock::time_point get_new_time() const = 0;
virtual ~Task() = default;
std::function<void()> f;
bool recur;
bool interval;
};
class InTask : public Task {
public:
explicit InTask(std::function<void()> &&f) : Task(std::move(f)) {}
// dummy time_point because it's not used
[[nodiscard]] Clock::time_point get_new_time() const override { return Clock::time_point(Clock::duration(0)); }
};
class EveryTask : public Task {
public:
EveryTask(Clock::duration time, std::function<void()> &&f, bool interval = false) :
Task(std::move(f), true, interval), time(time) {}
[[nodiscard]] Clock::time_point get_new_time() const override {
return Clock::now() + time;
};
Clock::duration time;
};
class CronTask : public Task {
public:
CronTask(const std::string &expression, std::function<void()> &&f) : Task(std::move(f), true),
cron(expression) {}
[[nodiscard]] Clock::time_point get_new_time() const override {
return cron.cron_to_next();
};
Cron cron;
};
inline bool try_parse(std::tm &tm, const std::string &expression, const std::string &format) {
std::stringstream ss(expression);
return !(ss >> std::get_time(&tm, format.c_str())).fail();
}
class Scheduler {
public:
explicit Scheduler(unsigned int max_n_tasks = 4) : done(false), threads(max_n_tasks + 1) {
threads.push([this](int) {
while (!done) {
Clock::time_point sleep_until_time;
if(find_sleep_time(sleep_until_time)) {
sleeper.sleep_until(sleep_until_time);
} else {
sleeper.sleep();
}
manage_tasks();
}
});
}
Scheduler(const Scheduler &) = delete;
Scheduler(Scheduler &&) noexcept = delete;
Scheduler &operator=(const Scheduler &) = delete;
Scheduler &operator=(Scheduler &&) noexcept = delete;
~Scheduler() {
done = true;
sleeper.interrupt();
}
template<typename _Callable, typename... _Args>
void in(const Clock::time_point time, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<InTask>(
std::bind(std::forward<_Callable>(f), std::forward<_Args>(args)...));
add_task(time, std::move(t));
}
template<typename _Callable, typename... _Args>
void in(const Clock::duration time, _Callable &&f, _Args &&... args) {
in(Clock::now() + time, std::forward<_Callable>(f), std::forward<_Args>(args)...);
}
template<typename _Callable, typename... _Args>
void at(const std::string &time, _Callable &&f, _Args &&... args) {
// get current time as a tm object
auto time_now = Clock::to_time_t(Clock::now());
std::tm tm = *std::localtime(&time_now);
// our final time as a time_point
Clock::time_point tp;
if (try_parse(tm, time, "%H:%M:%S")) {
// convert tm back to time_t, then to a time_point and assign to final
tp = Clock::from_time_t(std::mktime(&tm));
// if we've already passed this time, the user will mean next day, so add a day.
if (Clock::now() >= tp)
tp += std::chrono::hours(24);
} else if (try_parse(tm, time, "%Y-%m-%d %H:%M:%S")) {
tp = Clock::from_time_t(std::mktime(&tm));
} else if (try_parse(tm, time, "%Y/%m/%d %H:%M:%S")) {
tp = Clock::from_time_t(std::mktime(&tm));
} else {
// could not parse time
throw std::runtime_error("Cannot parse time string: " + time);
}
in(tp, std::forward<_Callable>(f), std::forward<_Args>(args)...);
}
template<typename _Callable, typename... _Args>
void every(const Clock::duration time, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<EveryTask>(time, std::bind(std::forward<_Callable>(f),
std::forward<_Args>(args)...));
auto next_time = t->get_new_time();
add_task(next_time, std::move(t));
}
// expression format:
// from https://en.wikipedia.org/wiki/Cron#Overview
// ┌───────────── minute (0 - 59)
// │ ┌───────────── hour (0 - 23)
// │ │ ┌───────────── day of month (1 - 31)
// │ │ │ ┌───────────── month (1 - 12)
// │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
// │ │ │ │ │
// │ │ │ │ │
// * * * * *
template<typename _Callable, typename... _Args>
void cron(const std::string &expression, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<CronTask>(expression, std::bind(std::forward<_Callable>(f),
std::forward<_Args>(args)...));
auto next_time = t->get_new_time();
add_task(next_time, std::move(t));
}
template<typename _Callable, typename... _Args>
void interval(const Clock::duration time, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<EveryTask>(time, std::bind(std::forward<_Callable>(f),
std::forward<_Args>(args)...), true);
add_task(Clock::now(), std::move(t));
}
private:
std::atomic<bool> done;
Bosma::InterruptableSleep sleeper;
std::multimap<Clock::time_point, std::shared_ptr<Task>> tasks;
std::mutex lock;
ctpl::thread_pool threads;
void add_task(const Clock::time_point time, std::shared_ptr<Task> t) {
std::lock_guard<std::mutex> l(lock);
tasks.emplace(time, std::move(t));
sleeper.interrupt();
}
bool find_sleep_time(Clock::time_point &sleep_value) {
std::lock_guard<std::mutex> l(lock);
if(tasks.empty()) {
return false;
}
sleep_value = (*tasks.begin()).first;
return true;
}
void manage_tasks() {
std::lock_guard<std::mutex> l(lock);
auto end_of_tasks_to_run = tasks.upper_bound(Clock::now());
// if there are any tasks to be run and removed
if (end_of_tasks_to_run != tasks.begin()) {
// keep track of tasks that will be re-added
decltype(tasks) recurred_tasks;
// for all tasks that have been triggered
for (auto i = tasks.begin(); i != end_of_tasks_to_run; ++i) {
auto &task = (*i).second;
if (task->interval) {
// if it's an interval task, only add the task back after f() is completed
threads.push([this, task](int) {
task->f();
// no risk of race-condition,
// add_task() will wait for manage_tasks() to release lock
add_task(task->get_new_time(), task);
});
} else {
threads.push([task](int) {
task->f();
});
// calculate time of next run and add the new task to the tasks to be recurred
if (task->recur)
recurred_tasks.emplace(task->get_new_time(), std::move(task));
}
}
// remove the completed tasks
tasks.erase(tasks.begin(), end_of_tasks_to_run);
// re-add the tasks that are recurring
for (auto &task : recurred_tasks)
tasks.emplace(task.first, std::move(task.second));
}
}
};
}

253
src/libs/ctpl_stl.h Normal file
View File

@@ -0,0 +1,253 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
/*********************************************************
*
* Copyright (C) 2014 by Vitaliy Vitsentiy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************/
#include <functional>
#include <thread>
#include <atomic>
#include <vector>
#include <memory>
#include <exception>
#include <future>
#include <mutex>
#include <queue>
// thread pool to run user's functors with signature
// ret func(int id, other_params)
// where id is the index of the thread that runs the functor
// ret is some return type
namespace ctpl {
namespace detail {
template <typename T>
class Queue {
public:
bool push(T const & value) {
std::unique_lock<std::mutex> lock(this->mutex);
this->q.push(value);
return true;
}
// deletes the retrieved element, do not use for non integral types
bool pop(T & v) {
std::unique_lock<std::mutex> lock(this->mutex);
if (this->q.empty())
return false;
v = this->q.front();
this->q.pop();
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(this->mutex);
return this->q.empty();
}
private:
std::queue<T> q;
std::mutex mutex;
};
}
class thread_pool {
public:
thread_pool() { this->init(); }
thread_pool(int nThreads) { this->init(); this->resize(nThreads); }
// the destructor waits for all the functions in the queue to be finished
~thread_pool() {
this->stop(true);
}
// get the number of running threads in the pool
int size() { return static_cast<int>(this->threads.size()); }
// number of idle threads
int n_idle() { return this->nWaiting; }
std::thread & get_thread(int i) { return *this->threads[i]; }
// change the number of threads in the pool
// should be called from one thread, otherwise be careful to not interleave, also with this->stop()
// nThreads must be >= 0
void resize(int nThreads) {
if (!this->isStop && !this->isDone) {
int oldNThreads = static_cast<int>(this->threads.size());
if (oldNThreads <= nThreads) { // if the number of threads is increased
this->threads.resize(nThreads);
this->flags.resize(nThreads);
for (int i = oldNThreads; i < nThreads; ++i) {
this->flags[i] = std::make_shared<std::atomic<bool>>(false);
this->set_thread(i);
}
}
else { // the number of threads is decreased
for (int i = oldNThreads - 1; i >= nThreads; --i) {
*this->flags[i] = true; // this thread will finish
this->threads[i]->detach();
}
{
// stop the detached threads that were waiting
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all();
}
this->threads.resize(nThreads); // safe to delete because the threads are detached
this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals
}
}
}
// empty the queue
void clear_queue() {
std::function<void(int id)> * _f;
while (this->q.pop(_f))
delete _f; // empty the queue
}
// pops a functional wrapper to the original function
std::function<void(int)> pop() {
std::function<void(int id)> * _f = nullptr;
this->q.pop(_f);
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
std::function<void(int)> f;
if (_f)
f = *_f;
return f;
}
// wait for all computing threads to finish and stop all threads
// may be called asynchronously to not pause the calling thread while waiting
// if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions
void stop(bool isWait = false) {
if (!isWait) {
if (this->isStop)
return;
this->isStop = true;
for (int i = 0, n = this->size(); i < n; ++i) {
*this->flags[i] = true; // command the threads to stop
}
this->clear_queue(); // empty the queue
}
else {
if (this->isDone || this->isStop)
return;
this->isDone = true; // give the waiting threads a command to finish
}
{
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all(); // stop all waiting threads
}
for (int i = 0; i < static_cast<int>(this->threads.size()); ++i) { // wait for the computing threads to finish
if (this->threads[i]->joinable())
this->threads[i]->join();
}
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
// therefore delete them here
this->clear_queue();
this->threads.clear();
this->flags.clear();
}
template<typename F, typename... Rest>
auto push(F && f, Rest&&... rest) ->std::future<decltype(f(0, rest...))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0, rest...))(int)>>(
std::bind(std::forward<F>(f), std::placeholders::_1, std::forward<Rest>(rest)...)
);
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
// run the user's function that excepts argument int - id of the running thread. returned value is templatized
// operator returns std::future, where the user can get the result and rethrow the catched exceptins
template<typename F>
auto push(F && f) ->std::future<decltype(f(0))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0))(int)>>(std::forward<F>(f));
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
private:
// deleted
thread_pool(const thread_pool &);// = delete;
thread_pool(thread_pool &&);// = delete;
thread_pool & operator=(const thread_pool &);// = delete;
thread_pool & operator=(thread_pool &&);// = delete;
void set_thread(int i) {
std::shared_ptr<std::atomic<bool>> flag(this->flags[i]); // a copy of the shared ptr to the flag
auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() {
std::atomic<bool> & _flag = *flag;
std::function<void(int id)> * _f;
bool isPop = this->q.pop(_f);
while (true) {
while (isPop) { // if there is anything in the queue
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
(*_f)(i);
if (_flag)
return; // the thread is wanted to stop, return even if the queue is not empty yet
else
isPop = this->q.pop(_f);
}
// the queue is empty here, wait for the next command
std::unique_lock<std::mutex> lock(this->mutex);
++this->nWaiting;
this->cv.wait(lock, [this, &_f, &isPop, &_flag](){ isPop = this->q.pop(_f); return isPop || this->isDone || _flag; });
--this->nWaiting;
if (!isPop)
return; // if the queue is empty and this->isDone == true or *flag then return
}
};
this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique()
}
void init() { this->nWaiting = 0; this->isStop = false; this->isDone = false; }
std::vector<std::unique_ptr<std::thread>> threads;
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
detail::Queue<std::function<void(int id)> *> q;
std::atomic<bool> isDone;
std::atomic<bool> isStop;
std::atomic<int> nWaiting; // how many threads are waiting
std::mutex mutex;
std::condition_variable cv;
};
}

View File

@@ -19,6 +19,7 @@
#include "Poco/Net/WebSocketImpl.h"
#include "Poco/Net/SocketAcceptor.h"
#include "Poco/Net/SocketAcceptor.h"
#include <algorithm>
#define DBGLINE \
@@ -221,7 +222,6 @@ namespace OpenWifi {
}
NewSocket.close();
} catch (const Poco::Exception &E) {
std::cout << "Exception onDeviceAccept: " << E.what() << std::endl;
Logger().log(E);
}
}
@@ -245,7 +245,7 @@ namespace OpenWifi {
void RTTYS_server::AddNewSocket(Poco::Net::StreamSocket &Socket, std::unique_ptr<Poco::Crypto::X509Certificate> P, bool valid, const std::string &cid, const std::string &cn) {
Socket.setNoDelay(true);
Socket.setKeepAlive(true);
Socket.setBlocking(false);
Socket.setBlocking(true);
Socket.setReceiveBufferSize(RTTY_RECEIVE_BUFFER);
Socket.setSendBufferSize(RTTY_RECEIVE_BUFFER);
Poco::Timespan TS2(300, 100);
@@ -261,10 +261,9 @@ namespace OpenWifi {
Poco::NObserver<RTTYS_server, Poco::Net::ErrorNotification>(
*this, &RTTYS_server::onConnectedDeviceSocketError));
int fd = Socket.impl()->sockfd();
Sockets_[fd] = std::make_unique<SecureSocketPair>(SecureSocketPair{Socket, std::move(P), valid, cid, cn});
Sockets_[fd] = std::make_unique<SecureSocketPair>(Socket, std::move(P), valid, cid, cn);
}
void RTTYS_server::RemoveSocket(const Poco::Net::Socket &Socket) {
auto hint = Sockets_.find(Socket.impl()->sockfd());
if(hint!=end(Sockets_)) {
@@ -295,16 +294,8 @@ namespace OpenWifi {
*this, &RTTYS_server::onClientSocketError));
}
int RTTYS_server::SendBytes(int fd, const unsigned char *buffer, std::size_t len) {
auto hint = Sockets_.find(fd);
if(hint==end(Sockets_)) {
poco_error(Logger(),fmt::format("Cannot find this socket: {}",fd));
return -1;
}
return hint->second->socket.impl()->sendBytes(buffer,len);
}
int RTTYS_server::SendBytes(const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len) {
int RTTYS_server::SendBytes(const std::shared_ptr<RTTYS_EndPoint> & Conn, const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len) {
Conn->tx += len;
return Socket.impl()->sendBytes(buffer,len);
}
@@ -318,14 +309,14 @@ namespace OpenWifi {
}
bool RTTYS_server::do_msgTypeRegister(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeRegister(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &Buffer, [[maybe_unused]] std::size_t msg_len) {
bool good = true;
try {
auto fd = Socket.impl()->sockfd();
std::string id_ = ReadString(Buffer, BufferCurrentSize, BufferPos);
std::string desc_ = ReadString(Buffer, BufferCurrentSize, BufferPos);
std::string token_ = ReadString(Buffer, BufferCurrentSize, BufferPos);
std::string id_ = ReadString(Buffer);
std::string desc_ = ReadString(Buffer);
std::string token_ = ReadString(Buffer);
poco_information(Logger(),fmt::format("Device registration: description:{} id:{} token:{}", desc_, id_, token_));
if (id_.size() != RTTY_DEVICE_TOKEN_LENGTH ||
@@ -380,7 +371,7 @@ namespace OpenWifi {
OutBuf[5] = 'K';
OutBuf[6] = 0;
if (SendBytes(Socket,OutBuf, 7) != 7) {
if (SendBytes(ConnectionEp,Socket,OutBuf, 7) != 7) {
poco_error(
Logger(),
fmt::format("{}: Description:{} Could not send data to complete registration",
@@ -418,19 +409,42 @@ namespace OpenWifi {
}
}
void RTTYS_server::EmptyBuffer(int fd, const std::uint8_t *buffer, std::size_t len) {
auto EndPoint = Connected_.find(fd);
if (EndPoint!=end(Connected_) && EndPoint->second->WSSocket_!= nullptr && EndPoint->second->WSSocket_->impl() != nullptr) {
SendToClient(*EndPoint->second->WSSocket_, buffer,
len);
EndPoint->second->rx += len;
// std::cout << "Total: " << EndPoint->second->rx << " bytes now: " << len << std::endl;
}
}
void RTTYS_server::onConnectedDeviceSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
std::shared_ptr<RTTYS_EndPoint> ConnectionPtr;
std::lock_guard Lock(ServerMutex_);
int fd = pNf->socket().impl()->sockfd();
try {
unsigned char Buffer[RTTY_RECEIVE_BUFFER];
std::size_t BufferCurrentSize=0, BufferPos=0;
auto hint = Sockets_.find(fd);
if(hint==end(Sockets_)) {
poco_error(Logger(),fmt::format("{}: unknown socket",fd));
return;
}
Poco::FIFOBuffer &buffer = *hint->second->buffer;
int received_bytes=0;
std::uint8_t agg_buffer[RTTY_RECEIVE_BUFFER];
std::size_t agg_buf_pos=0;
try {
BufferCurrentSize = pNf->socket().impl()->receiveBytes(Buffer, sizeof(Buffer));
if(BufferCurrentSize==0) {
// std::cout << "Available: " << buffer.available() << " ";
Poco::Timespan TS(5,0);
received_bytes = hint->second->socket.receiveBytes(buffer);
if(received_bytes==0) {
// std::cout << hint->second->socket.lastError() << std::endl;
poco_warning(Logger(), "Device Closing connection - 0 bytes received.");
EndConnection( pNf->socket(), __func__, __LINE__ );
return;
@@ -447,52 +461,68 @@ namespace OpenWifi {
bool good = true;
while (BufferPos<BufferCurrentSize && good) {
unsigned char LastCommand=0;
std::uint16_t msg_len = 0;
if (BufferCurrentSize >= RTTY_HDR_SIZE) {
LastCommand = Buffer[BufferPos+0];
msg_len = (Buffer[BufferPos+1] << 8) + Buffer[BufferPos+2];
BufferPos+=RTTY_HDR_SIZE;
} else {
good = false;
std::cout << "Funky..." << BufferCurrentSize << std::endl;
continue;
while (!buffer.isEmpty() && good) {
if(buffer.used() < RTTY_HDR_SIZE) {
if(agg_buf_pos>0) {
EmptyBuffer(fd, agg_buffer, agg_buf_pos);
}
// poco_debug(Logger(),fmt::format("Not enough data in the pipe for header",buffer.used()));
return;
}
std::uint8_t header[RTTY_HDR_SIZE];
buffer.peek((char*)header,RTTY_HDR_SIZE);
std::uint8_t LastCommand = header[0];
std::uint16_t msg_len = (header[1] << 8) + header[2];
if(buffer.used()<(RTTY_HDR_SIZE+msg_len)) {
if(agg_buf_pos>0) {
EmptyBuffer(fd, agg_buffer, agg_buf_pos);
}
// poco_debug(Logger(),fmt::format("Not enough data in the pipe for command data",buffer.used()));
return;
}
// std::cout << line++ << " Available: " << buffer.available() << " Cmd: " << (int) LastCommand << " Received: " << received_bytes
// << " MsgLen: " << msg_len << " Data in buffer: " << buffer.used() << std::endl;
buffer.drain(RTTY_HDR_SIZE);
switch (LastCommand) {
case RTTYS_EndPoint::msgTypeRegister: {
good = do_msgTypeRegister(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeRegister(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeLogin: {
good = do_msgTypeLogin(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeLogin(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeLogout: {
good = do_msgTypeLogout(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeLogout(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeTermData: {
good = do_msgTypeTermData(pNf->socket(), Buffer, BufferCurrentSize, BufferPos, msg_len);
good = do_msgTypeTermData(pNf->socket(), buffer, msg_len, agg_buffer, agg_buf_pos);
} break;
case RTTYS_EndPoint::msgTypeWinsize: {
good = do_msgTypeWinsize(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeWinsize(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeCmd: {
good = do_msgTypeCmd(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeCmd(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeHeartbeat: {
good = do_msgTypeHeartbeat(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeHeartbeat(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeFile: {
good = do_msgTypeFile(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeFile(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeHttp: {
good = do_msgTypeHttp(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeHttp(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeAck: {
good = do_msgTypeAck(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeAck(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeMax: {
good = do_msgTypeMax(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
good = do_msgTypeMax(pNf->socket(), buffer, msg_len);
} break;
default: {
poco_warning(Logger(),
@@ -503,6 +533,12 @@ namespace OpenWifi {
}
}
if(agg_buf_pos>0) {
EmptyBuffer(fd, agg_buffer, agg_buf_pos);
}
// std::cout << "Empty: " << buffer.isEmpty() << std::endl;
if (!good) {
EndConnection(pNf->socket(), __func__, __LINE__);
}
@@ -687,14 +723,20 @@ namespace OpenWifi {
return;
}
// OK Create and register this WS client
try {
// EndPoint->second->WSSocket_ = std::make_unique<Poco::Net::WebSocket>(request, response);
EndPoint->second->WSSocket_ = std::make_unique<Poco::Net::WebSocket>(request, response);
EndPoint->second->ClientConnected_ = std::chrono::high_resolution_clock::now();
EndPoint->second->WSSocket_->setBlocking(false);
EndPoint->second->WSSocket_->setNoDelay(true);
EndPoint->second->WSSocket_->setNoDelay(false);
EndPoint->second->WSSocket_->setKeepAlive(true);
Poco::Timespan ST(600,0);
EndPoint->second->WSSocket_->setSendTimeout(ST);
EndPoint->second->WSSocket_->setSendBufferSize(1000000);
EndPoint->second->WSSocket_->setReceiveTimeout(ST);
EndPoint->second->WSSocket_->setReceiveBufferSize(1000000);
AddClientEventHandlers(*EndPoint->second->WSSocket_, EndPoint->second);
if (EndPoint->second->DeviceIsAttached_ && !EndPoint->second->completed_) {
poco_information(Logger(),fmt::format("CLN{}: Device registered, Client Registered - sending login", EndPoint->second->SerialNumber_));
@@ -777,9 +819,8 @@ namespace OpenWifi {
} else {
EndPoints_.erase(hint->second->Id_);
}
} else {
std::cout << "Cannot find the associated WS..." << std::endl;
}
poco_debug(Logger(),fmt::format("Closing connection at {}:{}", func, Line));
}
@@ -823,7 +864,7 @@ namespace OpenWifi {
Conn->small_buf_[3] = Conn->sid_;
memcpy(&Conn->small_buf_[RTTY_HDR_SIZE + 1], &buf[1], len - 1);
try {
auto Sent = SendBytes(Conn->DeviceSocket_, Conn->small_buf_,
auto Sent = SendBytes(Conn,Conn->DeviceSocket_, Conn->small_buf_,
RTTY_HDR_SIZE + 1 + len - 1);
return (Sent == (int)(RTTY_HDR_SIZE + 1 + len - 1));
} catch (const Poco::Exception &E) {
@@ -841,7 +882,7 @@ namespace OpenWifi {
Msg.get()[3] = Conn->sid_;
memcpy((Msg.get() + RTTY_HDR_SIZE + 1), &buf[1], len - 1);
try {
auto Sent = SendBytes(Conn->DeviceSocket_,Msg.get(),
auto Sent = SendBytes(Conn,Conn->DeviceSocket_,Msg.get(),
RTTY_HDR_SIZE + 1 + len - 1);
return (Sent == (int)(RTTY_HDR_SIZE + 1 + len - 1));
} catch (const Poco::Exception &E) {
@@ -866,7 +907,7 @@ namespace OpenWifi {
outBuf[RTTY_HDR_SIZE + 2 + 1] = rows >> 8;
outBuf[RTTY_HDR_SIZE + 3 + 1] = rows & 0x00ff;
try {
auto Sent = SendBytes(Conn->DeviceSocket_, outBuf, RTTY_HDR_SIZE + 4 + 1);
auto Sent = SendBytes(Conn,Conn->DeviceSocket_, outBuf, RTTY_HDR_SIZE + 4 + 1);
return (Sent == (int)(RTTY_HDR_SIZE + 4 + 1));
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -884,7 +925,7 @@ namespace OpenWifi {
outBuf[2] = 0;
try {
poco_debug(Logger(), fmt::format("TID:{} Starting login on device.",Conn->TID_));
auto Sent = SendBytes(Socket,outBuf,RTTY_HDR_SIZE);
auto Sent = SendBytes(Conn,Socket,outBuf,RTTY_HDR_SIZE);
Conn->completed_ = true;
return Sent == RTTY_HDR_SIZE;
} catch (const Poco::Exception &E) {
@@ -903,7 +944,7 @@ namespace OpenWifi {
outBuf[3] = Conn->sid_;
poco_debug(Logger(), fmt::format("{}: Logout", Conn->TID_));
try {
auto Sent = SendBytes(Socket, outBuf, RTTY_HDR_SIZE + 1);
auto Sent = SendBytes(Conn,Socket, outBuf, RTTY_HDR_SIZE + 1);
return Sent == (int)(RTTY_HDR_SIZE + 1);
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -927,6 +968,20 @@ namespace OpenWifi {
return Res;
}
std::string RTTYS_server::ReadString(Poco::FIFOBuffer &Buffer) {
std::string Res;
while(Buffer.isReadable()) {
auto c = *Buffer.begin();
if(c==0) {
Buffer.drain(1);
break;
}
Res += c;
Buffer.drain(1);
}
return Res;
}
bool RTTYS_server::SendToClient(Poco::Net::WebSocket &WebSocket, const u_char *Buf, int len) {
WebSocket.sendFrame(
Buf, len, Poco::Net::WebSocket::FRAME_FLAG_FIN | Poco::Net::WebSocket::FRAME_OP_BINARY);
@@ -938,15 +993,17 @@ namespace OpenWifi {
return true;
}
bool RTTYS_server::do_msgTypeLogin(const Poco::Net::Socket &Socket, unsigned char *Buffer, [[maybe_unused]] std::size_t BufferCurrentSize, std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeLogin(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, [[maybe_unused]] std::size_t msg_len) {
poco_debug(Logger(), "Asking for login");
auto EndPoint = Connected_.find(Socket.impl()->sockfd());
if (EndPoint!=end(Connected_) && EndPoint->second->WSSocket_!= nullptr && EndPoint->second->WSSocket_->impl() != nullptr) {
try {
nlohmann::json doc;
unsigned char Error = Buffer[BufferPos++];
unsigned char Error = *buffer.begin();
buffer.drain(1);
if(Error==0) {
EndPoint->second->sid_ = Buffer[BufferPos++];
EndPoint->second->sid_ = *buffer.begin();
buffer.drain(1);
} else {
poco_error(Logger(),"Device login failed.");
return false;
@@ -964,85 +1021,86 @@ namespace OpenWifi {
return false;
}
bool RTTYS_server::do_msgTypeLogout([[maybe_unused]] const Poco::Net::Socket &Socket, unsigned char *Buffer, [[maybe_unused]] std::size_t BufferCurrentSize, std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeLogout([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
poco_debug(Logger(), "Logout");
[[maybe_unused]] unsigned char logout_session_id = Buffer[BufferPos++];
// [[maybe_unused]] unsigned char logout_session_id = Buffer[BufferPos];
buffer.drain(msg_len);
return false;
}
bool RTTYS_server::do_msgTypeTermData(const Poco::Net::Socket &Socket, unsigned char *Buffer, [[maybe_unused]] std::size_t BufferCurrentSize, std::size_t &BufferPos, std::size_t msg_len) {
bool RTTYS_server::do_msgTypeTermData(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len, std::uint8_t *buf, std::size_t &pos) {
auto EndPoint = Connected_.find(Socket.impl()->sockfd());
if (EndPoint!=end(Connected_) && EndPoint->second->WSSocket_!= nullptr && EndPoint->second->WSSocket_->impl() != nullptr) {
try {
BufferPos++;
buffer.drain(1);
msg_len--;
auto good = SendToClient(*EndPoint->second->WSSocket_, &Buffer[BufferPos], (int) msg_len );
BufferPos += msg_len;
return good;
buffer.read((char*)&(buf[pos]),msg_len);
pos+=msg_len;
// auto good = SendToClient(*EndPoint->second->WSSocket_, (unsigned char*) buffer.begin(), (int) msg_len );
// buffer.drain(msg_len);
return true;
} catch (const Poco::Exception &E) {
std::cout << "Failed to send WS stuff" << std::endl;
Logger().log(E);
return false;
} catch (const std::exception &E) {
LogStdException(E, "Cannot send data to UI Client");
return false;
}
}
return false;
}
bool RTTYS_server::do_msgTypeWinsize([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer,[[maybe_unused]] std::size_t BufferCurrentSize, [[maybe_unused]] std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeWinsize([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
poco_debug(Logger(), "Asking for msgTypeWinsize");
BufferPos = BufferCurrentSize;
buffer.drain(msg_len);
return true;
}
bool RTTYS_server::do_msgTypeCmd([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer,[[maybe_unused]] std::size_t BufferCurrentSize, [[maybe_unused]] std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeCmd([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
poco_debug(Logger(), "Asking for msgTypeCmd");
BufferPos = BufferCurrentSize;
buffer.drain(msg_len);
return true;
}
bool RTTYS_server::do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, [[maybe_unused]] Poco::FIFOBuffer &buffer, [[maybe_unused]] std::size_t msg_len) {
try {
u_char MsgBuf[RTTY_HDR_SIZE + 16]{0};
BufferPos = BufferCurrentSize;
MsgBuf[0] = RTTYS_EndPoint::msgTypeHeartbeat;
MsgBuf[1] = 0;
MsgBuf[2] = 0;
auto Sent = SendBytes(Socket,MsgBuf, RTTY_HDR_SIZE);
return Sent == RTTY_HDR_SIZE;
auto hint = Connected_.find(Socket.impl()->sockfd());
if(hint!=end(Connected_)) {
auto Sent = SendBytes(hint->second,Socket, MsgBuf, RTTY_HDR_SIZE);
return Sent == RTTY_HDR_SIZE;
}
} catch (const Poco::Exception &E) {
Logger().log(E);
return false;
} catch (const std::exception &E) {
LogStdException(E, "Cannot send heartbeat");
return false;
}
return false;
}
bool RTTYS_server::do_msgTypeFile([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeFile([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
poco_debug(Logger(), "Asking for msgTypeFile");
BufferPos = BufferCurrentSize;
buffer.drain(msg_len);
return true;
}
bool RTTYS_server::do_msgTypeHttp([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeHttp([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
poco_debug(Logger(), "Asking for msgTypeHttp");
BufferPos = BufferCurrentSize;
buffer.drain(msg_len);
return true;
}
bool RTTYS_server::do_msgTypeAck([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
bool RTTYS_server::do_msgTypeAck([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
poco_debug(Logger(), "Asking for msgTypeAck");
BufferPos = BufferCurrentSize;
buffer.drain(msg_len);
return true;
}
bool RTTYS_server::do_msgTypeMax([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
BufferPos = BufferCurrentSize;
bool RTTYS_server::do_msgTypeMax([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
poco_debug(Logger(), "Asking for msgTypeMax");
buffer.drain(msg_len);
return true;
}

View File

@@ -13,6 +13,7 @@
#include "Poco/Net/WebSocket.h"
#include "Poco/NotificationQueue.h"
#include "Poco/Timer.h"
#include <Poco/FIFOBuffer.h>
#include "framework/SubSystemServer.h"
#include "framework/utils.h"
@@ -25,7 +26,7 @@ namespace OpenWifi {
constexpr uint RTTY_DEVICE_TOKEN_LENGTH = 32;
constexpr std::size_t RTTY_SESSION_ID_LENGTH = 32;
constexpr std::size_t RTTY_HDR_SIZE = 3;
constexpr std::size_t RTTY_RECEIVE_BUFFER = 64000;
constexpr std::size_t RTTY_RECEIVE_BUFFER = 1024 << 10;
class RTTYS_server;
@@ -114,6 +115,7 @@ namespace OpenWifi {
std::chrono::time_point<std::chrono::high_resolution_clock> Created_{0s},
DeviceDisconnected_{0s}, ClientDisconnected_{0s}, DeviceConnected_{0s},
ClientConnected_{0s};
std::uint64_t rx=0,tx=0;
};
class RTTYS_server : public SubSystemServer {
@@ -129,6 +131,21 @@ namespace OpenWifi {
bool valid=false;
std::string cid;
std::string cn;
std::unique_ptr<Poco::FIFOBuffer> buffer;
SecureSocketPair(Poco::Net::StreamSocket &S,
std::unique_ptr<Poco::Crypto::X509Certificate> Cert,
bool Valid,
const std::string & Cid,
const std::string & CN) :
socket(S),
cert(std::move(Cert)),
valid(Valid),
cid(Cid),
cn(CN)
{
buffer = std::make_unique<Poco::FIFOBuffer>(RTTY_RECEIVE_BUFFER);
}
};
int Start() final;
@@ -184,8 +201,8 @@ namespace OpenWifi {
void SendData(std::shared_ptr<RTTYS_EndPoint> &Connection, const u_char *Buf, size_t len);
void SendData(std::shared_ptr<RTTYS_EndPoint> &Connection, const std::string &s);
int SendBytes(int fd, const unsigned char *buffer, std::size_t len);
int SendBytes(const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len);
// int SendBytes(int fd, const unsigned char *buffer, std::size_t len);
int SendBytes(const std::shared_ptr<RTTYS_EndPoint> & Conn,const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len);
std::shared_ptr<RTTYS_EndPoint> FindRegisteredEndPoint(const std::string &Id,
const std::string &Token);
@@ -194,18 +211,19 @@ namespace OpenWifi {
void RemoveSocket(const Poco::Net::Socket &Socket);
void LogStdException(const std::exception &E, const std::string & msg);
bool do_msgTypeRegister(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeLogin(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeTermData(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos, std::size_t msl_len);
bool do_msgTypeLogout(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeWinsize(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeCmd(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeFile(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeHttp(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeAck(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeMax(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
bool do_msgTypeRegister(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeLogin(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeTermData(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len, std::uint8_t *buf, std::size_t &pos);
bool do_msgTypeLogout(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeWinsize(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeCmd(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeFile(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeHttp(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeAck(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
bool do_msgTypeMax(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
void EmptyBuffer(int fd, const std::uint8_t *buffer, std::size_t len);
bool WindowSize(std::shared_ptr<RTTYS_EndPoint> Conn, int cols, int rows);
bool KeyStrokes(std::shared_ptr<RTTYS_EndPoint> Conn, const u_char *buf, size_t len);
@@ -213,6 +231,7 @@ namespace OpenWifi {
bool Logout(const Poco::Net::Socket &Socket, std::shared_ptr<RTTYS_EndPoint> Conn);
std::string ReadString(unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
std::string ReadString(Poco::FIFOBuffer &Buffer);
bool SendToClient(Poco::Net::WebSocket &WebSocket, const u_char *Buf, int len);
bool SendToClient(Poco::Net::WebSocket &WebSocket, const std::string &s);

View File

@@ -51,7 +51,10 @@ namespace OpenWifi {
"pendingConfiguration, "
"pendingConfigurationCmd, "
"restrictionDetails, "
"pendingUUID"};
"pendingUUID, "
"simulated,"
"lastRecordedContact"
};
const static std::string DB_DeviceUpdateFields{"SerialNumber=?,"
"DeviceType=?, "
@@ -79,16 +82,18 @@ namespace OpenWifi {
"pendingConfiguration=?, "
"pendingConfigurationCmd=?, "
"restrictionDetails=?, "
"pendingUUID=?"};
"pendingUUID=?, "
"simulated=?,"
"lastRecordedContact=? "};
const static std::string DB_DeviceInsertValues{
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
typedef Poco::Tuple<std::string, std::string, std::string, std::string, std::string,
std::string, std::string, std::string, std::string, std::string,
std::string, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, std::string,
std::string, std::string, std::string, uint64_t, std::string, bool,
std::string, std::string, std::string, std::uint64_t>
std::string, std::string, std::string, std::uint64_t, bool, std::uint64_t>
DeviceRecordTuple;
typedef std::vector<DeviceRecordTuple> DeviceRecordList;
@@ -121,6 +126,8 @@ namespace OpenWifi {
D.restrictionDetails =
RESTAPI_utils::to_object<OpenWifi::GWObjects::DeviceRestrictions>(R.get<25>());
D.pendingUUID = R.get<26>();
D.simulated = R.get<27>();
D.lastRecordedContact = R.get<28>();
}
void ConvertDeviceRecord(const GWObjects::Device &D, DeviceRecordTuple &R) {
@@ -151,6 +158,8 @@ namespace OpenWifi {
R.set<24>(D.pendingConfigurationCmd);
R.set<25>(RESTAPI_utils::to_string(D.restrictionDetails));
R.set<26>(D.pendingUUID);
R.set<27>(D.simulated);
R.set<28>(D.lastRecordedContact);
}
bool Storage::GetDeviceCount(uint64_t &Count) {
@@ -347,6 +356,23 @@ namespace OpenWifi {
return false;
}
bool Storage::SetDeviceLastRecordedContact(std::string &SerialNumber, std::uint64_t lastRecordedContact) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Update(Sess);
std::string St{"UPDATE Devices SET lastRecordedContact=? WHERE SerialNumber=?"};
Update << ConvertParams(St), Poco::Data::Keywords::use(lastRecordedContact),
Poco::Data::Keywords::use(SerialNumber);
Update.execute();
return true;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
return false;
}
bool Storage::CreateDevice(GWObjects::Device &DeviceDetails) {
std::string SerialNumber;
try {
@@ -425,7 +451,8 @@ namespace OpenWifi {
bool Storage::CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
std::string &Firmware,
const Poco::Net::IPAddress &IPAddress) {
const Poco::Net::IPAddress &IPAddress,
bool simulated) {
GWObjects::Device D;
poco_information(Logger(), fmt::format("AUTO-CREATION({})", SerialNumber));
@@ -468,6 +495,7 @@ namespace OpenWifi {
D.MACAddress = Utils::SerialToMAC(SerialNumber);
D.Manufacturer = Caps.Model();
D.Firmware = Firmware;
D.simulated = simulated;
D.Notes = SecurityObjects::NoteInfoVec{
SecurityObjects::NoteInfo{(uint64_t)Utils::Now(), "", "Auto-provisioned."}};
@@ -540,17 +568,17 @@ namespace OpenWifi {
bool Storage::DeleteDevice(std::string &SerialNumber) {
try {
std::vector<std::string> DBList{"Devices", "Statistics", "CommandList",
std::vector<std::string> TableNames{"Devices", "Statistics", "CommandList",
"HealthChecks", "Capabilities", "DeviceLogs"};
for (const auto &i : DBList) {
for (const auto &tableName : TableNames) {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
std::string St{"DELETE FROM " + i + " WHERE SerialNumber=?"};
std::string St = fmt::format("DELETE FROM {} WHERE SerialNumber='{}'", tableName, SerialNumber);
try {
Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber);
Delete << St;
Delete.execute();
} catch (...) {
}
@@ -564,7 +592,7 @@ namespace OpenWifi {
Message.set("timestamp", Utils::Now());
std::ostringstream StrPayload;
Message.stringify(StrPayload);
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, StrPayload.str());
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, std::make_shared<std::string>(StrPayload.str()));
}
return true;
@@ -574,6 +602,58 @@ namespace OpenWifi {
return false;
}
static void DeleteDeviceList(std::vector<std::string> &SerialNumbers, Poco::Logger &Logger) {
for (auto &serialNumber:SerialNumbers) {
poco_information(Logger,fmt::format("BATCH-DEVICE_DELETE: deleting {}", serialNumber));
StorageService()->DeleteDevice(serialNumber);
}
}
bool Storage::DeleteDevices(std::string &SerialPattern, bool SimulatedOnly) {
try {
std::vector<std::string> SerialNumbers;
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement GetSerialNumbers(Sess);
std::string SelectStatement = SimulatedOnly ?
fmt::format("SELECT SerialNumber FROM Devices WHERE simulated and SerialNumber LIKE '{}' limit 10000",SerialPattern) :
fmt::format("SELECT SerialNumber FROM Devices WHERE SerialNumber LIKE '{}' limit 10000", SerialPattern);
GetSerialNumbers << SelectStatement,
Poco::Data::Keywords::into(SerialNumbers);
GetSerialNumbers.execute();
poco_information(Logger(),fmt::format("BATCH-DEVICE_DELETE: Found {} devices that match the criteria {} to delete.", SerialNumbers.size(), SerialPattern));
DeleteDeviceList(SerialNumbers, Logger());
return true;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
return false;
}
bool Storage::DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly) {
try {
std::vector<std::string> SerialNumbers;
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement GetSerialNumbers(Sess);
std::string SelectStatement = SimulatedOnly ?
fmt::format("SELECT SerialNumber FROM Devices WHERE simulated and lastRecordedContact!=0 and lastRecordedContact<{} limit 10000",OlderContact) :
fmt::format("SELECT SerialNumber FROM Devices lastRecordedContact>0 and lastRecordedContact<{} limit 10000",OlderContact);
GetSerialNumbers << SelectStatement,
Poco::Data::Keywords::into(SerialNumbers);
GetSerialNumbers.execute();
poco_information(Logger(),fmt::format("BATCH-DEVICE_DELETE: Found {} devices that match with lastRecordedContact older than {} to delete.", SerialNumbers.size(), OlderContact));
DeleteDeviceList(SerialNumbers, Logger());
return true;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
return false;
}
bool Storage::GetDevice(std::string &SerialNumber, GWObjects::Device &DeviceDetails) {
try {
Poco::Data::Session Sess = Pool_->get();
@@ -746,6 +826,8 @@ namespace OpenWifi {
return "serial mismatch";
case GWObjects::VERIFIED:
return "verified";
case GWObjects::SIMULATED:
return "simulated";
}
return "unknown";
}

View File

@@ -87,7 +87,9 @@ namespace OpenWifi {
"pendingConfiguration TEXT, "
"pendingConfigurationCmd VARCHAR(64), "
"restrictionDetails TEXT, "
"pendingUUID BIGINT "
"pendingUUID BIGINT, "
"simulated BOOLEAN,"
"lastRecordedContact BIGINT"
",INDEX DeviceOwner (Owner ASC),"
"INDEX LocationIndex (Location ASC))",
Poco::Data::Keywords::now;
@@ -119,7 +121,9 @@ namespace OpenWifi {
"pendingConfiguration TEXT,"
"pendingConfigurationCmd VARCHAR(64), "
"restrictionDetails TEXT,"
"pendingUUID BIGINT "
"pendingUUID BIGINT, "
"simulated BOOLEAN, "
"lastRecordedContact BIGINT"
")",
Poco::Data::Keywords::now;
Sess << "CREATE INDEX IF NOT EXISTS DeviceOwner ON Devices (Owner ASC)",
@@ -138,7 +142,10 @@ namespace OpenWifi {
"alter table devices add column pendingConfiguration TEXT",
"alter table devices add column pendingConfigurationCmd VARCHAR(64)",
"alter table devices add column restrictionDetails TEXT",
"alter table devices add column pendingUUID bigint"};
"alter table devices add column pendingUUID bigint",
"alter table devices add column lastRecordedContact bigint",
"alter table devices add column simulated boolean"
};
for (const auto &i : Script) {
try {

View File

@@ -175,6 +175,22 @@ listdevices() {
jq < ${result_file}
}
deletesimdevices() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?simulatedOnly=true&macPattern=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
deletebulkdevices() {
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?macPattern=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
listdevicesk() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices" \
-H "Content-Type: application/json" \
@@ -842,6 +858,48 @@ regulatory_reload() {
jq < ${result_file}
}
radiussessions() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiussearch() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?userName=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiussearchmac() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?mac=$1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiusaps() {
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?serialNumberOnly=true" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
jq < ${result_file}
}
radiuscoadm() {
payload="$(printf '{ "accountingSessionId": "%s", "accountingMultiSessionId": "%s" , "callingStationId": "%s" }' "$2" "$3" "$4" )"
curl ${FLAGS} -X PUT "https://${OWGW}/api/v1/radiusSessions/$1?operation=coadm" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${token}" \
-d "$payload" > ${result_file}
jq < ${result_file}
}
check_response() {
if [ -s "$1" ]; then
@@ -1118,7 +1176,14 @@ case "$1" in
"regulatory") login; regulatory "$2"; logout;;
"regulatory_reload") login; regulatory_reload; logout;;
"gethealthrange") login; gethealthrange "$2" "$3"; logout;;
"radiussessions") login; radiussessions $2; logout;;
"radiusaps") login; radiusaps ; logout;;
"radiuscoadm") login; radiuscoadm "$2" "$3" "$4" "$5"; logout;;
"radiussearch") login; radiussearch "$2"; logout;;
"radiussearchmac") login; radiussearchmac "$2"; logout;;
"deletesimdevices") login; deletesimdevices "$2"; logout;;
"deletebulkdevices") login; deletebulkdevices "$2"; logout;;
"testtoken") testtoken;;
*) help ;;
*) help ;;
esac