mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-12-24 22:37:04 +00:00
Compare commits
438 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17fe350d8c | ||
|
|
73e4f0df94 | ||
|
|
702d863e6b | ||
|
|
c31ea8f632 | ||
|
|
82688aa4ca | ||
|
|
96e6ebdfa1 | ||
|
|
986cb57389 | ||
|
|
a39efd3204 | ||
|
|
350eeca6ec | ||
|
|
33d908db96 | ||
|
|
aa39497793 | ||
|
|
20cdc999f3 | ||
|
|
5cbf25260d | ||
|
|
9c9e6cb593 | ||
|
|
81fa16fb9c | ||
|
|
82e877393d | ||
|
|
02320b616a | ||
|
|
bf1137a99b | ||
|
|
5e2d3e7c81 | ||
|
|
61ab1f7904 | ||
|
|
d6a61c45ec | ||
|
|
f6e7693e39 | ||
|
|
0e605f9ada | ||
|
|
613a2adfca | ||
|
|
8955c614a8 | ||
|
|
1685aefda3 | ||
|
|
3a70f669ee | ||
|
|
57771f411a | ||
|
|
22df3fb8ef | ||
|
|
ea369afabf | ||
|
|
4a450269f5 | ||
|
|
e44bb3199c | ||
|
|
eee680686f | ||
|
|
0e9b13f2b3 | ||
|
|
117f24e0b6 | ||
|
|
f639710d38 | ||
|
|
6d59b45e6f | ||
|
|
540205763c | ||
|
|
ec450c30e5 | ||
|
|
ef9902c75a | ||
|
|
9384bed03d | ||
|
|
29e61bf432 | ||
|
|
510e56518a | ||
|
|
82004e3f2e | ||
|
|
2620baca91 | ||
|
|
f105b9386c | ||
|
|
24dffe09a4 | ||
|
|
c2c37ad0d2 | ||
|
|
5a306f1a70 | ||
|
|
629a3b390b | ||
|
|
3b5b9636f3 | ||
|
|
8e125732b3 | ||
|
|
8e0ae5f6c8 | ||
|
|
45a4211793 | ||
|
|
68e85d8c5a | ||
|
|
61deb1f589 | ||
|
|
a1df232de9 | ||
|
|
3ac0875b83 | ||
|
|
94f4930bd7 | ||
|
|
0bc515e3ab | ||
|
|
81e49026f8 | ||
|
|
1ae68019d3 | ||
|
|
2e316478d7 | ||
|
|
6c23a969d0 | ||
|
|
8e900aea69 | ||
|
|
16c32e53bd | ||
|
|
fb15504294 | ||
|
|
8357cd76ed | ||
|
|
716d3755fe | ||
|
|
3299aadf57 | ||
|
|
71ed6c90d1 | ||
|
|
f45b2baa4b | ||
|
|
e00aa23775 | ||
|
|
83c9476720 | ||
|
|
18d9947c0e | ||
|
|
3de2dd1931 | ||
|
|
847648f1ee | ||
|
|
d77a4a6bb9 | ||
|
|
05767cc1a7 | ||
|
|
0e5c7ef5c6 | ||
|
|
bc6773ac28 | ||
|
|
d39574aa22 | ||
|
|
b6795a4f04 | ||
|
|
b8fe03c74d | ||
|
|
47b182e481 | ||
|
|
f680135e53 | ||
|
|
f3aecbd034 | ||
|
|
15776c01ac | ||
|
|
8fc342770b | ||
|
|
27c1bbeb20 | ||
|
|
a4bb7a1c0e | ||
|
|
89134305e8 | ||
|
|
f7b4fe84e1 | ||
|
|
2c29200bbf | ||
|
|
1e2728423a | ||
|
|
24c9283a55 | ||
|
|
92e1afedfb | ||
|
|
b86f06b818 | ||
|
|
2f3a0cc756 | ||
|
|
713cd01b6b | ||
|
|
888cc94709 | ||
|
|
0926f57391 | ||
|
|
78396d28d7 | ||
|
|
9edcd5a330 | ||
|
|
dc9a04dbc3 | ||
|
|
1d675067fe | ||
|
|
f69bc3434a | ||
|
|
17c8d5ceaf | ||
|
|
caf133b6a2 | ||
|
|
dcfdb6d242 | ||
|
|
40535390b1 | ||
|
|
b86d7425ac | ||
|
|
907803eafa | ||
|
|
050a3e3584 | ||
|
|
1052bbee57 | ||
|
|
16a970feb3 | ||
|
|
a185377258 | ||
|
|
0871045b3c | ||
|
|
4e2b1e4ecc | ||
|
|
b3f7b16f30 | ||
|
|
2b7d96728b | ||
|
|
13e5eab8f4 | ||
|
|
fd3fbb3dbf | ||
|
|
7abd8af2e6 | ||
|
|
3d97f5a9e3 | ||
|
|
d70ed3cae2 | ||
|
|
814fe872f6 | ||
|
|
354f0057c1 | ||
|
|
390e050801 | ||
|
|
f8a157ddbe | ||
|
|
8d4abd42ec | ||
|
|
4a82af2bcd | ||
|
|
bfeb9f64e2 | ||
|
|
6678669188 | ||
|
|
afe989205f | ||
|
|
5955e2e845 | ||
|
|
2500dfdd80 | ||
|
|
cfa496653f | ||
|
|
e4b9920b56 | ||
|
|
ec156c203e | ||
|
|
13fd91b135 | ||
|
|
123a638080 | ||
|
|
c165a1d3de | ||
|
|
40d2cdf1b3 | ||
|
|
565199df70 | ||
|
|
c9599c3d86 | ||
|
|
988c90643d | ||
|
|
62951a502c | ||
|
|
05ec034f7a | ||
|
|
4e5bf7929c | ||
|
|
e39149337c | ||
|
|
d14da5612b | ||
|
|
e42852297d | ||
|
|
1501e0f037 | ||
|
|
2d3fd0b736 | ||
|
|
17a77ba02b | ||
|
|
2541e25ee6 | ||
|
|
7799b3f904 | ||
|
|
1762fdc859 | ||
|
|
339ce4734b | ||
|
|
3f6b469c3c | ||
|
|
442f614f1b | ||
|
|
2be63c60ee | ||
|
|
039cf7a83f | ||
|
|
0b502b9f8f | ||
|
|
a77fec4475 | ||
|
|
dfa9a09ded | ||
|
|
40f9d2d4fb | ||
|
|
1da30b61ef | ||
|
|
175fab0eb5 | ||
|
|
b311fbe44d | ||
|
|
636b82c28d | ||
|
|
183f06e5fa | ||
|
|
ac7d4ef048 | ||
|
|
0c5087960e | ||
|
|
e4be8c84f3 | ||
|
|
ce93663cb5 | ||
|
|
952442b32d | ||
|
|
e06f367eb9 | ||
|
|
c0bab98714 | ||
|
|
616f3864fb | ||
|
|
5f3974aac7 | ||
|
|
98a4bfc6c5 | ||
|
|
a518f13a2d | ||
|
|
981f6f7e6d | ||
|
|
253982a63f | ||
|
|
03e342a24d | ||
|
|
7b9db4bf4d | ||
|
|
fc92130fa4 | ||
|
|
e6d56fec79 | ||
|
|
c3094ce73b | ||
|
|
330577edb0 | ||
|
|
de6d5288f4 | ||
|
|
6e96e8bc9a | ||
|
|
10f8638d73 | ||
|
|
0b25e94a68 | ||
|
|
3d769634c6 | ||
|
|
17f8ca60cf | ||
|
|
544577bad8 | ||
|
|
24a0035ac0 | ||
|
|
cdea03bbb2 | ||
|
|
2783809ae9 | ||
|
|
565c05b4f3 | ||
|
|
e1d90f8ea3 | ||
|
|
60321902ec | ||
|
|
9ac0995fd4 | ||
|
|
00551fae2c | ||
|
|
42c937848d | ||
|
|
f0d63c69c1 | ||
|
|
d09f980a64 | ||
|
|
f09a8bd0fe | ||
|
|
7dcc8cabbb | ||
|
|
a816e0d1c1 | ||
|
|
01b3daa051 | ||
|
|
2bf9bb8935 | ||
|
|
218a49cb95 | ||
|
|
66ea0cf308 | ||
|
|
99a77cdcc4 | ||
|
|
b021d80300 | ||
|
|
798c40df23 | ||
|
|
d95007fae1 | ||
|
|
2745f1cfa0 | ||
|
|
9f7b78d0f1 | ||
|
|
91b0c95101 | ||
|
|
6d193699c1 | ||
|
|
a63cd8bb7b | ||
|
|
599c8d6fd3 | ||
|
|
305ea52737 | ||
|
|
7f26d8d49e | ||
|
|
09dbad5e05 | ||
|
|
de20856cc1 | ||
|
|
5c1e7f97dd | ||
|
|
ee9fdc8d1a | ||
|
|
c5269a9a3c | ||
|
|
79599e9b06 | ||
|
|
dd47234b4e | ||
|
|
9f14dc8196 | ||
|
|
286d313e69 | ||
|
|
e69f2cabf1 | ||
|
|
246c4dc8f2 | ||
|
|
7d7a12a903 | ||
|
|
69809eb243 | ||
|
|
db85dc82b5 | ||
|
|
a291a473b5 | ||
|
|
e8ae32d6d4 | ||
|
|
1d79d26dac | ||
|
|
b1f06462da | ||
|
|
f0de5dbf80 | ||
|
|
ad0f28d9ae | ||
|
|
bb89e49856 | ||
|
|
f4952d5865 | ||
|
|
ab655910ec | ||
|
|
b0666a0efd | ||
|
|
d6540a8c1c | ||
|
|
1016a98712 | ||
|
|
1a8574ea86 | ||
|
|
eeee8b2818 | ||
|
|
010d1f736b | ||
|
|
e2c71a7555 | ||
|
|
1bb6a68b4b | ||
|
|
055ea2e3f1 | ||
|
|
ad8b6163ac | ||
|
|
2c405c1cad | ||
|
|
cea975da8b | ||
|
|
217241eb6a | ||
|
|
85783e49c9 | ||
|
|
1d5e1a443b | ||
|
|
e31a5e69a2 | ||
|
|
59eae1535f | ||
|
|
622dcbaf78 | ||
|
|
bc736863dc | ||
|
|
5306cb4666 | ||
|
|
2e30a954b6 | ||
|
|
f170f5dc90 | ||
|
|
7901bca172 | ||
|
|
736a168233 | ||
|
|
556f4bd9d1 | ||
|
|
2c9fe98ab4 | ||
|
|
a8003a3f5f | ||
|
|
5a31c2be5f | ||
|
|
e32f3fc265 | ||
|
|
5a26c55ffb | ||
|
|
6aa18fa8ec | ||
|
|
995f8eedc3 | ||
|
|
ea3ba39e33 | ||
|
|
580cd0dcb0 | ||
|
|
1e95a45649 | ||
|
|
db6af2d2eb | ||
|
|
1008d10112 | ||
|
|
7b27970e64 | ||
|
|
c9c7d7194f | ||
|
|
9f364009ca | ||
|
|
58dd4f0002 | ||
|
|
4ca16d2c35 | ||
|
|
bc3b8eee00 | ||
|
|
7ea327df08 | ||
|
|
94f12c9e5b | ||
|
|
b273d0ecc9 | ||
|
|
ff44166aa4 | ||
|
|
2a06316d46 | ||
|
|
aae437df20 | ||
|
|
cfc516ce02 | ||
|
|
db6e547d3a | ||
|
|
e51fe3cd3b | ||
|
|
14a6e541e5 | ||
|
|
f9d3bc3c43 | ||
|
|
ad6f15671b | ||
|
|
f1f946c9ef | ||
|
|
38ca54ac55 | ||
|
|
341609bb39 | ||
|
|
1875d2a980 | ||
|
|
d888ba6ee4 | ||
|
|
b9fd3acf75 | ||
|
|
ed9ee69f2f | ||
|
|
d436b4b157 | ||
|
|
2855f87544 | ||
|
|
07ae3bad4d | ||
|
|
81651a4120 | ||
|
|
c456e73ab1 | ||
|
|
e919e35ea0 | ||
|
|
bea768bf8f | ||
|
|
32ec94b3b9 | ||
|
|
48553494ca | ||
|
|
163ee377c4 | ||
|
|
d3b5bd1f13 | ||
|
|
624242bbab | ||
|
|
6b49921e54 | ||
|
|
3439de3222 | ||
|
|
f74f48def7 | ||
|
|
0fd25c7089 | ||
|
|
eeb1044718 | ||
|
|
c32da56c92 | ||
|
|
02d5bce712 | ||
|
|
1baf06adea | ||
|
|
60a5049d05 | ||
|
|
692f0c0326 | ||
|
|
7ddcb36ad2 | ||
|
|
91700a3c1c | ||
|
|
5da93336fa | ||
|
|
feb1faec4f | ||
|
|
82e28f1728 | ||
|
|
bf3912a67f | ||
|
|
fe68b1e778 | ||
|
|
546ca9d0b2 | ||
|
|
14d5309637 | ||
|
|
e871708f41 | ||
|
|
135eae4931 | ||
|
|
beee84775e | ||
|
|
62a13bfaf5 | ||
|
|
42e0f67ce8 | ||
|
|
50a7d3a79e | ||
|
|
300f91db17 | ||
|
|
8fad2a1981 | ||
|
|
0e427d4799 | ||
|
|
0cb700ac7b | ||
|
|
23f03813eb | ||
|
|
44bedc6b8c | ||
|
|
4acfe59f78 | ||
|
|
cc66db4a33 | ||
|
|
cf87b00781 | ||
|
|
85b6e70132 | ||
|
|
446c2c7206 | ||
|
|
a66a472e9e | ||
|
|
d438f99f25 | ||
|
|
a2ae008755 | ||
|
|
12333b2bd3 | ||
|
|
f09106c3a9 | ||
|
|
05226c912e | ||
|
|
ef9eb0972d | ||
|
|
19b7803ca9 | ||
|
|
9f1726cc99 | ||
|
|
85c68d2fff | ||
|
|
0f924cdbba | ||
|
|
9433f337be | ||
|
|
feacd6544a | ||
|
|
0b79b180bb | ||
|
|
28bce56334 | ||
|
|
d26e7efb6a | ||
|
|
3d3b5b4404 | ||
|
|
db3cabb768 | ||
|
|
3ccf4b40b8 | ||
|
|
3c77fd1415 | ||
|
|
ff14d887bb | ||
|
|
10221f8b16 | ||
|
|
178fcccaac | ||
|
|
4f6f0aea26 | ||
|
|
332d093e72 | ||
|
|
6c275aefe8 | ||
|
|
1dd5efeb22 | ||
|
|
2ad0ec12dd | ||
|
|
b09cec0bc2 | ||
|
|
d14ca95010 | ||
|
|
2df1100795 | ||
|
|
2f961f992a | ||
|
|
ecdc5b3531 | ||
|
|
5f08a581f2 | ||
|
|
87b4a5d626 | ||
|
|
6aa2ef2878 | ||
|
|
9267a36529 | ||
|
|
72db313d8d | ||
|
|
93f0b2500e | ||
|
|
76b7aba5bd | ||
|
|
0585884033 | ||
|
|
c31fa08579 | ||
|
|
d9c3fea93d | ||
|
|
6325476325 | ||
|
|
054e172b64 | ||
|
|
7ae51f0fec | ||
|
|
531c0e24ba | ||
|
|
d97a31e002 | ||
|
|
70e5b1d0db | ||
|
|
63516e85db | ||
|
|
35b1dbdc2e | ||
|
|
c9abe16cfe | ||
|
|
aee7530b2b | ||
|
|
ceda99fa84 | ||
|
|
ce78b144e6 | ||
|
|
3fd3717978 | ||
|
|
9be3f1dfa9 | ||
|
|
2249367696 | ||
|
|
b68af82771 | ||
|
|
884d2e323b | ||
|
|
5a21b6f197 | ||
|
|
62c0178aa9 | ||
|
|
041452cf93 | ||
|
|
89ebaf78bc | ||
|
|
295a6496ef | ||
|
|
48fb10bcec | ||
|
|
525e464592 | ||
|
|
5f20866a31 | ||
|
|
05f60cd08b | ||
|
|
bd7b56757d | ||
|
|
bc3c85fe2d | ||
|
|
22c87decdc | ||
|
|
d13216e0e2 | ||
|
|
992d977312 | ||
|
|
9cb789d0b0 | ||
|
|
b4e9747bfa |
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owgw VERSION 2.6.0)
|
||||
project(owgw VERSION 2.7.1)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -30,6 +30,13 @@ else()
|
||||
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
|
||||
endif()
|
||||
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
add_compile_options(-fsanitize=undefined)
|
||||
add_link_options(-fsanitize=undefined)
|
||||
endif()
|
||||
|
||||
find_package(Git QUIET)
|
||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
|
||||
@@ -42,7 +49,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
||||
endif()
|
||||
|
||||
add_definitions(-DTIP_GATEWAY_SERVICE="1")
|
||||
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -64,12 +71,6 @@ include_directories(/usr/local/include /usr/local/opt/openssl/include src inclu
|
||||
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
|
||||
|
||||
add_compile_options(-Wall -Wextra)
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
add_compile_options(-fsanitize=undefined)
|
||||
add_link_options(-fsanitize=undefined)
|
||||
endif()
|
||||
|
||||
add_executable( owgw
|
||||
build
|
||||
@@ -105,7 +106,7 @@ add_executable( owgw
|
||||
src/storage/storage_tables.cpp
|
||||
src/RESTAPI/RESTAPI_routers.cpp
|
||||
src/Daemon.cpp src/Daemon.h
|
||||
src/WS_Server.cpp src/WS_Server.h
|
||||
src/AP_WS_Server.cpp src/AP_WS_Server.h
|
||||
src/StorageService.cpp src/StorageService.h
|
||||
src/DeviceRegistry.cpp src/DeviceRegistry.h
|
||||
src/CommandManager.cpp src/CommandManager.h
|
||||
@@ -118,7 +119,20 @@ add_executable( owgw
|
||||
src/TelemetryStream.cpp src/TelemetryStream.h
|
||||
src/framework/ConfigurationValidator.cpp src/framework/ConfigurationValidator.h
|
||||
src/ConfigurationCache.h
|
||||
src/CapabilitiesCache.h src/FindCountry.h src/rttys/RTTYS_server.cpp src/rttys/RTTYS_server.h src/rttys/RTTYS_device.cpp src/rttys/RTTYS_device.h src/rttys/RTTYS_ClientConnection.cpp src/rttys/RTTYS_ClientConnection.h src/rttys/RTTYS_WebServer.cpp src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h src/SDKcalls.cpp src/SDKcalls.h src/StateUtils.cpp src/StateUtils.h src/WS_ReactorPool.h src/WS_Connection.h src/WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h src/framework/ow_constants.h src/GwWebSocketClient.cpp src/GwWebSocketClient.h src/framework/WebSocketClientNotifications.h src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h src/ParseWifiScan.h src/RADIUS_helpers.h)
|
||||
src/CapabilitiesCache.h src/FindCountry.h
|
||||
src/rttys/RTTYS_server.cpp
|
||||
src/rttys/RTTYS_server.h
|
||||
src/rttys/RTTYS_device.cpp
|
||||
src/rttys/RTTYS_device.h
|
||||
src/rttys/RTTYS_ClientConnection.cpp
|
||||
src/rttys/RTTYS_ClientConnection.h
|
||||
src/rttys/RTTYS_WebServer.cpp
|
||||
src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h src/SDKcalls.cpp src/SDKcalls.h src/StateUtils.cpp src/StateUtils.h src/AP_WS_ReactorPool.h src/AP_WS_Connection.h src/AP_WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h src/framework/ow_constants.h src/GwWebSocketClient.cpp src/GwWebSocketClient.h src/framework/WebSocketClientNotifications.h src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h src/ParseWifiScan.h src/RADIUS_helpers.h src/VenueBroadcaster.h src/sdks/sdk_prov.h
|
||||
src/AP_WS_Process_connect.cpp
|
||||
src/AP_WS_Process_state.cpp
|
||||
src/AP_WS_Process_healthcheck.cpp
|
||||
src/AP_WS_Process_log.cpp
|
||||
src/AP_WS_Process_crashlog.cpp src/AP_WS_Process_ping.cpp src/AP_WS_Process_cfgpending.cpp src/AP_WS_Process_recovery.cpp src/AP_WS_Process_deviceupdate.cpp src/AP_WS_Process_telemetry.cpp src/AP_WS_Process_venuebroadcast.cpp src/RADSECserver.h src/framework/MicroServiceErrorHandler.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
|
||||
|
||||
36
Dockerfile
36
Dockerfile
@@ -1,15 +1,23 @@
|
||||
FROM alpine:3.15 AS build-base
|
||||
ARG ALPINE_VERSION=3.16.2
|
||||
ARG POCO_VERSION=poco-tip-v1
|
||||
ARG FMTLIB_VERSION=9.0.0
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
ARG JSON_VALIDATOR_VERSION=2.1.0
|
||||
|
||||
FROM alpine:$ALPINE_VERSION AS build-base
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
make cmake g++ git \
|
||||
unixodbc-dev postgresql-dev mariadb-dev \
|
||||
librdkafka-dev boost-dev openssl-dev \
|
||||
zlib-dev nlohmann-json
|
||||
zlib-dev nlohmann-json ca-certificates
|
||||
|
||||
FROM build-base AS poco-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
ARG POCO_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -20,8 +28,10 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt /fmtlib
|
||||
ARG FMTLIB_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
@@ -32,8 +42,10 @@ RUN make install
|
||||
|
||||
FROM build-base AS cppkafka-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
ARG CPPKAFKA_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -44,8 +56,10 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
ARG JSON_VALIDATOR_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
@@ -76,7 +90,7 @@ WORKDIR /owgw/cmake-build
|
||||
RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM alpine:3.15
|
||||
FROM alpine:$ALPINE_VERSION
|
||||
|
||||
ENV OWGW_USER=owgw \
|
||||
OWGW_ROOT=/owgw-data \
|
||||
|
||||
@@ -18,17 +18,29 @@ System messages are what maintains the collection of micro-services working on t
|
||||
}
|
||||
```
|
||||
|
||||
### Responsibilities
|
||||
Each micro service is responsible to generate its own messages and keep track of messages coming from other
|
||||
micro services. This is necessary so that any micro service may reach our any other micro service. This provides
|
||||
discovery for any micro service. All current micro services provided in OpenWiFi perform these functions. If you leverage
|
||||
the C++ framework, this functionality if performed automatically.
|
||||
|
||||
### `event-type`
|
||||
When a service joins the bus, it should generate an event-type of `join`. When a service shutdown, it should generate a `leave` event-type. Every 30 seconds, a service
|
||||
should generate a `keep-alive` message.
|
||||
Each micro service is responsible to generate and consume these events
|
||||
|
||||
#### `join` event
|
||||
When a service start and joins the bus, it should generate an event-type of `join`.
|
||||
|
||||
### `leave` event
|
||||
When a service shuts down, it should generate a `leave` event-type.
|
||||
|
||||
### `keep-alive` event
|
||||
Every 30 seconds, a service should generate a `keep-alive` message.
|
||||
|
||||
|
||||
### `id`
|
||||
You should generate a random number from some unique factor for the system. This ID is used to identify different services. You should reuse that ID
|
||||
when you restart.
|
||||
|
||||
## Micro-service maintaining bus state
|
||||
A micro-service should maintain its own lists of available micro-services by looking at the messages it receives and keep a list.
|
||||
|
||||
## The `type`
|
||||
The `type` in the system message is oen of the following:
|
||||
```c++
|
||||
@@ -47,11 +59,11 @@ The `type` in the system message is oen of the following:
|
||||
The `type` is what you should use to find the `privateEndPoint` you are looking to communicate with.
|
||||
|
||||
### Example
|
||||
Assume you want to communicate with the gateway t pconfigure a device.
|
||||
Assume you want to communicate with the gateway to configure a device.
|
||||
|
||||
```text
|
||||
1. Look into my list of current Micro-services for the type=owgw.
|
||||
2. Use the priovateEndPoint associated with that entry
|
||||
2. Use the privateEndPoint associated with that entry
|
||||
```
|
||||
|
||||
## REST API calls on the private interface
|
||||
@@ -72,9 +84,9 @@ This is the `publicEndPoint` you included in your `system-messages`.
|
||||
This method can _only_ be used to any another `privateEndPoint` in the system. You can use the exact same EndPoints provided in the OpenAPI files for any of the services.
|
||||
|
||||
## OpenAPI Integration
|
||||
To appear in the UI consoles, a micro-service should ne able to handle a get to the `/api/v1/system` endpoint on its `publicEndPoint` interface.
|
||||
To appear in the UI consoles, a microservice should be able to handle a get to the `/api/v1/system` endpoint on its `publicEndPoint` interface.
|
||||
|
||||
Here is a brief description of what the micro-service should answer:
|
||||
Here is a brief description of what the microservice should answer:
|
||||
```yaml
|
||||
/system:
|
||||
get:
|
||||
|
||||
23
PROTOCOL.md
23
PROTOCOL.md
@@ -184,6 +184,21 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Device requests a venue broadcast message
|
||||
Device send this message when it wants to reach out to all other APs in the same venue. The GW will find the
|
||||
venue where this device belongs and resend the same message to all other devices in the venue.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "venue_broadcast" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"timestamp" : <the UTC timestamp when the message was sent>,
|
||||
"data" : <an opaque string from the AP. This could be Zipped and so on and most likely base64 encoded>
|
||||
}
|
||||
}
|
||||
```
|
||||
Upon receiving a `venue_broadcast` message, the GW will simply resent the message to all the APs in the venue.
|
||||
|
||||
### Controller commands
|
||||
Most controller commands include a `when` member. This is a UTC clock time asking the AP
|
||||
to perform the command at that time. This is a suggestion only. The AP may ignore this
|
||||
@@ -734,7 +749,10 @@ Should other messages get larger, the client may decide to compress the. Only me
|
||||
|
||||
#### Identifying a compressed message
|
||||
A compressed message has a single member to the `params` field. It's only parameter must be called `compress_64`. Any other elements under
|
||||
params will be dropped. Additional compression schemes may be developed later.
|
||||
params will be dropped. Additional compression schemes may be developed later. The device should also include
|
||||
a hint to the actual size of the uncompressed data. This would allow listeners to create sufficiently sized
|
||||
buffers right away instead of guessing. If the device includes `compressed_sz` as the second field in the
|
||||
params objects. This should be an unsigned int representing the total size of the uncompressed data.
|
||||
|
||||
#### How to compress
|
||||
The original `params` element should be run through `zlib:compress` and then encoded using base64, and passed as a string. Here is an example
|
||||
@@ -744,7 +762,8 @@ of the completed message. The following should how the `state` event could be co
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "state" ,
|
||||
"params" : {
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk"
|
||||
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk",
|
||||
"compress_sz" : 212322
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
92
README.md
92
README.md
@@ -11,16 +11,16 @@ In order to build the uCentralGW, you will need to install its dependencies, whi
|
||||
- boost
|
||||
- POCO 1.10.1 or later
|
||||
- a C++17 compiler
|
||||
- libyaml
|
||||
- openssl
|
||||
- libpq-dev (PortgreSQL development libraries)
|
||||
- mysql-client (MySQL client)
|
||||
- librdkafka
|
||||
- cppkafka
|
||||
-
|
||||
|
||||
The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
|
||||
framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
|
||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/stephb9959/poco). Building
|
||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/AriliaWireless/poco). Building
|
||||
Poco may take several minutes depending on the platform you are building on.
|
||||
|
||||
### Ubuntu
|
||||
@@ -29,9 +29,10 @@ These instructions have proven to work on Ubuntu 20.4.
|
||||
sudo apt install git cmake g++ libssl-dev libmariadb-dev
|
||||
sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
|
||||
sudo apt install librdkafka-dev // default-libmysqlclient-dev
|
||||
sudo apt install nlohmann-json-dev
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -40,7 +41,7 @@ cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -49,17 +50,7 @@ cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/nlohmann/json.git
|
||||
cd json
|
||||
git checkout tags/v3.10.2
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -67,6 +58,14 @@ cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
|
||||
cd fmtlib
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -81,12 +80,12 @@ make -j 8
|
||||
### Fedora
|
||||
The following instructions have proven to work on Fedora 33
|
||||
```
|
||||
sudo yum install cmake g++ openssl-devel unixODBC-devel mysql-devel mysql apr-util-devel boost boost-devel
|
||||
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
|
||||
sudo yum install yaml-cpp-devel lua-devel
|
||||
sudo dnf install postgresql.x86_64 librdkafka-devel
|
||||
sudo dnf install postgresql-devel
|
||||
sudo dnf install postgresql-devel json-devel
|
||||
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -94,7 +93,7 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -102,6 +101,15 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -124,18 +132,18 @@ brew install apr-util
|
||||
brew install boost
|
||||
brew install yaml-cpp
|
||||
brew install postgresql
|
||||
brew install unixodbc
|
||||
brew install librdkafka
|
||||
brew install nlohmann-json
|
||||
|
||||
git clone https://github.com/stephb9959/poco
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release -j
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
git clone https://github.com/stephb9959/cppkafka
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -143,6 +151,15 @@ cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
|
||||
cd json-schema-validator
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
@@ -249,7 +266,7 @@ little changes if you keep the suggested directory structure. For the sample con
|
||||
environment variables.
|
||||
```
|
||||
export OWGW_ROOT=`pwd`
|
||||
export UCENTRALGW_CONFIG=`pwd`
|
||||
export OWGW_CONFIG=`pwd`
|
||||
```
|
||||
If you current working directory is the root of the project, this will set the variables properly. Otherwise, you can set the variables
|
||||
to point to wherever is necessary.
|
||||
@@ -561,6 +578,31 @@ Toe read more about Kafka, follow the [document](https://github.com/Telecominfra
|
||||
#### Securing `kafka`
|
||||
This is beyond the scope of this document. As it stands today, the communication between the gateway and `kafka` is expected to be behind a firewall.
|
||||
|
||||
#### `iptocountry` feature
|
||||
In the UI, you will notice the presence of small flags showing where the device connections are from. This feature is
|
||||
available through the `iptocountry` settings in the configuration. This feature is then also available through the `OpenAPI` for the CLI
|
||||
and other applications.
|
||||
|
||||
##### Config file entries
|
||||
In the configuration file, you must include the following lines:
|
||||
|
||||
```asm
|
||||
iptocountry.default = US
|
||||
iptocountry.provider = ipinfo
|
||||
#iptocountry.provider = ipdata
|
||||
#iptocountry.provider = ipdata
|
||||
iptocountry.ipinfo.token =
|
||||
#ip2location.ipinfo.token =
|
||||
#iptocountry.ipdata.apikey =
|
||||
#iptocountry.ip2location.apikey =
|
||||
```
|
||||
So you select your provider with the `iptocountry.provider` be specifying ipinfo, or ipdata, or ip2location.
|
||||
And then you provide the corresponding api key or token.
|
||||
Only select one. If you select 2, undefined behaviour. All the line you do not need, just put a `#` before to comment it
|
||||
out.
|
||||
You will find the supported providers at: `ip2location.com`, `ipinfo.io`, or `ipdata.co`. You MUST supply a valid default
|
||||
country code in `iptocountry.default`.
|
||||
|
||||
## Contributors
|
||||
We love ya! We need more of ya! If you want to contribute, make sure you review
|
||||
the [coding style](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CODING_STYLE.md) document.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{{- $root := . -}}
|
||||
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -48,6 +49,38 @@ spec:
|
||||
- tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }}
|
||||
- -timeout
|
||||
- 600s
|
||||
{{- if eq $storageType "postgresql" }}
|
||||
- name: wait-postgres
|
||||
image: "{{ .Values.images.owgw.repository }}:{{ .Values.images.owgw.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.owgw.pullPolicy }}
|
||||
command:
|
||||
- /wait-for-postgres.sh
|
||||
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
|
||||
- echo
|
||||
- "PostgreSQL is ready"
|
||||
env:
|
||||
- name: KUBERNETES_DEPLOYED
|
||||
value: "{{ now }}"
|
||||
{{- range $key, $value := .Values.public_env_variables }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := .Values.secret_env_variables }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "owgw.fullname" $root }}-env
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owgw }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
{{- if .subPath }}
|
||||
subPath: {{ .subPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
containers:
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owgw:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
|
||||
tag: v2.6.0
|
||||
tag: master
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
|
||||
@@ -190,6 +190,18 @@ components:
|
||||
type: string
|
||||
minLength: 2
|
||||
maxLength: 2
|
||||
started:
|
||||
type: integer
|
||||
format: int64
|
||||
sessionId:
|
||||
type: integer
|
||||
format: int64
|
||||
connectionCompletionTime:
|
||||
type: number
|
||||
format: double
|
||||
totalConnectionTime:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
DeviceList:
|
||||
type: object
|
||||
@@ -282,6 +294,17 @@ components:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
DeviceConnectionStatistics:
|
||||
type: object
|
||||
description: Return some basic device statistics.
|
||||
properties:
|
||||
connectedDevices:
|
||||
type: integer
|
||||
format: int64
|
||||
averageConnectionTime:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
StatisticsDetails:
|
||||
type: object
|
||||
properties:
|
||||
@@ -1049,6 +1072,33 @@ components:
|
||||
type: string
|
||||
certificate:
|
||||
type: string
|
||||
radsec:
|
||||
type: boolean
|
||||
default: false
|
||||
radsecPort:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 65535
|
||||
radsecSecret:
|
||||
type: string
|
||||
radsecCacerts:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
radsecCert:
|
||||
type: string
|
||||
description: this must be the base64 encoded of the entire content of the certificate file, including the -----BEGIN lines
|
||||
radsecKey:
|
||||
type: string
|
||||
description: this must be the base64 encoded of the entire content of the key file, including the -----BEGIN lines
|
||||
radsecRealms:
|
||||
description: each entry must be the base64 encoded of the entire content of the ca files, including the -----BEGIN lines
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ignore:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
RadiusProxyServerConfig:
|
||||
type: object
|
||||
@@ -1162,6 +1212,13 @@ paths:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
- in: query
|
||||
description: return extended information
|
||||
name: connectionStatistics
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List devices
|
||||
@@ -1173,6 +1230,7 @@ paths:
|
||||
- $ref: '#/components/schemas/DeviceListWithStatus'
|
||||
- $ref: '#/components/schemas/SerialNumberList'
|
||||
- $ref: '#/components/schemas/DeviceCount'
|
||||
- $ref: '#/components/schemas/DeviceConnectionStatistics'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
|
||||
205
radius-proxy-orion.json
Normal file
205
radius-proxy-orion.json
Normal file
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "wan",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh"
|
||||
],
|
||||
"ssids": []
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 100,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"gateway": "192.168.1.1",
|
||||
"send-hostname": true,
|
||||
"subnet": "192.168.1.1/24",
|
||||
"use-dns": []
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "lan",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"wifi-steering",
|
||||
"ssh"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "required",
|
||||
"proto": "wpa"
|
||||
},
|
||||
"hidden-ssid": false,
|
||||
"isolate-clients": false,
|
||||
"maximum-clients": 64,
|
||||
"name": "arilia-rad",
|
||||
"radius": {
|
||||
"authentication": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1812,
|
||||
"secret": "radsec"
|
||||
},
|
||||
"accounting": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1813,
|
||||
"secret": "radsec"
|
||||
}
|
||||
},
|
||||
"services": [
|
||||
"radius-gw-proxy"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G",
|
||||
"5G"
|
||||
],
|
||||
"pass-point": {
|
||||
"venue-name": [
|
||||
"eng:Example passpoint_venue",
|
||||
"fra:Exemple de lieu"
|
||||
],
|
||||
"domain-name": [
|
||||
"onboard.almondlabs.net",
|
||||
"test.com"
|
||||
],
|
||||
"asra": false,
|
||||
"internet": true,
|
||||
"esr": false,
|
||||
"uesa": false,
|
||||
"access-network-type": 0,
|
||||
"hessid":"11:22:33:44:55:66",
|
||||
"venue-group": 2,
|
||||
"venue-type": 8,
|
||||
"connection-capability":[
|
||||
"1:0:2",
|
||||
"6:22:1",
|
||||
"17:5060:0"
|
||||
],
|
||||
"roaming-consortium": [
|
||||
"F4F5E8F5F4",
|
||||
"BAA2D00100",
|
||||
"BAA2D00000"
|
||||
],
|
||||
"disable-dgaf": true,
|
||||
"anqp-domain": 8888,
|
||||
"ipaddr-type-available": 14,
|
||||
"nai-realm": [
|
||||
],
|
||||
"osen": false,
|
||||
"anqp-3gpp-cell-net": [
|
||||
],
|
||||
"friendly-name": [
|
||||
"eng:AlmondLabs",
|
||||
"fra:AlmondLabs"
|
||||
],
|
||||
"venue-url": [
|
||||
"http://www.example.com/info-fra",
|
||||
"http://www.example.com/info-eng"
|
||||
],
|
||||
"auth-type": {
|
||||
"type": "terms-and-conditions"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 60
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"bandwidth": 10,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HT",
|
||||
"channel-width": 20,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 0
|
||||
},
|
||||
{
|
||||
"band": "5G",
|
||||
"bandwidth": 20,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"channel-width": 40,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 0
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"ssh": {
|
||||
"password-authentication": true,
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 1661312631
|
||||
}
|
||||
32
radsec-config-sample.json
Normal file
32
radsec-config-sample.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"pools" : [
|
||||
{
|
||||
"name" : "master" ,
|
||||
"description" : "master pool",
|
||||
"useByDefault" : true,
|
||||
"authConfig" : {
|
||||
"strategy" : "weighted",
|
||||
"monitor" : false,
|
||||
"monitorMethod" : "none",
|
||||
"methodParameters" : [],
|
||||
"servers" : [ {
|
||||
"name" : "orion",
|
||||
"ip" : "216.239.32.91",
|
||||
"port" : 2083,
|
||||
"weight" : 10,
|
||||
"radsec" : true,
|
||||
"radsecPort" : 2083,
|
||||
"radsecSecret" : "radsec",
|
||||
"radsecKey" : "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUR6RnpXeTZlYXg0QVoxTySG9VUURRZ0FFS3BnWVBHMktPTVd2S0w1Z3NMRXpUc09rREg1M3NHaEQyS3RsRXBDTXVnNDNIZlFnTFVpUgpTR1R2S1l0bDFmbmJaU1lnY0RJdncxdjNYRy9hVDhOY2JBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=",
|
||||
"radsecCert" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNRVENDQWVpZ0F3SUJBZ0lVY3BKS3pVM0Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa0oxZEhSdmJuZHZiMlF4SFRBYkJnTlZCQU1URkVKMQpkSFJ2Ym5kdmIyUWdVbUZrYzJWaklFTkJNQjRYRFRJeU1EY3dNekExTWpVeE5Gb1hEVEkzTURVeE9UQTFNalV4Ck5Gb3dkVEVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFvVENrSjFkSFJ2Ym5kdmIyUXhOakEwQmdOVkJBTVQKTFdGeWFXeHBZUzVqWWpFd2FtTnVjemgxYlhCbk9HWnBjRFowTUM1dmNtbHZiaTVoY21WaE1USXdMbU52YlRFWgpNQmNHQ2dtU0pvbVQ4aXhrQVFFVENVZHZiMmRzWlRwVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQ3FZR0R4dGlqakZyeWkrWUxDeE0wN0RwQXgrZDdCb1E5aXJaUktRakxvT054MzBJQzFJa1Voazd5bUwKWmRYNTIyVW1JSEF5TDhOYjkxeHYyay9EWEd5amdZa3dnWVl3RGdZRFZSMFBBUUgvQkFRREFnZUFNQk1HQTFVZApKUVFNTUFvR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3T0FZRFZSMFJCREV3TDRJdFlYSnBiR2xoCkxtTmlNVEJxWTI1ek9IVnRjR2M0Wm1sd05uUXdMbTl5YVc5dUxtRnlaV0V4TWpBdVkyOXRNQmNHQTFVZElBUVEKTUE0d0RBWUtLd1lCQkFIdUtnRUJCVEFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFwTmM1dUNBSkp6KzVyakdqdwpCWGtOdHE3UU83bWU5dUg5bkNsTDZnSVE5Z0lnUHM2VkVKVW5CcEZ0RktXbFF4eWJ1YlBxYnpJNjBPSERHQ0ExCmhXUk1PS1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
|
||||
"radsecCacerts" : [
|
||||
"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ0akNDQVZ1Z0F3SUJBZ0lCQyOXZaREVkTUJzR0ExVUVBeE1VUW5WMGRHOXVkMjl2WkNCU1lXUnpaV01nUTBFdwpJQmNOTVRrd05qQTJNVFV4TlRNeVdoZ1BNalV4T1RBMk1EY3hOVEUxTXpKYU1FRXhDekFKQmdOVkJBWVRBbFZUCk1STXdFUVlEVlFRS0V3cENkWFIwYjI1M2IyOWtNUjB3R3dZRFZRUURFeFJDZFhSMGIyNTNiMjlrSUZKaFpITmwKWXlCRFFUQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJJUW40QVBKaXdvUVFQblR1cFgrZTk1Ugp0ZzVoQVFVbUhCN1E0UkpwSG4welF6TUJpMDdSejkxV05RamFHeERydktLVlQ1OThIM2dxYkI4TTViOHN3aytqClFqQkFNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBZ1lJS3dZQkJRVUgKQXdFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQTkrbHUwN2NlaGc1OQpxSi81dWtzN05oL3F2aXFHWCs1WDFwSVVxdENGVlJjQ0lRREZmUGhwZzZJOFE0SUdBbzNuamlHRTdDWC9nMm56CkRzSW5FcG9vRlkxV0xRPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
|
||||
],
|
||||
"radsecRealms" : [],
|
||||
"ignore" : false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
926
src/AP_WS_Connection.cpp
Normal file
926
src/AP_WS_Connection.cpp
Normal file
@@ -0,0 +1,926 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/HTTPServerResponseImpl.h"
|
||||
#include "Poco/Net/HTTPServerRequestImpl.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
|
||||
#include "Poco/zlib.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "CommandManager.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
#include "Poco/Net/WebSocketImpl.h"
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
#define DBL { std::cout << __LINE__ << " ID: " << ConnectionId_ << " Ser: " << SerialNumber_ << std::endl; }
|
||||
|
||||
void AP_WS_Connection::LogException(const Poco::Exception &E) {
|
||||
poco_information(Logger_,fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
|
||||
}
|
||||
|
||||
AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
std::uint64_t connection_id,
|
||||
Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R)
|
||||
: Logger_(L) ,
|
||||
Reactor_(R)
|
||||
{
|
||||
State_.sessionId = connection_id;
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request,response);
|
||||
|
||||
auto TS = Poco::Timespan(360, 0);
|
||||
|
||||
WS_->setMaxPayloadSize(BufSize);
|
||||
WS_->setReceiveTimeout(TS);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
WS_->setBlocking(false);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
Registered_ = true;
|
||||
}
|
||||
|
||||
class ThreadedCounter {
|
||||
public:
|
||||
ThreadedCounter(bool T, std::atomic_uint64_t &C) :
|
||||
C_(C),
|
||||
Threaded_(T) {
|
||||
if(Threaded_) {
|
||||
C_++;
|
||||
}
|
||||
}
|
||||
|
||||
~ThreadedCounter() {
|
||||
if(Threaded_ && C_>0) {
|
||||
C_--;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_uint64_t &C_;
|
||||
bool Threaded_;
|
||||
};
|
||||
|
||||
bool AP_WS_Connection::ValidatedDevice() {
|
||||
if(DeviceValidated_)
|
||||
return true;
|
||||
|
||||
try {
|
||||
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(SockImpl->streamSocketImpl());
|
||||
|
||||
PeerAddress_ = SS->peerAddress().host();
|
||||
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
|
||||
|
||||
State_.started = OpenWifi::Now();
|
||||
|
||||
if (!SS->secure()) {
|
||||
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is NOT secure. Device is not allowed.", CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
poco_debug(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is secure.", CId_, State_.sessionId ));
|
||||
|
||||
if (!SS->havePeerCertificate()) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
|
||||
if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not valid. Device is not allowed.",
|
||||
CId_, State_.sessionId ));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_debug(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_, State_.sessionId , CN_));
|
||||
|
||||
if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is not allowed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumber_)) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
poco_debug(Logger_, fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, State_.sessionId , CN_, ConcurrentStartingDevices_));
|
||||
DeviceValidated_ = true;
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate Validation failed during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket error during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionAbortedException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}):Session:{} Poco::ConnectionAbortedException Connection was aborted during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection was reset during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(Logger_,fmt::format(
|
||||
"CONNECTION({}): Session:{} Poco::InvalidCertificateException Invalid certificate. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::Exception caught during device connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. Device will have to retry. Unsecure connect denied.",
|
||||
CId_, State_.sessionId ));
|
||||
}
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::CompleteStartup() {
|
||||
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto TC = ThreadedCounter(Threaded_,ConcurrentStartingDevices_);
|
||||
|
||||
try {
|
||||
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(SockImpl->streamSocketImpl());
|
||||
|
||||
/* while (true) {
|
||||
auto V = SS->completeHandshake();
|
||||
if (V == 1)
|
||||
break;
|
||||
}
|
||||
*/
|
||||
PeerAddress_ = SS->peerAddress().host();
|
||||
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
|
||||
|
||||
State_.started = OpenWifi::Now();
|
||||
|
||||
if (!SS->secure()) {
|
||||
poco_warning(Logger_,fmt::format("CONNECTION({}): Session={} Connection is NOT secure. Device is not allowed.", CId_, State_.sessionId ));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
poco_debug(Logger_,fmt::format("CONNECTION({}): Session={} Connection is secure.", CId_, State_.sessionId ));
|
||||
|
||||
if (!SS->havePeerCertificate()) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_,fmt::format("CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId ));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
|
||||
if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
|
||||
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
poco_warning(Logger_, fmt::format("CONNECTION({}): Session={} Device certificate is not valid. Device is not allowed.",
|
||||
CId_, State_.sessionId ));
|
||||
return EndConnection();
|
||||
}
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_debug(Logger_,
|
||||
fmt::format("CONNECTION({}): Session={} Valid certificate: CN={}", CId_, State_.sessionId , CN_));
|
||||
|
||||
if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("CONNECTION({}): Session={} Sim Device {} is not allowed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumber_)) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
|
||||
CId_, State_.sessionId , CN_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
WS_->setMaxPayloadSize(BufSize);
|
||||
auto TS = Poco::Timespan(360, 0);
|
||||
WS_->setReceiveTimeout(TS);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
WS_->setBlocking(false);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
Registered_ = true;
|
||||
poco_debug(Logger_, fmt::format("CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, State_.sessionId , CN_, ConcurrentStartingDevices_));
|
||||
return;
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate Validation failed during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket error during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionAbortedException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}):Session:{} Poco::ConnectionAbortedException Connection was aborted during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection was reset during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(Logger_,fmt::format(
|
||||
"CONNECTION({}): Session:{} Poco::InvalidCertificateException Invalid certificate. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception during connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::Exception caught during device connection. Device will have to retry.",
|
||||
CId_, State_.sessionId ));
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. Device will have to retry. Unsecure connect denied.",
|
||||
CId_, State_.sessionId ));
|
||||
}
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string & SerialNumber) {
|
||||
try {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(Disconnect, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
if(!Dead_)
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection() {
|
||||
Dead_=true;
|
||||
poco_information(Logger_,fmt::format("CONNECTION-CLOSING({}): Session={} Serial={}.", CId_, State_.sessionId, SerialNumber_));
|
||||
auto SessionDeleted = DeviceRegistry()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
|
||||
if (Registered_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
}
|
||||
WS_->close();
|
||||
|
||||
if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
|
||||
std::string s(SerialNumber_);
|
||||
std::thread t([s]() { NotifyKafkaDisconnect(s); });
|
||||
t.detach();
|
||||
}
|
||||
if(SessionDeleted)
|
||||
WebSocketClientNotificationDeviceDisconnected(SerialNumber_);
|
||||
AP_WS_Server()->DeleteConnection(State_.sessionId);
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::LookForUpgrade(const uint64_t UUID, uint64_t & UpgradedUUID) {
|
||||
|
||||
// A UUID of zero means ignore updates for that connection.
|
||||
if (UUID == 0)
|
||||
return false;
|
||||
|
||||
uint64_t GoodConfig = ConfigurationCache().CurrentConfig(SerialNumberInt_);
|
||||
if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) {
|
||||
UpgradedUUID = UUID;
|
||||
return false;
|
||||
}
|
||||
|
||||
GWObjects::Device D;
|
||||
if (StorageService()->GetDevice(SerialNumber_, D)) {
|
||||
|
||||
// This is the case where the cache is empty after a restart. So GoodConfig will 0. If the device already has the right UUID, we just return.
|
||||
if (D.UUID == UUID) {
|
||||
UpgradedUUID = UUID;
|
||||
ConfigurationCache().Add(SerialNumberInt_, UUID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(UUID>D.UUID) {
|
||||
// so we have a problem, the device has a newer config than we have. So we need to make sure our config
|
||||
// is newer.
|
||||
Config::Config Cfg(D.Configuration);
|
||||
D.UUID = UUID+2;
|
||||
UpgradedUUID = D.UUID;
|
||||
Cfg.SetUUID(D.UUID);
|
||||
D.Configuration = Cfg.get();
|
||||
StorageService()->UpdateDevice(D);
|
||||
}
|
||||
|
||||
UpgradedUUID = D.UUID;
|
||||
State_.PendingUUID = D.UUID;
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroService::CreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::CONFIGURE;
|
||||
Poco::JSON::Parser P;
|
||||
auto ParsedConfig = P.parse(D.Configuration).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::UUID, D.UUID);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
|
||||
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
poco_information(Logger_,fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
|
||||
CId_, UUID, D.UUID));
|
||||
bool Sent;
|
||||
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
CommandManager()->PostCommand(CommandManager()->NextRPCId(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
|
||||
WebSocketClientNotificationDeviceConfigurationChange(D.SerialNumber, UUID, UpgradedUUID);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
|
||||
poco_debug(Logger_,fmt::format("RECEIVED-RPC({}): {}.", CId_, Doc->get(uCentralProtocol::ID).toString()));
|
||||
CommandManager()->PostCommandResult(SerialNumber_, *Doc);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc) {
|
||||
auto Method = Doc->get(uCentralProtocol::METHOD).toString();
|
||||
auto EventType = uCentralProtocol::Events::EventFromString(Method);
|
||||
if (EventType == uCentralProtocol::Events::ET_UNKNOWN) {
|
||||
poco_warning(Logger_,fmt::format("ILLEGAL-PROTOCOL({}): Unknown message type '{}'", CId_, Method));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Doc->isObject(uCentralProtocol::PARAMS)) {
|
||||
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): params must be an object.", CId_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
// expand params if necessary
|
||||
auto ParamsObj = Doc->get(uCentralProtocol::PARAMS).extract<Poco::JSON::Object::Ptr>();
|
||||
if (ParamsObj->has(uCentralProtocol::COMPRESS_64)) {
|
||||
std::string UncompressedData;
|
||||
try {
|
||||
auto CompressedData = ParamsObj->get(uCentralProtocol::COMPRESS_64).toString();
|
||||
uint64_t compress_sz = 0 ;
|
||||
if(ParamsObj->has("compress_sz")) {
|
||||
compress_sz = ParamsObj->get("compress_sz");
|
||||
}
|
||||
|
||||
if (Utils::ExtractBase64CompressedData(CompressedData, UncompressedData, compress_sz)) {
|
||||
poco_trace(Logger_,fmt::format("EVENT({}): Found compressed payload expanded to '{}'.",
|
||||
CId_, UncompressedData));
|
||||
Poco::JSON::Parser Parser;
|
||||
ParamsObj = Parser.parse(UncompressedData).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-DATA({}): Compressed cannot be uncompressed - content must be corrupt..: size={}",
|
||||
CId_, CompressedData.size()));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-JSON-DATA({}): Compressed cannot be parsed - JSON must be corrupt..",
|
||||
CId_));
|
||||
Logger_.log(E);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParamsObj->has(uCentralProtocol::SERIAL)) {
|
||||
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): Serial number is missing in message.", CId_));
|
||||
return;
|
||||
}
|
||||
|
||||
auto Serial = Poco::trim(Poco::toLower(ParamsObj->get(uCentralProtocol::SERIAL).toString()));
|
||||
if (!Utils::ValidSerialNumber(Serial)) {
|
||||
Poco::Exception E(
|
||||
fmt::format(
|
||||
"ILLEGAL-DEVICE-NAME({}): device name is illegal and not allowed to connect.",
|
||||
Serial),
|
||||
EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
if (StorageService()->IsBlackListed(Serial)) {
|
||||
Poco::Exception E(
|
||||
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
|
||||
Serial),
|
||||
EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
switch (EventType) {
|
||||
case uCentralProtocol::Events::ET_CONNECT: {
|
||||
Process_connect(ParamsObj, Serial);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_STATE: {
|
||||
Process_state(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_HEALTHCHECK: {
|
||||
Process_healthcheck(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_LOG: {
|
||||
Process_log(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_CRASHLOG: {
|
||||
Process_crashlog(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_PING: {
|
||||
Process_ping(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_CFGPENDING: {
|
||||
Process_cfgpending(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_RECOVERY: {
|
||||
Process_recovery(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_DEVICEUPDATE: {
|
||||
Process_deviceupdate(ParamsObj, Serial);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_TELEMETRY: {
|
||||
Process_telemetry(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_VENUEBROADCAST: {
|
||||
Process_venuebroadcast(ParamsObj);
|
||||
} break;
|
||||
|
||||
// this will never be called but some compilers will complain if we do not have a case for
|
||||
// every single values of an enum
|
||||
case uCentralProtocol::Events::ET_UNKNOWN: {
|
||||
poco_warning(Logger_, fmt::format("ILLEGAL-EVENT({}): Event '{}' unknown. CN={}", CId_, Method, CN_));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StartTelemetry(std::uint64_t RPCID) {
|
||||
poco_information(Logger_, fmt::format("TELEMETRY({}): Starting.", CId_));
|
||||
Poco::JSON::Object StartMessage;
|
||||
StartMessage.set("jsonrpc", "2.0");
|
||||
StartMessage.set("method", "telemetry");
|
||||
Poco::JSON::Object Params;
|
||||
Params.set("serial", SerialNumber_);
|
||||
Params.set("interval", TelemetryInterval_);
|
||||
Poco::JSON::Array Types;
|
||||
Types.add("wifi-frames");
|
||||
Types.add("dhcp-snooping");
|
||||
Types.add("state");
|
||||
Params.set(RESTAPI::Protocol::TYPES, Types);
|
||||
StartMessage.set("id", RPCID);
|
||||
StartMessage.set("params", Params);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(StartMessage, OS);
|
||||
return Send(OS.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopTelemetry(std::uint64_t RPCID) {
|
||||
poco_information(Logger_, fmt::format("TELEMETRY({}): Stopping.", CId_));
|
||||
Poco::JSON::Object StopMessage;
|
||||
StopMessage.set("jsonrpc", "2.0");
|
||||
StopMessage.set("method", "telemetry");
|
||||
Poco::JSON::Object Params;
|
||||
Params.set("serial", SerialNumber_);
|
||||
Params.set("interval", 0);
|
||||
StopMessage.set("id", RPCID);
|
||||
StopMessage.set("params", Params);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(StopMessage, OS);
|
||||
TelemetryKafkaPackets_ = TelemetryWebSocketPackets_ = TelemetryInterval_ =
|
||||
TelemetryKafkaTimer_ = TelemetryWebSocketTimer_ = 0;
|
||||
return Send(OS.str());
|
||||
}
|
||||
|
||||
void AP_WS_Connection::UpdateCounts() {
|
||||
State_.kafkaClients = TelemetryKafkaRefCount_;
|
||||
State_.webSocketClients = TelemetryWebSocketRefCount_;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t Interval,
|
||||
uint64_t LifeTime) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryWebSocketRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
|
||||
auto TelemetryWebSocketTimer = LifeTime + OpenWifi::Now();
|
||||
TelemetryWebSocketTimer_ = std::max(TelemetryWebSocketTimer, TelemetryWebSocketTimer_);
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
return StartTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t Interval, uint64_t LifeTime) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryKafkaRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
|
||||
auto TelemetryKafkaTimer = LifeTime + OpenWifi::Now();
|
||||
TelemetryKafkaTimer_ = std::max(TelemetryKafkaTimer, TelemetryKafkaTimer_);
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
return StartTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopWebSocketTelemetry(std::uint64_t RPCID) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
if (TelemetryWebSocketRefCount_)
|
||||
TelemetryWebSocketRefCount_--;
|
||||
UpdateCounts();
|
||||
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
|
||||
TelemetryReporting_ = false;
|
||||
StopTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::StopKafkaTelemetry(std::uint64_t RPCID) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
if (TelemetryKafkaRefCount_)
|
||||
TelemetryKafkaRefCount_--;
|
||||
UpdateCounts();
|
||||
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
|
||||
TelemetryReporting_ = false;
|
||||
StopTelemetry(RPCID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
if(!AP_WS_Server()->Running())
|
||||
return EndConnection();
|
||||
|
||||
if(!ValidatedDevice())
|
||||
return;
|
||||
|
||||
try {
|
||||
return ProcessIncomingFrame();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
return EndConnection();
|
||||
} catch (const std::exception &E) {
|
||||
std::string W = E.what();
|
||||
poco_information(Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_));
|
||||
return EndConnection();
|
||||
} catch (...) {
|
||||
poco_information(Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingFrame() {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
try {
|
||||
int Op, flags;
|
||||
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
|
||||
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
poco_information(Logger_, fmt::format("DISCONNECT({}): device has disconnected. Session={}", CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
IncomingFrame.append(0);
|
||||
|
||||
State_.RX += IncomingSize;
|
||||
State_.MessageCount++;
|
||||
State_.LastContact = OpenWifi::Now();
|
||||
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
State_.MessageCount++;
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Object PingObject;
|
||||
Poco::JSON::Object PingDetails;
|
||||
PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware);
|
||||
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
|
||||
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
PingDetails.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
PingDetails.set("locale", State_.locale );
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(PingObject, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
poco_trace(Logger_, fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", CId_,
|
||||
IncomingSize, flags, IncomingFrame.begin()));
|
||||
|
||||
Poco::JSON::Parser parser;
|
||||
auto ParsedMessage = parser.parse(IncomingFrame.begin());
|
||||
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
|
||||
if (IncomingJSON->has(uCentralProtocol::METHOD) &&
|
||||
IncomingJSON->has(uCentralProtocol::PARAMS)) {
|
||||
ProcessJSONRPCEvent(IncomingJSON);
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
|
||||
IncomingJSON->has(uCentralProtocol::ID)) {
|
||||
poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, IncomingFrame.begin()));
|
||||
ProcessJSONRPCResult(IncomingJSON);
|
||||
} else {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
|
||||
CId_, IncomingFrame.begin()));
|
||||
}
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
|
||||
ProcessIncomingRadiusData(IncomingJSON);
|
||||
} else {
|
||||
std::ostringstream iS;
|
||||
IncomingJSON->stringify(iS);
|
||||
std::cout << iS.str() << std::endl;
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"FRAME({}): illegal transaction header, missing 'jsonrpc'", CId_));
|
||||
Errors_++;
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
poco_information(Logger_,
|
||||
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
|
||||
return EndConnection();
|
||||
} break;
|
||||
|
||||
default: {
|
||||
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", CId_,
|
||||
std::to_string(Op)));
|
||||
} break;
|
||||
}
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_warning(Logger_, fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
poco_warning(Logger_, fmt::format("JSONException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_warning(Logger_, fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_warning(Logger_, fmt::format("SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_warning(Logger_, fmt::format("SSLException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_, fmt::format("NetException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::IOException &E) {
|
||||
poco_warning(Logger_, fmt::format("IOException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_, fmt::format("Exception({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (const std::exception &E) {
|
||||
poco_warning(Logger_, fmt::format("std::exception({}): Text:{} Payload:{} Session:{}",
|
||||
CId_,
|
||||
E.what(),
|
||||
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
} catch (...) {
|
||||
poco_error(Logger_,fmt::format("UnknownException({}): Device must be disconnected. Unknown exception. Session:{}", CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
if (Errors_ < 10)
|
||||
return;
|
||||
|
||||
poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::Send(const std::string &Payload) {
|
||||
try {
|
||||
size_t BytesSent = WS_->sendFrame(Payload.c_str(), (int)Payload.size());
|
||||
State_.TX += BytesSent;
|
||||
return BytesSent == Payload.size();
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Base64Encode(const unsigned char *buffer, std::size_t size) {
|
||||
return Utils::base64encode(buffer,size);
|
||||
}
|
||||
|
||||
std::string Base64Decode(const std::string &F) {
|
||||
std::istringstream ifs(F);
|
||||
Poco::Base64Decoder b64in(ifs);
|
||||
std::ostringstream ofs;
|
||||
Poco::StreamCopier::copyStream(b64in, ofs);
|
||||
return ofs.str();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSAUTH);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusAccountingData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSACCT);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SendRadiusCoAData(const unsigned char * buffer, std::size_t size) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSCOA);
|
||||
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
|
||||
|
||||
std::ostringstream Payload;
|
||||
Answer.stringify(Payload);
|
||||
return Send(Payload.str());
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
|
||||
if( Doc->has(uCentralProtocol::RADIUSDATA)) {
|
||||
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();
|
||||
if(Type==uCentralProtocol::RADIUSACCT) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAccountingData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
} else if(Type==uCentralProtocol::RADIUSAUTH) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
} else if(Type==uCentralProtocol::RADIUSCOA) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendCoAData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,20 @@
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WSConnection {
|
||||
static constexpr int BufSize = 128000;
|
||||
class AP_WS_Connection {
|
||||
static constexpr int BufSize = 256000;
|
||||
public:
|
||||
WSConnection(Poco::Net::StreamSocket& Socket, Poco::Net::SocketReactor& Reactor);
|
||||
~WSConnection();
|
||||
explicit AP_WS_Connection( Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
std::uint64_t connection_id,
|
||||
Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R);
|
||||
~AP_WS_Connection();
|
||||
|
||||
void EndConnection();
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr & Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
|
||||
void ProcessIncomingFrame();
|
||||
@@ -41,10 +47,25 @@ namespace OpenWifi {
|
||||
static bool ExtractBase64CompressedData(const std::string & CompressedData, std::string & UnCompressedData, uint64_t compress_sz);
|
||||
void LogException(const Poco::Exception &E);
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
bool SetWebSocketTelemetryReporting(uint64_t interval, uint64_t TelemetryWebSocketTimer);
|
||||
bool SetKafkaTelemetryReporting(uint64_t interval, uint64_t TelemetryKafkaTimer);
|
||||
bool StopWebSocketTelemetry();
|
||||
bool StopKafkaTelemetry();
|
||||
bool SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryWebSocketTimer);
|
||||
bool SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryKafkaTimer);
|
||||
bool StopWebSocketTelemetry(std::uint64_t RPCID);
|
||||
bool StopKafkaTelemetry(std::uint64_t RPCID);
|
||||
|
||||
void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
|
||||
void Process_state(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
|
||||
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
bool ValidatedDevice();
|
||||
|
||||
inline bool GetTelemetryParameters(bool & Reporting, uint64_t & Interval,
|
||||
uint64_t & WebSocketTimer, uint64_t & KafkaTimer,
|
||||
uint64_t &WebSocketCount, uint64_t & KafkaCount,
|
||||
@@ -61,36 +82,44 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class DeviceRegistry;
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
std::shared_mutex TelemetryMutex_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::StreamSocket Socket_;
|
||||
Poco::Net::SocketReactor & Reactor_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
std::string SerialNumber_;
|
||||
uint64_t SerialNumberInt_=0;
|
||||
std::string Compatible_;
|
||||
std::shared_ptr<DeviceRegistry::ConnectionEntry> Conn_;
|
||||
volatile bool Registered_ = false ;
|
||||
std::atomic_bool Registered_ = false ;
|
||||
std::string CId_;
|
||||
std::string CN_;
|
||||
GWObjects::CertificateValidation CertValidation_ = GWObjects::CertificateValidation::NO_CERTIFICATE;
|
||||
uint64_t Errors_=0;
|
||||
volatile bool Connected_=false;
|
||||
uint64_t ConnectionId_=0;
|
||||
Poco::Net::IPAddress PeerAddress_;
|
||||
volatile std::atomic_bool TelemetryReporting_ = false;
|
||||
volatile uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
volatile uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
std::atomic_bool TelemetryReporting_ = false;
|
||||
std::atomic_uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
uint64_t TelemetryKafkaTimer_ = 0 ;
|
||||
uint64_t TelemetryInterval_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketPackets_=0;
|
||||
volatile uint64_t TelemetryKafkaPackets_=0;
|
||||
std::atomic_uint64_t TelemetryWebSocketPackets_=0;
|
||||
std::atomic_uint64_t TelemetryKafkaPackets_=0;
|
||||
GWObjects::ConnectionState State_;
|
||||
std::string LastStats_;
|
||||
GWObjects::HealthCheck LastHealthcheck_;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
|
||||
bool Threaded_=false;
|
||||
std::atomic_bool Dead_=false;
|
||||
std::atomic_bool DeviceValidated_=false;
|
||||
|
||||
static inline std::atomic_uint64_t ConcurrentStartingDevices_=0;
|
||||
|
||||
void CompleteStartup();
|
||||
bool StartTelemetry();
|
||||
bool StopTelemetry();
|
||||
bool StartTelemetry(std::uint64_t RPCID);
|
||||
bool StopTelemetry(std::uint64_t RPCID);
|
||||
void UpdateCounts();
|
||||
};
|
||||
|
||||
24
src/AP_WS_Process_cfgpending.cpp
Normal file
24
src/AP_WS_Process_cfgpending.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::ACTIVE)) {
|
||||
|
||||
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
[[maybe_unused]] uint64_t Active = ParamsObj->get(uCentralProtocol::ACTIVE);
|
||||
poco_trace(Logger_, fmt::format("CFG-PENDING({}): Active: {} Target: {}", CId_, Active, UUID));
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("CFG-PENDING({}): Missing some parameters", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
124
src/AP_WS_Process_connect.cpp
Normal file
124
src/AP_WS_Process_connect.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
#include "FindCountry.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::FIRMWARE) &&
|
||||
ParamsObj->has(uCentralProtocol::CAPABILITIES)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
|
||||
auto Capabilities = ParamsObj->get(uCentralProtocol::CAPABILITIES).toString();
|
||||
|
||||
//// change this
|
||||
SerialNumber_ = Serial;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
CommandManager()->ClearQueue(SerialNumberInt_);
|
||||
|
||||
DeviceRegistry()->SetSessionDetails(State_.sessionId,SerialNumberInt_);
|
||||
State_.UUID = UUID;
|
||||
State_.Firmware = Firmware;
|
||||
State_.PendingUUID = 0;
|
||||
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
|
||||
CId_ = SerialNumber_ + "@" + CId_;
|
||||
|
||||
auto IP = PeerAddress_.toString();
|
||||
if(IP.substr(0,7)=="::ffff:") {
|
||||
IP = IP.substr(7);
|
||||
}
|
||||
|
||||
State_.locale = FindCountryFromIP()->Get(IP);
|
||||
GWObjects::Device DeviceInfo;
|
||||
auto DeviceExists = StorageService()->GetDevice(SerialNumber_,DeviceInfo);
|
||||
if (Daemon()->AutoProvisioning() && !DeviceExists) {
|
||||
StorageService()->CreateDefaultDevice(SerialNumber_, Capabilities, Firmware,
|
||||
Compatible_, PeerAddress_);
|
||||
} else if (DeviceExists) {
|
||||
StorageService()->UpdateDeviceCapabilities(SerialNumber_, Capabilities,
|
||||
Compatible_);
|
||||
bool Updated = false;
|
||||
if(!Firmware.empty() && Firmware!=DeviceInfo.Firmware) {
|
||||
DeviceInfo.Firmware = Firmware;
|
||||
Updated = true;
|
||||
WebSocketClientNotificationDeviceFirmwareUpdated(SerialNumber_, Firmware);
|
||||
}
|
||||
|
||||
if(DeviceInfo.locale != State_.locale) {
|
||||
DeviceInfo.locale = State_.locale;
|
||||
Updated = true;
|
||||
}
|
||||
|
||||
if(Compatible_ != DeviceInfo.DeviceType) {
|
||||
DeviceInfo.DeviceType = Compatible_;
|
||||
Updated = true;
|
||||
}
|
||||
|
||||
if(Updated) {
|
||||
StorageService()->UpdateDevice(DeviceInfo);
|
||||
}
|
||||
uint64_t UpgradedUUID=0;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
}
|
||||
|
||||
State_.Compatible = Compatible_;
|
||||
State_.Connected = true;
|
||||
ConnectionCompletionTime_ = std::chrono::high_resolution_clock::now() - ConnectionStart_;
|
||||
State_.connectionCompletionTime = ConnectionCompletionTime_.count();
|
||||
|
||||
if(State_.VerifiedCertificate == GWObjects::VALID_CERTIFICATE) {
|
||||
if (( Utils::SerialNumberMatch(CN_, SerialNumber_, AP_WS_Server()->MismatchDepth())) ||
|
||||
AP_WS_Server()->IsSimSerialNumber(CN_)) {
|
||||
State_.VerifiedCertificate = GWObjects::VERIFIED;
|
||||
poco_information(Logger_, fmt::format("CONNECT({}): Fully validated and authenticated device. Session={} ConnectionCompletion Time={}",
|
||||
CId_,
|
||||
State_.sessionId,
|
||||
State_.connectionCompletionTime ));
|
||||
} else {
|
||||
State_.VerifiedCertificate = GWObjects::MISMATCH_SERIAL;
|
||||
if(AP_WS_Server()->AllowSerialNumberMismatch()) {
|
||||
poco_information(
|
||||
Logger_, fmt::format("CONNECT({}): Serial number mismatch allowed. CN={} Serial={} Session={} ConnectionCompletion Time={}",
|
||||
CId_, CN_, SerialNumber_, State_.sessionId,
|
||||
State_.connectionCompletionTime));
|
||||
} else {
|
||||
poco_information(
|
||||
Logger_, fmt::format("CONNECT({}): Serial number mismatch disallowed. Device rejected. CN={} Serial={} Session={} ConnectionCompletion Time={}",
|
||||
CId_, CN_, SerialNumber_, State_.sessionId,
|
||||
State_.connectionCompletionTime));
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketClientNotificationDeviceConnected(SerialNumber_);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
ParamsObj->set("locale", State_.locale );
|
||||
ParamsObj->set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,fmt::format("INVALID-PROTOCOL({}): Missing one of uuid, firmware, or capabilities", CId_));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
34
src/AP_WS_Process_crashlog.cpp
Normal file
34
src/AP_WS_Process_crashlog.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
poco_trace(Logger_, fmt::format("CRASH-LOG({}): new entry.", CId_));
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/AP_WS_Process_deviceupdate.cpp
Normal file
25
src/AP_WS_Process_deviceupdate.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has("currentPassword")) {
|
||||
auto Password = ParamsObj->get("currentPassword").toString();
|
||||
|
||||
StorageService()->SetDevicePassword(Serial, Password);
|
||||
poco_trace(Logger_, fmt::format("DEVICEUPDATE({}): Device is updating its login password.", Serial));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
71
src/AP_WS_Process_healthcheck.cpp
Normal file
71
src/AP_WS_Process_healthcheck.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
|
||||
ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
|
||||
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
|
||||
if (CheckData.empty())
|
||||
CheckData = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("HEALTHCHECK({}): UUID={} Updating.", CId_, UUID));
|
||||
} else {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("HEALTHCHECK({}): UUID={} Updating for CMD={}.", CId_,
|
||||
UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
|
||||
GWObjects::HealthCheck Check;
|
||||
|
||||
Check.SerialNumber = SerialNumber_;
|
||||
Check.Recorded = OpenWifi::Now();
|
||||
Check.UUID = UUID;
|
||||
Check.Data = CheckData;
|
||||
Check.Sanity = Sanity;
|
||||
|
||||
StorageService()->AddHealthCheckData(Check);
|
||||
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, CheckData);
|
||||
}
|
||||
|
||||
LastHealthcheck_ = Check;
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
ParamsObj->set("timestamp", OpenWifi::Now());
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
41
src/AP_WS_Process_log.cpp
Normal file
41
src/AP_WS_Process_log.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::LOG) && ParamsObj->has(uCentralProtocol::SEVERITY)) {
|
||||
poco_trace(Logger_, fmt::format("LOG({}): new entry.", CId_));
|
||||
auto Log = ParamsObj->get(uCentralProtocol::LOG).toString();
|
||||
auto Severity = ParamsObj->get(uCentralProtocol::SEVERITY);
|
||||
std::string DataStr = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
if (ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
auto DataObj = ParamsObj->get(uCentralProtocol::DATA);
|
||||
if (DataObj.isStruct())
|
||||
DataStr = DataObj.toString();
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = Log,
|
||||
.Data = DataStr,
|
||||
.Severity = Severity,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 0,
|
||||
.UUID = State_.UUID};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/AP_WS_Process_ping.cpp
Normal file
16
src/AP_WS_Process_ping.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_ping(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID)) {
|
||||
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
poco_trace(Logger_, fmt::format("PING({}): Current config is {}", CId_, UUID));
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("PING({}): Missing parameter.", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/AP_WS_Process_recovery.cpp
Normal file
62
src/AP_WS_Process_recovery.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_recovery(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::SERIAL) &&
|
||||
ParamsObj->has(uCentralProtocol::FIRMWARE) && ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::REBOOT) &&
|
||||
ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
|
||||
LogText = "Firmware: " + ParamsObj->get(uCentralProtocol::FIRMWARE).toString() + "\r\n";
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
|
||||
if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroService::CreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::REBOOT;
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
bool Sent;
|
||||
CommandManager()->PostCommand(CommandManager()->NextRPCId(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
poco_information(Logger_, fmt::format("RECOVERY({}): Recovery mode received, need for a reboot.", CId_));
|
||||
} else {
|
||||
poco_information(Logger_, fmt::format(
|
||||
"RECOVERY({}): Recovery mode received, no need for a reboot.", CId_));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("RECOVERY({}): Recovery missing one of serialnumber, firmware, uuid, loglines, reboot",
|
||||
CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/AP_WS_Process_state.cpp
Normal file
67
src/AP_WS_Process_state.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
#include "StateUtils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_state(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::STATE)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto StateStr = ParamsObj->get(uCentralProtocol::STATE).toString();
|
||||
auto StateObj = ParamsObj->getObject(uCentralProtocol::STATE);
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty()) {
|
||||
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating.", CId_, UUID));
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating for CMD={}.",
|
||||
CId_, UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID,UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
LastStats_ = StateStr;
|
||||
|
||||
GWObjects::Statistics Stats{
|
||||
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
|
||||
Stats.Recorded = OpenWifi::Now();
|
||||
StorageService()->AddStatisticsData(Stats);
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, StateStr);
|
||||
}
|
||||
|
||||
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
|
||||
State_.Associations_5G);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
|
||||
}
|
||||
|
||||
WebSocketNotification<WebNotificationSingleDevice> N;
|
||||
N.content.serialNumber = SerialNumber_;
|
||||
N.type = "device_statistics";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("STATE({}): Invalid request. Missing serial, uuid, or state", CId_));
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/AP_WS_Process_telemetry.cpp
Normal file
54
src/AP_WS_Process_telemetry.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_telemetry(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (!State_.Connected) {
|
||||
poco_warning(Logger_, fmt::format(
|
||||
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (TelemetryReporting_) {
|
||||
if (ParamsObj->has("data")) {
|
||||
auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
|
||||
Payload->set("timestamp", OpenWifi::Now());
|
||||
std::ostringstream SS;
|
||||
Payload->stringify(SS);
|
||||
auto now=OpenWifi::Now();
|
||||
if (TelemetryWebSocketRefCount_) {
|
||||
if(now<TelemetryWebSocketTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
|
||||
TelemetryWebSocketPackets_++;
|
||||
State_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->UpdateEndPoint(SerialNumberInt_, SS.str());
|
||||
} else {
|
||||
StopWebSocketTelemetry(CommandManager()->NextRPCId());
|
||||
}
|
||||
}
|
||||
if (TelemetryKafkaRefCount_) {
|
||||
if(KafkaManager()->Enabled() && now<TelemetryKafkaTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl;
|
||||
TelemetryKafkaPackets_++;
|
||||
State_.kafkaPackets = TelemetryKafkaPackets_;
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
|
||||
SS.str());
|
||||
} else {
|
||||
StopKafkaTelemetry(CommandManager()->NextRPCId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poco_debug(Logger_,fmt::format("TELEMETRY({}): Invalid telemetry packet.",SerialNumber_));
|
||||
}
|
||||
} else {
|
||||
// if we are ignoring telemetry, then close it down on the device.
|
||||
poco_debug(Logger_,fmt::format("TELEMETRY({}): Stopping runaway telemetry.",SerialNumber_));
|
||||
StopTelemetry(CommandManager()->NextRPCId());
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/AP_WS_Process_venuebroadcast.cpp
Normal file
17
src/AP_WS_Process_venuebroadcast.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-26.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "VenueBroadcaster.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if(ParamsObj->has("data") && ParamsObj->has("serial") && ParamsObj->has("timestamp")) {
|
||||
VenueBroadcaster()->Broadcast(
|
||||
ParamsObj->get("serial").toString(),
|
||||
ParamsObj->get("data").toString(),
|
||||
ParamsObj->get("timestamp"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,63 +5,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include "Poco/Environment.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ReactorThreadPool {
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit ReactorThreadPool() {
|
||||
if(Poco::Environment::processorCount()>8)
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()/2;
|
||||
else
|
||||
NumberOfThreads_ = 2;
|
||||
Start("ReactorThreadPool");
|
||||
explicit AP_WS_ReactorThreadPool() {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount()*2;
|
||||
if(NumberOfThreads_==0)
|
||||
NumberOfThreads_=4;
|
||||
}
|
||||
|
||||
~ ReactorThreadPool() {
|
||||
~ AP_WS_ReactorThreadPool() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Start(const std::string & ThreadNamePrefix) {
|
||||
void Start() {
|
||||
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
|
||||
auto NewReactor = std::make_unique<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->setStackSize(2000000);
|
||||
NewThread->start(*NewReactor);
|
||||
std::string ThreadName{ThreadNamePrefix + "#" + std::to_string(i)};
|
||||
std::string ThreadName{"ap:react:" + std::to_string(i)};
|
||||
Utils::SetThreadName(*NewThread,ThreadName.c_str());
|
||||
Reactors_.emplace_back(std::move(NewReactor));
|
||||
Threads_.emplace_back(std::move(NewThread));
|
||||
}
|
||||
}
|
||||
|
||||
inline static auto instance() {
|
||||
static auto instance_ = new ReactorThreadPool;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for (auto &i : Reactors_)
|
||||
i->stop();
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor &NextReactor() {
|
||||
std::lock_guard G(Mutex_);
|
||||
std::shared_lock Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
std::shared_mutex Mutex_;
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
|
||||
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
|
||||
};
|
||||
inline auto ReactorThreadPool() { return ReactorThreadPool::instance(); }
|
||||
}
|
||||
163
src/AP_WS_Server.cpp
Normal file
163
src/AP_WS_Server.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/JSON/Array.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "TelemetryStream.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) {
|
||||
try {
|
||||
AP_WS_Server()->AddConnection(id_,std::make_shared<AP_WS_Connection>(request,response,id_, Logger_, AP_WS_Server()->NextReactor()));
|
||||
} catch (...) {
|
||||
poco_warning(Logger_,"Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
bool AP_WS_Server::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
|
||||
if(IsCertOk()) {
|
||||
if(!Certificate.issuedBy(*IssuerCert_)) {
|
||||
poco_warning(Logger(),fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AP_WS_Server::Start() {
|
||||
|
||||
AllowSerialNumberMismatch_ = MicroService::instance().ConfigGetBool("openwifi.certificates.allowmismatch",true);
|
||||
MismatchDepth_ = MicroService::instance().ConfigGetInt("openwifi.certificates.mismatchdepth",2);
|
||||
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
|
||||
Reactor_pool_->Start();
|
||||
|
||||
for(const auto & Svr : ConfigServersList_ ) {
|
||||
|
||||
poco_notice(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(),
|
||||
Svr.Port(), Svr.KeyFile(), Svr.CertFile()));
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if (!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
|
||||
if (!IsCertOk()) {
|
||||
IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
|
||||
poco_information(Logger(),
|
||||
fmt::format("Certificate Issuer Name:{}", IssuerCert_->issuerName()));
|
||||
}
|
||||
|
||||
Poco::Net::Context::Params P;
|
||||
|
||||
P.verificationMode = Poco::Net::Context::VERIFY_ONCE;
|
||||
P.verificationDepth = 9;
|
||||
P.loadDefaultCAs = Svr.RootCA().empty();
|
||||
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
|
||||
P.dhUse2048Bits = true;
|
||||
P.caLocation = Svr.Cas();
|
||||
|
||||
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
|
||||
|
||||
if(!Svr.KeyFilePassword().empty()) {
|
||||
auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(Svr.KeyFilePassword(),Logger()));
|
||||
Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr,Context);
|
||||
}
|
||||
|
||||
Poco::Crypto::X509Certificate Cert(Svr.CertFile());
|
||||
Poco::Crypto::X509Certificate Root(Svr.RootCA());
|
||||
|
||||
Context->useCertificate(Cert);
|
||||
Context->addChainCertificate(Root);
|
||||
|
||||
Context->addCertificateAuthority(Root);
|
||||
Poco::Crypto::X509Certificate Issuing(Svr.IssuerCertFile());
|
||||
Context->addChainCertificate(Issuing);
|
||||
Context->addCertificateAuthority(Issuing);
|
||||
|
||||
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
|
||||
Context->usePrivateKey(Key);
|
||||
|
||||
Context->setSessionCacheSize(0);
|
||||
Context->setSessionTimeout(120);
|
||||
Context->flushSessionCache();
|
||||
Context->enableSessionCache(true);
|
||||
Context->enableExtendedCertificateVerification(false);
|
||||
// Context->disableStatelessSessionResumption();
|
||||
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 | Poco::Net::Context::PROTO_TLSV1_1);
|
||||
|
||||
auto WebServerHttpParams = new Poco::Net::HTTPServerParams;
|
||||
WebServerHttpParams->setMaxThreads(50);
|
||||
WebServerHttpParams->setMaxQueued(200);
|
||||
WebServerHttpParams->setKeepAlive(true);
|
||||
WebServerHttpParams->setName("ws:ap_dispatch");
|
||||
|
||||
if (Svr.Address() == "*") {
|
||||
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
|
||||
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
|
||||
: Poco::Net::AddressFamily::IPv4));
|
||||
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
|
||||
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
} else {
|
||||
Poco::Net::IPAddress Addr(Svr.Address());
|
||||
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
|
||||
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &server:WebServers_) {
|
||||
server->start();
|
||||
}
|
||||
|
||||
ReactorThread_.start(Reactor_);
|
||||
|
||||
auto ProvString = MicroService::instance().ConfigGetString("autoprovisioning.process","default");
|
||||
if(ProvString!="default") {
|
||||
auto Tokens = Poco::StringTokenizer(ProvString, ",");
|
||||
for (const auto &i : Tokens) {
|
||||
if (i == "prov")
|
||||
LookAtProvisioning_ = true;
|
||||
else
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
} else {
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
|
||||
SimulatorId_ = MicroService::instance().ConfigGetString("simulatorid","");
|
||||
SimulatorEnabled_ = !SimulatorId_.empty();
|
||||
Utils::SetThreadName(ReactorThread_,"dev:react:head");
|
||||
|
||||
Running_ = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_Server::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
|
||||
for(auto &server:WebServers_) {
|
||||
server->stopAll();
|
||||
}
|
||||
Reactor_pool_->Stop();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
} //namespace
|
||||
145
src/AP_WS_Server.h
Normal file
145
src/AP_WS_Server.h
Normal file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/ParallelSocketAcceptor.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t id)
|
||||
: Logger_(L),
|
||||
id_(id){
|
||||
};
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
std::uint64_t id_=0;
|
||||
};
|
||||
|
||||
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L)
|
||||
: Logger_(L) {
|
||||
}
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *
|
||||
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
|
||||
if (request.find("Upgrade") != request.end() &&
|
||||
Poco::icompare(request["Upgrade"], "websocket") == 0) {
|
||||
Utils::SetThreadName("ws:conn-init");
|
||||
return new AP_WS_RequestHandler(Logger_,id_++);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static std::uint64_t id_=1;
|
||||
};
|
||||
|
||||
class AP_WS_Server : public SubSystemServer {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new AP_WS_Server;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool IsCertOk() { return IssuerCert_!= nullptr; }
|
||||
bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
|
||||
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
|
||||
|
||||
inline bool IsSimSerialNumber(const std::string & SerialNumber) const {
|
||||
return IsSim(Poco::toLower(SerialNumber)) && Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
|
||||
}
|
||||
|
||||
inline static bool IsSim(const std::string & SerialNumber) {
|
||||
return SerialNumber.substr(0,6) == "53494d";
|
||||
}
|
||||
|
||||
inline bool IsSimEnabled() const {
|
||||
return SimulatorEnabled_;
|
||||
}
|
||||
|
||||
inline bool AllowSerialNumberMismatch() const {
|
||||
return AllowSerialNumberMismatch_;
|
||||
}
|
||||
|
||||
inline std::uint64_t MismatchDepth() const {
|
||||
return MismatchDepth_;
|
||||
}
|
||||
|
||||
inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
|
||||
[[nodiscard]] inline Poco::Net::SocketReactor & NextReactor() { return Reactor_pool_->NextReactor(); }
|
||||
[[nodiscard]] inline bool Running() const { return Running_; }
|
||||
|
||||
inline void AddConnection(std::uint64_t session_id, std::shared_ptr<AP_WS_Connection> Connection ) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
Connections_[session_id] = Connection;
|
||||
}
|
||||
|
||||
inline void DeleteConnection(std::uint64_t session_id) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
Connections_.erase(session_id);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<AP_WS_Connection> FindConnection(std::uint64_t session_id) const {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
auto Connection = Connections_.find(session_id);
|
||||
if(Connection!=end(Connections_))
|
||||
return Connection->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex LocalMutex_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
std::string SimulatorId_;
|
||||
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 2, 32};
|
||||
bool LookAtProvisioning_ = false;
|
||||
bool UseDefaultConfig_ = true;
|
||||
bool SimulatorEnabled_=false;
|
||||
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
|
||||
std::atomic_bool Running_=false;
|
||||
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Connections_;
|
||||
std::atomic_bool AllowSerialNumberMismatch_=true;
|
||||
std::atomic_uint64_t MismatchDepth_=2;
|
||||
|
||||
AP_WS_Server() noexcept:
|
||||
SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto AP_WS_Server() { return AP_WS_Server::instance(); }
|
||||
|
||||
} //namespace
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -7,115 +7,148 @@
|
||||
//
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/File.h"
|
||||
|
||||
#include "CentralConfig.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace OpenWifi::Config {
|
||||
|
||||
const static std::string BasicConfig {
|
||||
R"lit({
|
||||
"uuid": 1,
|
||||
"radios": [
|
||||
{
|
||||
"band": "5G",
|
||||
"country": "CA",
|
||||
"channel-mode": "HE",
|
||||
"channel-width": 80,
|
||||
"channel": 32
|
||||
}
|
||||
],
|
||||
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "WAN",
|
||||
"role": "upstream",
|
||||
"services": [ "lldp" ],
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ssids": [
|
||||
{
|
||||
"name": "OpenWifi",
|
||||
"wifi-bands": [
|
||||
"5G"
|
||||
],
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"proto": "psk2",
|
||||
"key": "OpenWifi",
|
||||
"ieee80211w": "optional"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LAN",
|
||||
"role": "downstream",
|
||||
"services": [ "ssh", "lldp" ],
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "192.168.1.1/24",
|
||||
"dhcp": {
|
||||
"lease-first": 10,
|
||||
"lease-count": 100,
|
||||
"lease-time": "6h"
|
||||
}
|
||||
},
|
||||
"ssids": [
|
||||
{
|
||||
"name": "OpenWifi",
|
||||
"wifi-bands": [
|
||||
"5G"
|
||||
],
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"proto": "psk2",
|
||||
"key": "OpenWifi",
|
||||
"ieee80211w": "optional"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"statistics": {
|
||||
"interval": 120,
|
||||
"types": [ "ssids", "lldp", "clients" ]
|
||||
},
|
||||
"health": {
|
||||
"interval": 120
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"lldp": {
|
||||
"describe": "uCentral",
|
||||
"location": "universe"
|
||||
},
|
||||
"ssh": {
|
||||
"port": 22
|
||||
}
|
||||
}
|
||||
})lit"};
|
||||
R"lit(
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "WAN",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh",
|
||||
"lldp",
|
||||
"dhcp-snooping"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "optional",
|
||||
"key": "OpenWifi",
|
||||
"proto": "psk2"
|
||||
},
|
||||
"name": "OpenWifi",
|
||||
"services": [
|
||||
"wifi-frames"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G","5G"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 10000,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"subnet": "192.168.1.1/16"
|
||||
},
|
||||
"name": "LAN",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"ssh",
|
||||
"lldp",
|
||||
"dhcp-snooping"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 120
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"country": "CA"
|
||||
},
|
||||
{
|
||||
"allow-dfs": true,
|
||||
"band": "5G",
|
||||
"channel": "auto",
|
||||
"channel-mode": "HE",
|
||||
"country": "CA"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"lldp": {
|
||||
"describe": "TIP OpenWiFi",
|
||||
"location": "QA"
|
||||
},
|
||||
"ssh": {
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 2
|
||||
}
|
||||
)lit"};
|
||||
|
||||
void Config::SetBasicConfigFile() {
|
||||
try {
|
||||
|
||||
@@ -8,214 +8,277 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void CommandManager::run() {
|
||||
Utils::SetThreadName("cmd-mgr");
|
||||
Utils::SetThreadName("cmd:mgr");
|
||||
Running_ = true;
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while(NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification*>(NextMsg.get());
|
||||
|
||||
if(Resp!= nullptr) {
|
||||
const Poco::JSON::Object & Payload = Resp->Payload_;
|
||||
const std::string & SerialNumber = Resp->SerialNumber_;
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
|
||||
while (NextMsg && Running_) {
|
||||
auto Resp = dynamic_cast<RPCResponseNotification *>(NextMsg.get());
|
||||
|
||||
std::ostringstream SS;
|
||||
Payload.stringify(SS);
|
||||
try {
|
||||
if (Resp != nullptr) {
|
||||
const Poco::JSON::Object &Payload = Resp->Payload_;
|
||||
const std::string &SerialNumber = Resp->SerialNumber_;
|
||||
|
||||
Logger().debug(fmt::format("({}): RPC Response received.", SerialNumber));
|
||||
if(!Payload.has(uCentralProtocol::ID)){
|
||||
Logger().error(fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
} else {
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
if (ID < 2) {
|
||||
Logger().debug(fmt::format("({}): Ignoring RPC response.", SerialNumber));
|
||||
std::ostringstream SS;
|
||||
Payload.stringify(SS);
|
||||
|
||||
if (!Payload.has(uCentralProtocol::ID)) {
|
||||
poco_error(Logger(), fmt::format("({}): Invalid RPC response.", SerialNumber));
|
||||
} else {
|
||||
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
|
||||
std::lock_guard G(Mutex_);
|
||||
auto RPC = OutStandingRequests_.find(Idx);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
Logger().warning(
|
||||
fmt::format("({}): Outdated RPC {}", SerialNumber, ID));
|
||||
} else {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time =
|
||||
std::chrono::high_resolution_clock::now() - RPC->second->submitted;
|
||||
StorageService()->CommandCompleted(RPC->second->uuid, Payload,
|
||||
rpc_execution_time, true);
|
||||
if (RPC->second->rpc_entry) {
|
||||
RPC->second->rpc_entry->set_value(Payload);
|
||||
uint64_t ID = Payload.get(uCentralProtocol::ID);
|
||||
poco_debug(Logger(),fmt::format("({}): Processing {} response.", SerialNumber, ID));
|
||||
if (ID > 1) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
auto RPC = OutStandingRequests_.find(ID);
|
||||
if (RPC == OutStandingRequests_.end() ||
|
||||
RPC->second.SerialNumber !=
|
||||
Utils::SerialNumberToInt(Resp->SerialNumber_)) {
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): RPC {} completed.", SerialNumber, ID));
|
||||
} else {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time =
|
||||
std::chrono::high_resolution_clock::now() -
|
||||
RPC->second.submitted;
|
||||
StorageService()->CommandCompleted(RPC->second.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
if (RPC->second.rpc_entry) {
|
||||
RPC->second.rpc_entry->set_value(Payload);
|
||||
}
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): Received RPC answer {}. Command={}",
|
||||
SerialNumber, ID, RPC->second.Command));
|
||||
OutStandingRequests_.erase(ID);
|
||||
}
|
||||
OutstandingUUIDs_.erase(RPC->second->uuid);
|
||||
OutStandingRequests_.erase(Idx);
|
||||
Logger().information(
|
||||
fmt::format("({}): Received RPC answer {}", SerialNumber, ID));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),"Exception occurred during run.");
|
||||
}
|
||||
NextMsg = ResponseQueue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger(),"RPC Command processor stopping.");
|
||||
}
|
||||
|
||||
int CommandManager::Start() {
|
||||
Logger().notice("Starting...");
|
||||
ManagerThread.start(*this);
|
||||
poco_notice(Logger(),"Starting...");
|
||||
|
||||
ManagerThread.start(*this);
|
||||
|
||||
JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onJanitorTimer);
|
||||
JanitorTimer_.setStartInterval( 10000 );
|
||||
JanitorTimer_.setPeriodicInterval(10 * 60 * 1000); // 1 hours
|
||||
JanitorTimer_.start(*JanitorCallback_);
|
||||
JanitorTimer_.start(*JanitorCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
CommandRunnerCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onCommandRunnerTimer);
|
||||
CommandRunnerTimer_.setStartInterval( 10000 );
|
||||
CommandRunnerTimer_.setPeriodicInterval(30 * 1000); // 1 hours
|
||||
CommandRunnerTimer_.start(*CommandRunnerCallback_);
|
||||
CommandRunnerTimer_.start(*CommandRunnerCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CommandManager::Stop() {
|
||||
Logger().notice("Stopping...");
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
JanitorTimer_.stop();
|
||||
CommandRunnerTimer_.stop();
|
||||
ResponseQueue_.wakeUpAll();
|
||||
ManagerThread.wakeUp();
|
||||
ManagerThread.join();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void CommandManager::WakeUp() {
|
||||
Logger().notice("Waking up...");
|
||||
poco_notice(Logger(),"Waking up...");
|
||||
ManagerThread.wakeUp();
|
||||
}
|
||||
|
||||
void CommandManager::onJanitorTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Utils::SetThreadName("cmd-janitor");
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
Utils::SetThreadName("cmd:janitor");
|
||||
Poco::Logger & MyLogger = Poco::Logger::get("CMD-MGR-JANITOR");
|
||||
MyLogger.information(
|
||||
fmt::format("Removing expired commands: start. {} outstanding-requests {} outstanding-uuids commands.",
|
||||
OutStandingRequests_.size(), OutstandingUUIDs_.size() ));
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
for(auto i=OutStandingRequests_.begin();i!=OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - i->second->submitted;
|
||||
if(delta > 6000000ms) {
|
||||
MyLogger.debug(fmt::format("{}: Timed out.", i->second->uuid));
|
||||
OutstandingUUIDs_.erase(i->second->uuid);
|
||||
i = OutStandingRequests_.erase(i);
|
||||
for(auto request=OutStandingRequests_.begin();request!=OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
|
||||
if(delta > 10min) {
|
||||
MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.",
|
||||
request->second.UUID,
|
||||
request->second.Command,
|
||||
Utils::IntToSerialNumber(request->second.SerialNumber)));
|
||||
request = OutStandingRequests_.erase(request);
|
||||
} else {
|
||||
++i;
|
||||
++request;
|
||||
}
|
||||
}
|
||||
MyLogger.information("Removing expired commands: done.");
|
||||
poco_information(MyLogger,
|
||||
fmt::format("Outstanding-requests {}", OutStandingRequests_.size()));
|
||||
}
|
||||
|
||||
bool CommandManager::IsCommandRunning(const std::string &C) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
for (const auto &request : OutStandingRequests_) {
|
||||
if (request.second.UUID == C) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandManager::onCommandRunnerTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
Utils::SetThreadName("cmd-schdlr");
|
||||
Poco::Logger & MyLogger = Poco::Logger::get("CMD-MGR-SCHEDULER");
|
||||
Utils::SetThreadName("cmd:schdlr");
|
||||
Poco::Logger &MyLogger = Poco::Logger::get("CMD-MGR-SCHEDULER");
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if(StorageService()->GetReadyToExecuteCommands(0,200,Commands))
|
||||
{
|
||||
for(auto & Cmd: Commands)
|
||||
{
|
||||
if(!Running_)
|
||||
break;
|
||||
try {
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
if(OutstandingUUIDs_.find(Cmd.UUID)!=OutstandingUUIDs_.end())
|
||||
poco_trace(MyLogger,"Scheduler starting.");
|
||||
|
||||
try {
|
||||
|
||||
StorageService()->RemovedExpiredCommands();
|
||||
StorageService()->RemoveTimedOutCommands();
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
|
||||
poco_trace(MyLogger,fmt::format("Scheduler about to process {} commands.", Commands.size()));
|
||||
for (auto &Cmd : Commands) {
|
||||
if (!Running_) {
|
||||
poco_warning(MyLogger,"Scheduler quitting because service is stopping.");
|
||||
break;
|
||||
}
|
||||
poco_trace(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} Starting processing.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
try {
|
||||
|
||||
// Skip an already running command
|
||||
if(IsCommandRunning(Cmd.UUID))
|
||||
continue;
|
||||
}
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
MyLogger.information(fmt::format("{}: Preparing execution of {} for {}.", Cmd.UUID, Cmd.Command, Cmd.SerialNumber));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk( Cmd.SerialNumber,
|
||||
Cmd.Command,
|
||||
*Params,
|
||||
Cmd.UUID,
|
||||
Sent);
|
||||
if(Sent) {
|
||||
auto now = OpenWifi::Now();
|
||||
// 2 hour timeout for commands
|
||||
if ((now - Cmd.Submitted) > (1 * 60 * 60)) {
|
||||
poco_information(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandTimedOut(Cmd.UUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DeviceRegistry()->Connected(
|
||||
Utils::SerialNumberToInt(Cmd.SerialNumber))) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Device is not connected.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string ExecutingCommand, ExecutingUUID;
|
||||
if (CommandRunningForDevice(Utils::SerialNumberToInt(Cmd.SerialNumber),
|
||||
ExecutingUUID, ExecutingCommand)) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Device is already busy with command {} (Command={})."
|
||||
, Cmd.UUID, Cmd.SerialNumber, Cmd.Command,ExecutingUUID, ExecutingCommand));
|
||||
continue;
|
||||
}
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
poco_information(MyLogger, fmt::format("{}: Serial={} Command={} Preparing execution.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk(NextRPCId(), Cmd.SerialNumber, Cmd.Command,
|
||||
*Params, Cmd.UUID, Sent);
|
||||
if (Sent) {
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Sent.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
} else {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Re-queued command.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Failed. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Hard failure. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
std::lock_guard M(Mutex_);
|
||||
OutstandingUUIDs_.insert(Cmd.UUID);
|
||||
MyLogger.information(fmt::format("{}: Queued command.", Cmd.UUID));
|
||||
} else {
|
||||
MyLogger.information(fmt::format("{}: Could queue command.", Cmd.UUID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
MyLogger.information(fmt::format("{}: Failed. Command marked as completed.", Cmd.UUID));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
MyLogger.information(fmt::format("{}: Hard failure.", Cmd.UUID));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
}
|
||||
}
|
||||
} catch (Poco::Exception &E) {
|
||||
MyLogger.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(MyLogger,"Exception during command processing.");
|
||||
}
|
||||
poco_trace(MyLogger,"Scheduler done.");
|
||||
}
|
||||
|
||||
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool oneway_rpc,
|
||||
bool disk_only,
|
||||
bool & Sent) {
|
||||
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Command,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool oneway_rpc,
|
||||
bool disk_only,
|
||||
bool & Sent) {
|
||||
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(SerialNumber);
|
||||
Sent=false;
|
||||
if(!DeviceRegistry()->Connected(SerialNumber)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::stringstream ToSend;
|
||||
auto Object = std::make_shared<RpcObject>();
|
||||
|
||||
CommandTagIndex Idx;
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
if (oneway_rpc)
|
||||
Idx.Id = 1;
|
||||
else
|
||||
Idx.Id = ++Id_;
|
||||
Idx.SerialNumber = SerialNumber;
|
||||
CommandInfo Idx;
|
||||
Idx.Id = oneway_rpc ? 1 : RPCID;
|
||||
Idx.SerialNumber = SerialNumberInt;
|
||||
Idx.Command = Command;
|
||||
Idx.UUID = UUID;
|
||||
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, Idx.Id);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
Object->submitted = std::chrono::high_resolution_clock::now();
|
||||
Object->uuid = UUID;
|
||||
if(disk_only) {
|
||||
Object->rpc_entry = nullptr;
|
||||
} else {
|
||||
Object->rpc_entry = std::make_shared<CommandManager::promise_type_t>();
|
||||
}
|
||||
if(!oneway_rpc) {
|
||||
OutStandingRequests_[Idx] = Object;
|
||||
OutstandingUUIDs_.insert(UUID);
|
||||
}
|
||||
}
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, RPCID);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Command);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
Idx.rpc_entry = disk_only ? nullptr : std::make_shared<CommandManager::promise_type_t>();
|
||||
|
||||
Logger().information(fmt::format("{}: Sending command. ID: {}", UUID, Idx.Id));
|
||||
poco_debug(Logger(), fmt::format("{}: Sending command. ID: {}", UUID, RPCID));
|
||||
if(DeviceRegistry()->SendFrame(SerialNumber, ToSend.str())) {
|
||||
Logger().information(fmt::format("{}: Sent command. ID: {}", UUID, Idx.Id));
|
||||
if(!oneway_rpc) {
|
||||
std::lock_guard M(Mutex_);
|
||||
OutStandingRequests_[RPCID] = Idx;
|
||||
}
|
||||
poco_debug(Logger(), fmt::format("{}: Sent command. ID: {}", UUID, RPCID));
|
||||
Sent=true;
|
||||
return Object->rpc_entry;
|
||||
return Idx.rpc_entry;
|
||||
}
|
||||
Logger().information(fmt::format("{}: Failed to send command. ID: {}", UUID, Idx.Id));
|
||||
|
||||
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPCID));
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
@@ -13,6 +13,9 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
@@ -20,29 +23,9 @@
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
struct CommandTagIndex {
|
||||
uint64_t Id=0;
|
||||
std::string SerialNumber;
|
||||
};
|
||||
|
||||
inline bool operator <(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id<rhs.Id)
|
||||
return true;
|
||||
if(lhs.Id>rhs.Id)
|
||||
return false;
|
||||
return lhs.SerialNumber<rhs.SerialNumber;
|
||||
}
|
||||
|
||||
inline bool operator ==(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id == rhs.Id && lhs.SerialNumber == rhs.SerialNumber)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
class RPCResponseNotification: public Poco::Notification {
|
||||
public:
|
||||
RPCResponseNotification(const std::string &ser,
|
||||
@@ -61,8 +44,12 @@ namespace OpenWifi {
|
||||
public:
|
||||
typedef Poco::JSON::Object objtype_t;
|
||||
typedef std::promise<objtype_t> promise_type_t;
|
||||
struct RpcObject {
|
||||
std::string uuid;
|
||||
|
||||
struct CommandInfo {
|
||||
std::uint64_t Id=0;
|
||||
std::uint64_t SerialNumber=0;
|
||||
std::string Command;
|
||||
std::string UUID;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> submitted = std::chrono::high_resolution_clock::now();
|
||||
std::shared_ptr<promise_type_t> rpc_entry;
|
||||
};
|
||||
@@ -82,18 +69,17 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
void WakeUp();
|
||||
inline void PostCommandResult(const std::string &SerialNumber, const Poco::JSON::Object &Obj) {
|
||||
std::lock_guard G(Mutex_);
|
||||
// RPCResponseQueue_->Write(RPCResponse{.serialNumber=SerialNumber, .payload = Obj});
|
||||
ResponseQueue_.enqueueNotification(new RPCResponseNotification(SerialNumber,Obj));
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID, SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -101,12 +87,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandDisk(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -114,12 +102,13 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommand(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID, SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -128,12 +117,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommandOneWay(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
bool & Sent) {
|
||||
return PostCommand(SerialNumber,
|
||||
return PostCommand(RPCID,
|
||||
SerialNumber,
|
||||
Method,
|
||||
Params,
|
||||
UUID,
|
||||
@@ -141,6 +132,8 @@ namespace OpenWifi {
|
||||
false, Sent );
|
||||
}
|
||||
|
||||
bool IsCommandRunning(const std::string &C);
|
||||
|
||||
void run() override;
|
||||
|
||||
static auto instance() {
|
||||
@@ -152,13 +145,42 @@ namespace OpenWifi {
|
||||
void onJanitorTimer(Poco::Timer & timer);
|
||||
void onCommandRunnerTimer(Poco::Timer & timer);
|
||||
void onRPCAnswer(bool& b);
|
||||
inline uint64_t NextRPCId() { return ++Id_; }
|
||||
|
||||
void RemovePendingCommand(std::uint64_t Id) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
OutStandingRequests_.erase(Id);
|
||||
}
|
||||
|
||||
inline bool CommandRunningForDevice(std::uint64_t SerialNumber, std::string & uuid, std::string &command) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
for(const auto &[Request,Command]:OutStandingRequests_) {
|
||||
if(Command.SerialNumber==SerialNumber) {
|
||||
uuid = Command.UUID;
|
||||
command = Command.Command;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void ClearQueue(std::uint64_t SerialNumber) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
for(auto Request = OutStandingRequests_.begin(); Request != OutStandingRequests_.end() ; ) {
|
||||
if(Request->second.SerialNumber==SerialNumber)
|
||||
Request = OutStandingRequests_.erase(Request);
|
||||
else
|
||||
++Request;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
volatile bool Running_ = false;
|
||||
mutable std::shared_mutex LocalMutex_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
volatile uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
std::map<CommandTagIndex,std::shared_ptr<RpcObject>> OutStandingRequests_;
|
||||
std::set<std::string> OutstandingUUIDs_;
|
||||
std::atomic_uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
std::map<std::uint64_t , CommandInfo> OutStandingRequests_;
|
||||
Poco::Timer JanitorTimer_;
|
||||
std::unique_ptr<Poco::TimerCallback<CommandManager>> JanitorCallback_;
|
||||
Poco::Timer CommandRunnerTimer_;
|
||||
@@ -166,6 +188,7 @@ namespace OpenWifi {
|
||||
Poco::NotificationQueue ResponseQueue_;
|
||||
|
||||
std::shared_ptr<promise_type_t> PostCommand(
|
||||
uint64_t RPCID,
|
||||
const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
|
||||
@@ -6,25 +6,29 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CommandManager.h"
|
||||
#include "Daemon.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "FileUploader.h"
|
||||
#include "FindCountry.h"
|
||||
#include "OUIServer.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "StorageArchiver.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "WS_Server.h"
|
||||
#include "VenueBroadcaster.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "FindCountry.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class Daemon *Daemon::instance() {
|
||||
@@ -46,8 +50,9 @@ namespace OpenWifi {
|
||||
StorageArchiver(),
|
||||
TelemetryStream(),
|
||||
RTTYS_server(),
|
||||
WebSocketServer(),
|
||||
RADIUS_proxy_server()
|
||||
RADIUS_proxy_server(),
|
||||
VenueBroadcaster(),
|
||||
AP_WS_Server()
|
||||
});
|
||||
return &instance;
|
||||
}
|
||||
@@ -103,16 +108,25 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ExitCode;
|
||||
try {
|
||||
|
||||
Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr);
|
||||
auto App = OpenWifi::Daemon::instance();
|
||||
auto ExitCode = App->run(argc, argv);
|
||||
return ExitCode;
|
||||
|
||||
ExitCode = App->run(argc, argv);
|
||||
Poco::Net::SSLManager::instance().shutdown();
|
||||
} catch (Poco::Exception &exc) {
|
||||
std::cerr << exc.displayText() << std::endl;
|
||||
return Poco::Util::Application::EXIT_SOFTWARE;
|
||||
ExitCode = Poco::Util::Application::EXIT_SOFTWARE;
|
||||
std::cout << exc.displayText() << std::endl;
|
||||
} catch (std::exception &exc) {
|
||||
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
|
||||
std::cout << exc.what() << std::endl;
|
||||
} catch (...) {
|
||||
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
|
||||
std::cout << "Exception on closure" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Exitcode: " << ExitCode << std::endl;
|
||||
return ExitCode;
|
||||
}
|
||||
|
||||
// end of namespace
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/ServerApplication.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
@@ -25,7 +27,6 @@
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
|
||||
#include "Dashboard.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "GwWebSocketClient.h"
|
||||
|
||||
|
||||
@@ -7,195 +7,257 @@
|
||||
//
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "WS_Server.h"
|
||||
#include "OUIServer.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int DeviceRegistry::Start() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Starting ");
|
||||
return 0;
|
||||
poco_notice(Logger(),"Starting");
|
||||
|
||||
ArchiverCallback_ = std::make_unique<Poco::TimerCallback<DeviceRegistry>>(*this,&DeviceRegistry::onConnectionJanitor);
|
||||
Timer_.setStartInterval(60 * 1000);
|
||||
Timer_.setPeriodicInterval(20 * 1000); // every minute
|
||||
Timer_.start(*ArchiverCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeviceRegistry::Stop() {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Stopping ");
|
||||
Timer_.stop();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
Statistics = Device->second->LastStats;
|
||||
return true;
|
||||
}
|
||||
void DeviceRegistry::onConnectionJanitor([[maybe_unused]] Poco::Timer &timer) {
|
||||
|
||||
void DeviceRegistry::SetStatistics(uint64_t SerialNumber, const std::string &Statistics) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
static std::uint64_t last_log = OpenWifi::Now();
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->Conn_.LastContact = time(nullptr);
|
||||
Device->second->LastStats = Statistics;
|
||||
}
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
std::uint64_t total_connected_time=0;
|
||||
|
||||
State = Device->second->Conn_;
|
||||
return true;
|
||||
}
|
||||
auto now = OpenWifi::Now();
|
||||
for (auto connection=SerialNumbers_.begin(); connection!=SerialNumbers_.end();) {
|
||||
|
||||
void DeviceRegistry::SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->Conn_.LastContact = time(nullptr);
|
||||
Device->second->Conn_ = State;
|
||||
}
|
||||
}
|
||||
if(connection->second.second== nullptr) {
|
||||
connection++;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end()) {
|
||||
CheckData = Device->second->LastHealthcheck;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck & CheckData) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->LastHealthcheck = CheckData;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceRegistry::ConnectionEntry> DeviceRegistry::Register(uint64_t SerialNumber, WSConnection *Ptr, uint64_t & ConnectionId )
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
const auto & E = Devices_[SerialNumber] = std::make_shared<ConnectionEntry>();
|
||||
E->WSConn_ = Ptr;
|
||||
E->Conn_.LastContact = OpenWifi::Now();
|
||||
E->Conn_.Connected = true ;
|
||||
E->Conn_.UUID = 0 ;
|
||||
E->Conn_.MessageCount = 0 ;
|
||||
E->Conn_.Address = "";
|
||||
E->Conn_.TX = 0 ;
|
||||
E->Conn_.RX = 0;
|
||||
E->Conn_.VerifiedCertificate = GWObjects::CertificateValidation::NO_CERTIFICATE;
|
||||
ConnectionId = E->ConnectionId = ++Id_;
|
||||
return E;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::Connected(uint64_t SerialNumber) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
return Device->second->Conn_.Connected;
|
||||
}
|
||||
|
||||
void DeviceRegistry::UnRegister(uint64_t SerialNumber, uint64_t ConnectionId) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto It = Devices_.find(SerialNumber);
|
||||
if(It!=Devices_.end()) {
|
||||
if(It->second->ConnectionId == ConnectionId)
|
||||
Devices_.erase(SerialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->Send(Payload);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
if (connection->second.second->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time += (now - connection->second.second->State_.started);
|
||||
connection++;
|
||||
} else {
|
||||
NumberOfConnectingDevices_++;
|
||||
connection++;
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ = (NumberOfConnectedDevices_!=0) ? total_connected_time/NumberOfConnectedDevices_ : 0;
|
||||
if((now-last_log)>120) {
|
||||
last_log = now;
|
||||
poco_information(Logger(),
|
||||
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
|
||||
NumberOfConnectedDevices_, NumberOfConnectingDevices_, AverageDeviceConnectionTime_));
|
||||
}
|
||||
WebSocketClientNotificationNumberOfConnections(NumberOfConnectedDevices_,
|
||||
AverageDeviceConnectionTime_,
|
||||
NumberOfConnectingDevices_);
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
|
||||
return false;
|
||||
Statistics = Device->second.second->LastStats_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
|
||||
return false;
|
||||
State = Device->second.second->State_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
|
||||
return false;
|
||||
|
||||
CheckData = Device->second.second->LastHealthcheck_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::EndSession(std::uint64_t connection_id, std::uint64_t serial_number) {
|
||||
std::unique_lock G(LocalMutex_);
|
||||
|
||||
auto Connection = SerialNumbers_.find(serial_number);
|
||||
if(Connection==end(SerialNumbers_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Connection->second.first!=connection_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SerialNumbers_.erase(Connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber) {
|
||||
auto Connection = AP_WS_Server()->FindConnection(connection_id);
|
||||
|
||||
if(Connection== nullptr)
|
||||
return;
|
||||
|
||||
std::unique_lock G(LocalMutex_);
|
||||
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
|
||||
if( (CurrentSerialNumber==SerialNumbers_.end()) ||
|
||||
(CurrentSerialNumber->second.first<connection_id)) {
|
||||
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Connection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceRegistry::Connected(uint64_t SerialNumber) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
return Device->second.second->State_.Connected;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) const {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
// std::cout << "Device connection pointer: " << (std::uint64_t) Device->second.second << std::endl;
|
||||
return Device->second.second->Send(Payload);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
|
||||
return;
|
||||
Device->second.second->StopWebSocketTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
|
||||
return;
|
||||
Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
|
||||
return;
|
||||
Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
|
||||
}
|
||||
|
||||
void DeviceRegistry::StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
|
||||
return;
|
||||
Device->second.second->StopKafkaTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void DeviceRegistry::GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
|
||||
uint64_t & TelemetryInterval,
|
||||
uint64_t & TelemetryWebSocketTimer,
|
||||
uint64_t & TelemetryKafkaTimer,
|
||||
uint64_t & TelemetryWebSocketCount,
|
||||
uint64_t & TelemetryKafkaCount,
|
||||
uint64_t & TelemetryWebSocketPackets,
|
||||
uint64_t & TelemetryKafkaPackets) {
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if(Device==end(SerialNumbers_)|| Device->second.second== nullptr)
|
||||
return;
|
||||
Device->second.second->GetTelemetryParameters(TelemetryRunning,
|
||||
TelemetryInterval,
|
||||
TelemetryWebSocketTimer,
|
||||
TelemetryKafkaTimer,
|
||||
TelemetryWebSocketCount,
|
||||
TelemetryKafkaCount,
|
||||
TelemetryWebSocketPackets,
|
||||
TelemetryKafkaPackets);
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->SendRadiusAccountingData(buffer,size);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
return Device->second.second->SendRadiusAccountingData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->SendRadiusAuthenticationData(buffer,size);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
return Device->second.second->SendRadiusAuthenticationData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
try {
|
||||
return Device->second->WSConn_->SendRadiusCoAData(buffer,size);
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
|
||||
Device->second->Conn_.Address = "";
|
||||
Device->second->WSConn_ = nullptr;
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
std::shared_lock Guard(LocalMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
|
||||
return false;
|
||||
|
||||
try {
|
||||
return Device->second.second->SendRadiusCoAData(buffer,size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end()) {
|
||||
Device->second->Conn_.PendingUUID = PendingUUID;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -8,25 +8,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
// class uCentral::WebSocket::WSConnection;
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Timer.h"
|
||||
#include "RESTObjects//RESTAPI_GWobjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WSConnection;
|
||||
class AP_WS_Connection;
|
||||
class DeviceRegistry : public SubSystemServer {
|
||||
public:
|
||||
struct ConnectionEntry {
|
||||
WSConnection * WSConn_ = nullptr;
|
||||
GWObjects::ConnectionState Conn_;
|
||||
std::string LastStats;
|
||||
GWObjects::HealthCheck LastHealthcheck;
|
||||
uint64_t ConnectionId=0;
|
||||
};
|
||||
|
||||
DeviceRegistry() noexcept:
|
||||
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
|
||||
}
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new DeviceRegistry;
|
||||
@@ -36,84 +34,68 @@ namespace OpenWifi {
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) {
|
||||
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) const {
|
||||
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
|
||||
}
|
||||
bool GetStatistics(uint64_t SerialNumber, std::string & Statistics);
|
||||
bool GetStatistics(std::uint64_t SerialNumber, std::string & Statistics) const;
|
||||
|
||||
inline void SetStatistics(const std::string &SerialNumber, const std::string &Statistics) {
|
||||
return SetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
|
||||
}
|
||||
void SetStatistics(uint64_t SerialNumber, const std::string &stats);
|
||||
|
||||
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) {
|
||||
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) const {
|
||||
return GetState(Utils::SerialNumberToInt(SerialNumber), State);
|
||||
}
|
||||
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State);
|
||||
bool GetState(std::uint64_t SerialNumber, GWObjects::ConnectionState & State) const;
|
||||
|
||||
inline void SetState(const std::string & SerialNumber, const GWObjects::ConnectionState & State) {
|
||||
return SetState(Utils::SerialNumberToInt(SerialNumber), State);
|
||||
}
|
||||
void SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State);
|
||||
|
||||
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) {
|
||||
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) const {
|
||||
return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
|
||||
}
|
||||
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData);
|
||||
bool GetHealthcheck(std::uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const ;
|
||||
|
||||
inline void SetHealthcheck(const std::string &SerialNumber, const GWObjects::HealthCheck &H) {
|
||||
return SetHealthcheck(Utils::SerialNumberToInt(SerialNumber),H);
|
||||
}
|
||||
void SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck &H);
|
||||
bool Connected(uint64_t SerialNumber) const ;
|
||||
|
||||
std::shared_ptr<ConnectionEntry> Register(uint64_t SerialNumber, WSConnection *Conn, uint64_t & ConnectionId);
|
||||
|
||||
inline void UnRegister(const std::string & SerialNumber, uint64_t ConnectionId) {
|
||||
return UnRegister(Utils::SerialNumberToInt(SerialNumber),ConnectionId);
|
||||
}
|
||||
void UnRegister(uint64_t SerialNumber, uint64_t ConnectionId);
|
||||
|
||||
inline bool Connected(const std::string & SerialNumber) {
|
||||
return Connected(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
|
||||
bool Connected(uint64_t SerialNumber);
|
||||
|
||||
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) {
|
||||
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) const {
|
||||
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
|
||||
}
|
||||
|
||||
bool SendFrame(uint64_t SerialNumber, const std::string & Payload);
|
||||
|
||||
inline void SetPendingUUID(const std::string & SerialNumber, uint64_t PendingUUID) {
|
||||
return SetPendingUUID(Utils::SerialNumberToInt(SerialNumber), PendingUUID);
|
||||
}
|
||||
void SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID);
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(const std::string & SerialNumber) {
|
||||
return GetDeviceConnection(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(uint64_t SerialNumber) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
return Device->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
bool SendFrame(std::uint64_t SerialNumber, const std::string & Payload) const ;
|
||||
|
||||
bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
|
||||
|
||||
private:
|
||||
inline static std::atomic_uint64_t Id_=1;
|
||||
std::map<uint64_t ,std::shared_ptr<ConnectionEntry>> Devices_;
|
||||
void SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber);
|
||||
bool EndSession(std::uint64_t connection_id, std::uint64_t serial_number);
|
||||
|
||||
DeviceRegistry() noexcept:
|
||||
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
|
||||
void SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
|
||||
void StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
|
||||
void SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
|
||||
void StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
|
||||
void GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
|
||||
uint64_t & TelemetryInterval,
|
||||
uint64_t & TelemetryWebSocketTimer,
|
||||
uint64_t & TelemetryKafkaTimer,
|
||||
uint64_t & TelemetryWebSocketCount,
|
||||
uint64_t & TelemetryKafkaCount,
|
||||
uint64_t & TelemetryWebSocketPackets,
|
||||
uint64_t & TelemetryKafkaPackets);
|
||||
|
||||
void onConnectionJanitor(Poco::Timer & timer);
|
||||
|
||||
inline void AverageDeviceStatistics( std::uint64_t & Connections, std::uint64_t & AverageConnectionTime, std::uint64_t & NumberOfConnectingDevices) const {
|
||||
Connections = NumberOfConnectedDevices_;
|
||||
AverageConnectionTime = AverageDeviceConnectionTime_;
|
||||
NumberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex LocalMutex_;
|
||||
std::map<std::uint64_t, std::pair<std::uint64_t,std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
|
||||
|
||||
std::unique_ptr<Poco::TimerCallback<DeviceRegistry>> ArchiverCallback_;
|
||||
Poco::Timer Timer_;
|
||||
Poco::Thread ConnectionJanitor_;
|
||||
std::atomic_uint64_t NumberOfConnectedDevices_=0;
|
||||
std::atomic_uint64_t AverageDeviceConnectionTime_=0;
|
||||
std::atomic_uint64_t NumberOfConnectingDevices_=0;
|
||||
|
||||
};
|
||||
|
||||
inline auto DeviceRegistry() { return DeviceRegistry::instance(); }
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/HTTPServerParams.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
@@ -22,14 +22,13 @@
|
||||
|
||||
#include "FileUploader.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string URI_BASE{"/v1/upload/"};
|
||||
|
||||
int FileUploader::Start() {
|
||||
Logger().notice("Starting.");
|
||||
poco_notice(Logger(),"Starting.");
|
||||
|
||||
Poco::File UploadsDir(MicroService::instance().ConfigPath("openwifi.fileuploader.path","/tmp"));
|
||||
Path_ = UploadsDir.path();
|
||||
@@ -44,13 +43,14 @@ namespace OpenWifi {
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Logger().information(fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
poco_notice(Logger(), fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
|
||||
|
||||
auto Sock{Svr.CreateSocket(Logger())};
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
@@ -61,17 +61,18 @@ namespace OpenWifi {
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
Logger().information(fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
poco_information(Logger(),fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
|
||||
Params->setName("file-upldr");
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
} else {
|
||||
std::string l{"Starting: " + Svr.Address() + ":" + std::to_string(Svr.Port()) +
|
||||
" key:" + Svr.KeyFile() + " cert:" + Svr.CertFile()};
|
||||
Logger().information(l);
|
||||
poco_information(Logger(),l);
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
|
||||
@@ -82,6 +83,7 @@ namespace OpenWifi {
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setMaxThreads(16);
|
||||
Params->setMaxQueued(100);
|
||||
Params->setName("ws:upldr");
|
||||
|
||||
if (FullName_.empty()) {
|
||||
std::string TmpName =
|
||||
@@ -92,7 +94,7 @@ namespace OpenWifi {
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE;
|
||||
}
|
||||
Logger().information(fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
poco_information(Logger(), fmt::format("Uploader URI base is '{}'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
|
||||
@@ -109,7 +111,7 @@ namespace OpenWifi {
|
||||
|
||||
void FileUploader::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
MicroService::instance().LoadConfigurationFile();
|
||||
Logger().information("Reinitializing.");
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
@@ -198,7 +200,7 @@ namespace OpenWifi {
|
||||
const auto ContentType = Request.getContentType();
|
||||
const auto Tokens = Poco::StringTokenizer(ContentType,";",Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
Logger().debug(fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Preparing to upload trace file.",UUID_));
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
try {
|
||||
@@ -223,7 +225,7 @@ namespace OpenWifi {
|
||||
Poco::StreamCopier::copyStream(Reader.stream(), FileContent);
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 0);
|
||||
Logger().debug(fmt::format("{}: Trace file uploaded.", UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Trace file uploaded.", UUID_));
|
||||
StorageService()->AttachFileDataToCommand(UUID_, FileContent);
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
@@ -241,10 +243,10 @@ namespace OpenWifi {
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
Logger().debug("Exception while receiving trace file.");
|
||||
poco_debug(Logger(),"Exception while receiving trace file.");
|
||||
}
|
||||
|
||||
Logger().debug(fmt::format("{}: Failed to upload trace file.",UUID_));
|
||||
poco_debug(Logger(),fmt::format("{}: Failed to upload trace file.",UUID_));
|
||||
std::string Error{"Trace file rejected"};
|
||||
StorageService()->CancelWaitFile(UUID_, Error);
|
||||
Answer.set("filename", UUID_);
|
||||
@@ -264,7 +266,13 @@ namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler *FileUpLoaderRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest & Request) {
|
||||
|
||||
Logger().debug(fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
poco_debug(Logger(),fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
|
||||
if(Request.getMethod()!=Poco::Net::HTTPRequest::HTTP_POST ||
|
||||
Request.getURI().size()<(URI_BASE.size()+36)) {
|
||||
poco_warning(Logger(),fmt::format("ILLEGAL-REQUEST({}): {} {}. Dropped.", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The UUID should be after the /v1/upload/ part...
|
||||
auto UUIDLocation = Request.getURI().find_first_of(URI_BASE);
|
||||
@@ -280,17 +288,18 @@ namespace OpenWifi {
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger().warning(fmt::format("Unknown UUID={}",UUID));
|
||||
poco_warning(Logger(),fmt::format("Unknown UUID={}",UUID));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FileUploader::Stop() {
|
||||
Logger().notice("Stopping ");
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
for( const auto & svr : Servers_ )
|
||||
svr->stop();
|
||||
svr->stopAll(true);
|
||||
Servers_.clear();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
@@ -8,12 +8,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/HTTPRequestHandler.h"
|
||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/IPAddress.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
@@ -133,6 +134,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline int Start() final {
|
||||
poco_notice(Logger(),"Starting...");
|
||||
ProviderName_ = MicroService::instance().ConfigGetString("iptocountry.provider","");
|
||||
if(!ProviderName_.empty()) {
|
||||
Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(ProviderName_);
|
||||
@@ -145,6 +147,9 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline void Stop() final {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
// Nothing to do - just to provide the same look at the others.
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline std::string ReformatAddress(const std::string & I )
|
||||
|
||||
@@ -37,7 +37,6 @@ namespace OpenWifi {
|
||||
bool &Done, std::string &Answer) {
|
||||
Done = false;
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
Logger().information(Poco::format("serial_number_search: %s", Prefix));
|
||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||
std::vector<uint64_t> Numbers;
|
||||
SerialNumberCache()->FindNumbers(Prefix, 50, Numbers);
|
||||
|
||||
@@ -5,13 +5,10 @@
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "OUIServer.h"
|
||||
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/URIStreamOpener.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/File.h"
|
||||
|
||||
#include "OUIServer.h"
|
||||
@@ -27,18 +24,20 @@ namespace OpenWifi {
|
||||
UpdaterCallBack_ = std::make_unique<Poco::TimerCallback<OUIServer>>(*this, &OUIServer::onTimer);
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
|
||||
Timer_.setPeriodicInterval(7 * 24 * 60 * 60 * 1000);
|
||||
Timer_.start(*UpdaterCallBack_);
|
||||
Timer_.start(*UpdaterCallBack_, MicroService::instance().TimerPool());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OUIServer::Stop() {
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
Running_=false;
|
||||
Timer_.stop();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void OUIServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
MicroService::instance().LoadConfigurationFile();
|
||||
Logger().information("Reinitializing.");
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
@@ -46,14 +45,14 @@ namespace OpenWifi {
|
||||
bool OUIServer::GetFile(const std::string &FileName) {
|
||||
try {
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
Logger().information(fmt::format("Start: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
poco_information(Logger(), fmt::format("Start: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
std::unique_ptr<std::istream> pStr(
|
||||
Poco::URIStreamOpener::defaultOpener().open(MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
std::ofstream OS;
|
||||
OS.open(FileName);
|
||||
Poco::StreamCopier::copyStream(*pStr, OS);
|
||||
OS.close();
|
||||
Logger().information(fmt::format("Done: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
poco_information(Logger(), fmt::format("Done: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -111,7 +110,7 @@ namespace OpenWifi {
|
||||
if(ProcessFile(CurrentOUIFileName_, OUIs_)) {
|
||||
Initialized_ = true;
|
||||
Updating_=false;
|
||||
Logger().information("Using cached file.");
|
||||
poco_information(Logger(), "Using cached file.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -131,7 +130,7 @@ namespace OpenWifi {
|
||||
F1.remove();
|
||||
Poco::File F2(LatestOUIFileName_);
|
||||
F2.renameTo(CurrentOUIFileName_);
|
||||
Logger().information(fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
poco_information(Logger(), fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
|
||||
} else if(OUIs_.empty()) {
|
||||
if(ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
|
||||
LastUpdate_ = OpenWifi::Now();
|
||||
|
||||
@@ -1565,6 +1565,7 @@ namespace OpenWifi {
|
||||
ie["TLV Block"] = BufferToHex(&b[offset],l-offset);
|
||||
} break;
|
||||
default:
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1612,7 +1613,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_wfa(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Wi-Fi Alliance";
|
||||
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1620,6 +1621,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_aironet(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Cisco Wireless (Aironet)";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1627,6 +1629,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_marvell(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Marvell Semiconductor";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1634,6 +1637,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_atheros(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Atheros Communications";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1641,6 +1645,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_aruba(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Aruba Networks";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1648,6 +1653,7 @@ namespace OpenWifi {
|
||||
inline nlohmann::json dissect_vendor_ie_nintendo(const unsigned char *b, uint l) {
|
||||
nlohmann::json ie;
|
||||
ie["vendor"] = "Nintendo";
|
||||
ie["Data"] = BufferToHex(&b[1],l-1);
|
||||
b++;l++;
|
||||
return ie;
|
||||
}
|
||||
@@ -1705,7 +1711,7 @@ namespace OpenWifi {
|
||||
nlohmann::json new_ie;
|
||||
nlohmann::json content;
|
||||
|
||||
std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
// std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
uint offset=0;
|
||||
auto sub_ie = data[offset++];
|
||||
switch (sub_ie) {
|
||||
@@ -1737,92 +1743,112 @@ namespace OpenWifi {
|
||||
std::ostringstream ofs;
|
||||
Obj->stringify(ofs);
|
||||
|
||||
nlohmann::json D = nlohmann::json::parse(ofs.str());
|
||||
std::cout << "Start of parsing wifi" << std::endl;
|
||||
if (D.contains("status")) {
|
||||
auto Status = D["status"];
|
||||
|
||||
if (Status.contains("scan") && Status["scan"].is_array()) {
|
||||
nlohmann::json ScanArray = Status["scan"];
|
||||
nlohmann::json ParsedScan = nlohmann::json::array();
|
||||
for (auto &scan_entry : ScanArray) {
|
||||
if (scan_entry.contains("ies") && scan_entry["ies"].is_array()) {
|
||||
auto ies = scan_entry["ies"];
|
||||
nlohmann::json new_ies=nlohmann::json::array();
|
||||
for (auto &ie : ies) {
|
||||
try {
|
||||
if (ie.contains("type") && ie.contains("data")) {
|
||||
uint64_t ie_type = ie["type"];
|
||||
std::string ie_data = ie["data"];
|
||||
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data << std::endl;
|
||||
auto data = Base64Decode2Vec(ie_data);
|
||||
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_FH_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_FH_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_DS_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_DS_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TIM) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TIM(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_QBSS_LOAD) {
|
||||
new_ies.push_back(WFS_WLAN_EID_QBSS_LOAD(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_PWR_CONSTRAINT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_PWR_CONSTRAINT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_ERP_INFO) {
|
||||
new_ies.push_back(WFS_WLAN_EID_ERP_INFO(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPPORTED_REGULATORY_CLASSES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPPORTED_REGULATORY_CLASSES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_HT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_HT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXT_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TX_POWER_ENVELOPE) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TX_POWER_ENVELOPE(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_VHT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VHT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RRM_ENABLED_CAPABILITIES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RRM_ENABLED_CAPABILITIES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TPC_REPORT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TPC_REPORT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RSN) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RSN(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_VENDOR_SPECIFIC) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VENDOR_SPECIFIC(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
|
||||
try {
|
||||
nlohmann::json D = nlohmann::json::parse(ofs.str());
|
||||
// std::cout << "Start of parsing wifi" << std::endl;
|
||||
if (D.contains("status")) {
|
||||
auto Status = D["status"];
|
||||
if (Status.contains("scan") && Status["scan"].is_array()) {
|
||||
nlohmann::json ScanArray = Status["scan"];
|
||||
nlohmann::json ParsedScan = nlohmann::json::array();
|
||||
for (auto &scan_entry : ScanArray) {
|
||||
if (scan_entry.contains("ies") && scan_entry["ies"].is_array()) {
|
||||
auto ies = scan_entry["ies"];
|
||||
nlohmann::json new_ies = nlohmann::json::array();
|
||||
for (auto &ie : ies) {
|
||||
try {
|
||||
if (ie.contains("type") && ie.contains("data")) {
|
||||
uint64_t ie_type = ie["type"];
|
||||
std::string ie_data = ie["data"];
|
||||
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data << std::endl;
|
||||
auto data = Base64Decode2Vec(ie_data);
|
||||
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_SUPP_RATES(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_FH_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_FH_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_DS_PARAMS) {
|
||||
new_ies.push_back(WFS_WLAN_EID_DS_PARAMS(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TIM) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TIM(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_QBSS_LOAD) {
|
||||
new_ies.push_back(WFS_WLAN_EID_QBSS_LOAD(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_PWR_CONSTRAINT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_PWR_CONSTRAINT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_ERP_INFO) {
|
||||
new_ies.push_back(WFS_WLAN_EID_ERP_INFO(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES) {
|
||||
new_ies.push_back(
|
||||
WFS_WLAN_EID_SUPPORTED_REGULATORY_CLASSES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_HT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_HT_CAPABILITY(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_EXT_SUPP_RATES) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_SUPP_RATES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_TX_POWER_ENVELOPE) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TX_POWER_ENVELOPE(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_VHT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VHT_CAPABILITY(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::
|
||||
WLAN_EID_RRM_ENABLED_CAPABILITIES) {
|
||||
new_ies.push_back(
|
||||
WFS_WLAN_EID_RRM_ENABLED_CAPABILITIES(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_EXT_CAPABILITY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXT_CAPABILITY(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_TPC_REPORT) {
|
||||
new_ies.push_back(WFS_WLAN_EID_TPC_REPORT(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_RSN) {
|
||||
new_ies.push_back(WFS_WLAN_EID_RSN(data));
|
||||
} else if (ie_type ==
|
||||
ieee80211_eid::WLAN_EID_VENDOR_SPECIFIC) {
|
||||
new_ies.push_back(WFS_WLAN_EID_VENDOR_SPECIFIC(data));
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
|
||||
} else {
|
||||
// std::cout
|
||||
// << "Skipping IE: no parsing available: " << ie_type
|
||||
// << std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} else {
|
||||
std::cout
|
||||
<< "Skipping IE: no parsing available: " << ie_type
|
||||
<< std::endl;
|
||||
// std::cout << "Skipping IE: no data and type" << std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} else {
|
||||
std::cout << "Skipping IE: no data and type" << std::endl;
|
||||
} catch (...) {
|
||||
// std::cout << "Skipping IE: exception" << std::endl;
|
||||
Logger.information(fmt::format("Error parsing IEs"));
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} catch (...) {
|
||||
std::cout << "Skipping IE: exception" << std::endl;
|
||||
Logger.information(fmt::format("Error parsing IEs"));
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
// std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
Status["scan"] = ParsedScan;
|
||||
D["status"] = Status;
|
||||
}
|
||||
Status["scan"] = ParsedScan;
|
||||
D["status"] = Status;
|
||||
}
|
||||
Result << to_string(D);
|
||||
// std::cout << "End of parsing wifi" << std::endl;
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger.log(E);
|
||||
Logger.error(fmt::format("Failure to parse WifiScan."));
|
||||
} catch (...) {
|
||||
Logger.error(fmt::format("Failure to parse WifiScan."));
|
||||
}
|
||||
Result << to_string(D);
|
||||
std::cout << "End of parsing wifi" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,255 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "Poco/HMACEngine.h"
|
||||
#include "Poco/MD5Engine.h"
|
||||
|
||||
namespace OpenWifi::RADIUS {
|
||||
|
||||
#define RADCMD_ACCESS_REQ 1 /* Access-Request */
|
||||
#define RADCMD_ACCESS_ACC 2 /* Access-Accept */
|
||||
#define RADCMD_ACCESS_REJ 3 /* Access-Reject */
|
||||
#define RADCMD_ACCOUN_REQ 4 /* Accounting-Request */
|
||||
#define RADCMD_ACCOUN_RES 5 /* Accounting-Response */
|
||||
#define RADCMD_ACCOUN_STATUS 6 /* Accounting-Status */
|
||||
#define RADCMD_PASSWORD_REQUEST 7 /* Password-Request [RFC3575] */
|
||||
#define RADCMD_PASSWORD_ACK 8 /* Password-Ack [RFC3575] */
|
||||
#define RADCMD_PASSWORD_REJECT 9 /* Password-Reject [RFC3575] */
|
||||
#define RADCMD_ACCOUN_MESSAGE 10 /* Accounting-Message [RFC3575] */
|
||||
|
||||
#define RADCMD_RES_FREE_REQ 21 /* Resource-Free-Request [RFC3575] */
|
||||
#define RADCMD_RES_FREE_RES 22 /* Resource-Free-Response [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_REQ 23 /* Resource-Query-Request [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_RES 24 /* Resource-Query-Response [RFC3575] */
|
||||
#define RADCMD_RES_ALT_RECLAIM_REQ 25 /* Alternate-Resource-Reclaim-Request [RFC3575] */
|
||||
|
||||
#define RADCMD_ACCESS_CHA 11 /* Access-Challenge */
|
||||
#define RADCMD_STATUS_SER 12 /* Status-Server */
|
||||
#define RADCMD_STATUS_CLI 13 /* Status-Client */
|
||||
#define RADCMD_DISCON_REQ 40 /* Disconnect-Request */
|
||||
#define RADCMD_DISCON_ACK 41 /* Disconnect-ACK */
|
||||
#define RADCMD_DISCON_NAK 42 /* Disconnect-NAK */
|
||||
#define RADCMD_COA_REQ 43 /* CoA-Request */
|
||||
#define RADCMD_COA_ACK 44 /* CoA-ACK */
|
||||
#define RADCMD_COA_NAK 45 /* CoA-NAK */
|
||||
#define RADCMD_RESERVED 255 /* Reserved */
|
||||
|
||||
/*
|
||||
21 Resource-Free-Request [RFC3575]
|
||||
22 Resource-Free-Response [RFC3575]
|
||||
23 Resource-Query-Request [RFC3575]
|
||||
24 Resource-Query-Response [RFC3575]
|
||||
25 Alternate-Resource-Reclaim-Request [RFC3575]
|
||||
|
||||
26 NAS-Reboot-Request [RFC3575]
|
||||
27 NAS-Reboot-Response [RFC3575]
|
||||
28 Reserved
|
||||
29 Next-Passcode [RFC3575]
|
||||
30 New-Pin [RFC3575]
|
||||
31 Terminate-Session [RFC3575]
|
||||
32 Password-Expired [RFC3575]
|
||||
33 Event-Request [RFC3575]
|
||||
34 Event-Response [RFC3575]
|
||||
35-39 Unassigned
|
||||
40 Disconnect-Request [RFC3575][RFC5176]
|
||||
41 Disconnect-ACK [RFC3575][RFC5176]
|
||||
42 Disconnect-NAK [RFC3575][RFC5176]
|
||||
43 CoA-Request [RFC3575][RFC5176]
|
||||
44 CoA-ACK [RFC3575][RFC5176]
|
||||
45 CoA-NAK [RFC3575][RFC5176]
|
||||
46-49 Unassigned
|
||||
50 IP-Address-Allocate [RFC3575]
|
||||
51 IP-Address-Release [RFC3575]
|
||||
52 Protocol-Error [RFC7930]
|
||||
53-249 Unassigned
|
||||
250-253 Experimental Use [RFC3575]
|
||||
254 Reserved [RFC3575]
|
||||
255 Reserved [RFC3575]
|
||||
*/
|
||||
|
||||
struct tok {
|
||||
uint cmd;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Radius commands
|
||||
|
||||
char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
|
||||
"", //!< 0
|
||||
"Access-Request",
|
||||
"Access-Accept",
|
||||
"Access-Reject",
|
||||
"Accounting-Request",
|
||||
"Accounting-Response",
|
||||
"Accounting-Status",
|
||||
"Password-Request",
|
||||
"Password-Accept",
|
||||
"Password-Reject",
|
||||
"Accounting-Message", //!< 10
|
||||
"Access-Challenge",
|
||||
"Status-Server",
|
||||
"Status-Client",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
"18",
|
||||
"19",
|
||||
"20", //!< 20
|
||||
"Resource-Free-Request",
|
||||
"Resource-Free-Response",
|
||||
"Resource-Query-Request",
|
||||
"Resource-Query-Response",
|
||||
"Alternate-Resource-Reclaim-Request",
|
||||
"NAS-Reboot-Request",
|
||||
"NAS-Reboot-Response",
|
||||
"28",
|
||||
"Next-Passcode",
|
||||
"New-Pin", //!< 30
|
||||
"Terminate-Session",
|
||||
"Password-Expired",
|
||||
"Event-Request",
|
||||
"Event-Response",
|
||||
"35",
|
||||
"36",
|
||||
"37",
|
||||
"38",
|
||||
"39",
|
||||
"Disconnect-Request", //!< 40
|
||||
"Disconnect-ACK",
|
||||
"Disconnect-NAK",
|
||||
"CoA-Request",
|
||||
"CoA-ACK",
|
||||
"CoA-NAK",
|
||||
"46",
|
||||
"47",
|
||||
"48",
|
||||
"49",
|
||||
"IP-Address-Allocate",
|
||||
"IP-Address-Release", //!< 50
|
||||
};
|
||||
|
||||
|
||||
*/
|
||||
|
||||
static const struct tok radius_command_values[] = {
|
||||
{ RADCMD_ACCESS_REQ, "Access-Request" },
|
||||
{ RADCMD_ACCESS_ACC, "Access-Accept" },
|
||||
{ RADCMD_ACCESS_REJ, "Access-Reject" },
|
||||
{ RADCMD_ACCOUN_REQ, "Accounting-Request" },
|
||||
{ RADCMD_ACCOUN_RES, "Accounting-Response" },
|
||||
{ RADCMD_ACCESS_CHA, "Access-Challenge" },
|
||||
{ RADCMD_STATUS_SER, "Status-Server" },
|
||||
{ RADCMD_STATUS_CLI, "Status-Client" },
|
||||
{ RADCMD_DISCON_REQ, "Disconnect-Request" },
|
||||
{ RADCMD_DISCON_ACK, "Disconnect-ACK" },
|
||||
{ RADCMD_DISCON_NAK, "Disconnect-NAK" },
|
||||
{ RADCMD_COA_REQ, "CoA-Request" },
|
||||
{ RADCMD_COA_ACK, "CoA-ACK" },
|
||||
{ RADCMD_COA_NAK, "CoA-NAK" },
|
||||
{ RADCMD_RESERVED, "Reserved" },
|
||||
{ RADCMD_ACCOUN_STATUS, "Accounting-Status"},
|
||||
{ RADCMD_PASSWORD_REQUEST, "Password-Request"},
|
||||
{ RADCMD_PASSWORD_ACK, "Password-Ack"},
|
||||
{ RADCMD_PASSWORD_REJECT, "Password-Reject"},
|
||||
{ RADCMD_ACCOUN_MESSAGE, "Accounting-Message"},
|
||||
{ RADCMD_RES_FREE_REQ, "Resource-Free-Request"},
|
||||
{ RADCMD_RES_FREE_RES, "Resource-Free-Response"},
|
||||
{ RADCMD_RES_QUERY_REQ, "Resource-Query-Request"},
|
||||
{ RADCMD_RES_QUERY_RES, "Resource-Query-Response"},
|
||||
{ RADCMD_RES_ALT_RECLAIM_REQ, "Alternate-Resource-Reclaim-Request"},
|
||||
{ 0, nullptr}
|
||||
};
|
||||
|
||||
static const struct tok radius_attribute_names[] = {
|
||||
{1,"User-Name"},
|
||||
{2,"User-Password"},
|
||||
{3,"CHAP-Password"},
|
||||
{4,"NAS-IP Address"},
|
||||
{5,"NAS-Port"},
|
||||
{6,"Service-Type"},
|
||||
{7,"Framed-Protocol"},
|
||||
{8,"Framed-IP-Address"},
|
||||
{9,"Framed-IP-Netmask"},
|
||||
{10,"Framed-Routing"},
|
||||
{11,"Filter-Id"},
|
||||
{12,"Framed-MTU"},
|
||||
{13,"Framed-Compression"},
|
||||
{14,"Login-IP-Host"},
|
||||
{15,"Login-Service"},
|
||||
{16,"Login-TCP-Port"},
|
||||
{18,"Reply-Message"},
|
||||
{19,"Callback-Number"},
|
||||
{20,"Callback-ID"},
|
||||
{22,"Framed-Route"},
|
||||
{23,"Framed-IPX-Network"},
|
||||
{24,"State"},
|
||||
{25,"Class"},
|
||||
{26,"Vendor-Specific"},
|
||||
{27,"Session-Timeout"},
|
||||
{28,"Idle-Timeout"},
|
||||
{29,"Termination-Action"},
|
||||
{30,"Called-Station-Id"},
|
||||
{31,"Calling-Station-Id"},
|
||||
{32,"NAS-Identifier"},
|
||||
{33,"Proxy-State"},
|
||||
{34,"Login-LAT-Service"},
|
||||
{35,"Login-LAT-Node"},
|
||||
{36,"Login-LAT-Group"},
|
||||
{37,"Framed-AppleTalk-Link"},
|
||||
{38,"Framed-AppleTalk-Network"},
|
||||
{39,"Framed-AppleTalk-Zone"},
|
||||
{40,"Acct-Status-Type"},
|
||||
{41,"Acct-Delay-Time"},
|
||||
{42,"Acct-Input-Octets"},
|
||||
{43,"Acct-Output-Octets"},
|
||||
{44,"Acct-Session-Id"},
|
||||
{45,"Acct-Authentic"},
|
||||
{46,"Acct-Session-Time"},
|
||||
{47,"Acct-Input-Packets"},
|
||||
{48,"Acct-Output-Packets"},
|
||||
{49,"Acct-Terminate-Cause"},
|
||||
{50,"Acct-Multi-Session-Id"},
|
||||
{51,"Acct-Link-Count"},
|
||||
{52,"Acct-Input-Gigawords"},
|
||||
{53,"Acct-Output-Gigawords"},
|
||||
{55,"Event-Timestamp"},
|
||||
{60,"CHAP-Challenge"},
|
||||
{61,"NAS-Port-Type"},
|
||||
{62,"Port-Limit"},
|
||||
{63,"Login-LAT-Port"},
|
||||
{64,"Tunnel-Type3"},
|
||||
{65,"Tunnel-Medium-Type1"},
|
||||
{66,"Tunnel-Client-Endpoint"},
|
||||
{67,"Tunnel-Server-Endpoint1"},
|
||||
{68,"Acct-Tunnel-Connection-ID"},
|
||||
{69,"Tunnel-Password1"},
|
||||
{70,"ARAP-Password"},
|
||||
{71,"ARAP-Features"},
|
||||
{72,"ARAP-Zone-Access"},
|
||||
{73,"ARAP-Security"},
|
||||
{74,"ARAP-Security-Data"},
|
||||
{75,"Password-Retry"},
|
||||
{76,"Prompt"},
|
||||
{77,"Connect-Info"},
|
||||
{78,"Configuration-Token"},
|
||||
{79,"EAP-Message"},
|
||||
{80,"Message-Authenticator"},
|
||||
{81,"Tunnel-Private-Group-ID"},
|
||||
{82,"Tunnel-Assignment-ID1"},
|
||||
{83,"Tunnel-Preference"},
|
||||
{84,"ARAP-Challenge-Response"},
|
||||
{85,"Acct-Interim-Interval"},
|
||||
{86,"Acct-Tunnel-Packets-Lost"},
|
||||
{87,"NAS-Port-ID"},
|
||||
{88,"Framed-Pool"},
|
||||
{90,"Tunnel-Client-Auth-ID"},
|
||||
{91,"Tunnel-Server-Auth-ID"},
|
||||
{0, nullptr}
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct RadiusAttribute {
|
||||
unsigned char type{0};
|
||||
@@ -20,12 +267,68 @@ namespace OpenWifi::RADIUS {
|
||||
struct RawRadiusPacket {
|
||||
unsigned char code{1};
|
||||
unsigned char identifier{0};
|
||||
uint16_t len{0};
|
||||
uint16_t rawlen{0};
|
||||
unsigned char authenticator[16]{0};
|
||||
unsigned char attributes[4096]{0};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr unsigned char Access_Request = 1;
|
||||
constexpr unsigned char Access_Accept = 2;
|
||||
constexpr unsigned char Access_Reject = 3;
|
||||
constexpr unsigned char Access_Challenge = 11;
|
||||
|
||||
constexpr unsigned char Accounting_Request = 4;
|
||||
constexpr unsigned char Accounting_Response = 5;
|
||||
constexpr unsigned char Accounting_Status = 6;
|
||||
constexpr unsigned char Accounting_Message = 10;
|
||||
|
||||
constexpr unsigned char Disconnect_Request = 40;
|
||||
constexpr unsigned char Disconnect_ACK = 41;
|
||||
constexpr unsigned char Disconnect_NAK = 42;
|
||||
constexpr unsigned char CoA_Request = 43;
|
||||
constexpr unsigned char CoA_ACK = 44;
|
||||
constexpr unsigned char CoA_NAK = 45;
|
||||
|
||||
inline bool IsAuthentication(unsigned char t) {
|
||||
return (t == RADIUS::Access_Request ||
|
||||
t == RADIUS::Access_Accept ||
|
||||
t == RADIUS::Access_Challenge ||
|
||||
t == RADIUS::Access_Reject);
|
||||
}
|
||||
|
||||
inline bool IsAccounting(unsigned char t) {
|
||||
return (t == RADIUS::Accounting_Request ||
|
||||
t == RADIUS::Accounting_Response ||
|
||||
t == RADIUS::Accounting_Status ||
|
||||
t == RADIUS::Accounting_Message);
|
||||
}
|
||||
|
||||
inline bool IsAuthority(unsigned char t) {
|
||||
return (t == RADIUS::Disconnect_Request ||
|
||||
t == RADIUS::Disconnect_ACK ||
|
||||
t == RADIUS::Disconnect_NAK ||
|
||||
t == RADIUS::CoA_Request ||
|
||||
t == RADIUS::CoA_ACK ||
|
||||
t == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
inline const char * CommandName(uint cmd) {
|
||||
auto cmds = radius_command_values;
|
||||
while(cmds->cmd && (cmds->cmd!=cmd))
|
||||
cmds++;
|
||||
if(cmds->cmd==cmd) return cmds->name;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char * AttributeName(uint cmd) {
|
||||
auto cmds = radius_attribute_names;
|
||||
while(cmds->cmd && (cmds->cmd!=cmd))
|
||||
cmds++;
|
||||
if(cmds->cmd==cmd) return cmds->name;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
//
|
||||
// From: https://github.com/Telecominfraproject/wlan-dictionary/blob/main/dictionary.tip
|
||||
//
|
||||
@@ -34,23 +337,21 @@ namespace OpenWifi::RADIUS {
|
||||
static const unsigned char TIP_AAAipaddr = 2;
|
||||
static const unsigned char TIP_AAAipv6addr = 3;
|
||||
|
||||
|
||||
using AttributeList = std::list<RadiusAttribute>;
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, AttributeList const &P) {
|
||||
inline std::ostream &operator<<(std::ostream &os, AttributeList const &P) {
|
||||
for(const auto &attr:P) {
|
||||
os << "\tAttr: " << (uint16_t) attr.type << " Size: " << (uint16_t) attr.len << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
bool ParseRadius(uint32_t offset, const unsigned char *Buffer, uint16_t Size, AttributeList &Attrs) {
|
||||
inline bool ParseRadius(uint32_t offset, const unsigned char *Buffer, uint16_t Size, AttributeList &Attrs) {
|
||||
Attrs.clear();
|
||||
uint16_t pos=0;
|
||||
auto x=25;
|
||||
while(pos<Size && x) {
|
||||
RadiusAttribute Attr{ .type=Buffer[pos], .pos=(uint16_t )(pos+2+offset), .len=Buffer[pos+1]};
|
||||
// std::cout << "POS: " << pos << " P:" << (uint32_t) Attr.pos << " T:" << (uint32_t) Attr.type << " L:" << (uint32_t) Attr.len << " S:" << (uint32_t) Size << std::endl;
|
||||
RadiusAttribute Attr{ .type=Buffer[pos], .pos=(uint16_t)(pos+2+offset), .len=(unsigned int)(Buffer[pos+1]-2)};
|
||||
if(pos+Attr.len<=Size) {
|
||||
Attrs.emplace_back(Attr);
|
||||
} else {
|
||||
@@ -64,25 +365,55 @@ namespace OpenWifi::RADIUS {
|
||||
pos+=Buffer[pos+1];
|
||||
x--;
|
||||
}
|
||||
// std::cout << "Good parse" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
class RadiusPacket {
|
||||
public:
|
||||
explicit RadiusPacket(const Poco::Buffer<char> & Buf) {
|
||||
if(Buf.size() >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,Buf.begin(), Buf.size());
|
||||
Size_=Buf.size();
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const unsigned char *buffer, uint16_t size) {
|
||||
if(size >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,buffer, size);
|
||||
Size_=size;
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const std::string &p) {
|
||||
if(p.size() >= sizeof(RawRadiusPacket)) {
|
||||
Valid_ = false;
|
||||
return;
|
||||
}
|
||||
memcpy((void *)&P_,(const unsigned char*) p.c_str(), p.size());
|
||||
Size_=p.size();
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
Valid_ = (Size_== htons(P_.rawlen));
|
||||
if(Valid_)
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
RadiusPacket() = default;
|
||||
explicit RadiusPacket(const RadiusPacket &P) {
|
||||
Valid_ = P.Valid_;
|
||||
Size_ = P.Size_;
|
||||
P_ = P.P_;
|
||||
Attrs_ = P.Attrs_;
|
||||
}
|
||||
|
||||
explicit RadiusPacket() = default;
|
||||
|
||||
unsigned char * Buffer() { return (unsigned char *)&P_; }
|
||||
[[nodiscard]] uint16_t BufferLen() const { return sizeof(P_);}
|
||||
@@ -92,11 +423,39 @@ namespace OpenWifi::RADIUS {
|
||||
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.len); }
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.rawlen); }
|
||||
[[nodiscard]] uint16_t Size() const { return Size_; }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
|
||||
|
||||
inline bool IsAuthentication() {
|
||||
return (P_.code == RADIUS::Access_Request ||
|
||||
P_.code == RADIUS::Access_Accept ||
|
||||
P_.code == RADIUS::Access_Challenge ||
|
||||
P_.code == RADIUS::Access_Reject ||
|
||||
P_.code == RADCMD_RES_FREE_REQ ||
|
||||
P_.code == RADCMD_RES_FREE_RES ||
|
||||
P_.code == RADCMD_RES_QUERY_REQ ||
|
||||
P_.code == RADCMD_RES_QUERY_RES ||
|
||||
P_.code == RADCMD_RES_ALT_RECLAIM_REQ);
|
||||
}
|
||||
|
||||
inline bool IsAccounting() {
|
||||
return (P_.code == RADIUS::Accounting_Request ||
|
||||
P_.code == RADIUS::Accounting_Response ||
|
||||
P_.code == RADIUS::Accounting_Status ||
|
||||
P_.code == RADIUS::Accounting_Message);
|
||||
}
|
||||
|
||||
inline bool IsAuthority() {
|
||||
return (P_.code == RADIUS::Disconnect_Request ||
|
||||
P_.code == RADIUS::Disconnect_ACK ||
|
||||
P_.code == RADIUS::Disconnect_NAK ||
|
||||
P_.code == RADIUS::CoA_Request ||
|
||||
P_.code == RADIUS::CoA_ACK ||
|
||||
P_.code == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
void Log(std::ostream &os) {
|
||||
uint16_t p = 0;
|
||||
|
||||
@@ -110,9 +469,102 @@ namespace OpenWifi::RADIUS {
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec << std::endl;
|
||||
os << std::dec << std::endl << std::endl;
|
||||
Print(os);
|
||||
}
|
||||
|
||||
inline const char * PacketType() {
|
||||
return CommandName(P_.code);
|
||||
}
|
||||
|
||||
inline int PacketTypeInt() {
|
||||
return (int)(P_.code);
|
||||
}
|
||||
|
||||
void ComputeMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
|
||||
if(P_.code==1) {
|
||||
unsigned char OldAuthenticator[16]{0};
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
|
||||
memset(&P.attributes[attr.pos], 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char NewAuthenticator[16]{0};
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(secret);
|
||||
H.update((const unsigned char *)&P, Size_);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
NewAuthenticator[p++] = i;
|
||||
|
||||
if (memcmp(OldAuthenticator, NewAuthenticator, 16) == 0) {
|
||||
std::cout << "Authenticator match..." << std::endl;
|
||||
} else {
|
||||
std::cout << "Authenticator MIS-match..." << std::endl;
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(&P_.attributes[attr.pos], NewAuthenticator, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VerifyMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
if(P_.code==1) {
|
||||
unsigned char OldAuthenticator[16]{0};
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
|
||||
memset(&P.attributes[attr.pos], 0, 16);
|
||||
}
|
||||
}
|
||||
unsigned char NewAuthenticator[16]{0};
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(secret);
|
||||
H.update((const unsigned char *)&P, Size_);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
NewAuthenticator[p++] = i;
|
||||
return memcmp(OldAuthenticator, NewAuthenticator, 16) == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void BufLog(std::ostream & os, const char * pre, const unsigned char *b, uint s) {
|
||||
uint16_t p = 0;
|
||||
while(p<s) {
|
||||
os << pre << std::setfill('0') << std::setw(4) << p << ": ";
|
||||
uint16_t v=0;
|
||||
while(v<16 && p+v<s) {
|
||||
os << std::setfill('0') << std::setw(2) << std::right << std::hex << (uint16_t )b[p+v] << " ";
|
||||
v++;
|
||||
}
|
||||
os << std::endl;
|
||||
p+=16;
|
||||
}
|
||||
os << std::dec ;
|
||||
}
|
||||
|
||||
inline void Print(std::ostream &os) {
|
||||
os << "Packet type: (" << (uint) P_.code << ") " << CommandName(P_.code) << std::endl;
|
||||
os << " Identifier: " << (uint) P_.identifier << std::endl;
|
||||
os << " Length: " << Size_ << std::endl;
|
||||
os << " Authenticator: " ;
|
||||
BufLog(os, "", P_.authenticator, sizeof(P_.authenticator));
|
||||
os << " Attributes: " << std::endl;
|
||||
for(const auto &attr:Attrs_) {
|
||||
os << " " << std::setfill(' ') << "(" << std::setw(4) << (uint) attr.type << ") " << AttributeName(attr.type) << " Len:" << attr.len << std::endl;
|
||||
BufLog(os, " " , &P_.attributes[attr.pos], attr.len);
|
||||
}
|
||||
os << std::dec << std::endl << std::endl;
|
||||
}
|
||||
|
||||
std::string ExtractSerialNumberTIP() {
|
||||
std::string R;
|
||||
|
||||
@@ -121,7 +573,7 @@ namespace OpenWifi::RADIUS {
|
||||
AttributeList VendorAttributes;
|
||||
uint32_t VendorId = htonl( *(const uint32_t *)&(P_.attributes[attribute.pos]));
|
||||
// std::cout << VendorId << std::endl;
|
||||
if(VendorId==TIP_vendor_id) {
|
||||
if(VendorId==TIP_vendor_id && attribute.len>(4+2)) {
|
||||
if (ParseRadius(attribute.pos + 4, &P_.attributes[attribute.pos + 4], attribute.len - 4 - 2,
|
||||
VendorAttributes)) {
|
||||
// std::cout << VendorAttributes << std::endl;
|
||||
@@ -139,7 +591,6 @@ namespace OpenWifi::RADIUS {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
@@ -197,6 +648,16 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string UserName() const {
|
||||
for(const auto &attr:Attrs_) {
|
||||
if(attr.type==1) {
|
||||
std::string user_name{(const char *)&P_.attributes[attr.pos],attr.len};
|
||||
return user_name;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
RawRadiusPacket P_;
|
||||
uint16_t Size_{0};
|
||||
@@ -204,7 +665,7 @@ namespace OpenWifi::RADIUS {
|
||||
bool Valid_=false;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
inline std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
|
||||
os << P.Attrs_ ;
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -15,13 +15,14 @@ namespace OpenWifi {
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
ConfigFilename_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
|
||||
Poco::File Config(ConfigFilename_);
|
||||
|
||||
enabled_ = MicroService::instance().ConfigGetBool("radius.proxy.enable",false);
|
||||
if(!enabled_)
|
||||
if(!enabled_ && !Config.exists())
|
||||
return 0;
|
||||
|
||||
ConfigFilename_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
|
||||
|
||||
|
||||
enabled_ = true;
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(Poco::Net::AddressFamily::IPv4,
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.authentication.port",DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
@@ -44,74 +45,88 @@ namespace OpenWifi {
|
||||
MicroService::instance().ConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6,true);
|
||||
|
||||
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
AccountingReactor_.addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
|
||||
CoAReactor_.addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
CoAReactor_.addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
RadiusReactor_.addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
ParseConfig();
|
||||
|
||||
AuthenticationReactorThread_.start(AuthenticationReactor_);
|
||||
AccountingReactorThread_.start(AccountingReactor_);
|
||||
CoAReactorThread_.start(CoAReactor_);
|
||||
// start RADSEC servers...
|
||||
StartRADSECServers();
|
||||
RadiusReactorThread_.start(RadiusReactor_);
|
||||
|
||||
Utils::SetThreadName(AuthenticationReactorThread_,"radproxy-auth");
|
||||
Utils::SetThreadName(AccountingReactorThread_,"radproxy-acct");
|
||||
Utils::SetThreadName(CoAReactorThread_,"radproxy-coa");
|
||||
Utils::SetThreadName(RadiusReactorThread_,"rad:reactor");
|
||||
|
||||
running_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::Stop() {
|
||||
if(enabled_) {
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(enabled_ && running_) {
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
AuthenticationReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
AccountingReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
AccountingReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
CoAReactor_.removeEventHandler(
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
CoAReactor_.removeEventHandler(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_.removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
AuthenticationReactor_.stop();
|
||||
AuthenticationReactorThread_.join();
|
||||
for(auto &[_,radsec_server]:RADSECservers_)
|
||||
radsec_server->Stop();
|
||||
|
||||
AccountingReactor_.stop();
|
||||
AccountingReactorThread_.join();
|
||||
|
||||
CoAReactor_.stop();
|
||||
CoAReactorThread_.join();
|
||||
RadiusReactor_.stop();
|
||||
RadiusReactorThread_.join();
|
||||
enabled_=false;
|
||||
running_=false;
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StartRADSECServers() {
|
||||
for(const auto &pool:PoolList_.pools) {
|
||||
for(const auto &entry:pool.authConfig.servers) {
|
||||
if(entry.radsec) {
|
||||
StartRADSECServer(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E) {
|
||||
RADSECservers_[ Poco::Net::SocketAddress(E.ip,0) ] = std::make_unique<RADSECserver>(RadiusReactor_,E);
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
@@ -120,19 +135,19 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("Accounting: bad packet received.");
|
||||
poco_warning(Logger(),"Accounting: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("Accounting: missing serial number.");
|
||||
poco_warning(Logger(),"Accounting: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
poco_information(Logger(), fmt::format("Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAccountingData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
@@ -142,19 +157,19 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("Authentication: bad packet received.");
|
||||
poco_warning(Logger(),"Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("Authentication: missing serial number.");
|
||||
poco_warning(Logger(),"Authentication: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
poco_information(Logger(), fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusAuthenticationData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
@@ -164,19 +179,19 @@ namespace OpenWifi {
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
|
||||
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
|
||||
Logger().warning("CoA/DM: bad packet received.");
|
||||
poco_warning(Logger(),"CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if(SerialNumber.empty()) {
|
||||
Logger().warning("CoA/DM: missing serial number.");
|
||||
poco_warning(Logger(),"CoA/DM: missing serial number.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
Logger().information(fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
poco_information(Logger(), fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
|
||||
DeviceRegistry()->SendRadiusCoAData(SerialNumber,P.Buffer(),P.Size());
|
||||
}
|
||||
|
||||
@@ -188,12 +203,27 @@ namespace OpenWifi {
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
auto FinalDestination = Route(radius_type::auth, Dst);
|
||||
auto AllSent = SendData(Dst.family()==Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_ : *AccountingSocketV6_, (const unsigned char *)buffer, size, FinalDestination);
|
||||
if(!AllSent)
|
||||
Logger().error(fmt::format("{}: Could not send Accounting packet packet to {}.", serialNumber, Destination));
|
||||
else
|
||||
Logger().information(fmt::format("{}: Sending Accounting Packet to {}, CalledStationID: {}, CallingStationID:{}", serialNumber, FinalDestination.toString(), CalledStationID, CallingStationID));
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
|
||||
: *AccountingSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),fmt::format("{}: Could not send Accounting packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_information(Logger(), fmt::format(
|
||||
"{}: Sending Accounting Packet to {}, CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(), CalledStationID, CallingStationID));
|
||||
}
|
||||
}
|
||||
|
||||
bool RADIUS_proxy_server::SendData( Poco::Net::DatagramSocket & Sock, const unsigned char *buf , std::size_t size, const Poco::Net::SocketAddress &S) {
|
||||
@@ -208,19 +238,32 @@ namespace OpenWifi {
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
auto FinalDestination = Route(radius_type::auth, Dst);
|
||||
auto AllSent = SendData(Dst.family()==Poco::Net::SocketAddress::IPv4 ? *AuthenticationSocketV4_ : *AuthenticationSocketV6_, (const unsigned char *)buffer, size, FinalDestination);
|
||||
if(!AllSent)
|
||||
Logger().error(fmt::format("{}: Could not send Authentication packet packet to {}.", serialNumber, Destination));
|
||||
else
|
||||
Logger().information(fmt::format("{}: Sending Authentication Packet to {}, CalledStationID: {}, CallingStationID:{}", serialNumber, FinalDestination.toString(), CalledStationID, CallingStationID));
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AuthenticationSocketV4_
|
||||
: *AuthenticationSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),fmt::format("{}: Could not send Authentication packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_information(Logger(), fmt::format("{}: Sending Authentication Packet to {}, CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(),
|
||||
CalledStationID, CallingStationID));
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size) {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
// auto CallingStationID = P.ExtractCallingStationID();
|
||||
// auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
if(Destination.empty()) {
|
||||
Destination = "0.0.0.0:0";
|
||||
@@ -228,12 +271,25 @@ namespace OpenWifi {
|
||||
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
std::lock_guard G(Mutex_);
|
||||
auto FinalDestination = Route(radius_type::auth, Dst);
|
||||
auto AllSent = SendData(Dst.family()==Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_ : *CoASocketV6_, (const unsigned char *)buffer, size, FinalDestination);
|
||||
if(!AllSent)
|
||||
Logger().error(fmt::format("{}: Could not send CoA packet packet to {}.", serialNumber, Destination));
|
||||
else
|
||||
Logger().information(fmt::format("{}: Sending CoA Packet to {}", serialNumber, FinalDestination.toString()));
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
|
||||
if(UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if(DestinationServer!=end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
auto AllSent = SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_
|
||||
: *CoASocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),fmt::format("{}: Could not send CoA packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_information(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
|
||||
FinalDestination.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault) {
|
||||
@@ -242,7 +298,7 @@ namespace OpenWifi {
|
||||
for(const auto &server:Config.servers) {
|
||||
Poco::Net::IPAddress a;
|
||||
if(!Poco::Net::IPAddress::tryParse(server.ip,a)) {
|
||||
Logger().error(fmt::format("RADIUS-PARSE Config: server address {} is nto a valid address in v4 or v6. Entry skipped.",server.ip));
|
||||
poco_error(Logger(),fmt::format("RADIUS-PARSE Config: server address {} is nto a valid address in v4 or v6. Entry skipped.",server.ip));
|
||||
continue;
|
||||
}
|
||||
auto S = Poco::Net::SocketAddress(fmt::format("{}:{}",server.ip,server.port));
|
||||
@@ -256,9 +312,14 @@ namespace OpenWifi {
|
||||
.monitor = Config. monitor,
|
||||
.monitorMethod = Config.monitorMethod,
|
||||
.methodParameters = Config.methodParameters,
|
||||
.useAsDefault = setAsDefault
|
||||
.useAsDefault = setAsDefault,
|
||||
.useRADSEC = server.radsec,
|
||||
.realms = server.radsecRealms
|
||||
};
|
||||
|
||||
if(setAsDefault && D.useRADSEC)
|
||||
defaultIsRADSEC_ = true;
|
||||
|
||||
if(S.family()==Poco::Net::IPAddress::IPv4) {
|
||||
TotalV4 += server.weight;
|
||||
V4.push_back(D);
|
||||
@@ -308,82 +369,119 @@ namespace OpenWifi {
|
||||
Pools_.push_back(NewPool);
|
||||
}
|
||||
} else {
|
||||
Logger().warning(fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
poco_warning(Logger(),fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
|
||||
}
|
||||
} else {
|
||||
Logger().warning(fmt::format("No configuration file '{}' exists.",ConfigFilename_));
|
||||
poco_warning(Logger(),fmt::format("No configuration file '{}' exists.",ConfigFilename_));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
Logger().error(fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
|
||||
poco_error(Logger(),fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
static bool RealmMatch(const std::string &user_realm, const std::string & realm) {
|
||||
if(realm.find_first_of('*') == std::string::npos)
|
||||
return user_realm == realm;
|
||||
return realm.find(user_realm) != std::string::npos;
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::DefaultRoute(radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
|
||||
// find the realm...
|
||||
auto UserName = P.UserName();
|
||||
if(!UserName.empty()) {
|
||||
auto UserTokens = Poco::StringTokenizer(UserName, "@");
|
||||
auto UserRealm = ((UserTokens.count() > 1) ? UserTokens[1] : UserName);
|
||||
Poco::toLowerInPlace(UserRealm);
|
||||
|
||||
for(const auto &pool:Pools_) {
|
||||
for(const auto &server:pool.AuthV4) {
|
||||
if(!server.realms.empty()) {
|
||||
for(const auto &realm:server.realms) {
|
||||
if (RealmMatch(UserRealm,realm)) {
|
||||
std::cout << "Realm match..." << std::endl;
|
||||
UseRADSEC = true;
|
||||
return server.Addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(defaultIsRADSEC_) {
|
||||
UseRADSEC = true;
|
||||
return (IsV4 ? Pools_[defaultPoolIndex_].AuthV4[0].Addr : Pools_[defaultPoolIndex_].AuthV6[0].Addr );
|
||||
}
|
||||
|
||||
switch(rtype) {
|
||||
case radius_type::coa: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].CoaV4
|
||||
: Pools_[defaultPoolIndex_].CoaV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::auth: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AuthV4
|
||||
: Pools_[defaultPoolIndex_].AuthV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::acct:
|
||||
default: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AcctV4
|
||||
: Pools_[defaultPoolIndex_].AcctV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
}
|
||||
case radius_type::auth: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AuthV4
|
||||
: Pools_[defaultPoolIndex_].AuthV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::acct:
|
||||
default: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AcctV4
|
||||
: Pools_[defaultPoolIndex_].AcctV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
case radius_type::coa: {
|
||||
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].CoaV4
|
||||
: Pools_[defaultPoolIndex_].CoaV6,
|
||||
RequestedAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress) {
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if(Pools_.empty()) {
|
||||
UseRADSEC = false;
|
||||
return RequestedAddress;
|
||||
}
|
||||
|
||||
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
|
||||
bool useDefault = false;
|
||||
bool useDefault;
|
||||
useDefault = IsV4 ? RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4) : RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6) ;
|
||||
|
||||
if(useDefault) {
|
||||
return DefaultRoute(rtype, RequestedAddress);
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
|
||||
}
|
||||
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D) -> bool {
|
||||
auto isAddressInPool = [&](const std::vector<Destination> & D, bool &UseRADSEC) -> bool {
|
||||
for(const auto &entry:D)
|
||||
if(entry.Addr.host()==RequestedAddress.host())
|
||||
if(entry.Addr.host()==RequestedAddress.host()) {
|
||||
UseRADSEC = entry.useRADSEC;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for(auto &i:Pools_) {
|
||||
switch(rtype) {
|
||||
case radius_type::coa: {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::auth: {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
case radius_type::acct: {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6))) {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return DefaultRoute(rtype, RequestedAddress);
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
|
||||
}
|
||||
|
||||
Poco::Net::SocketAddress RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress) {
|
||||
@@ -459,6 +557,10 @@ namespace OpenWifi {
|
||||
Disk.stringify(ofs);
|
||||
ofs.close();
|
||||
|
||||
if(!running_) {
|
||||
Start();
|
||||
}
|
||||
|
||||
ParseConfig();
|
||||
}
|
||||
|
||||
@@ -479,6 +581,7 @@ namespace OpenWifi {
|
||||
|
||||
}
|
||||
ResetConfig();
|
||||
Stop();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::GetConfig(GWObjects::RadiusProxyPoolList &C) {
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Net/DatagramSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "RADSECserver.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -15,6 +18,7 @@ namespace OpenWifi {
|
||||
auth, acct, coa
|
||||
};
|
||||
|
||||
|
||||
class RADIUS_proxy_server : public SubSystemServer {
|
||||
public:
|
||||
inline static auto instance() {
|
||||
@@ -38,6 +42,9 @@ namespace OpenWifi {
|
||||
void DeleteConfig();
|
||||
void GetConfig(GWObjects::RadiusProxyPoolList &C);
|
||||
|
||||
void StartRADSECServers();
|
||||
void StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E);
|
||||
|
||||
struct Destination {
|
||||
Poco::Net::SocketAddress Addr;
|
||||
uint64_t state = 0;
|
||||
@@ -49,6 +56,8 @@ namespace OpenWifi {
|
||||
std::string monitorMethod;
|
||||
std::vector<std::string> methodParameters;
|
||||
bool useAsDefault=false;
|
||||
bool useRADSEC=false;
|
||||
std::vector<std::string> realms;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -58,16 +67,14 @@ namespace OpenWifi {
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
|
||||
Poco::Net::SocketReactor AccountingReactor_;
|
||||
Poco::Net::SocketReactor AuthenticationReactor_;
|
||||
Poco::Net::SocketReactor CoAReactor_;
|
||||
Poco::Thread AuthenticationReactorThread_;
|
||||
Poco::Thread AccountingReactorThread_;
|
||||
Poco::Thread CoAReactorThread_;
|
||||
Poco::Net::SocketReactor RadiusReactor_;
|
||||
Poco::Thread RadiusReactorThread_;
|
||||
|
||||
GWObjects::RadiusProxyPoolList PoolList_;
|
||||
std::string ConfigFilename_;
|
||||
|
||||
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSECserver>> RADSECservers_;
|
||||
|
||||
struct RadiusPool {
|
||||
std::vector<Destination> AuthV4;
|
||||
std::vector<Destination> AuthV6;
|
||||
@@ -80,6 +87,8 @@ namespace OpenWifi {
|
||||
std::vector<RadiusPool> Pools_;
|
||||
uint defaultPoolIndex_=0;
|
||||
bool enabled_=false;
|
||||
bool defaultIsRADSEC_=false;
|
||||
std::atomic_bool running_=false;
|
||||
|
||||
RADIUS_proxy_server() noexcept:
|
||||
SubSystemServer("RADIUS-PROXY", "RADIUS-PROXY", "radius.proxy")
|
||||
@@ -90,10 +99,10 @@ namespace OpenWifi {
|
||||
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A);
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
void ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault);
|
||||
static Poco::Net::SocketAddress ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
};
|
||||
|
||||
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
|
||||
|
||||
251
src/RADSECserver.h
Normal file
251
src/RADSECserver.h
Normal file
@@ -0,0 +1,251 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-08-15.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
|
||||
#include "RADIUS_helpers.h"
|
||||
#include "DeviceRegistry.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RADSECserver : public Poco::Runnable {
|
||||
public:
|
||||
RADSECserver(Poco::Net::SocketReactor & R, GWObjects::RadiusProxyServerEntry E) :
|
||||
Reactor_(R),
|
||||
Server_(std::move(E)),
|
||||
Logger_(Poco::Logger::get(fmt::format("RADSEC: {}@{}:{}",
|
||||
Server_.name ,
|
||||
Server_.ip,
|
||||
Server_.port)))
|
||||
{
|
||||
ReconnectorThr_.start(*this);
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
while(TryAgain_) {
|
||||
if(!Connected_) {
|
||||
std::unique_lock G(Mutex_);
|
||||
Connect();
|
||||
}
|
||||
Poco::Thread::trySleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SendData(const std::string &serial_number, const unsigned char *buffer, int length) {
|
||||
try {
|
||||
if (Connected_) {
|
||||
RADIUS::RadiusPacket P(buffer, length);
|
||||
// std::cout << serial_number << " Sending " << P.PacketType() << " " << length << " bytes" << std::endl;
|
||||
int sent_bytes;
|
||||
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
|
||||
Logger_.debug(fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
sent_bytes = Socket_->sendBytes(buffer, length);
|
||||
} else {
|
||||
Logger_.debug(fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
P.ComputeMessageAuthenticator(Server_.radsecSecret);
|
||||
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
|
||||
}
|
||||
return (sent_bytes == length);
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
unsigned char Buffer[4096];
|
||||
|
||||
try {
|
||||
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer,sizeof(Buffer));
|
||||
if(NumberOfReceivedBytes>40) {
|
||||
RADIUS::RadiusPacket P(Buffer,NumberOfReceivedBytes);
|
||||
// P.Log(std::cout);
|
||||
// std::cout << "RADSEC: " << P.PacketType() << " " << (int) P.PacketTypeInt() << " Received " << NumberOfReceivedBytes << " bytes" << std::endl;
|
||||
if (P.IsAuthentication()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
Logger_.debug(fmt::format("{}: {} Received {} bytes.", SerialNumber, P.PacketType(), NumberOfReceivedBytes));
|
||||
DeviceRegistry()->SendRadiusAuthenticationData(
|
||||
SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else if (P.IsAccounting()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
Logger_.debug(fmt::format("{}: {} Received {} bytes.", SerialNumber, P.PacketType(), NumberOfReceivedBytes));
|
||||
DeviceRegistry()->SendRadiusAccountingData(
|
||||
SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else if (P.IsAuthority()) {
|
||||
}
|
||||
} else {
|
||||
Disconnect();
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
inline void onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
|
||||
std::cout << "onError" << std::endl;
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
std::cout << "onShutdown" << std::endl;
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline bool Connect() {
|
||||
if(TryAgain_) {
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroService::instance().DataDir());
|
||||
Poco::TemporaryFile KeyFile_(MicroService::instance().DataDir());
|
||||
std::vector<Poco::TemporaryFile> CaCertFiles_;
|
||||
|
||||
DecodeFile(CertFile_.path(), Server_.radsecCert);
|
||||
DecodeFile(KeyFile_.path(), Server_.radsecKey);
|
||||
|
||||
for(auto &cert:Server_.radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(Poco::TemporaryFile(MicroService::instance().DataDir()));
|
||||
DecodeFile(CaCertFiles_[CaCertFiles_.size()-1].path(), cert);
|
||||
}
|
||||
|
||||
Poco::Net::Context::Ptr SecureContext = Poco::AutoPtr<Poco::Net::Context>(
|
||||
new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE,
|
||||
KeyFile_.path(),
|
||||
CertFile_.path(),""));
|
||||
|
||||
for(const auto &ca:CaCertFiles_) {
|
||||
Poco::Crypto::X509Certificate cert(ca.path());
|
||||
SecureContext->addCertificateAuthority(cert);
|
||||
}
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
|
||||
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
|
||||
|
||||
try {
|
||||
poco_information(Logger_, "Attempting to connect");
|
||||
Socket_->connect(Destination, Poco::Timespan(100, 0));
|
||||
Socket_->completeHandshake();
|
||||
Socket_->verifyPeerCertificate();
|
||||
|
||||
if(Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADSECserver, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSECserver::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSECserver::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADSECserver, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSECserver::onShutdown));
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_,fmt::format("Connected. CN={}",CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_information(Logger_,"Could not connect.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Disconnect() {
|
||||
if(Connected_) {
|
||||
std::unique_lock G(Mutex_);
|
||||
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSECserver::onData));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSECserver::onError));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSECserver::onShutdown));
|
||||
Connected_ = false;
|
||||
}
|
||||
poco_information(Logger_,"Disconnecting.");
|
||||
}
|
||||
|
||||
inline void Stop() {
|
||||
TryAgain_ = false;
|
||||
Disconnect();
|
||||
ReconnectorThr_.wakeUp();
|
||||
ReconnectorThr_.join();
|
||||
}
|
||||
|
||||
static void DecodeFile(const std::string &filename, const std::string &s) {
|
||||
std::ofstream sec_file(filename,std::ios_base::out|std::ios_base::trunc|std::ios_base::binary);
|
||||
std::stringstream is(s);
|
||||
Poco::Base64Decoder ds(is);
|
||||
Poco::StreamCopier::copyStream(ds,sec_file);
|
||||
sec_file.close();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string CommonName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->commonName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string IssuerName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->issuerName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string SubjectName() {
|
||||
if(Peer_Cert_)
|
||||
return Peer_Cert_->subjectName();
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_mutex Mutex_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
GWObjects::RadiusProxyServerEntry Server_;
|
||||
Poco::Logger &Logger_;
|
||||
std::atomic_bool Connected_=false;
|
||||
std::atomic_bool TryAgain_=true;
|
||||
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
|
||||
Poco::Thread ReconnectorThr_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
|
||||
};
|
||||
}
|
||||
@@ -31,7 +31,9 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
void WaitForCommand(GWObjects::CommandDetails &Cmd,
|
||||
void WaitForCommand(uint64_t RPCID,
|
||||
bool RetryLater,
|
||||
GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
@@ -40,15 +42,19 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger) {
|
||||
|
||||
Logger.information(fmt::format("{}: New {} command. User={} Serial={}. ", Cmd.UUID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
|
||||
Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID, RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
|
||||
|
||||
// if the command should be executed in the future, or if the device is not connected,
|
||||
// then we should just add the command to
|
||||
// the DB and let it figure out when to deliver the command.
|
||||
if (Cmd.RunAt || !DeviceRegistry()->Connected(Cmd.SerialNumber)) {
|
||||
Logger.information(fmt::format("{}: Command will be run in the future or when device is connected again.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
|
||||
if (Cmd.RunAt || (!DeviceRegistry()->Connected(SerialNumberInt) && RetryLater)) {
|
||||
Logger.information(fmt::format("{},{}: Command will be run in the future or when device is connected again.", Cmd.UUID, RPCID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
return;
|
||||
} else if ((!DeviceRegistry()->Connected(SerialNumberInt) && !RetryLater)){
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
|
||||
Cmd.Executed = OpenWifi::Now();
|
||||
@@ -56,25 +62,27 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
bool Sent;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> rpc_submitted = std::chrono::high_resolution_clock::now();
|
||||
std::shared_ptr<CommandManager::promise_type_t> rpc_endpoint =
|
||||
CommandManager()->PostCommand(Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
CommandManager()->PostCommand(RPCID, Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
|
||||
|
||||
if(!Sent || rpc_endpoint== nullptr) {
|
||||
Logger.information(fmt::format("{}: Pending completion. Device is not connected.", Cmd.UUID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
if(RetryLater && (!Sent || rpc_endpoint== nullptr)) {
|
||||
Logger.information(fmt::format("{},{}: Pending completion. Device is not connected.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
}
|
||||
|
||||
Logger.information(fmt::format("{}: Command sent.", Cmd.UUID));
|
||||
|
||||
Poco::JSON::Object L;
|
||||
if(!RetryLater && !Sent) {
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
|
||||
Logger.information(fmt::format("{},{}: Command sent.", Cmd.UUID, RPCID));
|
||||
std::future<CommandManager::objtype_t> rpc_future(rpc_endpoint->get_future());
|
||||
auto rpc_result = rpc_future.wait_for(WaitTimeInMs);
|
||||
if (rpc_result == std::future_status::ready) {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - rpc_submitted;
|
||||
auto rpc_answer = rpc_future.get();
|
||||
if (!rpc_answer.has(uCentralProtocol::RESULT) || !rpc_answer.isObject(uCentralProtocol::RESULT)) {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response. Missing result.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response. Missing result.", Cmd.UUID, RPCID));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,11 +90,11 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if (!ResultFields->has(uCentralProtocol::STATUS) || !ResultFields->isObject(uCentralProtocol::STATUS)) {
|
||||
Cmd.executionTime = rpc_execution_time.count();
|
||||
if(Cmd.Command=="ping") {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_COMPLETED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response from device (ping: fix override). Missing status.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_COMPLETED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response from device (ping: fix override). Missing status.", Cmd.UUID, RPCID));
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{}: Invalid response from device. Missing status.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
Logger.information(fmt::format("{},{}: Invalid response from device. Missing status.", Cmd.UUID,RPCID));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +134,7 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
}
|
||||
|
||||
// Add the completed command to the database...
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::COMMAND_COMPLETED);
|
||||
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
|
||||
if (ObjectToReturn && Handler) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
@@ -136,10 +144,16 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if(Handler)
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
Logger.information( fmt::format("{}: Completed in {:.3f}ms.", Cmd.UUID, Cmd.executionTime));
|
||||
Logger.information( fmt::format("{},{}: Completed in {:.3f}ms.", Cmd.UUID, RPCID, Cmd.executionTime));
|
||||
return;
|
||||
}
|
||||
Logger.information(fmt::format( "{}: Pending completion.", Cmd.UUID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
CommandManager()->RemovePendingCommand(RPCID);
|
||||
if(RetryLater) {
|
||||
Logger.information(fmt::format("{},{}: Pending completion.", Cmd.UUID, RPCID));
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
|
||||
} else {
|
||||
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,14 +20,17 @@
|
||||
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
|
||||
void WaitForCommand( GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger);
|
||||
void WaitForCommand(
|
||||
uint64_t RPCID,
|
||||
bool RetryLater,
|
||||
GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger);
|
||||
|
||||
void SetCommandStatus( GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_blacklist::DoDelete() {
|
||||
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_blacklist::DoGet() {
|
||||
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -51,13 +51,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RESTAPI_blacklist::DoPost() {
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!D.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(D.serialNumber.empty()) {
|
||||
if(D.serialNumber.empty() || !Utils::NormalizeMac(D.serialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_blacklist::DoPut() {
|
||||
auto SerialNumber = Poco::toLower(GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""));
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_commands::DoGet() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (QB_.Newest) {
|
||||
StorageService()->GetNewestCommands(SerialNumber, QB_.Limit, Commands);
|
||||
@@ -33,10 +37,10 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_commands::DoDelete() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
if (StorageService()->DeleteCommands(SerialNumber, QB_.StartDate, QB_.EndDate)) {
|
||||
return OK();
|
||||
}
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "framework/orm.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_default_configuration::DoGet() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (StorageService()->GetDefaultConfiguration(Name, DefConfig)) {
|
||||
Poco::JSON::Object Obj;
|
||||
@@ -28,7 +29,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RESTAPI_default_configuration::DoDelete() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
|
||||
if(Name.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_device_commandHandler : public RESTAPIHandler {
|
||||
@@ -30,22 +31,22 @@ namespace OpenWifi {
|
||||
void GetStatistics();
|
||||
void DeleteStatistics();
|
||||
void GetStatus();
|
||||
void ExecuteCommand();
|
||||
void Configure();
|
||||
void GetChecks();
|
||||
void DeleteChecks();
|
||||
void Upgrade();
|
||||
void Reboot();
|
||||
void Factory();
|
||||
void LEDs();
|
||||
void Trace();
|
||||
void MakeRequest();
|
||||
void WifiScan();
|
||||
void EventQueue();
|
||||
void Rtty();
|
||||
void Telemetry();
|
||||
void Ping();
|
||||
void Script();
|
||||
void ExecuteCommand(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Configure(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Upgrade(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Reboot(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Factory(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void LEDs(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Trace(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void MakeRequest(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void WifiScan(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void EventQueue(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Rtty(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Telemetry(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Ping(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
|
||||
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"}; };
|
||||
void DoGet() final;
|
||||
@@ -53,6 +54,9 @@ namespace OpenWifi {
|
||||
void DoPost() final;
|
||||
void DoPut() final {};
|
||||
|
||||
void CallCanceled(const char * Cmd,const std::string &UUID, uint64_t RPC, const OpenWifi::RESTAPI::Errors::msg & Err);
|
||||
void CallCanceled(const char * Cmd, const OpenWifi::RESTAPI::Errors::msg &Err, const std::string & Details="");
|
||||
|
||||
inline bool ValidateParameters() {
|
||||
Command_ = GetBinding(RESTAPI::Protocol::COMMAND, "");
|
||||
if (Command_.empty()) {
|
||||
@@ -66,6 +70,8 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string SerialNumber_, Command_;
|
||||
std::string SerialNumber_,
|
||||
Command_;
|
||||
std::uint64_t SerialNumberInt_=0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoGet() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoDelete() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoPost() {
|
||||
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -116,6 +116,10 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(!Utils::NormalizeMac(Device.SerialNumber)) {
|
||||
return BadRequest( RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
if(SerialNumber!=Device.SerialNumber) {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
}
|
||||
@@ -149,7 +153,7 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoPut() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
if(!Utils::ValidSerialNumber(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTAPI/RESTAPI_device_helper.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "framework/orm.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
bool PrepareOrderBy(const std::string &OrderByList, std::string &OrderByString) {
|
||||
bool PrepareOrderBy(const std::string &OrderByListRaw, std::string &OrderByString) {
|
||||
auto OrderByList = ORM::Escape(OrderByListRaw);
|
||||
auto items = Poco::StringTokenizer(OrderByList,",");
|
||||
std::string ItemList;
|
||||
|
||||
@@ -55,6 +57,15 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_devices_handler::DoGet() {
|
||||
|
||||
if(GetBoolParameter("connectionStatistics")) {
|
||||
GWObjects::DeviceConnectionStatistics DCS;
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
DeviceRegistry()->AverageDeviceStatistics(DCS.connectedDevices,DCS.averageConnectionTime, DCS.connectingDevices);
|
||||
DCS.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
if(GetBoolParameter("orderSpec")) {
|
||||
Types::StringVec Fields;
|
||||
StorageService()->GetDeviceDbFieldList(Fields);
|
||||
@@ -80,6 +91,8 @@ namespace OpenWifi {
|
||||
Poco::JSON::Array Objects;
|
||||
for (auto &i : SelectedRecords()) {
|
||||
auto SerialNumber = i;
|
||||
if(!Utils::ValidSerialNumber(i))
|
||||
continue;
|
||||
GWObjects::Device D;
|
||||
if (StorageService()->GetDevice(SerialNumber, D)) {
|
||||
if(completeInfo) {
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
GWObjects::RadiusProxyPoolList C;
|
||||
if(!C.from_json(ParsedBody_)) {
|
||||
if(!C.from_json(ParsedBody_) || C.pools.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace OpenWifi {
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
|
||||
|
||||
Poco::Thread::current()->setName("ExtWebServerThread_" + std::to_string(TransactionId));
|
||||
return RESTAPI_Router<
|
||||
RESTAPI_devices_handler,
|
||||
RESTAPI_device_handler,
|
||||
@@ -50,7 +49,6 @@ namespace OpenWifi {
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
|
||||
|
||||
Poco::Thread::current()->setName("IntWebServerThread_" + std::to_string(TransactionId));
|
||||
return RESTAPI_Router_I<
|
||||
RESTAPI_devices_handler,
|
||||
RESTAPI_device_handler,
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace OpenWifi {
|
||||
|
||||
void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
// try and upgrade this session to websocket...
|
||||
Poco::Thread::current()->setName(fmt::format("TELEMETRY-WS({})",UserInfo_.userinfo.email));
|
||||
if (Request->find("Upgrade") != Request->end() &&
|
||||
Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
|
||||
try {
|
||||
@@ -26,6 +25,10 @@ void RESTAPI_telemetryWebSocket::DoGet() {
|
||||
}
|
||||
}
|
||||
|
||||
if(!Utils::NormalizeMac(SNum)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
auto SerialNumber = Utils::SerialNumberToInt(SNum);
|
||||
|
||||
if(!TelemetryStream()->IsValidEndPoint(SerialNumber,UUID)) {
|
||||
|
||||
@@ -203,6 +203,10 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"kafkaClients", kafkaClients);
|
||||
field_to_json(Obj,"kafkaPackets", kafkaPackets);
|
||||
field_to_json(Obj,"locale", locale);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"sessionId", sessionId);
|
||||
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
|
||||
field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started);
|
||||
|
||||
switch(VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
@@ -218,6 +222,23 @@ namespace OpenWifi::GWObjects {
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_to_json(Obj,"connectedDevices", connectedDevices );
|
||||
field_to_json(Obj,"connectingDevices", connectingDevices );
|
||||
}
|
||||
|
||||
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_from_json(Obj,"connectedDevices", connectedDevices );
|
||||
field_from_json(Obj,"connectingDevices", connectingDevices );
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"server", Server);
|
||||
@@ -293,7 +314,6 @@ namespace OpenWifi::GWObjects {
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
|
||||
@@ -361,11 +381,13 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"secret",secret);
|
||||
field_to_json(Obj,"certificate",certificate);
|
||||
field_to_json(Obj,"radsec",radsec);
|
||||
field_to_json(Obj,"radsec_secret",radsec_secret);
|
||||
field_to_json(Obj,"radsec_port",radsec_port);
|
||||
field_to_json(Obj,"radsec_cacerts",radsec_cacerts);
|
||||
field_to_json(Obj,"radsec_cert",radsec_cert);
|
||||
field_to_json(Obj,"radsec_key",radsec_key);
|
||||
field_to_json(Obj,"radsecPort",radsecPort);
|
||||
field_to_json(Obj,"radsecSecret",radsecSecret);
|
||||
field_to_json(Obj,"radsecCacerts",radsecCacerts);
|
||||
field_to_json(Obj,"radsecCert",radsecCert);
|
||||
field_to_json(Obj,"radsecKey",radsecKey);
|
||||
field_to_json(Obj,"radsecRealms",radsecRealms);
|
||||
field_to_json(Obj,"ignore",ignore);
|
||||
}
|
||||
|
||||
bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -377,11 +399,13 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"secret",secret);
|
||||
field_from_json(Obj,"certificate",certificate);
|
||||
field_from_json(Obj,"radsec",radsec);
|
||||
field_from_json(Obj,"radsec_port",radsec_port);
|
||||
field_from_json(Obj,"radsec_secret",radsec_secret);
|
||||
field_from_json(Obj,"radsec_cacerts",radsec_cacerts);
|
||||
field_from_json(Obj,"radsec_cert",radsec_cert);
|
||||
field_from_json(Obj,"radsec_key",radsec_key);
|
||||
field_from_json(Obj,"radsecSecret",radsecSecret);
|
||||
field_from_json(Obj,"radsecPort",radsecPort);
|
||||
field_from_json(Obj,"radsecCacerts",radsecCacerts);
|
||||
field_from_json(Obj,"radsecCert",radsecCert);
|
||||
field_from_json(Obj,"radsecKey",radsecKey);
|
||||
field_from_json(Obj,"radsecRealms",radsecRealms);
|
||||
field_from_json(Obj,"ignore",ignore);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ namespace OpenWifi::GWObjects {
|
||||
uint64_t kafkaPackets=0;
|
||||
uint64_t websocketPackets=0;
|
||||
std::string locale;
|
||||
uint64_t started=0;
|
||||
uint64_t sessionId=0;
|
||||
double connectionCompletionTime=0.0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
@@ -71,6 +75,15 @@ namespace OpenWifi::GWObjects {
|
||||
void Print() const;
|
||||
};
|
||||
|
||||
struct DeviceConnectionStatistics {
|
||||
std::uint64_t connectedDevices = 0;
|
||||
std::uint64_t averageConnectionTime = 0;
|
||||
std::uint64_t connectingDevices = 0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID = 0 ;
|
||||
@@ -219,11 +232,13 @@ namespace OpenWifi::GWObjects {
|
||||
std::string secret;
|
||||
std::string certificate;
|
||||
bool radsec=false;
|
||||
uint16_t radsec_port=2084;
|
||||
std::string radsec_secret;
|
||||
std::string radsec_key;
|
||||
std::string radsec_cert;
|
||||
std::string radsec_cacerts;
|
||||
uint16_t radsecPort=2083;
|
||||
std::string radsecSecret;
|
||||
std::string radsecKey;
|
||||
std::string radsecCert;
|
||||
std::vector<std::string> radsecCacerts;
|
||||
std::vector<std::string> radsecRealms;
|
||||
bool ignore=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
|
||||
@@ -2,20 +2,24 @@
|
||||
// Created by stephane bourque on 2021-08-11.
|
||||
//
|
||||
|
||||
#include "SerialNumberCache.h"
|
||||
#include <mutex>
|
||||
|
||||
#include "SerialNumberCache.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int SerialNumberCache::Start() {
|
||||
poco_notice(Logger(),"Starting...");
|
||||
StorageService()->UpdateSerialNumberCache();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SerialNumberCache::Stop() {
|
||||
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
SNs_.clear();
|
||||
Reverse_SNs_.clear();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void SerialNumberCache::AddSerialNumber(const std::string &S) {
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "StorageArchiver.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -15,23 +16,23 @@ namespace OpenWifi {
|
||||
auto now = OpenWifi::Now();
|
||||
for(const auto &i:DBs_) {
|
||||
if (!Poco::icompare(i.DBName, "healthchecks")) {
|
||||
Logger().information("Archiving HealthChecks...");
|
||||
poco_information(Logger(),"Archiving HealthChecks...");
|
||||
StorageService()->RemoveHealthChecksRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else if (!Poco::icompare(i.DBName, "statistics")) {
|
||||
Logger().information("Archiving Statistics...");
|
||||
poco_information(Logger(),"Archiving Statistics...");
|
||||
StorageService()->RemoveStatisticsRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else if (!Poco::icompare(i.DBName, "devicelogs")) {
|
||||
Logger().information("Archiving Device Logs...");
|
||||
poco_information(Logger(),"Archiving Device Logs...");
|
||||
StorageService()->RemoveDeviceLogsRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else if (!Poco::icompare(i.DBName, "commandlist")) {
|
||||
Logger().information("Archiving Command History...");
|
||||
poco_information(Logger(),"Archiving Command History...");
|
||||
StorageService()->RemoveCommandListRecordsOlderThan(
|
||||
now - (i.HowManyDays * 24 * 60 * 60));
|
||||
} else {
|
||||
Logger().information(fmt::format("Cannot archive DB '{}'", i.DBName));
|
||||
poco_information(Logger(),fmt::format("Cannot archive DB '{}'", i.DBName));
|
||||
}
|
||||
}
|
||||
AppServiceRegistry().Set("lastStorageArchiverRun", (uint64_t) Now);
|
||||
@@ -54,11 +55,12 @@ namespace OpenWifi {
|
||||
|
||||
Enabled_ = MicroService::instance().ConfigGetBool("archiver.enabled",false);
|
||||
if(!Enabled_) {
|
||||
Logger().information("Archiver is disabled.");
|
||||
poco_information(Logger(),"Archiver is disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ArchiverCallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer);
|
||||
Archiver_ = std::make_unique<Archiver>(Logger());
|
||||
ArchiverCallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(*Archiver_,&Archiver::onTimer);
|
||||
|
||||
auto Schedule = MicroService::instance().ConfigGetString("archiver.schedule","03:00");
|
||||
auto S = Poco::StringTokenizer(Schedule,":");
|
||||
@@ -80,7 +82,7 @@ namespace OpenWifi {
|
||||
if(Poco::icompare(DBName,DB)==0) {
|
||||
std::string Key = "archiver.db." + std::to_string(i) + ".keep";
|
||||
auto Keep = MicroService::instance().ConfigGetInt(Key,7);
|
||||
Archiver_.AddDb(Archiver::ArchiverDBEntry{
|
||||
Archiver_->AddDb(Archiver::ArchiverDBEntry{
|
||||
.DBName = DB,
|
||||
.HowManyDays = Keep
|
||||
});
|
||||
@@ -91,19 +93,21 @@ namespace OpenWifi {
|
||||
|
||||
int NextRun = CalculateDelta(RunAtHour_,RunAtMin_);
|
||||
|
||||
Logger().information(fmt::format("Next run in {} seconds.",NextRun));
|
||||
poco_information(Logger(),fmt::format("Next run in {} seconds.",NextRun));
|
||||
|
||||
Timer_.setStartInterval( NextRun * 1000);
|
||||
Timer_.setPeriodicInterval(24 * 60 * 60 * 1000); // 1 hours
|
||||
Timer_.start(*ArchiverCallback_);
|
||||
Timer_.start(*ArchiverCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StorageArchiver::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(Enabled_) {
|
||||
Timer_.stop();
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace OpenWifi {
|
||||
private:
|
||||
std::atomic_bool Enabled_ = false;
|
||||
Poco::Timer Timer_;
|
||||
Archiver Archiver_{Logger()};
|
||||
std::unique_ptr<Archiver> Archiver_;
|
||||
std::unique_ptr<Poco::TimerCallback<Archiver>> ArchiverCallback_;
|
||||
|
||||
StorageArchiver() noexcept:
|
||||
|
||||
@@ -22,8 +22,9 @@ namespace OpenWifi {
|
||||
|
||||
void Storage::Stop() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Stopping.");
|
||||
poco_notice(Logger(),"Stopping...");
|
||||
StorageClass::Stop();
|
||||
poco_notice(Logger(),"Stopped...");
|
||||
}
|
||||
}
|
||||
// namespace
|
||||
@@ -19,14 +19,30 @@ namespace OpenWifi {
|
||||
|
||||
public:
|
||||
|
||||
enum CommandExecutionType {
|
||||
enum class CommandExecutionType {
|
||||
COMMAND_PENDING,
|
||||
COMMAND_EXECUTED,
|
||||
COMMAND_COMPLETED,
|
||||
COMMAND_TIMEDOUT,
|
||||
COMMAND_FAILED
|
||||
COMMAND_FAILED,
|
||||
COMMAND_EXPIRED,
|
||||
COMMAND_EXECUTING
|
||||
};
|
||||
|
||||
inline std::string to_string(const CommandExecutionType &C) {
|
||||
switch(C) {
|
||||
case CommandExecutionType::COMMAND_PENDING: return "pending";
|
||||
case CommandExecutionType::COMMAND_EXECUTED: return "executed";
|
||||
case CommandExecutionType::COMMAND_COMPLETED: return "completed";
|
||||
case CommandExecutionType::COMMAND_TIMEDOUT: return "timedout";
|
||||
case CommandExecutionType::COMMAND_FAILED: return "failed";
|
||||
case CommandExecutionType::COMMAND_EXPIRED: return "expired";
|
||||
case CommandExecutionType::COMMAND_EXECUTING:
|
||||
default:
|
||||
return "executing";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) {
|
||||
if(dbType_==sqlite) {
|
||||
return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " ";
|
||||
@@ -125,7 +141,7 @@ namespace OpenWifi {
|
||||
bool DeleteCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate);
|
||||
bool GetNonExecutedCommands( uint64_t Offset, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands );
|
||||
bool UpdateCommand( std::string &UUID, GWObjects::CommandDetails & Command );
|
||||
bool GetCommand( std::string &UUID, GWObjects::CommandDetails & Command );
|
||||
bool GetCommand( const std::string &UUID, GWObjects::CommandDetails & Command );
|
||||
bool DeleteCommand( std::string &UUID );
|
||||
bool GetReadyToExecuteCommands( uint64_t Offset, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands );
|
||||
bool CommandExecuted(std::string & UUID);
|
||||
@@ -139,6 +155,10 @@ namespace OpenWifi {
|
||||
bool SetCommandResult(std::string & UUID, std::string & Result);
|
||||
bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany, std::vector<GWObjects::CommandDetails> & Commands);
|
||||
bool SetCommandExecuted(std::string & CommandUUID);
|
||||
bool SetCommandTimedOut(std::string &CommandUUID);
|
||||
|
||||
void RemovedExpiredCommands();
|
||||
void RemoveTimedOutCommands();
|
||||
|
||||
bool RemoveOldCommands(std::string & SerilNumber, std::string & Command);
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Net/SSLException.h"
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "TelemetryClient.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "WS_Connection.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include "Poco/Net/SSLException.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace OpenWifi {
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
WS_->setMaxPayloadSize(2048);
|
||||
WS_->setBlocking(false);
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<TelemetryClient, Poco::Net::ReadableNotification>(
|
||||
*this, &TelemetryClient::OnSocketReadable));
|
||||
@@ -56,7 +57,7 @@ namespace OpenWifi {
|
||||
*WS_, Poco::NObserver<TelemetryClient, Poco::Net::ErrorNotification>(
|
||||
*this, &TelemetryClient::OnSocketError));
|
||||
Registered_ = true;
|
||||
Logger().information(fmt::format("CONNECTION({}): Connection completed.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-CONNECTION({}): Connection completed.", CId_));
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
@@ -69,7 +70,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
TelemetryClient::~TelemetryClient() {
|
||||
Logger().information(fmt::format("CONNECTION({}): Closing connection.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-CONNECTION({}): Closing connection.", CId_));
|
||||
if(Registered_ && WS_)
|
||||
{
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
@@ -92,23 +93,19 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void TelemetryClient::SendTelemetryShutdown() {
|
||||
Logger().information(fmt::format("TELEMETRY-SHUTDOWN({}): Closing.",CId_));
|
||||
auto Device = DeviceRegistry()->GetDeviceConnection(SerialNumber_);
|
||||
if(Device) {
|
||||
if(Device->WSConn_)
|
||||
Device->WSConn_->StopWebSocketTelemetry();
|
||||
}
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-SHUTDOWN({}): Closing.",CId_));
|
||||
DeviceRegistry()->StopWebSocketTelemetry(CommandManager()->NextRPCId(), SerialNumber_);
|
||||
TelemetryStream()->DeRegisterClient(UUID_);
|
||||
delete this;
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
Logger().information(fmt::format("SOCKET-SHUTDOWN({}): Orderly shutdown.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-SOCKET-SHUTDOWN({}): Orderly shutdown.", CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
void TelemetryClient::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
|
||||
Logger().information(fmt::format("SOCKET-ERROR({}): Closing.",CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-SOCKET-ERROR({}): Closing.",CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
@@ -125,11 +122,11 @@ namespace OpenWifi {
|
||||
}
|
||||
catch (const std::exception & E) {
|
||||
std::string W = E.what();
|
||||
Logger().information(fmt::format("std::exception caught: {}. Connection terminated with {}",W,CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-std::exception caught: {}. Connection terminated with {}",W,CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
catch ( ... ) {
|
||||
Logger().information(fmt::format("Unknown exception for {}. Connection terminated.",CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-Unknown exception for {}. Connection terminated.",CId_));
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
}
|
||||
@@ -146,16 +143,16 @@ namespace OpenWifi {
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
Logger().information(fmt::format("DISCONNECT({}): device has disconnected.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-DISCONNECT({}): device has disconnected.", CId_));
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
if (Op == Poco::Net::WebSocket::FRAME_OP_PING) {
|
||||
Logger().debug(fmt::format("WS-PING({}): received. PONG sent back.", CId_));
|
||||
Logger().debug(fmt::format("TELEMETRY-WS-PING({}): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} else if (Op == Poco::Net::WebSocket::FRAME_OP_CLOSE) {
|
||||
Logger().information(fmt::format("DISCONNECT({}): device wants to disconnect.", CId_));
|
||||
poco_information(Logger(),fmt::format("TELEMETRY-DISCONNECT({}): device wants to disconnect.", CId_));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,34 +3,34 @@
|
||||
//
|
||||
#include <thread>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/JSON/Array.h"
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/URI.h"
|
||||
|
||||
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int TelemetryStream::Start() {
|
||||
Running_ = true;
|
||||
Messages_->Readable_ += Poco::delegate(this,&TelemetryStream::onMessage);
|
||||
// ReactorPool_.Start("TelemetryWebSocketPool_");
|
||||
Thr_.start(Reactor_);
|
||||
Utils::SetThreadName(Thr_,"telemetry-svr");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TelemetryStream::Stop() {
|
||||
Logger().notice("Stopping reactors...");
|
||||
// ReactorPool_.Stop();
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Reactor_.stop();
|
||||
Thr_.join();
|
||||
if(Running_) {
|
||||
Running_ = false;
|
||||
Messages_->Readable_ -= Poco::delegate( this, &TelemetryStream::onMessage);
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
bool TelemetryStream::IsValidEndPoint(uint64_t SerialNumber, const std::string & UUID) {
|
||||
@@ -47,12 +47,11 @@ namespace OpenWifi {
|
||||
return (N->second.find(UUID) != N->second.end());
|
||||
}
|
||||
|
||||
bool TelemetryStream::CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, std::string &UUID) {
|
||||
bool TelemetryStream::CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, const std::string &UUID) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
Poco::URI Public(MicroService::instance().ConfigGetString("openwifi.system.uri.public"));
|
||||
Poco::URI U;
|
||||
UUID = MicroService::CreateUUID();
|
||||
U.setScheme("wss");
|
||||
U.setHost(Public.getHost());
|
||||
U.setPort(Public.getPort());
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
#include "TelemetryClient.h"
|
||||
#include "WS_ReactorPool.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
|
||||
bool IsValidEndPoint(uint64_t SerialNumber, const std::string & UUID);
|
||||
bool CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, std::string &UUID);
|
||||
bool CreateEndpoint(uint64_t SerialNumber, std::string &EndPoint, const std::string &UUID);
|
||||
void UpdateEndPoint(uint64_t SerialNumber, const std::string &PayLoad);
|
||||
bool RegisterClient(const std::string &UUID, TelemetryClient *Client);
|
||||
void DeRegisterClient(const std::string &UUID);
|
||||
|
||||
144
src/VenueBroadcaster.h
Normal file
144
src/VenueBroadcaster.h
Normal file
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-16.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "sdks/sdk_prov.h"
|
||||
#include "DeviceRegistry.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class VenueBroadcastNotification : public Poco::Notification {
|
||||
public:
|
||||
VenueBroadcastNotification(const std::string &SourceSerialNumber, const std::string &Data, uint64_t TimeStamp) :
|
||||
SourceSerialNumber_(SourceSerialNumber),
|
||||
Data_(Data),
|
||||
TimeStamp_(TimeStamp) {
|
||||
|
||||
}
|
||||
std::string SourceSerialNumber_;
|
||||
std::string Data_;
|
||||
uint64_t TimeStamp_=OpenWifi::Now();
|
||||
};
|
||||
|
||||
class VenueBroadcaster : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new VenueBroadcaster;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
inline int Start() override {
|
||||
Enabled_ = MicroService::instance().ConfigGetBool("venue_broadcast.enabled",true);
|
||||
if(Enabled_) {
|
||||
BroadcastManager_.start(*this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() override {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(Enabled_ && Running_) {
|
||||
BroadcastQueue_.wakeUpAll();
|
||||
BroadcastManager_.wakeUp();
|
||||
BroadcastManager_.join();
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
}
|
||||
|
||||
|
||||
struct VenueInfo {
|
||||
uint64_t timestamp=OpenWifi::Now();
|
||||
Types::StringVec serialNumbers;
|
||||
};
|
||||
|
||||
inline bool FindSerialNumberList(const std::string &Source, OpenWifi::Types::StringVec & SerialNumbers) {
|
||||
// Can we find our serial number in any of the lists so far...
|
||||
for(const auto &venue:Venues_) {
|
||||
auto entry = std::find(venue.second.serialNumbers.begin(),venue.second.serialNumbers.end(),Source);
|
||||
if(entry!=venue.second.serialNumbers.end() && (OpenWifi::Now()-venue.second.timestamp)<600) {
|
||||
SerialNumbers = venue.second.serialNumbers;
|
||||
auto entry2 = std::find(SerialNumbers.begin(),SerialNumbers.end(),Source);
|
||||
SerialNumbers.erase(entry2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// get the venue from Prov and the serial numbers.
|
||||
Types::UUID_t Venue;
|
||||
Types::StringVec TmpSerialNumbers;
|
||||
if(OpenWifi::SDK::Prov::GetSerialNumbersForVenueOfSerialNumber(Source,Venue,TmpSerialNumbers,Logger())) {
|
||||
std::sort(TmpSerialNumbers.begin(),TmpSerialNumbers.end());
|
||||
VenueInfo V{.timestamp=OpenWifi::Now(), .serialNumbers=TmpSerialNumbers};
|
||||
Venues_[Venue] = V;
|
||||
auto p = std::find(TmpSerialNumbers.begin(),TmpSerialNumbers.end(),Source);
|
||||
if(p!=TmpSerialNumbers.end()) {
|
||||
TmpSerialNumbers.erase(p);
|
||||
SerialNumbers = TmpSerialNumbers;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void SendToDevice(const std::string &SerialNumber,const std::string &Payload) {
|
||||
DeviceRegistry()->SendFrame(SerialNumber,Payload);
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("venue-bcast");
|
||||
Poco::AutoPtr<Poco::Notification> NextNotification(BroadcastQueue_.waitDequeueNotification());
|
||||
while (NextNotification && Running_) {
|
||||
auto Notification = dynamic_cast<VenueBroadcastNotification *>(NextNotification.get());
|
||||
if (Notification != nullptr) {
|
||||
Types::StringVec SerialNumbers;
|
||||
if(FindSerialNumberList(Notification->SourceSerialNumber_,SerialNumbers)) {
|
||||
Poco::JSON::Object Payload;
|
||||
Payload.set("jsonrpc","2.0");
|
||||
Payload.set("method","venue_broadcast");
|
||||
Poco::JSON::Object ParamBlock;
|
||||
ParamBlock.set("serial",Notification->SourceSerialNumber_);
|
||||
ParamBlock.set("timestamp",Notification->TimeStamp_);
|
||||
ParamBlock.set("data",Notification->Data_);
|
||||
Payload.set("params", ParamBlock);
|
||||
std::ostringstream o;
|
||||
Payload.stringify(o);
|
||||
for(const auto &Device:SerialNumbers) {
|
||||
SendToDevice(Device,o.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
NextNotification = BroadcastQueue_.waitDequeueNotification();
|
||||
}
|
||||
Running_=false;
|
||||
}
|
||||
|
||||
inline void Broadcast(const std::string &SourceSerial, const std::string &Data, uint64_t TimeStamp) {
|
||||
BroadcastQueue_.enqueueNotification(new VenueBroadcastNotification(SourceSerial,Data,TimeStamp));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::atomic_bool Running_=false;
|
||||
bool Enabled_=false;
|
||||
Poco::NotificationQueue BroadcastQueue_;
|
||||
Poco::Thread BroadcastManager_;
|
||||
|
||||
std::map<OpenWifi::Types::UUID_t,VenueInfo> Venues_;
|
||||
|
||||
VenueBroadcaster() noexcept:
|
||||
SubSystemServer("VenueBroadcaster", "VENUE-BCAST", "venue.broacast")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline auto VenueBroadcaster() { return VenueBroadcaster::instance(); }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/JSON/Array.h"
|
||||
|
||||
#include "ConfigurationCache.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "WS_Server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
bool WebSocketServer::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
|
||||
if(IsCertOk()) {
|
||||
Logger().debug(fmt::format("CERTIFICATE({}): issuer='{}' cn='{}'", ConnectionId, Certificate.issuerName(),Certificate.commonName()));
|
||||
if(!Certificate.issuedBy(*IssuerCert_)) {
|
||||
Logger().debug(fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int WebSocketServer::Start() {
|
||||
// ReactorPool_.Start("DeviceReactorPool_");
|
||||
for(const auto & Svr : ConfigServersList_ ) {
|
||||
Logger().notice( fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}",
|
||||
Svr.Address(),
|
||||
Svr.Port(),
|
||||
Svr.KeyFile(),Svr.CertFile()));
|
||||
|
||||
Svr.LogCert(Logger());
|
||||
if(!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
|
||||
if(!IsCertOk()) {
|
||||
IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
|
||||
Logger().information( fmt::format("Certificate Issuer Name:{}",IssuerCert_->issuerName()));
|
||||
}
|
||||
auto NewSocketAcceptor = std::make_unique<ws_server_reactor_type_t>(Sock, Reactor_); // , 2 /*Poco::Environment::processorCount()*2) */ );
|
||||
Acceptors_.push_back(std::move(NewSocketAcceptor));
|
||||
}
|
||||
|
||||
auto ProvString = MicroService::instance().ConfigGetString("autoprovisioning.process","default");
|
||||
if(ProvString!="default") {
|
||||
auto Tokens = Poco::StringTokenizer(ProvString, ",");
|
||||
for (const auto &i : Tokens) {
|
||||
if (i == "prov")
|
||||
LookAtProvisioning_ = true;
|
||||
else
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
} else {
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
|
||||
SimulatorId_ = MicroService::instance().ConfigGetString("simulatorid","");
|
||||
SimulatorEnabled_ = !SimulatorId_.empty();
|
||||
|
||||
ReactorThread_.setStackSize(3000000);
|
||||
ReactorThread_.start(Reactor_);
|
||||
Utils::SetThreadName(ReactorThread_,"device-reactor");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebSocketServer::Stop() {
|
||||
Logger().notice("Stopping reactors...");
|
||||
// ReactorPool_.Stop();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
}
|
||||
|
||||
} //namespace
|
||||
@@ -1,76 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/ParallelSocketAcceptor.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
|
||||
#include "WS_Connection.h"
|
||||
#include "WS_ReactorPool.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WebSocketServer : public SubSystemServer {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new WebSocketServer;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool IsCertOk() { return IssuerCert_!= nullptr; }
|
||||
bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
|
||||
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
|
||||
|
||||
inline bool IsSimSerialNumber(const std::string & SerialNumber) const {
|
||||
return IsSim(SerialNumber) && SerialNumber == SimulatorId_;
|
||||
}
|
||||
|
||||
inline static bool IsSim(const std::string & SerialNumber) {
|
||||
return SerialNumber.substr(0,6) == "53494d";
|
||||
}
|
||||
|
||||
inline bool IsSimEnabled() const {
|
||||
return SimulatorEnabled_;
|
||||
}
|
||||
|
||||
inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
// typedef std::unique_ptr<Poco::Net::ParallelSocketAcceptor<WSConnection, Poco::Net::SocketReactor>> ws_server_reactor_type_t;
|
||||
typedef Poco::Net::SocketAcceptor<WSConnection> ws_server_reactor_type_t;
|
||||
std::vector<std::unique_ptr<ws_server_reactor_type_t>> Acceptors_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
std::string SimulatorId_;
|
||||
bool LookAtProvisioning_ = false;
|
||||
bool UseDefaultConfig_ = true;
|
||||
bool SimulatorEnabled_=false;
|
||||
|
||||
WebSocketServer() noexcept:
|
||||
SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
inline auto WebSocketServer() { return WebSocketServer::instance(); }
|
||||
|
||||
} //namespace
|
||||
206
src/attributes.json
Normal file
206
src/attributes.json
Normal file
@@ -0,0 +1,206 @@
|
||||
{
|
||||
"interfaces": [
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"WAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "wan",
|
||||
"role": "upstream",
|
||||
"services": [
|
||||
"ssh"
|
||||
],
|
||||
"ssids": []
|
||||
},
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"LAN*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"dhcp": {
|
||||
"lease-count": 100,
|
||||
"lease-first": 10,
|
||||
"lease-time": "6h"
|
||||
},
|
||||
"gateway": "192.168.1.1",
|
||||
"send-hostname": true,
|
||||
"subnet": "192.168.1.1/24",
|
||||
"use-dns": []
|
||||
},
|
||||
"ipv6": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"name": "lan",
|
||||
"role": "downstream",
|
||||
"services": [
|
||||
"wifi-steering",
|
||||
"ssh"
|
||||
],
|
||||
"ssids": [
|
||||
{
|
||||
"bss-mode": "ap",
|
||||
"encryption": {
|
||||
"ieee80211w": "optional",
|
||||
"proto": "wpa-mixed"
|
||||
},
|
||||
"hidden-ssid": false,
|
||||
"isolate-clients": false,
|
||||
"maximum-clients": 64,
|
||||
"name": "arilia-rad",
|
||||
"pass-point": {
|
||||
"access-network-type": 0,
|
||||
"anqp-3gpp-cell-net": [],
|
||||
"anqp-domain": 8888,
|
||||
"asra": false,
|
||||
"auth-type": {
|
||||
"type": "terms-and-conditions"
|
||||
},
|
||||
"connection-capability": [
|
||||
"1:0:2",
|
||||
"6:22:1",
|
||||
"17:5060:0"
|
||||
],
|
||||
"disable-dgaf": true,
|
||||
"domain-name": [
|
||||
"main.arilia.com"
|
||||
],
|
||||
"esr": false,
|
||||
"friendly-name": [
|
||||
"eng:AriliaWifi",
|
||||
"fra:AriliaWifi"
|
||||
],
|
||||
"hessid": "11:22:33:44:55:66",
|
||||
"internet": true,
|
||||
"ipaddr-type-available": 14,
|
||||
"nai-realm": [],
|
||||
"osen": false,
|
||||
"roaming-consortium": [
|
||||
"F4F5E8F5F4"
|
||||
],
|
||||
"uesa": false,
|
||||
"venue-group": 2,
|
||||
"venue-name": [
|
||||
"eng:Bowen Development 1",
|
||||
"fra:Bowen Development 1"
|
||||
],
|
||||
"venue-type": 8,
|
||||
"venue-url": [
|
||||
"http://www.example.com/info-fra",
|
||||
"http://www.example.com/info-eng"
|
||||
]
|
||||
},
|
||||
"radius": {
|
||||
"accounting": {
|
||||
"interval" : 600,
|
||||
"host": "0.0.0.0",
|
||||
"port": 1813,
|
||||
"secret": "radsec"
|
||||
},
|
||||
"authentication": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 1812,
|
||||
"secret": "radsec",
|
||||
},
|
||||
"chargeable-user-id" : true,
|
||||
"nas-identifier": "AriliaWifi",
|
||||
"realm" : [
|
||||
"c2k2q8e2pcs2udar1pa0.orion.area120.com"
|
||||
]
|
||||
},
|
||||
"services": [
|
||||
"radius-gw-proxy"
|
||||
],
|
||||
"wifi-bands": [
|
||||
"2G",
|
||||
"5G"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 60
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 60,
|
||||
"types": [
|
||||
"ssids",
|
||||
"lldp",
|
||||
"clients"
|
||||
]
|
||||
},
|
||||
"wifi-frames": {
|
||||
"filters": [
|
||||
"probe",
|
||||
"auth",
|
||||
"assoc",
|
||||
"disassoc",
|
||||
"deauth",
|
||||
"local-deauth",
|
||||
"inactive-deauth",
|
||||
"key-mismatch",
|
||||
"beacon-report",
|
||||
"radar-detected"
|
||||
]
|
||||
}
|
||||
},
|
||||
"radios": [
|
||||
{
|
||||
"band": "2G",
|
||||
"bandwidth": 10,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "HT",
|
||||
"channel-width": 20,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 23
|
||||
},
|
||||
{
|
||||
"band": "5G",
|
||||
"bandwidth": 20,
|
||||
"beacon-interval": 100,
|
||||
"channel": "auto",
|
||||
"channel-mode": "VHT",
|
||||
"channel-width": 80,
|
||||
"country": "CA",
|
||||
"dtim-period": 2,
|
||||
"maximum-clients": 64,
|
||||
"tx-power": 23
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"ssh": {
|
||||
"password-authentication": true,
|
||||
"port": 22
|
||||
}
|
||||
},
|
||||
"uuid": 1661409802
|
||||
}
|
||||
@@ -44,7 +44,7 @@ static json DefaultUCentralSchema = R"(
|
||||
"switch": {
|
||||
"$ref": "#/$defs/switch"
|
||||
},
|
||||
"radios": {
|
||||
"radiosgrep": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/radio"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
169
src/framework/MicroServiceErrorHandler.h
Normal file
169
src/framework/MicroServiceErrorHandler.h
Normal file
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-09-29.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/JSON/Template.h"
|
||||
#include "Poco/Thread.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class MicroServiceErrorHandler : public Poco::ErrorHandler {
|
||||
public:
|
||||
explicit MicroServiceErrorHandler(Poco::Util::Application &App) : App_(App) {
|
||||
}
|
||||
|
||||
inline void exception(const Poco::Exception & Base) override {
|
||||
try {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
|
||||
App_.logger().log(Base);
|
||||
Base.rethrow();
|
||||
|
||||
} catch (const Poco::Net::InvalidCertificateException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidCertificateException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::InvalidSocketException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::WebSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::ConnectionResetException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::CertificateValidationException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::CertificateValidationException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLConnectionUnexpectedlyClosedException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLContextException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLContextException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::SSLException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::Net::InvalidAddressException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidAddressException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Net::NetException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
|
||||
} catch (const Poco::IOException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::IOException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::RuntimeException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::JSON::JSONTemplateException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONTemplateException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::ApplicationException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::ApplicationException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::Exception thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (...) {
|
||||
poco_error(App_.logger(), fmt::format("Poco:Generic thr_name={}",t_name, t_id));
|
||||
}
|
||||
}
|
||||
|
||||
inline void exception(const std::exception & E) override {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
poco_warning(App_.logger(), fmt::format("std::exception in {}: {} thr_id={}",
|
||||
t_name,E.what(),
|
||||
t_id));
|
||||
}
|
||||
|
||||
inline void exception() override {
|
||||
if(Poco::Thread::current()!= nullptr) {
|
||||
t_name = Poco::Thread::current()->getName();
|
||||
t_id = Poco::Thread::current()->id();
|
||||
} else {
|
||||
t_name = "startup_code";
|
||||
t_id = 0;
|
||||
}
|
||||
poco_warning(App_.logger(), fmt::format("generic exception in {} thr_id={}",
|
||||
t_name, t_id));
|
||||
}
|
||||
private:
|
||||
Poco::Util::Application &App_;
|
||||
std::string t_name;
|
||||
int t_id=0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -33,7 +33,6 @@ namespace OpenWifi {
|
||||
int Start() override {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
Logger().setLevel(Poco::Message::PRIO_INFORMATION);
|
||||
Logger().notice("Starting.");
|
||||
std::string DBType = MicroService::instance().ConfigGetString("storage.type");
|
||||
|
||||
|
||||
@@ -69,6 +69,41 @@ namespace OpenWifi {
|
||||
}
|
||||
};
|
||||
|
||||
struct WebSocketClientNotificationNumberOfConnection {
|
||||
std::uint64_t numberOfDevices=0;
|
||||
std::uint64_t averageConnectedTime=0;
|
||||
std::uint64_t numberOfConnectingDevices=0;
|
||||
|
||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"numberOfDevices", numberOfDevices);
|
||||
RESTAPI_utils::field_to_json(Obj,"averageConnectedTime", averageConnectedTime);
|
||||
RESTAPI_utils::field_to_json(Obj,"numberOfConnectingDevices", numberOfConnectingDevices);
|
||||
}
|
||||
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"numberOfDevices", numberOfDevices);
|
||||
RESTAPI_utils::field_from_json(Obj,"averageConnectedTime", averageConnectedTime);
|
||||
RESTAPI_utils::field_from_json(Obj,"numberOfConnectingDevices", numberOfConnectingDevices);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
inline void WebSocketClientNotificationNumberOfConnections(std::uint64_t numberOfDevices,
|
||||
std::uint64_t averageConnectedTime,
|
||||
std::uint64_t numberOfConnectingDevices) {
|
||||
WebSocketNotification<WebSocketClientNotificationNumberOfConnection> N;
|
||||
N.content.numberOfDevices = numberOfDevices;
|
||||
N.content.averageConnectedTime = averageConnectedTime;
|
||||
N.content.numberOfConnectingDevices = numberOfConnectingDevices;
|
||||
N.type = "device_connections_statistics";
|
||||
WebSocketClientServer()->SendNotification(N);
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationDeviceConfigurationChange(const std::string &SerialNumber, uint64_t oldUUID, uint64_t newUUID) {
|
||||
WebSocketNotification<WebNotificationSingleDeviceConfigurationChange> N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
@@ -146,6 +181,10 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationRebootList {
|
||||
std::string title,
|
||||
details,
|
||||
@@ -189,5 +228,58 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationUpgradeList {
|
||||
std::string title,
|
||||
details,
|
||||
jobId;
|
||||
std::vector<std::string> success,
|
||||
skipped,
|
||||
no_firmware,
|
||||
not_connected;
|
||||
uint64_t timeStamp=OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
typedef WebSocketNotification<WebSocketNotificationUpgradeList> WebSocketClientNotificationVenueUpgradeList_t;
|
||||
|
||||
inline void WebSocketNotificationUpgradeList::to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_to_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_to_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_to_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_to_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||
}
|
||||
|
||||
inline bool WebSocketNotificationUpgradeList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_from_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_from_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_from_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_from_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationVenueUpgradeCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpgradeList_t &N) {
|
||||
N.type = "venue_upgrader";
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
|
||||
@@ -196,6 +196,8 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
static const struct msg InvalidRadiusServerEntry{1142,"RADIUS Server IP address invalid or port missing."};
|
||||
static const struct msg InvalidRadiusServerWeigth{1143,"RADIUS Server IP weight cannot be 0."};
|
||||
|
||||
static const struct msg MaximumRTTYSessionsReached{1144,"Too many RTTY sessions currently active"};
|
||||
static const struct msg DeviceIsAlreadyBusy{1145,"Device is already executing a command. Please try later."};
|
||||
}
|
||||
|
||||
|
||||
@@ -445,6 +447,7 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
static const char *RECOVERY = "recovery";
|
||||
static const char *TELEMETRY = "telemetry";
|
||||
static const char *DEVICEUPDATE = "deviceupdate";
|
||||
static const char *VENUE_BROADCAST = "venue_broadcast";
|
||||
|
||||
enum EVENT_MSG {
|
||||
ET_UNKNOWN,
|
||||
@@ -457,7 +460,8 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
ET_CFGPENDING,
|
||||
ET_RECOVERY,
|
||||
ET_DEVICEUPDATE,
|
||||
ET_TELEMETRY
|
||||
ET_TELEMETRY,
|
||||
ET_VENUEBROADCAST
|
||||
};
|
||||
|
||||
inline EVENT_MSG EventFromString(const std::string & Method) {
|
||||
@@ -481,6 +485,8 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
return ET_RECOVERY;
|
||||
else if(strcmp(TELEMETRY,Method.c_str())==0)
|
||||
return ET_TELEMETRY;
|
||||
else if(strcmp(VENUE_BROADCAST,Method.c_str())==0)
|
||||
return ET_VENUEBROADCAST;
|
||||
return ET_UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,128 +8,138 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
RTTYS_ClientConnection::RTTYS_ClientConnection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
Poco::Net::SocketReactor &reactor,
|
||||
const std::string &Id)
|
||||
RTTYS_ClientConnection::RTTYS_ClientConnection(
|
||||
Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
Poco::Net::SocketReactor &reactor,
|
||||
const std::string &Id)
|
||||
:
|
||||
Reactor_(reactor),
|
||||
Id_(Id),
|
||||
Logger_(Poco::Logger::get(fmt::format("RTTY-client({})",Id_)))
|
||||
{
|
||||
Logger_.information("Starting connection");
|
||||
Valid_ = true;
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request,response);
|
||||
WS_->setBlocking(false);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
Registered_ = true;
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
Logger_.information("Starting connection");
|
||||
}
|
||||
|
||||
RTTYS_ClientConnection::~RTTYS_ClientConnection() {
|
||||
if(Valid_) {
|
||||
MyGuard G(Mutex_);
|
||||
EndConnection(false);
|
||||
poco_information(Logger_,
|
||||
fmt::format("Client {} session ending", Id_)
|
||||
);
|
||||
DeRegister();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::DeRegister() {
|
||||
Valid_ = false;
|
||||
if(Registered_) {
|
||||
Registered_ = false;
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::EndConnection(bool SendNotification) {
|
||||
if(Valid_) {
|
||||
Valid_=false;
|
||||
try {
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketReadable));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<RTTYS_ClientConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_ClientConnection::onSocketShutdown));
|
||||
// WS_->shutdown();
|
||||
if (SendNotification)
|
||||
RTTYS_server()->NotifyClientDisconnect(Id_, this);
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
Logger_.information("Disconnected.");
|
||||
|
||||
}
|
||||
void RTTYS_ClientConnection::EndConnection() {
|
||||
DeRegister();
|
||||
RTTYS_server()->NotifyClientDisconnect(Id_, this);
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::onSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
MyGuard G(Mutex_);
|
||||
bool MustDisconnect = false;
|
||||
try {
|
||||
int flags;
|
||||
auto n = WS_->receiveFrame(Buffer_, sizeof(Buffer_), flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
if (n == 0) {
|
||||
Logger_.information("Socket readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
std::string s((char *)Buffer_, n);
|
||||
try {
|
||||
auto Doc = nlohmann::json::parse(s);
|
||||
if (Doc.contains("type")) {
|
||||
auto Type = Doc["type"];
|
||||
if (Type == "winsize") {
|
||||
auto cols = Doc["cols"];
|
||||
auto rows = Doc["rows"];
|
||||
if (!RTTYS_server()->WindowSize(Id_, cols, rows)) {
|
||||
Logger_.information("Winsize shutdown.");
|
||||
MustDisconnect = true;
|
||||
|
||||
{
|
||||
if(!Valid_ || !Registered_)
|
||||
return;
|
||||
std::shared_lock G(Mutex_);
|
||||
try {
|
||||
int flags;
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
auto n = WS_->receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
if (n == 0) {
|
||||
Logger_.information("Socket readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
std::string s((char *)IncomingFrame.begin(), IncomingFrame.size());
|
||||
try {
|
||||
auto Doc = nlohmann::json::parse(s);
|
||||
if (Doc.contains("type")) {
|
||||
auto Type = Doc["type"];
|
||||
if (Type == "winsize") {
|
||||
auto cols = Doc["cols"];
|
||||
auto rows = Doc["rows"];
|
||||
if (!RTTYS_server()->WindowSize(Id_, cols, rows)) {
|
||||
Logger_.information("Winsize shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
// just ignore parse errors
|
||||
Logger_.information("Frame text exception shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
} catch (...) {
|
||||
// just ignore parse errors
|
||||
Logger_.information("Frame text exception shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_BINARY: {
|
||||
if (n == 0) {
|
||||
Logger_.information("Frame binary size shutdown.");
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_BINARY: {
|
||||
if (n == 0) {
|
||||
Logger_.information("Frame binary size shutdown.");
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("Sending {} key strokes to device.", n));
|
||||
if (!RTTYS_server()->SendKeyStrokes(
|
||||
Id_, (const unsigned char *)IncomingFrame.begin(),
|
||||
IncomingFrame.size())) {
|
||||
Logger_.information("Sendkeystrokes shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger_.information("Frame frame close shutdown.");
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("Sending {} key strokes to device.", n));
|
||||
if (!RTTYS_server()->SendKeyStrokes(Id_, Buffer_, n)) {
|
||||
Logger_.information("Sendkeystrokes shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger_.information("Frame frame close shutdown.");
|
||||
MustDisconnect = true;
|
||||
} break;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
default: {
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
Logger_.information("Frame readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
Logger_.information("Frame readable shutdown.");
|
||||
MustDisconnect = true;
|
||||
}
|
||||
|
||||
if(MustDisconnect)
|
||||
if(MustDisconnect) {
|
||||
EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::SendData( const u_char *Buf, size_t len ) {
|
||||
if(!Valid_)
|
||||
if(!Valid_ || !Registered_)
|
||||
return;
|
||||
// MyGuard G(Mutex_);
|
||||
try {
|
||||
WS_->sendFrame(Buf, len,
|
||||
Poco::Net::WebSocket::FRAME_FLAG_FIN |
|
||||
@@ -138,26 +148,22 @@ namespace OpenWifi {
|
||||
} catch (...) {
|
||||
Logger_.information("SendData shutdown.");
|
||||
}
|
||||
MyGuard G(Mutex_);
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::SendData( const std::string &s) {
|
||||
if(!Valid_)
|
||||
if(!Valid_ || !Registered_)
|
||||
return;
|
||||
// MyGuard G(Mutex_);
|
||||
try {
|
||||
WS_->sendFrame(s.c_str(), s.length());
|
||||
return;
|
||||
} catch (...) {
|
||||
Logger_.information("SendData shutdown.");
|
||||
}
|
||||
MyGuard G(Mutex_);
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void RTTYS_ClientConnection::onSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
MyGuard G(Mutex_);
|
||||
Logger_.information("Socket shutdown.");
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
@@ -11,11 +11,9 @@
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/FIFOBuffer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
#include <shared_mutex>
|
||||
|
||||
enum class connection_state {
|
||||
initialized, waiting_for_login, connected, aborting, shutting_down, done
|
||||
};
|
||||
namespace OpenWifi {
|
||||
|
||||
class RTTYS_ClientConnection {
|
||||
public:
|
||||
@@ -29,11 +27,10 @@ namespace OpenWifi {
|
||||
|
||||
void SendData( const u_char *Buf, size_t len );
|
||||
void SendData( const std::string & S );
|
||||
void DeRegister();
|
||||
|
||||
[[nodiscard]] inline std::string ID() { return Id_; }
|
||||
[[nodiscard]] inline bool Valid() { return Valid_; }
|
||||
using MyMutexType = std::recursive_mutex;
|
||||
using MyGuard = std::lock_guard<MyMutexType>;
|
||||
|
||||
private:
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
@@ -41,12 +38,11 @@ namespace OpenWifi {
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
Poco::Logger &Logger_;
|
||||
std::string Sid_;
|
||||
std::atomic_bool Valid_=false;
|
||||
u_char Buffer_[64000]{0};
|
||||
MyMutexType Mutex_;
|
||||
// volatile connection_state state_ = connection_state::initialized;
|
||||
std::shared_mutex Mutex_;
|
||||
volatile bool Valid_=false;
|
||||
volatile bool Registered_=false;
|
||||
|
||||
void EndConnection(bool SendNotification=true);
|
||||
void EndConnection();
|
||||
|
||||
};
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace OpenWifi {
|
||||
try {
|
||||
RTTYS_server()->CreateNewClient(request,response,T[2]);
|
||||
} catch (...) {
|
||||
Logger_.warning("Exception during WS creation");
|
||||
poco_warning(Logger_,"Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -211,10 +211,11 @@ namespace OpenWifi {
|
||||
try {
|
||||
if (request.find("Upgrade") != request.end() &&
|
||||
Poco::icompare(request["Upgrade"], "websocket") == 0) {
|
||||
Utils::SetThreadName("rtty-websvr-ws");
|
||||
Poco::Thread::current()->setName("WebRTTYRequest_WSHandler");
|
||||
return new RTTYS_Client_WebSocketRequestHandler(Logger_);
|
||||
} else {
|
||||
Poco::Thread::current()->setName("WebRTTYRequest_PageHandler");
|
||||
Utils::SetThreadName("rtty-websvr-pg");
|
||||
return new PageRequestHandler(Logger_);
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenWifi {
|
||||
|
||||
class PageRequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
PageRequestHandler(Poco::Logger &L)
|
||||
explicit PageRequestHandler(Poco::Logger &L)
|
||||
: Logger_(L) {
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,29 @@
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
|
||||
|
||||
void dump(const u_char *b, uint s) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
int l=0;
|
||||
std::cout << std::endl;
|
||||
while(s) {
|
||||
std::string SS;
|
||||
SS += (hex[(*b & 0xf0) >> 4]);
|
||||
SS += (hex[(*b & 0x0f)]);
|
||||
std::cout << SS << " ";
|
||||
l++;
|
||||
if((l % 16) == 0)
|
||||
std::cout << std::endl;
|
||||
b++;
|
||||
--s;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
#define SOCKET_DEBUG(X,Y,Z) { std::cout << __func__ << ":" << __LINE__ << std::endl; (Z)=socket_.sendBytes(X,Y); dump(X,Y); }
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
RTTYS_Device_ConnectionHandler::RTTYS_Device_ConnectionHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor & reactor):
|
||||
@@ -23,19 +46,23 @@ namespace OpenWifi {
|
||||
try {
|
||||
valid_=true;
|
||||
device_address_ = socket_.peerAddress();
|
||||
if (MicroService::instance().NoAPISecurity()) {
|
||||
poco_information(Logger(),"Unsecured connection.");
|
||||
} else {
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl *>(socket_.impl());
|
||||
while (true) {
|
||||
auto V = SS->completeHandshake();
|
||||
if (V == 1)
|
||||
break;
|
||||
}
|
||||
if ((SS->secure())) {
|
||||
poco_information(Logger(), "Secure connection.");
|
||||
}
|
||||
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl *>(socket_.impl());
|
||||
while (true) {
|
||||
auto V = SS->completeHandshake();
|
||||
if (V == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((SS->secure())) {
|
||||
poco_information(Logger(), "Secure connection.");
|
||||
}
|
||||
|
||||
socket_.setBlocking(false);
|
||||
socket_.setKeepAlive(true);
|
||||
socket_.setNoDelay(true);
|
||||
|
||||
registered_=true;
|
||||
reactor_.addEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
@@ -46,38 +73,37 @@ namespace OpenWifi {
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketShutdown));
|
||||
} catch (...) {
|
||||
poco_warning(Logger(), "Device caused exception while completing connection.");
|
||||
Guard G(M_);
|
||||
std::unique_lock G(M_);
|
||||
EndConnection();
|
||||
}
|
||||
}
|
||||
|
||||
RTTYS_Device_ConnectionHandler::~RTTYS_Device_ConnectionHandler() {
|
||||
if(valid_) {
|
||||
Guard G(M_);
|
||||
poco_warning(Logger(), "Device connection being deleted.");
|
||||
EndConnection(false);
|
||||
poco_information(Logger_,
|
||||
fmt::format("Device {} session ending", id_)
|
||||
);
|
||||
DeRegister();
|
||||
}
|
||||
|
||||
void RTTYS_Device_ConnectionHandler::DeRegister() {
|
||||
if(registered_) {
|
||||
registered_ = false;
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketReadable));
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketShutdown));
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_Device_ConnectionHandler::EndConnection(bool SendNotification) {
|
||||
try {
|
||||
if(valid_) {
|
||||
valid_ = false;
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ReadableNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketReadable));
|
||||
reactor_.removeEventHandler(
|
||||
socket_,
|
||||
Poco::NObserver<RTTYS_Device_ConnectionHandler, Poco::Net::ShutdownNotification>(
|
||||
*this, &RTTYS_Device_ConnectionHandler::onSocketShutdown));
|
||||
if(SendNotification)
|
||||
RTTYS_server()->NotifyDeviceDisconnect(Id_,this);
|
||||
poco_information(Logger(), "Connection done.");
|
||||
socket_.close();
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
void RTTYS_Device_ConnectionHandler::EndConnection() {
|
||||
if(valid_) {
|
||||
valid_ = false;
|
||||
DeRegister();
|
||||
RTTYS_server()->NotifyDeviceDisconnect(id_, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,12 +119,14 @@ namespace OpenWifi {
|
||||
void RTTYS_Device_ConnectionHandler::onSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
bool good = true;
|
||||
|
||||
Guard G(M_);
|
||||
if(!valid_ || !registered_)
|
||||
return;
|
||||
|
||||
std::unique_lock G(M_);
|
||||
try {
|
||||
auto received_bytes = socket_.receiveBytes(inBuf_);
|
||||
if (received_bytes == 0) {
|
||||
poco_information(Logger(), fmt::format("{}: Device Closing connection - 0 bytes received.",Id_));
|
||||
poco_information(Logger(), fmt::format("{}: Device Closing connection - 0 bytes received.",id_));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
@@ -107,15 +135,13 @@ namespace OpenWifi {
|
||||
if (waiting_for_bytes_ != 0) {
|
||||
|
||||
} else {
|
||||
if (inBuf_.used() >= 3) {
|
||||
if (inBuf_.used() >= RTTY_HDR_SIZE) {
|
||||
auto *head = (unsigned char *)inBuf_.begin();
|
||||
last_command_ = head[0];
|
||||
msg_len = head[1] * 256 + head[2];
|
||||
inBuf_.drain(3);
|
||||
inBuf_.drain(RTTY_HDR_SIZE);
|
||||
} else {
|
||||
good = false;
|
||||
if (!good)
|
||||
std::cout << "do_msgTypeTermData:5 " << inBuf_.used() << std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -156,7 +182,7 @@ namespace OpenWifi {
|
||||
} break;
|
||||
default: {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("{}: Unknown command {} from device. GW closing connection.", Id_,
|
||||
fmt::format("{}: Unknown command {} from device. GW closing connection.", id_,
|
||||
(int)last_command_));
|
||||
good = false;
|
||||
}
|
||||
@@ -165,9 +191,9 @@ namespace OpenWifi {
|
||||
} catch (const Poco::Exception &E) {
|
||||
good = false;
|
||||
Logger().log(E,__FILE__,__LINE__);
|
||||
poco_warning(Logger(),fmt::format("{}: Exception. GW closing connection.", Id_));
|
||||
poco_warning(Logger(),fmt::format("{}: Exception. GW closing connection.", id_));
|
||||
} catch (const std::exception &E) {
|
||||
poco_warning(Logger(),fmt::format("{}: Exception. GW closing connection.", Id_));
|
||||
poco_warning(Logger(),fmt::format("{}: Exception. GW closing connection.", id_));
|
||||
good = false;
|
||||
}
|
||||
|
||||
@@ -177,83 +203,76 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RTTYS_Device_ConnectionHandler::onSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
Guard G(M_);
|
||||
poco_information(Logger(),fmt::format("{}: Connection being closed - socket shutdown.",Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Connection being closed - socket shutdown.",id_));
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::SendToClient(const u_char *Buf, int Len) {
|
||||
return RTTYS_server()->SendToClient(Id_, Buf, Len);
|
||||
u_char bb[64000]{0};
|
||||
if(old_rtty_) {
|
||||
bb[0] = session_id_[0];
|
||||
memcpy(&bb[1],Buf,Len);
|
||||
} else {
|
||||
bb[0] = 0;
|
||||
memcpy(&bb[1],Buf,Len);
|
||||
}
|
||||
return RTTYS_server()->SendToClient(id_, Buf, Len );
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::SendToClient(const std::string &S) {
|
||||
return RTTYS_server()->SendToClient(Id_, S);
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
return RTTYS_server()->SendToClient(id_,S);
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::KeyStrokes(const u_char *buf, size_t len) {
|
||||
if(!valid_)
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
if(len<=(sizeof(small_buf_)-3)) {
|
||||
if(len<=(sizeof(small_buf_)-RTTY_HDR_SIZE-session_length_)) {
|
||||
small_buf_[0] = msgTypeTermData;
|
||||
small_buf_[1] = (len & 0xff00) >> 8;
|
||||
small_buf_[2] = (len & 0x00ff);
|
||||
memcpy(&small_buf_[3],buf,len);
|
||||
small_buf_[1] = ((len-1+session_length_) & 0xff00) >> 8;
|
||||
small_buf_[2] = ((len-1+session_length_) & 0x00ff);
|
||||
memcpy(&small_buf_[RTTY_HDR_SIZE],session_id_,session_length_);
|
||||
memcpy(&small_buf_[RTTY_HDR_SIZE+session_length_], &buf[1], len-1);
|
||||
try {
|
||||
socket_.sendBytes(small_buf_,len+3);
|
||||
return true;
|
||||
auto Sent = socket_.sendBytes(small_buf_, RTTY_HDR_SIZE + session_length_ + len - 1);
|
||||
return (Sent==(int)(RTTY_HDR_SIZE + session_length_ + len - 1));
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
auto Msg = std::make_unique<unsigned char []>(len + 3);
|
||||
auto Msg = std::make_unique<unsigned char []>(len + RTTY_HDR_SIZE + session_length_);
|
||||
Msg.get()[0] = msgTypeTermData;
|
||||
Msg.get()[1] = (len & 0xff00) >> 8;
|
||||
Msg.get()[2] = (len & 0x00ff);
|
||||
memcpy((void *)(Msg.get() + 3), buf, len);
|
||||
Msg.get()[1] = ((len-1+session_length_) & 0xff00) >> 8;
|
||||
Msg.get()[2] = ((len-1+session_length_) & 0x00ff);
|
||||
memcpy((Msg.get()+RTTY_HDR_SIZE),session_id_,session_length_);
|
||||
memcpy((Msg.get()+RTTY_HDR_SIZE+session_length_), &buf[1], len-1);
|
||||
try {
|
||||
socket_.sendBytes(Msg.get(), len + 3);
|
||||
return true;
|
||||
auto Sent = socket_.sendBytes(Msg.get(), RTTY_HDR_SIZE + session_length_ + len - 1);
|
||||
return (Sent==(int)( RTTY_HDR_SIZE + session_length_ + len - 1));
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
unsigned char Msg[64];
|
||||
Msg[0] = msgTypeTermData;
|
||||
Msg[1] = (len & 0xff00) >> 8;
|
||||
Msg[2] = (len & 0x00ff);
|
||||
|
||||
Poco::Net::SocketBufVec MsgParts{ Poco::Net::SocketBuf{ .iov_base=Msg, .iov_len=3},
|
||||
Poco::Net::SocketBuf{ .iov_base=(unsigned char *)buf, .iov_len=len}};
|
||||
try {
|
||||
socket_.sendBytes(MsgParts);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::WindowSize(int cols, int rows) {
|
||||
if(!valid_)
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
// Guard G(M_);
|
||||
|
||||
u_char outBuf[8]{0};
|
||||
u_char outBuf[8+RTTY_SESSION_ID_LENGTH]{0};
|
||||
outBuf[0] = msgTypeWinsize;
|
||||
outBuf[1] = 0 ;
|
||||
outBuf[2] = 4 + 1 ;
|
||||
outBuf[3] = sid_;
|
||||
outBuf[4] = cols >> 8 ;
|
||||
outBuf[5] = cols & 0x00ff;
|
||||
outBuf[6] = rows >> 8;
|
||||
outBuf[7] = rows & 0x00ff;
|
||||
outBuf[2] = 4 + session_length_ ;
|
||||
memcpy(&outBuf[RTTY_HDR_SIZE],session_id_,session_length_);
|
||||
outBuf[RTTY_HDR_SIZE+0+session_length_] = cols >> 8 ;
|
||||
outBuf[RTTY_HDR_SIZE+1+session_length_] = cols & 0x00ff;
|
||||
outBuf[RTTY_HDR_SIZE+2+session_length_] = rows >> 8;
|
||||
outBuf[RTTY_HDR_SIZE+3+session_length_] = rows & 0x00ff;
|
||||
try {
|
||||
socket_.sendBytes(outBuf, 8);
|
||||
return true;
|
||||
auto Sent = socket_.sendBytes(outBuf, RTTY_HDR_SIZE + 4 + session_length_ );
|
||||
return (Sent==(int)(RTTY_HDR_SIZE + 4 + session_length_));
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
@@ -261,40 +280,43 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::Login() {
|
||||
if(!valid_)
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
// Guard G(M_);
|
||||
u_char outBuf[3]{0};
|
||||
u_char outBuf[RTTY_HDR_SIZE+RTTY_SESSION_ID_LENGTH]{0};
|
||||
outBuf[0] = msgTypeLogin;
|
||||
outBuf[1] = 0;
|
||||
outBuf[2] = 0;
|
||||
if(old_rtty_) {
|
||||
outBuf[2] = 0;
|
||||
} else {
|
||||
outBuf[2] = RTTY_SESSION_ID_LENGTH;
|
||||
std::strncpy(session_id_,Utils::ComputeHash(id_,token_).substr(0,RTTY_SESSION_ID_LENGTH/2).c_str(),RTTY_SESSION_ID_LENGTH);
|
||||
memcpy(&outBuf[RTTY_HDR_SIZE],session_id_,RTTY_SESSION_ID_LENGTH);
|
||||
}
|
||||
try {
|
||||
socket_.sendBytes(outBuf, 3);
|
||||
poco_information(Logger(),fmt::format("{}: Device login", id_));
|
||||
auto Sent = socket_.sendBytes( outBuf, RTTY_HDR_SIZE + (old_rtty_ ? 0 : RTTY_SESSION_ID_LENGTH));
|
||||
return Sent==(int)(RTTY_HDR_SIZE + (old_rtty_ ? 0 : RTTY_SESSION_ID_LENGTH));
|
||||
} catch (const Poco::IOException &E) {
|
||||
return false;
|
||||
} catch (const Poco::Exception &E) {
|
||||
return false;
|
||||
}
|
||||
poco_information(Logger(),fmt::format("{}: Device login", Id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::Logout() {
|
||||
if(!valid_)
|
||||
if(!valid_ || !registered_)
|
||||
return false;
|
||||
|
||||
Guard G(M_);
|
||||
|
||||
u_char outBuf[4]{0};
|
||||
u_char outBuf[4+RTTY_SESSION_ID_LENGTH]{0};
|
||||
outBuf[0] = msgTypeLogout;
|
||||
outBuf[1] = 0;
|
||||
outBuf[2] = 1;
|
||||
outBuf[3] = sid_;
|
||||
poco_information(Logger(),fmt::format("{}: Logout", Id_));
|
||||
outBuf[2] = session_length_;
|
||||
memcpy(&outBuf[3],session_id_,session_length_);
|
||||
poco_information(Logger(),fmt::format("{}: Logout", id_));
|
||||
try {
|
||||
socket_.sendBytes(outBuf, 4);
|
||||
return true;
|
||||
auto Sent = socket_.sendBytes(outBuf, RTTY_HDR_SIZE + session_length_);
|
||||
return Sent==(int)(RTTY_HDR_SIZE+session_length_);
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
@@ -319,25 +341,34 @@ namespace OpenWifi {
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeRegister([[maybe_unused]] std::size_t msg_len) {
|
||||
bool good = true;
|
||||
try {
|
||||
Id_ = ReadString();
|
||||
// establish if this is an old rtty or a new one.
|
||||
old_rtty_ = (inBuf_[0] != 0x03); // rtty_proto_ver for full session ID inclusion
|
||||
if(old_rtty_) {
|
||||
session_length_ = 1;
|
||||
} else {
|
||||
inBuf_.drain(1); // remove protocol if used.
|
||||
session_length_ = RTTY_SESSION_ID_LENGTH;
|
||||
}
|
||||
|
||||
id_ = ReadString();
|
||||
desc_ = ReadString();
|
||||
token_ = ReadString();
|
||||
|
||||
poco_information(Logger(),
|
||||
fmt::format("{}: Description:{} Device registration", Id_, desc_));
|
||||
RTTYS_server()->NotifyDeviceRegistration(Id_,token_,this);
|
||||
fmt::format("{}: Description:{} Device registration", id_, desc_));
|
||||
RTTYS_server()->NotifyDeviceRegistration(id_,token_,this);
|
||||
u_char OutBuf[8];
|
||||
OutBuf[0] = msgTypeRegister;
|
||||
OutBuf[1] = 0;
|
||||
OutBuf[2] = 4;
|
||||
OutBuf[3] = 0;
|
||||
OutBuf[1] = 0; // Data length
|
||||
OutBuf[2] = 4; //
|
||||
OutBuf[3] = 0; // Error
|
||||
OutBuf[4] = 'O';
|
||||
OutBuf[5] = 'K';
|
||||
OutBuf[6] = 0;
|
||||
if (socket_.sendBytes(OutBuf, 7) != 7) {
|
||||
poco_information(Logger(),
|
||||
fmt::format("{}: Description:{} Could not send data to complete registration",
|
||||
Id_, desc_));
|
||||
id_, desc_));
|
||||
good = false;
|
||||
}
|
||||
} catch (...) {
|
||||
@@ -347,11 +378,17 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeLogin([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for login", Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Asking for login", id_));
|
||||
nlohmann::json doc;
|
||||
char Error;
|
||||
inBuf_.read(&Error, 1);
|
||||
inBuf_.read(&sid_, 1);
|
||||
if(old_rtty_) {
|
||||
inBuf_.read(&Error, 1);
|
||||
inBuf_.read(&session_id_[0], session_length_);
|
||||
} else {
|
||||
char session[RTTY_SESSION_ID_LENGTH+1]{0};
|
||||
inBuf_.read(&session[0], session_length_);
|
||||
inBuf_.read(&Error, 1);
|
||||
}
|
||||
doc["type"] = "login";
|
||||
doc["err"] = Error;
|
||||
const auto login_msg = to_string(doc);
|
||||
@@ -359,8 +396,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeLogout([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for logout", Id_));
|
||||
return true;
|
||||
char session[RTTY_SESSION_ID_LENGTH];
|
||||
if(old_rtty_) {
|
||||
inBuf_.read(&session[0],1);
|
||||
} else {
|
||||
inBuf_.read(&session[0],RTTY_SESSION_ID_LENGTH);
|
||||
}
|
||||
poco_information(Logger(),fmt::format("{}: Logout", id_));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeTermData(std::size_t msg_len) {
|
||||
@@ -369,24 +412,27 @@ namespace OpenWifi {
|
||||
if(inBuf_.used()<waiting_for_bytes_) {
|
||||
waiting_for_bytes_ = waiting_for_bytes_ - inBuf_.used();
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), (int) inBuf_.used());
|
||||
if(!good) std::cout << "do_msgTypeTermData:1" << std::endl;
|
||||
inBuf_.drain();
|
||||
} else {
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), waiting_for_bytes_);
|
||||
if(!good) std::cout << "do_msgTypeTermData:2" << std::endl;
|
||||
inBuf_.drain(waiting_for_bytes_);
|
||||
waiting_for_bytes_ = 0 ;
|
||||
}
|
||||
} else {
|
||||
if(old_rtty_) {
|
||||
inBuf_.drain(1);
|
||||
msg_len -= 1;
|
||||
} else {
|
||||
inBuf_.drain(RTTY_SESSION_ID_LENGTH);
|
||||
msg_len -= RTTY_SESSION_ID_LENGTH;
|
||||
}
|
||||
if(inBuf_.used()<msg_len) {
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), inBuf_.used());
|
||||
if(!good) std::cout << "do_msgTypeTermData:3" << std::endl;
|
||||
waiting_for_bytes_ = msg_len - inBuf_.used();
|
||||
inBuf_.drain();
|
||||
} else {
|
||||
waiting_for_bytes_ = 0 ;
|
||||
good = SendToClient((unsigned char *)inBuf_.begin(), msg_len);
|
||||
if(!good) std::cout << "do_msgTypeTermData:4" << std::endl;
|
||||
inBuf_.drain(msg_len);
|
||||
}
|
||||
}
|
||||
@@ -394,40 +440,43 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeWinsize([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeWinsize", Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeWinsize", id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeCmd([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeCmd", Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeCmd", id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeHeartbeat([[maybe_unused]] std::size_t msg_len) {
|
||||
if(!RTTYS_server()->ValidClient(Id_))
|
||||
return false;
|
||||
u_char MsgBuf[3]{0};
|
||||
u_char MsgBuf[RTTY_HDR_SIZE + 16]{0};
|
||||
if(msg_len)
|
||||
inBuf_.drain(msg_len);
|
||||
MsgBuf[0] = msgTypeHeartbeat;
|
||||
return socket_.sendBytes(MsgBuf, 3)==3;
|
||||
MsgBuf[1] = 0;
|
||||
MsgBuf[2] = 0;
|
||||
auto Sent = socket_.sendBytes(MsgBuf, RTTY_HDR_SIZE);
|
||||
return Sent == RTTY_HDR_SIZE;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeFile([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeFile", Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeFile", id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeHttp([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeHttp", Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeHttp", id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeAck([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeAck", Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeAck", id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_Device_ConnectionHandler::do_msgTypeMax([[maybe_unused]] std::size_t msg_len) {
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeMax", Id_));
|
||||
poco_information(Logger(),fmt::format("{}: Asking for msgTypeMax", id_));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <shared_mutex>
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/FIFOBuffer.h"
|
||||
#include "Poco/Net/TCPServerConnectionFactory.h"
|
||||
@@ -12,6 +13,8 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
constexpr std::size_t RTTY_DEVICE_BUFSIZE=64000;
|
||||
constexpr std::size_t RTTY_SESSION_ID_LENGTH=32;
|
||||
constexpr std::size_t RTTY_HDR_SIZE=3;
|
||||
|
||||
class RTTYS_Device_ConnectionHandler{
|
||||
public:
|
||||
@@ -44,9 +47,6 @@ namespace OpenWifi {
|
||||
void onSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void onSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);
|
||||
|
||||
using My_mutex_type = std::recursive_mutex;
|
||||
using Guard = std::lock_guard<My_mutex_type>;
|
||||
|
||||
inline Poco::Logger &Logger() { return Logger_; }
|
||||
inline bool Valid() { return valid_; }
|
||||
|
||||
@@ -57,18 +57,22 @@ namespace OpenWifi {
|
||||
Poco::Logger &Logger_;
|
||||
|
||||
std::atomic_bool valid_=false;
|
||||
bool old_rtty_=true;
|
||||
Poco::Net::SocketAddress device_address_;
|
||||
My_mutex_type M_;
|
||||
std::string Id_;
|
||||
std::shared_mutex M_;
|
||||
std::string id_;
|
||||
std::string token_;
|
||||
std::string desc_;
|
||||
char sid_=0;
|
||||
char session_id_[RTTY_SESSION_ID_LENGTH+1]{0};
|
||||
std::uint64_t session_length_=1;
|
||||
std::size_t waiting_for_bytes_{0};
|
||||
u_char last_command_=0;
|
||||
unsigned char small_buf_[64];
|
||||
std::atomic_bool registered_=false;
|
||||
unsigned char small_buf_[64+RTTY_SESSION_ID_LENGTH];
|
||||
|
||||
void EndConnection(bool SendNotification=true) ;
|
||||
void EndConnection() ;
|
||||
void CompleteConnection();
|
||||
void DeRegister();
|
||||
|
||||
[[nodiscard]] bool do_msgTypeRegister(std::size_t msg_len);
|
||||
[[nodiscard]] bool do_msgTypeLogin(std::size_t msg_len);
|
||||
|
||||
@@ -16,23 +16,19 @@ namespace OpenWifi {
|
||||
int DSport = (int) MicroService::instance().ConfigGetInt("rtty.port", 5912);
|
||||
int CSport = (int) MicroService::instance().ConfigGetInt("rtty.viewport", 5913);
|
||||
RTTY_UIAssets_ = MicroService::instance().ConfigPath("rtty.assets", "$OWGW_ROOT/rtty_ui");
|
||||
MaxConcurrentSessions_ = MicroService::instance().ConfigGetInt("rtty.maxsessions",0);
|
||||
|
||||
const auto & CertFileName = MicroService::instance().ConfigPath("openwifi.restapi.host.0.cert");
|
||||
const auto & KeyFileName = MicroService::instance().ConfigPath("openwifi.restapi.host.0.key");
|
||||
const auto & RootCa = MicroService::instance().ConfigPath("openwifi.restapi.host.0.rootca");
|
||||
|
||||
auto TcpServerParams = new Poco::Net::TCPServerParams();
|
||||
TcpServerParams->setMaxThreads(50);
|
||||
TcpServerParams->setMaxQueued(100);
|
||||
TcpServerParams->setThreadIdleTime(Poco::Timespan(10,0));
|
||||
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Poco::Net::ServerSocket DeviceSocket(DSport, 64);
|
||||
DeviceAcceptor_ = std::make_unique<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>>(DeviceSocket,DeviceReactor_);
|
||||
} else {
|
||||
auto DeviceSecureContext = new Poco::Net::Context(Poco::Net::Context::SERVER_USE,
|
||||
auto DeviceSecureContext = Poco::AutoPtr<Poco::Net::Context>( new Poco::Net::Context(Poco::Net::Context::SERVER_USE,
|
||||
KeyFileName, CertFileName, "",
|
||||
Poco::Net::Context::VERIFY_RELAXED);
|
||||
Poco::Net::Context::VERIFY_RELAXED));
|
||||
Poco::Crypto::X509Certificate DeviceRoot(RootCa);
|
||||
DeviceSecureContext->addCertificateAuthority(DeviceRoot);
|
||||
DeviceSecureContext->disableStatelessSessionResumption();
|
||||
@@ -53,6 +49,7 @@ namespace OpenWifi {
|
||||
WebServerHttpParams->setMaxThreads(50);
|
||||
WebServerHttpParams->setMaxQueued(200);
|
||||
WebServerHttpParams->setKeepAlive(true);
|
||||
WebServerHttpParams->setName("rt:dispatch");
|
||||
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
Poco::Net::ServerSocket ClientSocket(CSport, 64);
|
||||
@@ -82,38 +79,36 @@ namespace OpenWifi {
|
||||
|
||||
GCCallBack_ = std::make_unique<Poco::TimerCallback<RTTYS_server>>(*this, &RTTYS_server::onTimer);
|
||||
Timer_.setStartInterval(30 * 1000); // first run in 30 seconds
|
||||
Timer_.setPeriodicInterval(20 * 1000);
|
||||
Timer_.start(*GCCallBack_);
|
||||
|
||||
Timer_.setPeriodicInterval(5 * 1000);
|
||||
Timer_.start(*GCCallBack_, MicroService::instance().TimerPool() );
|
||||
NotificationManager_.start(*this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RTTYS_server::Stop() {
|
||||
Timer_.stop();
|
||||
if(Internal_) {
|
||||
NotificationManagerRunning_=false;
|
||||
ResponseQueue_.wakeUpAll();
|
||||
NotificationManager_.wakeUp();
|
||||
NotificationManager_.join();
|
||||
Timer_.stop();
|
||||
WebServer_->stopAll();
|
||||
WebServer_->stopAll(true);
|
||||
WebServer_->stop();
|
||||
DeviceAcceptor_->unregisterAcceptor();
|
||||
DeviceReactor_.stop();
|
||||
DeviceReactorThread_.join();
|
||||
ClientReactor_.stop();
|
||||
ClientReactorThread_.join();
|
||||
DeviceReactor_.stop();
|
||||
DeviceAcceptor_->unregisterAcceptor();
|
||||
DeviceReactorThread_.join();
|
||||
NotificationManagerRunning_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::onTimer([[maybe_unused]] Poco::Timer & timer) {
|
||||
poco_debug(Logger(),"Removing stale connections.");
|
||||
poco_trace(Logger(),"Removing stale connections.");
|
||||
Utils::SetThreadName("rt:janitor");
|
||||
static int count = 0;
|
||||
// MutexLockerDbg L(__func__ ,M_);
|
||||
static auto LastStats = OpenWifi::Now();
|
||||
|
||||
std::unique_lock G(M_);
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
for(auto element=EndPoints_.begin();element!=EndPoints_.end();) {
|
||||
if(element->second->TooOld()) {
|
||||
auto c = fmt::format("Removing {}. Serial: {} Device connection time: {}s. Client connection time: {}s",
|
||||
@@ -131,33 +126,34 @@ namespace OpenWifi {
|
||||
}
|
||||
FailedDevices.clear();
|
||||
FailedClients.clear();
|
||||
count++;
|
||||
if(count==10) {
|
||||
count=0;
|
||||
Logger().information(fmt::format("Total connections:{} Total Device Connection Time: {}s Total Client Connection Time: {}s Device failures: {} Client failures: {}",
|
||||
|
||||
if(Now()-LastStats>(60*5)) {
|
||||
LastStats = Now();
|
||||
Logger().information(fmt::format("Statistics: Total connections:{} Total Device Connection Time: {}s Total Client Connection Time: {}s Device failures: {} Client failures: {}",
|
||||
TotalEndPoints_,
|
||||
TotalConnectedDeviceTime_,
|
||||
TotalConnectedClientTime_,
|
||||
FaildedNumDevices_,
|
||||
FailedNumDevices_,
|
||||
FailedNumClients_));
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::CreateNewClient(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response, const std::string &id) {
|
||||
void RTTYS_server::CreateNewClient( Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
const std::string &id) {
|
||||
|
||||
auto NewClient = new RTTYS_ClientConnection(request, response, ClientReactor_, id);
|
||||
NotifyClientRegistration(id,NewClient);
|
||||
}
|
||||
|
||||
void RTTYS_server::run() {
|
||||
Utils::SetThreadName("rtty-mgr");
|
||||
Utils::SetThreadName("rt:manager");
|
||||
NotificationManagerRunning_ = true;
|
||||
Poco::AutoPtr<Poco::Notification> NextNotification(ResponseQueue_.waitDequeueNotification());
|
||||
while (NextNotification && NotificationManagerRunning_) {
|
||||
auto Notification = dynamic_cast<RTTYS_Notification *>(NextNotification.get());
|
||||
if (Notification != nullptr) {
|
||||
std::unique_lock G(M_);
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
auto It = EndPoints_.find(Notification->id_);
|
||||
if (It != EndPoints_.end()) {
|
||||
switch (Notification->type_) {
|
||||
@@ -168,16 +164,14 @@ namespace OpenWifi {
|
||||
It->second->DisconnectClient();
|
||||
} break;
|
||||
case RTTYS_Notification_type::device_registration: {
|
||||
auto ptr = std::unique_ptr<RTTYS_Device_ConnectionHandler>{Notification->device_};
|
||||
It->second->SetDevice(std::move(ptr));
|
||||
It->second->SetDevice(Notification->device_);
|
||||
if(!It->second->Joined() && It->second->ValidClient()) {
|
||||
It->second->Join();
|
||||
It->second->Login();
|
||||
}
|
||||
} break;
|
||||
case RTTYS_Notification_type::client_registration: {
|
||||
auto ptr = std::unique_ptr<RTTYS_ClientConnection>{Notification->client_};
|
||||
It->second->SetClient(std::move(ptr));
|
||||
It->second->SetClient(Notification->client_);
|
||||
if(!It->second->Joined() && It->second->ValidDevice()) {
|
||||
It->second->Join();
|
||||
It->second->Login();
|
||||
@@ -188,7 +182,7 @@ namespace OpenWifi {
|
||||
};
|
||||
} else {
|
||||
if(Notification->type_==RTTYS_Notification_type::device_registration) {
|
||||
FaildedNumDevices_++;
|
||||
FailedNumDevices_++;
|
||||
auto ptr = std::unique_ptr<RTTYS_Device_ConnectionHandler>{Notification->device_};
|
||||
FailedDevices.push_back(std::move(ptr));
|
||||
} else if(Notification->type_==RTTYS_Notification_type::client_registration) {
|
||||
@@ -203,10 +197,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendToClient(const std::string &Id, const u_char *Buf, std::size_t Len) {
|
||||
std::shared_lock Guard(M_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
try {
|
||||
auto It = EndPoints_.find(Id);
|
||||
if (It != EndPoints_.end()) {
|
||||
if (It != EndPoints_.end() && It->second!=nullptr) {
|
||||
return It->second->SendToClient(Buf,Len);
|
||||
}
|
||||
} catch(const Poco::Exception &E) {
|
||||
@@ -218,10 +213,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendToClient(const std::string &Id, const std::string &s) {
|
||||
std::shared_lock Guard(M_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
try {
|
||||
auto It = EndPoints_.find(Id);
|
||||
if (It != EndPoints_.end()) {
|
||||
if (It != EndPoints_.end() && It->second!=nullptr) {
|
||||
return It->second->SendToClient(s);
|
||||
}
|
||||
} catch(const Poco::Exception &E) {
|
||||
@@ -232,22 +228,17 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::ValidClient(const std::string &Id) {
|
||||
std::shared_lock Guard(M_);
|
||||
auto It = EndPoints_.find(Id);
|
||||
return It!=EndPoints_.end() && It->second->ValidClient();
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendKeyStrokes(const std::string &Id, const u_char *buffer, std::size_t len) {
|
||||
std::shared_lock Guard(M_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
auto It=EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
if(It==EndPoints_.end() || It->second==nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return It->second->KeyStrokes(buffer, len);
|
||||
auto res = It->second->KeyStrokes(buffer, len);
|
||||
return res;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
@@ -256,9 +247,10 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool RTTYS_server::WindowSize(const std::string &Id, int cols, int rows) {
|
||||
std::shared_lock Guard(M_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
|
||||
auto It=EndPoints_.find(Id);
|
||||
if(It==EndPoints_.end()) {
|
||||
if(It==EndPoints_.end() || It->second==nullptr) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
@@ -270,35 +262,21 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool RTTYS_server::CreateEndPoint(const std::string &Id, const std::string & Token, const std::string & UserName, const std::string & SerialNumber ) {
|
||||
std::unique_lock Guard(M_);
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
|
||||
auto NewEP = std::make_unique<RTTYS_EndPoint>(Token, SerialNumber, UserName );
|
||||
EndPoints_[Id] = std::move(NewEP);
|
||||
if(MaxConcurrentSessions_!=0 && EndPoints_.size()==MaxConcurrentSessions_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EndPoints_[Id] = std::make_unique<RTTYS_EndPoint>(Token, SerialNumber, UserName );
|
||||
++TotalEndPoints_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::ValidId(const std::string &Token) {
|
||||
std::shared_lock Guard(M_);
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
return EndPoints_.find(Token) != EndPoints_.end();
|
||||
}
|
||||
|
||||
bool RTTYS_server::Login(const std::string & Id) {
|
||||
std::shared_lock Guard(M_);
|
||||
|
||||
auto ep = EndPoints_.find(Id);
|
||||
if(ep == EndPoints_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return ep->second->Login();
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -90,14 +90,14 @@ namespace OpenWifi {
|
||||
Created_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
inline void SetClient(std::unique_ptr<RTTYS_ClientConnection> Client) {
|
||||
inline void SetClient(RTTYS_ClientConnection *Client) {
|
||||
ClientConnected_ = std::chrono::high_resolution_clock::now();
|
||||
Client_ = std::move(Client);
|
||||
Client_ = std::unique_ptr<RTTYS_ClientConnection>(Client);
|
||||
}
|
||||
|
||||
inline void SetDevice(std::unique_ptr<RTTYS_Device_ConnectionHandler> Device) {
|
||||
inline void SetDevice(RTTYS_Device_ConnectionHandler* Device) {
|
||||
DeviceConnected_ = std::chrono::high_resolution_clock::now();
|
||||
Device_ = std::move(Device);
|
||||
Device_ = std::unique_ptr<RTTYS_Device_ConnectionHandler>(Device);
|
||||
}
|
||||
|
||||
inline bool Login() {
|
||||
@@ -107,12 +107,6 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
RTTYS_EndPoint & operator=(RTTYS_EndPoint Other) {
|
||||
Other.Client_ = std::move(Client_);
|
||||
Other.Device_ = std::move(Device_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void DisconnectClient() {
|
||||
ClientDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
@@ -123,13 +117,13 @@ namespace OpenWifi {
|
||||
|
||||
[[nodiscard]] inline bool TooOld() {
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();
|
||||
if(ClientDisconnected_!=std::chrono::time_point<std::chrono::high_resolution_clock>{0s} && (now-ClientDisconnected_)>15s) {
|
||||
if(ClientDisconnected_!=std::chrono::time_point<std::chrono::high_resolution_clock>{0s} && (now-ClientDisconnected_)>5s) {
|
||||
if(DeviceDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
DeviceDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(DeviceDisconnected_!=std::chrono::time_point<std::chrono::high_resolution_clock>{0s} && (now-DeviceDisconnected_)>15s) {
|
||||
if(DeviceDisconnected_!=std::chrono::time_point<std::chrono::high_resolution_clock>{0s} && (now-DeviceDisconnected_)>5s) {
|
||||
if(ClientDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
ClientDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
@@ -140,7 +134,6 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
// std::cout << ClientDisconnected_ << " " << ClientConnected_ << " " << DeviceDisconnected_ << " " << DeviceConnected_ << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -149,7 +142,6 @@ namespace OpenWifi {
|
||||
Client_->SendData(Buf,Len);
|
||||
return true;
|
||||
}
|
||||
std::cout << "SendToClientFailure: " << (Client_!= nullptr) << " " << Client_->Valid() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -189,8 +181,18 @@ namespace OpenWifi {
|
||||
[[nodiscard]] inline const std::string & UserName() const { return UserName_; }
|
||||
[[nodiscard]] inline const std::string & SerialNumber() const { return SerialNumber_; }
|
||||
|
||||
[[nodiscard]] inline auto TimeDeviceConnected() const { return std::chrono::duration<double>{DeviceDisconnected_ - DeviceConnected_}.count(); }
|
||||
[[nodiscard]] inline auto TimeClientConnected() const { return std::chrono::duration<double>{ClientDisconnected_ - ClientConnected_}.count(); }
|
||||
[[nodiscard]] inline auto TimeDeviceConnected() {
|
||||
if(DeviceDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
DeviceDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
return std::chrono::duration<double>{DeviceDisconnected_ - DeviceConnected_}.count(); }
|
||||
|
||||
[[nodiscard]] inline auto TimeClientConnected() {
|
||||
if(ClientDisconnected_==std::chrono::time_point<std::chrono::high_resolution_clock>{0s}) {
|
||||
ClientDisconnected_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
return std::chrono::duration<double>{ClientDisconnected_ - ClientConnected_}.count();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string Token_;
|
||||
@@ -219,12 +221,10 @@ namespace OpenWifi {
|
||||
inline auto UIAssets() { return RTTY_UIAssets_; }
|
||||
|
||||
bool CreateEndPoint(const std::string &Id, const std::string & Token, const std::string & UserName, const std::string & SerialNumber );
|
||||
bool Login(const std::string & Id_);
|
||||
bool SendKeyStrokes(const std::string &Id, const u_char *buffer, std::size_t s);
|
||||
bool WindowSize(const std::string &Id, int cols, int rows);
|
||||
bool SendToClient(const std::string &id, const u_char *Buf, std::size_t Len);
|
||||
bool SendToClient(const std::string &id, const std::string &s);
|
||||
bool ValidClient(const std::string &id);
|
||||
bool ValidId(const std::string &Id);
|
||||
|
||||
void run() final;
|
||||
@@ -255,6 +255,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline Poco::Net::SocketReactor & ClientReactor() { return ClientReactor_; }
|
||||
inline auto Uptime() const { return OpenWifi::Now() - Started_; }
|
||||
|
||||
private:
|
||||
Poco::Net::SocketReactor ClientReactor_;
|
||||
@@ -268,21 +269,23 @@ namespace OpenWifi {
|
||||
std::unique_ptr<Poco::Net::SocketAcceptor<RTTYS_Device_ConnectionHandler>> DeviceAcceptor_;
|
||||
Poco::Thread DeviceReactorThread_;
|
||||
Poco::NotificationQueue ResponseQueue_;
|
||||
mutable bool NotificationManagerRunning_=false;
|
||||
std::atomic_bool NotificationManagerRunning_=false;
|
||||
Poco::Thread NotificationManager_;
|
||||
|
||||
Poco::Timer Timer_;
|
||||
std::unique_ptr<Poco::TimerCallback<RTTYS_server>> GCCallBack_;
|
||||
std::list<std::unique_ptr<RTTYS_Device_ConnectionHandler>> FailedDevices;
|
||||
std::list<std::unique_ptr<RTTYS_ClientConnection>> FailedClients;
|
||||
mutable std::shared_mutex M_;
|
||||
std::shared_mutex LocalMutex_;
|
||||
|
||||
uint64_t TotalEndPoints_=0;
|
||||
uint64_t FaildedNumDevices_=0;
|
||||
uint64_t FailedNumClients_=0;
|
||||
std::atomic_uint64_t TotalEndPoints_=0;
|
||||
std::atomic_uint64_t FailedNumDevices_=0;
|
||||
std::atomic_uint64_t FailedNumClients_=0;
|
||||
double TotalConnectedDeviceTime_=0.0;
|
||||
double TotalConnectedClientTime_=0.0;
|
||||
|
||||
std::atomic_uint64_t Started_=OpenWifi::Now();
|
||||
std::atomic_uint64_t MaxConcurrentSessions_=0;
|
||||
|
||||
explicit RTTYS_server() noexcept:
|
||||
SubSystemServer("RTTY_Server", "RTTY-SVR", "rtty.server")
|
||||
|
||||
52
src/sdks/sdk_prov.h
Normal file
52
src/sdks/sdk_prov.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-16.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_ProvObjects.h"
|
||||
|
||||
namespace OpenWifi::SDK::Prov {
|
||||
|
||||
inline bool GetSerialNumbersForVenueOfSerialNumber( const std::string & SerialNumber, Types::UUID_t &Venue, Types::StringVec & AdjacentSerialNumbers , Poco::Logger &Logger ) {
|
||||
OpenAPIRequestGet GetInventoryForSerialNumber( uSERVICE_PROVISIONING, "/api/v1/inventory/" + SerialNumber , {} , 30000);
|
||||
|
||||
auto CallResponse1 = Poco::makeShared<Poco::JSON::Object>();
|
||||
if(!GetInventoryForSerialNumber.Do(CallResponse1,"")) {
|
||||
Logger.error(fmt::format("{}: Cannot find serial number in inventory.", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
ProvObjects::InventoryTag Device;
|
||||
if(!Device.from_json(CallResponse1)) {
|
||||
Logger.error(fmt::format("{}: Invalid Inventory response.", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
Venue = Device.venue;
|
||||
|
||||
OpenAPIRequestGet GetInventoryForVenue( uSERVICE_PROVISIONING, "/api/v1/inventory" ,
|
||||
{
|
||||
{"serialOnly","true"},
|
||||
{"venue", Venue}
|
||||
}, 30000);
|
||||
|
||||
auto CallResponse2 = Poco::makeShared<Poco::JSON::Object>();
|
||||
if(!GetInventoryForVenue.Do(CallResponse2,"")) {
|
||||
Logger.error(fmt::format("{}: Cannot get inventory for venue.", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
OpenWifi::RESTAPI_utils::field_from_json(CallResponse2, "serialNumbers",
|
||||
AdjacentSerialNumbers);
|
||||
} catch(...) {
|
||||
Logger.error(fmt::format("{}: Cannot parse inventory list", SerialNumber));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return true;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -99,7 +99,7 @@ namespace OpenWifi {
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ namespace OpenWifi {
|
||||
BlackListDevices.erase(SerialNumber);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -155,7 +155,7 @@ namespace OpenWifi {
|
||||
|
||||
return Select.rowsExtracted()==1;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning( fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ bool Storage::CreateDeviceCapabilities(std::string &SerialNumber, std::string &C
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -128,22 +128,16 @@ typedef Poco::Tuple<
|
||||
|
||||
bool Storage::AddCommand(std::string &SerialNumber, GWObjects::CommandDetails &Command, CommandExecutionType Type) {
|
||||
try {
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
|
||||
if(Type == COMMAND_PENDING) {
|
||||
Command.Status = "pending";
|
||||
} else if(Type == COMMAND_COMPLETED) {
|
||||
Command.Status = "completed";
|
||||
Command.Status = to_string(Type);
|
||||
if( Type==CommandExecutionType::COMMAND_COMPLETED ||
|
||||
Type==CommandExecutionType::COMMAND_TIMEDOUT ||
|
||||
Type==CommandExecutionType::COMMAND_FAILED ||
|
||||
Type==CommandExecutionType::COMMAND_EXPIRED ||
|
||||
Type==CommandExecutionType::COMMAND_EXECUTED
|
||||
) {
|
||||
Command.Executed = Now;
|
||||
} else if (Type == COMMAND_TIMEDOUT) {
|
||||
Command.Executed = Now;
|
||||
Command.Status = "timedout";
|
||||
} else if (Type == COMMAND_FAILED) {
|
||||
Command.Executed = Now;
|
||||
Command.Status = "failed";
|
||||
} else {
|
||||
Command.Executed = Now;
|
||||
Command.Status = "executing";
|
||||
}
|
||||
|
||||
RemoveOldCommands(SerialNumber, Command.Command);
|
||||
@@ -271,7 +265,7 @@ typedef Poco::Tuple<
|
||||
Offset++;
|
||||
GWObjects::CommandDetails R;
|
||||
ConvertCommandRecord(i,R);
|
||||
if (DeviceRegistry()->Connected(R.SerialNumber))
|
||||
if (DeviceRegistry()->Connected(Utils::SerialNumberToInt(R.SerialNumber)))
|
||||
Commands.push_back(R);
|
||||
}
|
||||
|
||||
@@ -317,11 +311,14 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
std::string St{"UPDATE CommandList SET Executed=? WHERE UUID=?"};
|
||||
auto Now = OpenWifi::Now();
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status=? WHERE UUID=?"};
|
||||
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use( CommandUUID);
|
||||
Update.execute();
|
||||
return true;
|
||||
@@ -331,7 +328,63 @@ typedef Poco::Tuple<
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetCommand(std::string &UUID, GWObjects::CommandDetails &Command) {
|
||||
void Storage::RemovedExpiredCommands() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = OpenWifi::Now(), Window = Now-(4*60*60);
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_EXPIRED);
|
||||
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status=? WHERE submitted<? and executed=0"};
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(Window);
|
||||
Update.execute();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::RemoveTimedOutCommands() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = OpenWifi::Now(), Window = Now-(1*60*60);
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status='timedout' WHERE Executed<? and completed=0"};
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Window);
|
||||
Update.execute();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
}
|
||||
|
||||
bool Storage::SetCommandTimedOut(std::string &CommandUUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = OpenWifi::Now();
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_TIMEDOUT);
|
||||
std::string St{"UPDATE CommandList SET Executed=?, Status=? WHERE UUID=?"};
|
||||
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(CommandUUID);
|
||||
Update.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetCommand(const std::string &UUID, GWObjects::CommandDetails &Command) {
|
||||
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
@@ -341,11 +394,11 @@ typedef Poco::Tuple<
|
||||
"SELECT " +
|
||||
DB_Command_SelectFields +
|
||||
" FROM CommandList WHERE UUID=?"};
|
||||
|
||||
auto tmp_uuid = UUID;
|
||||
CommandDetailsRecordTuple R;
|
||||
Select << ConvertParams(St),
|
||||
Poco::Data::Keywords::into(R),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Poco::Data::Keywords::use(tmp_uuid);
|
||||
ConvertCommandRecord(R,Command);
|
||||
Select.execute();
|
||||
return true;
|
||||
@@ -406,12 +459,12 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
std::string St{
|
||||
"SELECT " +
|
||||
DB_Command_SelectFields
|
||||
+ " FROM CommandList "
|
||||
" WHERE ((RunAt<=?) And (Executed=0)) ORDER BY UUID ASC "};
|
||||
" WHERE ((RunAt<=?) And (Executed=0)) ORDER BY Submitted ASC "};
|
||||
CommandDetailsRecordList Records;
|
||||
|
||||
std::string SS = ConvertParams(St) + ComputeRange(Offset, HowMany);
|
||||
@@ -423,7 +476,7 @@ typedef Poco::Tuple<
|
||||
for(const auto &i : Records) {
|
||||
GWObjects::CommandDetails R;
|
||||
ConvertCommandRecord(i,R);
|
||||
if (DeviceRegistry()->Connected(R.SerialNumber))
|
||||
if (DeviceRegistry()->Connected(Utils::SerialNumberToInt(R.SerialNumber)))
|
||||
Commands.push_back(R);
|
||||
}
|
||||
return true;
|
||||
@@ -435,7 +488,7 @@ typedef Poco::Tuple<
|
||||
|
||||
bool Storage::CommandExecuted(std::string &UUID) {
|
||||
try {
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
@@ -451,7 +504,6 @@ typedef Poco::Tuple<
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -460,7 +512,7 @@ typedef Poco::Tuple<
|
||||
bool FullCommand) {
|
||||
try {
|
||||
|
||||
uint64_t Now = FullCommand ? time(nullptr) : 0;
|
||||
auto Now = FullCommand ? OpenWifi::Now() : 0;
|
||||
|
||||
// Parse the result to get the ErrorText and make sure that this is a JSON document
|
||||
uint64_t ErrorCode = 0;
|
||||
@@ -486,7 +538,7 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string StatusText{"completed"};
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
std::string St{"UPDATE CommandList SET Completed=?, ErrorCode=?, ErrorText=?, Results=?, Status=?, executionTime=? WHERE UUID=?"};
|
||||
double tET{execution_time.count()};
|
||||
Update << ConvertParams(St),
|
||||
@@ -494,23 +546,21 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Keywords::use(ErrorCode),
|
||||
Poco::Data::Keywords::use(ErrorText),
|
||||
Poco::Data::Keywords::use(ResultStr),
|
||||
Poco::Data::Keywords::use(StatusText),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(tET),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CancelWaitFile( std::string & UUID, std::string & ErrorText ) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
uint64_t Now = time(nullptr);
|
||||
auto Now = OpenWifi::Now();
|
||||
uint64_t Size = 0, WaitForFile = 0;
|
||||
|
||||
Poco::Data::Statement Update(Sess);
|
||||
@@ -531,79 +581,12 @@ typedef Poco::Tuple<
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/* bool Storage::AttachFileToCommand(std::string &UUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
uint64_t WaitForFile = 0;
|
||||
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
Poco::File FileName = FileUploader()->Path() + "/" + UUID;
|
||||
std::cout << __LINE__ << std::endl;
|
||||
uint64_t Size = FileName.getSize();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
std::string St{
|
||||
"UPDATE CommandList SET WaitingForFile=?, AttachDate=?, AttachSize=? WHERE UUID=?"};
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(WaitForFile),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Size),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
if (FileName.getSize() < FileUploader()->MaxSize()) {
|
||||
|
||||
Poco::Data::BLOB TheBlob;
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
std::ifstream f(FileName.path(), std::ios::binary);
|
||||
std::ostringstream SS;
|
||||
Poco::StreamCopier::copyStream(f, SS);
|
||||
TheBlob.appendRaw((const unsigned char *)SS.str().c_str(),SS.str().size());
|
||||
|
||||
std::cout << "Attach file size: " << SS.str().size() << std::endl;
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
std::string FileType{"trace"};
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
std::string St2{
|
||||
"INSERT INTO FileUploads (UUID,Type,Created,FileContent) VALUES(?,?,?,?)"};
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Insert << ConvertParams(St2), Poco::Data::Keywords::use(UUID),
|
||||
Poco::Data::Keywords::use(FileType),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(TheBlob);
|
||||
Insert.execute();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
FileName.remove();
|
||||
return true;
|
||||
} else {
|
||||
Logger().warning(fmt::format("File {} is too large.", FileName.path()));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
bool Storage::AttachFileDataToCommand(std::string & UUID, const std::stringstream & FileContent) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
auto Now = OpenWifi::Now();
|
||||
uint64_t WaitForFile = 0;
|
||||
|
||||
Poco::Data::Statement Update(Sess);
|
||||
@@ -639,7 +622,7 @@ typedef Poco::Tuple<
|
||||
Insert.execute();
|
||||
return true;
|
||||
} else {
|
||||
Logger().warning(fmt::format("File {} is too large.", UUID));
|
||||
poco_warning(Logger(),fmt::format("File {} is too large.", UUID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -647,48 +630,6 @@ typedef Poco::Tuple<
|
||||
return false;
|
||||
}
|
||||
|
||||
/* bool Storage::GetAttachedFile(std::string &UUID, const std::string & SerialNumber, const std::string &FileName, std::string &Type) {
|
||||
try {
|
||||
Poco::Data::BLOB L;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select1(Sess);
|
||||
|
||||
std::string TmpSerialNumber;
|
||||
std::string st1{"SELECT SerialNumber FROM CommandList WHERE UUID=?"};
|
||||
Select1 << ConvertParams(st1),
|
||||
Poco::Data::Keywords::into(TmpSerialNumber),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Select1.execute();
|
||||
|
||||
if(TmpSerialNumber!=SerialNumber) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string St2{"SELECT FileContent, Type FROM FileUploads WHERE UUID=?"};
|
||||
|
||||
Poco::Data::Statement Select2(Sess);
|
||||
Select2 << ConvertParams(St2),
|
||||
Poco::Data::Keywords::into(L),
|
||||
Poco::Data::Keywords::into(Type),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Select2.execute();
|
||||
|
||||
// Poco::Data::BLOBInputStream IL(L);
|
||||
std::ofstream f(FileName, std::ios::binary | std::ios::trunc );
|
||||
auto Content = L.content();
|
||||
std::string SS(L.content().begin(),L.content().end());
|
||||
f << SS;
|
||||
|
||||
std::cout << "Get Attach Size: " << L.content().size() << std::endl;
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
bool Storage::GetAttachedFileContent(std::string &UUID, const std::string & SerialNumber, std::string &FileContent, std::string &Type) {
|
||||
try {
|
||||
Poco::Data::BLOB L;
|
||||
@@ -734,11 +675,15 @@ typedef Poco::Tuple<
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
std::string St{"UPDATE CommandList SET Completed=?, Results=? WHERE UUID=?"};
|
||||
auto Now = OpenWifi::Now();
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
std::string St{"UPDATE CommandList SET Completed=?, Results=?, Status=? WHERE UUID=?"};
|
||||
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Result), Poco::Data::Keywords::use(UUID);
|
||||
Update << ConvertParams(St),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Result),
|
||||
Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
return true;
|
||||
|
||||
@@ -763,7 +708,6 @@ typedef Poco::Tuple<
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace OpenWifi {
|
||||
std::string St{"SELECT name FROM DefaultConfigs WHERE Name=?"};
|
||||
Select << ConvertParams(St) ,
|
||||
Poco::Data::Keywords::into(TmpName) ,
|
||||
Name;
|
||||
Poco::Data::Keywords::use(Name);
|
||||
Select.execute();
|
||||
|
||||
if (!TmpName.empty())
|
||||
@@ -90,12 +90,12 @@ namespace OpenWifi {
|
||||
Insert.execute();
|
||||
return true;
|
||||
} else {
|
||||
Logger().warning("Cannot create device: invalid configuration.");
|
||||
poco_warning(Logger(),"Cannot create device: invalid configuration.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -167,7 +167,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -190,7 +190,7 @@ namespace OpenWifi {
|
||||
return Select.rowsExtracted()==1;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -215,7 +215,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -245,7 +245,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -261,7 +261,7 @@ namespace OpenWifi {
|
||||
return Count;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "Daemon.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "FindCountry.h"
|
||||
#include "OUIServer.h"
|
||||
#include "Poco/Data/RecordSet.h"
|
||||
#include "Poco/Net/IPAddress.h"
|
||||
#include "SDKcalls.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "StateUtils.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#include "FindCountry.h"
|
||||
#include "WS_Server.h"
|
||||
#include "SDKcalls.h"
|
||||
#include "StateUtils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace OpenWifi {
|
||||
|
||||
bool Found = false;
|
||||
std::string FoundConfig;
|
||||
if(WebSocketServer()->UseProvisioning()) {
|
||||
if(AP_WS_Server()->UseProvisioning()) {
|
||||
if(SDKCalls::GetProvisioningConfiguration(SerialNumber, FoundConfig)) {
|
||||
if(FoundConfig != "none") {
|
||||
Found = true;
|
||||
@@ -337,7 +337,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found && WebSocketServer()->UseDefaults() && FindDefaultConfigurationForModel(Compat, DefConfig)) {
|
||||
if (!Found && AP_WS_Server()->UseDefaults() && FindDefaultConfigurationForModel(Compat, DefConfig)) {
|
||||
Config::Config NewConfig(DefConfig.Configuration);
|
||||
NewConfig.SetUUID(Now);
|
||||
D.Configuration = NewConfig.get();
|
||||
@@ -433,7 +433,7 @@ namespace OpenWifi {
|
||||
|
||||
bool Storage::DeleteDevice(std::string &SerialNumber) {
|
||||
try {
|
||||
std::vector<std::string> DBList{"Devices", "Statistics", "CommandList", "HealthChecks", "LifetimeStats", "Capabilities", "DeviceLogs"};
|
||||
std::vector<std::string> DBList{"Devices", "Statistics", "CommandList", "HealthChecks", "Capabilities", "DeviceLogs"};
|
||||
|
||||
for(const auto &i:DBList) {
|
||||
|
||||
@@ -453,10 +453,14 @@ namespace OpenWifi {
|
||||
SerialNumberCache()->DeleteSerialNumber(SerialNumber);
|
||||
|
||||
if(KafkaManager()->Enabled()) {
|
||||
nlohmann::json Message;
|
||||
Message["command"] = "delete_device";
|
||||
Message["payload"]["serialNumber"] = SerialNumber;
|
||||
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, to_string(Message));
|
||||
Poco::JSON::Object Message;
|
||||
Message.set("command","command");
|
||||
Poco::JSON::Object Payload;
|
||||
Payload.set("serialNumber", SerialNumber);
|
||||
Message.set("payload",Payload);
|
||||
std::ostringstream StrPayload;
|
||||
Message.stringify(StrPayload);
|
||||
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, StrPayload.str());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -162,7 +162,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ namespace OpenWifi {
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -147,7 +147,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ namespace OpenWifi {
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -36,12 +36,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool Storage::AddStatisticsData(const GWObjects::Statistics & Stats) {
|
||||
DeviceRegistry()->SetStatistics(Stats.SerialNumber, Stats.Data);
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
poco_debug(Logger(),"Device:" + Stats.SerialNumber + " Stats size:" + std::to_string(Stats.Data.size()));
|
||||
poco_trace(Logger(),fmt::format("{}: Adding stats. Size={}",Stats.SerialNumber,std::to_string(Stats.Data.size())));
|
||||
std::string St{"INSERT INTO Statistics ( " +
|
||||
DB_StatsSelectFields +
|
||||
" ) VALUES ( " +
|
||||
@@ -54,7 +53,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -97,7 +96,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -124,7 +123,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -157,7 +156,7 @@ bool Storage::DeleteStatisticsData(std::string &SerialNumber, uint64_t FromDate,
|
||||
return true;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText())));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -172,7 +171,7 @@ bool Storage::DeleteStatisticsData(std::string &SerialNumber, uint64_t FromDate,
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().warning(fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
poco_warning(Logger(),fmt::format("{}: Failed with: {}", std::string(__func__), E.displayText()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -180,6 +180,14 @@ listdevices() {
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
listdevices() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
ldevs() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices?offset=$1&limit=$2" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -191,7 +199,8 @@ ldevs() {
|
||||
deletedevice() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/device/$1" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deleteoui() {
|
||||
@@ -237,7 +246,8 @@ setloglevel() {
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload"
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
getloglevels() {
|
||||
@@ -246,7 +256,8 @@ getloglevels() {
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload"
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
getloglevelnames() {
|
||||
@@ -255,7 +266,8 @@ getloglevelnames() {
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload"
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
getsubsystemnames() {
|
||||
@@ -264,7 +276,8 @@ getsubsystemnames() {
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload"
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
systeminfo() {
|
||||
@@ -294,7 +307,8 @@ getdevicestatus() {
|
||||
|
||||
getdevicecomplete() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/device/$1?completeInfo=true" \
|
||||
-H "accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
@@ -507,7 +521,7 @@ deviceserialnumbers() {
|
||||
}
|
||||
|
||||
deviceswithstatus() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices?deviceWithStatus=true" \
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices?deviceWithStatus=true&limit=500" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
@@ -654,7 +668,7 @@ telemetry_to_kafka() {
|
||||
|
||||
runscript() {
|
||||
payload="$(printf '{ "serialNumber": "%s", "type": "%s" , "kafka": true, "timeout": 30, "scriptId": "cli-manual", "script" : "%s" }' "$1" "$2" "$3" )"
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/telemetry" \
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/script" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
@@ -705,6 +719,14 @@ getradiusconfig() {
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
connectionstatistics() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices?connectionStatistics=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
check_response() {
|
||||
|
||||
if [ -s "$1" ]; then
|
||||
@@ -970,5 +992,6 @@ case "$1" in
|
||||
"getradiusconfig") login; getradiusconfig ; logout;;
|
||||
"setradiusconfig") login; setradiusconfig $2; logout;;
|
||||
"deviceping") login; deviceping $2; logout;;
|
||||
"connectionstatistics") login; connectionstatistics $2; logout;;
|
||||
*) help ;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user