mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-11-02 03:37:57 +00:00
Compare commits
218 Commits
v2.11.0-RC
...
sqlopt1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
915a2c936d | ||
|
|
e1bf6a9ab7 | ||
|
|
58fc925a2f | ||
|
|
3dda87b41f | ||
|
|
a5fe59086a | ||
|
|
c66b936c1e | ||
|
|
0e763cf034 | ||
|
|
eb441d71aa | ||
|
|
082153a229 | ||
|
|
25a03ca801 | ||
|
|
0d549137de | ||
|
|
40e814cab8 | ||
|
|
e40d53f3e5 | ||
|
|
607507ce9a | ||
|
|
b3ec5b1e81 | ||
|
|
c52d3c92f6 | ||
|
|
d1216a8ac4 | ||
|
|
c27f0390f8 | ||
|
|
052d379e2b | ||
|
|
4eda1b813f | ||
|
|
5364adf509 | ||
|
|
3b5580a525 | ||
|
|
644918fa14 | ||
|
|
8cdd398a6e | ||
|
|
9f7f4683df | ||
|
|
1c6e35fa8b | ||
|
|
af17823df0 | ||
|
|
0cff2163bb | ||
|
|
0a5fe39bde | ||
|
|
c42feca957 | ||
|
|
d3c5b17733 | ||
|
|
30bc8e8283 | ||
|
|
336c94a25a | ||
|
|
84f42e5a7d | ||
|
|
17752fdefe | ||
|
|
ef300b0349 | ||
|
|
9c4ecb6165 | ||
|
|
efd099b6fa | ||
|
|
15805dcaf6 | ||
|
|
e5ed1750cc | ||
|
|
87d74568f2 | ||
|
|
0cca3caa9b | ||
|
|
1d22e1153f | ||
|
|
f3ccc49647 | ||
|
|
46fb410108 | ||
|
|
fc680a6bc4 | ||
|
|
246f9c8aad | ||
|
|
3f06f00a88 | ||
|
|
0288d905b7 | ||
|
|
135b63c021 | ||
|
|
12e07fa65f | ||
|
|
567c2d1514 | ||
|
|
b9bd768ca6 | ||
|
|
f2dec010ee | ||
|
|
329d8d4441 | ||
|
|
d4dbbeb54b | ||
|
|
b1c6884d49 | ||
|
|
3ffa35bb14 | ||
|
|
bd06722948 | ||
|
|
8c70ec5280 | ||
|
|
6c13d845f1 | ||
|
|
77cc0b250b | ||
|
|
a3c424d8fe | ||
|
|
3f834a967b | ||
|
|
4120aefcd4 | ||
|
|
909ee66ef0 | ||
|
|
c3ad34d84b | ||
|
|
fbb9f40529 | ||
|
|
5f6300bb17 | ||
|
|
0bcfb26579 | ||
|
|
5b199bc4f5 | ||
|
|
4c6fb85542 | ||
|
|
63993789ca | ||
|
|
cc9d4c5f68 | ||
|
|
50fa1de62c | ||
|
|
14ef6608d6 | ||
|
|
8e48d30d6a | ||
|
|
46c6321674 | ||
|
|
77f67fe545 | ||
|
|
ceda1fc8f6 | ||
|
|
5b1a4fb9c0 | ||
|
|
2ddc0d3117 | ||
|
|
2cfc6c30e9 | ||
|
|
0318b475f5 | ||
|
|
c5c2dc1a1e | ||
|
|
7b899adb88 | ||
|
|
aa472ed79e | ||
|
|
1778912264 | ||
|
|
142bc4f271 | ||
|
|
a01d006d4e | ||
|
|
135a195081 | ||
|
|
ef7cb883fb | ||
|
|
2e361a41d7 | ||
|
|
84281ec58e | ||
|
|
3560871f44 | ||
|
|
b072f1e2ab | ||
|
|
72173ed4b5 | ||
|
|
ff53d4ba2e | ||
|
|
81721b4a61 | ||
|
|
3619be1832 | ||
|
|
a8fc823b94 | ||
|
|
a8a33013be | ||
|
|
9560f908a6 | ||
|
|
8400b8cfcb | ||
|
|
82897f5b76 | ||
|
|
4b472fd112 | ||
|
|
ecb6312f0f | ||
|
|
0aba846277 | ||
|
|
5be884ef98 | ||
|
|
10c890a196 | ||
|
|
0974abd510 | ||
|
|
8dbbfc3298 | ||
|
|
c981ae14ee | ||
|
|
97547068d7 | ||
|
|
16cc443786 | ||
|
|
7d8e15bf66 | ||
|
|
3f60c5abc6 | ||
|
|
d85fb32af9 | ||
|
|
030991f13c | ||
|
|
142541180f | ||
|
|
9bd48bf029 | ||
|
|
8581048528 | ||
|
|
6cfb0ae975 | ||
|
|
45561de44b | ||
|
|
2fccfd756e | ||
|
|
df42837a76 | ||
|
|
4bc1ac1aef | ||
|
|
77ee9d48d0 | ||
|
|
7154cca4b9 | ||
|
|
77732bdb95 | ||
|
|
7a8a05d77d | ||
|
|
aa2c28355b | ||
|
|
b6cb5d003b | ||
|
|
c93acdf54a | ||
|
|
0c5e0d649e | ||
|
|
1757440cfe | ||
|
|
c3ccfe455e | ||
|
|
66ec7745bb | ||
|
|
531c51dd64 | ||
|
|
227ec2dc96 | ||
|
|
50c5c76484 | ||
|
|
7a567e400b | ||
|
|
148eabdbc2 | ||
|
|
94ae20ce65 | ||
|
|
fd80f02f0b | ||
|
|
943cdd5010 | ||
|
|
36a5f4a5da | ||
|
|
e0e8cc1295 | ||
|
|
d7bad290e9 | ||
|
|
06766d2ed9 | ||
|
|
913a3e4ce1 | ||
|
|
4e713e4471 | ||
|
|
cb10ea6a7f | ||
|
|
f5095b9f79 | ||
|
|
8a69089513 | ||
|
|
ba6c657587 | ||
|
|
177deb8cd2 | ||
|
|
1dfc478d0e | ||
|
|
f077fb7fad | ||
|
|
0dc1be1f41 | ||
|
|
e1a0864b68 | ||
|
|
222c796eee | ||
|
|
15fe0df04a | ||
|
|
ad1a3c694c | ||
|
|
04be75f037 | ||
|
|
8cd26ce8cb | ||
|
|
525f53aaa9 | ||
|
|
ab95733067 | ||
|
|
35f4e26ca4 | ||
|
|
14f63cb324 | ||
|
|
0962c8383a | ||
|
|
891965a321 | ||
|
|
4d2adc3c3a | ||
|
|
24eb4079d7 | ||
|
|
53010fca84 | ||
|
|
6f3079ab0a | ||
|
|
c73a7c6c09 | ||
|
|
bb60fef3d6 | ||
|
|
b52766d23a | ||
|
|
6f9a9471c3 | ||
|
|
992c169ac7 | ||
|
|
ba8a932b36 | ||
|
|
13dc97d35b | ||
|
|
0ef01e5547 | ||
|
|
138b236832 | ||
|
|
a0d4606c22 | ||
|
|
a5200e46b7 | ||
|
|
2d3866a987 | ||
|
|
0251b40287 | ||
|
|
1e2f215902 | ||
|
|
8184027534 | ||
|
|
a43841b867 | ||
|
|
c391ea2f04 | ||
|
|
111faaa80d | ||
|
|
687cbcd0a4 | ||
|
|
c48665d4c5 | ||
|
|
c873681adc | ||
|
|
cb64f8a809 | ||
|
|
0d8be1fd46 | ||
|
|
e496f71e7d | ||
|
|
de7c8b687a | ||
|
|
61e346e0bf | ||
|
|
67bf9ca8c6 | ||
|
|
14b7fc8a0e | ||
|
|
546d6f9ee0 | ||
|
|
fe74fdecf9 | ||
|
|
c53a67edd5 | ||
|
|
5207f1e1a0 | ||
|
|
53aa2f05d2 | ||
|
|
2405b9fe95 | ||
|
|
bc14bf28bf | ||
|
|
878e705db5 | ||
|
|
be62022344 | ||
|
|
432434a377 | ||
|
|
60860ad9de | ||
|
|
29d6f2dda1 | ||
|
|
330b4176f2 | ||
|
|
75b76bb380 |
@@ -24,7 +24,7 @@ sudo apt install librdkafka-dev // default-libmysqlclient-dev
|
||||
sudo apt install nlohmann-json-dev
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -75,7 +75,7 @@ sudo yum install yaml-cpp-devel lua-devel
|
||||
sudo dnf install postgresql.x86_64 librdkafka-devel
|
||||
sudo dnf install postgresql-devel json-devel
|
||||
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
@@ -125,7 +125,7 @@ brew install openssl \
|
||||
nlohmann-json \
|
||||
fmt
|
||||
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
|
||||
pushd poco
|
||||
mkdir cmake-build
|
||||
push cmake-build
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owgw VERSION 2.11.0)
|
||||
project(owgw VERSION 3.0.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -175,7 +175,7 @@ add_executable( owgw
|
||||
src/SDKcalls.cpp
|
||||
src/SDKcalls.h
|
||||
src/StateUtils.cpp src/StateUtils.h
|
||||
src/AP_WS_ReactorPool.h
|
||||
src/AP_WS_Reactor_Pool.h
|
||||
src/AP_WS_Connection.h
|
||||
src/AP_WS_Connection.cpp
|
||||
src/TelemetryClient.h src/TelemetryClient.cpp
|
||||
@@ -199,7 +199,7 @@ add_executable( owgw
|
||||
src/AP_WS_Process_deviceupdate.cpp
|
||||
src/AP_WS_Process_telemetry.cpp
|
||||
src/AP_WS_Process_venuebroadcast.cpp
|
||||
src/RADSEC_server.h
|
||||
src/RADIUS_Destination.h
|
||||
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h
|
||||
src/framework/RESTAPI_SystemConfiguration.h
|
||||
src/ScriptManager.cpp src/ScriptManager.h
|
||||
@@ -211,7 +211,8 @@ add_executable( owgw
|
||||
src/RegulatoryInfo.cpp src/RegulatoryInfo.h
|
||||
src/RADIUSSessionTracker.cpp src/RADIUSSessionTracker.h
|
||||
src/libs/Scheduler.h src/libs/InterruptableSleep.h src/libs/ctpl_stl.h src/libs/Cron.h
|
||||
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h)
|
||||
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h
|
||||
src/AP_WS_LookForUpgrade.cpp)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
|
||||
@@ -223,14 +224,17 @@ INSTALL(TARGETS owgw
|
||||
|
||||
target_link_libraries(owgw PUBLIC
|
||||
${Poco_LIBRARIES}
|
||||
${ZLIB_LIBRARIES})
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(owgw PUBLIC
|
||||
${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
|
||||
CppKafka::cppkafka
|
||||
fmt::fmt
|
||||
)
|
||||
${MySQL_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
CppKafka::cppkafka
|
||||
fmt::fmt
|
||||
resolv
|
||||
)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(owgw PUBLIC PocoJSON)
|
||||
endif()
|
||||
|
||||
@@ -87,6 +87,11 @@ ENV APP_NAME=$APP_NAME \
|
||||
APP_CONFIG=/$APP_NAME-data \
|
||||
APP_HOME_DIR=$APP_HOME_DIR
|
||||
|
||||
# This is for legacy
|
||||
ENV OWGW_USER=$APP_USER \
|
||||
OWGW_ROOT=$APP_ROOT \
|
||||
OWGW_CONFIG=$APP_CONFIG
|
||||
|
||||
RUN useradd $APP_USER
|
||||
|
||||
RUN mkdir $APP_HOME_DIR
|
||||
|
||||
140
PROTOCOL.md
140
PROTOCOL.md
@@ -775,6 +775,146 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to replace its certificates
|
||||
Controller sends this command to run a predefined script. Extreme care must be taken.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "certupdate" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"certificates" : <BASE64 encoded tar file of the cert package from the certificate portal>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
"txt" : <text describing the error or success>
|
||||
},
|
||||
"id" : <same number as request>
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to switch to another controller
|
||||
Controller sends this when the device should change the controller it connects to without looking up a new redirector.
|
||||
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "transfer" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"server" : <controller hostname>,
|
||||
"port" : <controller port number (integer)>,
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
"txt" : <text describing the error or success>
|
||||
},
|
||||
"id" : <same number as request>
|
||||
}
|
||||
```
|
||||
|
||||
### RRM AP device commands
|
||||
The following command is used to send RRM commands to an AP. RRM commands are send to an AP, however the
|
||||
controller will not or cannot verify if they have been sent or the action was performed.
|
||||
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "rrm" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"actions" : [ array of actions. Each possible action is defined next]
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
"txt" : <text describing the error or success>
|
||||
},
|
||||
"id" : <same number as request>
|
||||
}
|
||||
```
|
||||
|
||||
#### RRM Roam action
|
||||
|
||||
##### Kick
|
||||
```json
|
||||
{
|
||||
"action" : "kick" ,
|
||||
"addr" : <mac if the client that shall be kicked> ,
|
||||
"reason": <number>, (default: 5, https://www.cisco.com/assets/sol/sb/WAP371_Emulators/WAP371_Emulator_v1-0-1-5/help/Apx_ReasonCodes2.html)
|
||||
"ban_time": <number> (seconds, optional)
|
||||
}
|
||||
```
|
||||
|
||||
##### Channel Switch Announcement
|
||||
```json
|
||||
{
|
||||
"action" : "channel_switch" ,
|
||||
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
|
||||
"channel" : <number> (HT/HW mode will be retained upon issuing the CSA)
|
||||
}
|
||||
```
|
||||
|
||||
##### Change TX-Power
|
||||
```json
|
||||
{
|
||||
"action" : "tx_power" ,
|
||||
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
|
||||
"level" : <number> (DBm inside the positive number space)
|
||||
}
|
||||
```
|
||||
|
||||
##### Beacon Scan
|
||||
```json
|
||||
{
|
||||
"action" : "beacon_request" ,
|
||||
"addr" : <mac if the client that shall perform the scan> ,
|
||||
"ssid": <string>, (the SSID the client shall scan for on all frequencies),
|
||||
"channel": <number> (the channel that shall be scanned)
|
||||
}
|
||||
```
|
||||
|
||||
##### BSS Transition
|
||||
```json
|
||||
{
|
||||
"action" : "bss_transition" ,
|
||||
"addr" : <mac if the client that shall perform the roam> ,
|
||||
"neighbors": [ <string> ], (an array of BSSIDs the client shall consider as roamin candidates)
|
||||
}
|
||||
```
|
||||
|
||||
##### Update neighbours
|
||||
```json
|
||||
{
|
||||
"action" : "neighbors" ,
|
||||
"bssid" : <mac of the SSID> , (the SSID of the specific VAP)
|
||||
"neighbors": [ [ <BSS>, <ssid>, <neighbor report> ] ]
|
||||
}
|
||||
```
|
||||
|
||||
### `rtty server`
|
||||
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.
|
||||
|
||||
|
||||
@@ -903,6 +903,114 @@ components:
|
||||
kafkaClients:
|
||||
type: integer
|
||||
|
||||
RRM_Kick:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- kick
|
||||
addr:
|
||||
type: string
|
||||
format: mac
|
||||
reason:
|
||||
type: integer
|
||||
default: 5
|
||||
ban_time:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
RRM_channel_switch:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- channel_switch
|
||||
bssid:
|
||||
type: string
|
||||
format: mac
|
||||
channel:
|
||||
type: integer
|
||||
|
||||
RRM_tx_power:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- tx_power
|
||||
bssid:
|
||||
type: string
|
||||
format: mac
|
||||
level:
|
||||
type: integer
|
||||
|
||||
RRM_beacon_request:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- beacon_request
|
||||
addr:
|
||||
type: string
|
||||
format: mac
|
||||
ssid:
|
||||
type: string
|
||||
channel:
|
||||
type: integer
|
||||
|
||||
RRM_bss_transition:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- bss_transition
|
||||
addr:
|
||||
type: string
|
||||
format: mac
|
||||
neighbors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: mac
|
||||
|
||||
RRM_neighbors:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- neighbors
|
||||
bssid:
|
||||
type: string
|
||||
format: mac
|
||||
neighbors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: mac
|
||||
|
||||
RRM_action:
|
||||
type: object
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/RRM_Kick'
|
||||
- $ref: '#/components/schemas/RRM_channel_switch'
|
||||
- $ref: '#/components/schemas/RRM_tx_power'
|
||||
- $ref: '#/components/schemas/RRM_beacon_request'
|
||||
- $ref: '#/components/schemas/RRM_bss_transition'
|
||||
- $ref: '#/components/schemas/RRM_neighbors'
|
||||
|
||||
RRM_actions:
|
||||
type: object
|
||||
properties:
|
||||
actions:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RRM_action'
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## These are endpoints that all services in the uCentral stack must provide
|
||||
@@ -1345,6 +1453,7 @@ components:
|
||||
- generic
|
||||
- orion
|
||||
- globalreach
|
||||
- radsec
|
||||
default:
|
||||
generic
|
||||
poolProxyIp:
|
||||
@@ -1434,6 +1543,28 @@ components:
|
||||
userName:
|
||||
type: string
|
||||
|
||||
DeviceTransferRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
format: uuid
|
||||
server:
|
||||
type: string
|
||||
format: hostname
|
||||
port:
|
||||
type: integer
|
||||
format: int32
|
||||
|
||||
DeviceCertificateUpdateRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
encodedCertificate:
|
||||
type: string
|
||||
format: base64
|
||||
description: This is a base64 encoded string of the certificate bundle (the current bundle .tar.gz file from the PKI portal)
|
||||
|
||||
paths:
|
||||
/devices:
|
||||
@@ -1581,8 +1712,12 @@ paths:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
|
||||
|
||||
- in: query
|
||||
description: Filter the results
|
||||
name: simulatedDevices
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
@@ -2575,7 +2710,7 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/:
|
||||
/device/{serialNumber}/script:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
@@ -2789,6 +2924,88 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/rrm:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Send RRM commands to a device.
|
||||
operationId: sendRRMcommandsForADevice
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Commands to send
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RRM_actions'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/transfer:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Transfer a device to a new redirector.
|
||||
operationId: transferDevice
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Transfer details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/DeviceTransferRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/certupdate:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Update the certificates for a device.
|
||||
operationId: updateCertificates
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Certificate update details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/DeviceCertificateUpdateRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/ouis:
|
||||
get:
|
||||
tags:
|
||||
@@ -3295,8 +3512,6 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
|
||||
/deviceDashboard:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -145,7 +145,7 @@ storage.type.sqlite.db = devices.db
|
||||
storage.type.sqlite.idletime = 120
|
||||
storage.type.sqlite.maxsessions = 128
|
||||
|
||||
storage.type.postgresql.maxsessions = 64
|
||||
storage.type.postgresql.maxsessions = 250
|
||||
storage.type.postgresql.idletime = 60
|
||||
storage.type.postgresql.host = ${STORAGE_TYPE_POSTGRESQL_HOST}
|
||||
storage.type.postgresql.username = ${STORAGE_TYPE_POSTGRESQL_USERNAME}
|
||||
|
||||
@@ -36,22 +36,20 @@
|
||||
|
||||
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,
|
||||
uint64_t connection_id, Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R)
|
||||
: Logger_(L), Reactor_(R) {
|
||||
State_.sessionId = connection_id;
|
||||
uint64_t session_id, Poco::Logger &L,
|
||||
std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R)
|
||||
: Logger_(L) {
|
||||
|
||||
Reactor_ = R.first;
|
||||
DbSession_ = R.second;
|
||||
State_.sessionId = session_id;
|
||||
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request, response);
|
||||
|
||||
auto TS = Poco::Timespan(360, 0);
|
||||
@@ -61,29 +59,89 @@ namespace OpenWifi {
|
||||
WS_->setNoDelay(false);
|
||||
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;
|
||||
Valid_ = true;
|
||||
uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::Start() {
|
||||
Registered_ = true;
|
||||
LastContact_ = Utils::Now();
|
||||
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
// poco_information(Logger_, fmt::format("DESTRUCTOR({}): 0 - Session={} Connection closed.", SerialNumber_,
|
||||
// State_.sessionId));
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
// poco_information(Logger_, fmt::format("DESTRUCTOR({}): 1 - Session={} Connection closed.", SerialNumber_,
|
||||
// State_.sessionId));
|
||||
EndConnection(false);
|
||||
poco_debug(Logger_, fmt::format("TERMINATION({}): Session={}, Connection removed.", SerialNumber_,
|
||||
State_.sessionId));
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
try {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
Details.set(uCentralProtocol::UUID,uuid);
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection(bool Clean) {
|
||||
bool expectedValue=false;
|
||||
if (Dead_.compare_exchange_strong(expectedValue,true,std::memory_order_release,std::memory_order_relaxed)) {
|
||||
|
||||
if(!SerialNumber_.empty() && State_.LastContact!=0) {
|
||||
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
|
||||
}
|
||||
|
||||
if (Registered_) {
|
||||
Registered_ = false;
|
||||
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));
|
||||
Registered_=false;
|
||||
}
|
||||
WS_->close();
|
||||
|
||||
if(!SerialNumber_.empty()) {
|
||||
DeviceDisconnectionCleanup(SerialNumber_, uuid_);
|
||||
}
|
||||
|
||||
if(Clean)
|
||||
AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::ValidatedDevice() {
|
||||
|
||||
if(Dead_)
|
||||
return false;
|
||||
|
||||
if (DeviceValidated_)
|
||||
return true;
|
||||
|
||||
if (!Valid_)
|
||||
return false;
|
||||
|
||||
std::lock_guard Lock(ConnectionMutex_);
|
||||
try {
|
||||
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
|
||||
auto SS =
|
||||
@@ -98,7 +156,6 @@ namespace OpenWifi {
|
||||
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Connection is "
|
||||
"NOT secure. Device is not allowed.",
|
||||
CId_, State_.sessionId));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -111,7 +168,6 @@ namespace OpenWifi {
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_,
|
||||
State_.sessionId));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -122,11 +178,19 @@ namespace OpenWifi {
|
||||
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()));
|
||||
if(!Utils::ValidSerialNumber(CN_)) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Invalid serial number: CN={}", CId_,
|
||||
State_.sessionId, CN_));
|
||||
return false;
|
||||
}
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_,
|
||||
@@ -136,30 +200,27 @@ namespace OpenWifi {
|
||||
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is "
|
||||
"not allowed. Disconnecting.",
|
||||
CId_, State_.sessionId, CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(AP_WS_Server::IsSim(CN_)) {
|
||||
if(AP_WS_Server::IsSim(SerialNumber_)) {
|
||||
State_.VerifiedCertificate = GWObjects::SIMULATED;
|
||||
Simulated_ = true;
|
||||
}
|
||||
|
||||
std::string reason, author;
|
||||
std::uint64_t created;
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(CN_, reason, author, created)) {
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumberInt_, reason, author, created)) {
|
||||
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
|
||||
CId_, State_.sessionId, CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,
|
||||
@@ -223,149 +284,14 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
try {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
Details.set(uCentralProtocol::UUID,uuid);
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
Valid_ = false;
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
void AP_WS_Connection::DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
if (KafkaManager()->Enabled()) {
|
||||
NotifyKafkaDisconnect(SerialNumber, uuid);
|
||||
}
|
||||
RADIUSSessionTracker()->DeviceDisconnect(SerialNumber);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection(bool DeleteSession) {
|
||||
Valid_ = false;
|
||||
if (!Dead_.test_and_set()) {
|
||||
|
||||
if(!SerialNumber_.empty() && State_.LastContact!=0) {
|
||||
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
|
||||
}
|
||||
|
||||
if (Registered_) {
|
||||
Registered_ = false;
|
||||
Reactor_.removeEventHandler(
|
||||
*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(!SerialNumber_.empty()) {
|
||||
std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_, uuid_);
|
||||
Cleanup.detach();
|
||||
}
|
||||
|
||||
bool SessionDeleted = false;
|
||||
if(DeleteSession)
|
||||
SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
|
||||
if (SessionDeleted || !DeleteSession) {
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
N.content.serialNumber = SerialNumber_;
|
||||
GWWebSocketNotifications::DeviceDisconnected(N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
if(D.pendingUUID!=0 && UUID==D.pendingUUID) {
|
||||
// so we sent an upgrade to a device, and now it is completing now...
|
||||
UpgradedUUID = D.pendingUUID;
|
||||
StorageService()->CompleteDeviceConfigurationChange(SerialNumber_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
Config::Config Cfg(D.Configuration);
|
||||
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.
|
||||
D.UUID = UUID + 2;
|
||||
UpgradedUUID = D.UUID;
|
||||
}
|
||||
|
||||
Cfg.SetUUID(D.UUID);
|
||||
D.Configuration = Cfg.get();
|
||||
State_.PendingUUID = UpgradedUUID = D.UUID;
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroServiceCreateUUID();
|
||||
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()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
|
||||
SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false);
|
||||
|
||||
GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
|
||||
Notification.content.serialNumber = D.SerialNumber;
|
||||
Notification.content.oldUUID = UUID;
|
||||
Notification.content.newUUID = UpgradedUUID;
|
||||
GWWebSocketNotifications::DeviceConfigurationChange(Notification);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
GWWebSocketNotifications::DeviceDisconnected(N);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
|
||||
@@ -446,7 +372,7 @@ namespace OpenWifi {
|
||||
|
||||
std::string reason, author;
|
||||
std::uint64_t created;
|
||||
if (StorageService()->IsBlackListed(Serial, reason, author, created)) {
|
||||
if (StorageService()->IsBlackListed(SerialNumberInt_, reason, author, created)) {
|
||||
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
|
||||
Poco::Exception E(
|
||||
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
|
||||
@@ -577,17 +503,17 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetWebSocketTelemetryReporting(
|
||||
uint64_t RPCID, uint64_t Interval, uint64_t LifeTime,
|
||||
std::uint64_t RPCID, std::uint64_t Interval, std::uint64_t LifeTime,
|
||||
const std::vector<std::string> &TelemetryTypes) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryWebSocketRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_
|
||||
? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
|
||||
? (Interval < (std::uint64_t)TelemetryInterval_ ? Interval : (std::uint64_t )TelemetryInterval_)
|
||||
: Interval;
|
||||
auto TelemetryWebSocketTimer = LifeTime + Utils::Now();
|
||||
TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > TelemetryWebSocketTimer_
|
||||
? TelemetryWebSocketTimer
|
||||
: TelemetryWebSocketTimer_;
|
||||
TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > (std::uint64_t)TelemetryWebSocketTimer_
|
||||
? (std::uint64_t)TelemetryWebSocketTimer
|
||||
: (std::uint64_t)TelemetryWebSocketTimer_;
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
@@ -603,11 +529,11 @@ namespace OpenWifi {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryKafkaRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_
|
||||
? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
|
||||
? (Interval < (std::uint64_t)TelemetryInterval_ ? (std::uint64_t)Interval : (std::uint64_t)TelemetryInterval_)
|
||||
: Interval;
|
||||
auto TelemetryKafkaTimer = LifeTime + Utils::Now();
|
||||
TelemetryKafkaTimer_ =
|
||||
TelemetryKafkaTimer > TelemetryKafkaTimer_ ? TelemetryKafkaTimer : TelemetryKafkaTimer_;
|
||||
TelemetryKafkaTimer > (std::uint64_t)TelemetryKafkaTimer_ ? (std::uint64_t)TelemetryKafkaTimer : (std::uint64_t)TelemetryKafkaTimer_;
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
@@ -643,49 +569,50 @@ namespace OpenWifi {
|
||||
void AP_WS_Connection::OnSocketShutdown(
|
||||
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketError(
|
||||
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketReadable(
|
||||
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
|
||||
if (!Valid_)
|
||||
if (Dead_) // we are dead, so we do not process anything.
|
||||
return;
|
||||
|
||||
if (!AP_WS_Server()->Running())
|
||||
return EndConnection();
|
||||
std::lock_guard DeviceLock(ConnectionMutex_);
|
||||
|
||||
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();
|
||||
State_.LastContact = LastContact_ = Utils::Now();
|
||||
if (AP_WS_Server()->Running() && (DeviceValidated_ || ValidatedDevice())) {
|
||||
try {
|
||||
return ProcessIncomingFrame();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (const std::exception &E) {
|
||||
std::string W = E.what();
|
||||
poco_information(
|
||||
Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}",
|
||||
W, CId_));
|
||||
} catch (...) {
|
||||
poco_information(
|
||||
Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_));
|
||||
}
|
||||
}
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingFrame() {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
|
||||
bool KillConnection=false;
|
||||
try {
|
||||
int Op, flags;
|
||||
int Op, flags;
|
||||
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
|
||||
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
@@ -705,83 +632,81 @@ namespace OpenWifi {
|
||||
State_.LastContact = Utils::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);
|
||||
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);
|
||||
|
||||
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, Utils::Now());
|
||||
PingDetails.set(uCentralProtocol::UUID, uuid_);
|
||||
PingDetails.set("locale", State_.locale);
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
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, Utils::Now());
|
||||
PingDetails.set(uCentralProtocol::UUID, uuid_);
|
||||
PingDetails.set("locale", State_.locale);
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
|
||||
}
|
||||
} 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_PONG: {
|
||||
poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}",
|
||||
CId_, IncomingSize, flags, IncomingFrame.begin()));
|
||||
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>();
|
||||
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);
|
||||
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);
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
|
||||
CId_, IncomingFrame.begin()));
|
||||
fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc': {}",
|
||||
CId_, iS.str()));
|
||||
Errors_++;
|
||||
}
|
||||
} 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_));
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
poco_information(Logger_,
|
||||
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
|
||||
KillConnection=true;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}",
|
||||
CId_, std::to_string(Op)));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
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_,
|
||||
@@ -789,21 +714,21 @@ namespace OpenWifi {
|
||||
CId_, E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} 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();
|
||||
KillConnection=true;
|
||||
} 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();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
@@ -812,54 +737,54 @@ namespace OpenWifi {
|
||||
CId_, E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} 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();
|
||||
KillConnection=true;
|
||||
} 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();
|
||||
KillConnection=true;
|
||||
} 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();
|
||||
KillConnection=true;
|
||||
} 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();
|
||||
KillConnection=true;
|
||||
} 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();
|
||||
KillConnection=true;
|
||||
} catch (...) {
|
||||
poco_error(Logger_, fmt::format("UnknownException({}): Device must be disconnected. "
|
||||
"Unknown exception. Session:{}",
|
||||
CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
}
|
||||
|
||||
if (Errors_ < 10)
|
||||
if (!KillConnection && Errors_ < 10)
|
||||
return;
|
||||
|
||||
poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_));
|
||||
return EndConnection();
|
||||
poco_warning(Logger_, fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}", CId_, KillConnection, Errors_ ));
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::Send(const std::string &Payload) {
|
||||
@@ -952,24 +877,55 @@ namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
|
||||
if (Doc->has(uCentralProtocol::RADIUSDATA)) {
|
||||
std::string secret;
|
||||
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();
|
||||
if (Type == uCentralProtocol::RADIUSACCT) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAccountingData(SerialNumber_, DecodedData.c_str(),
|
||||
DecodedData.size(),secret);
|
||||
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(), secret);
|
||||
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(), secret);
|
||||
DecodedData.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::SetLastStats(const std::string &LastStats) {
|
||||
RawLastStats_ = LastStats;
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
|
||||
hasGPS_ = Stats->isObject("gps");
|
||||
auto Unit = Stats->getObject("unit");
|
||||
auto Memory = Unit->getObject("memory");
|
||||
std::uint64_t TotalMemory = Memory->get("total");
|
||||
std::uint64_t FreeMemory = Memory->get("free");
|
||||
if (TotalMemory > 0) {
|
||||
memory_used_ =
|
||||
(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
|
||||
}
|
||||
if (Unit->isArray("load")) {
|
||||
Poco::JSON::Array::Ptr Load = Unit->getArray("load");
|
||||
if (Load->size() > 1) {
|
||||
cpu_load_ = Load->get(1);
|
||||
}
|
||||
}
|
||||
if (Unit->isArray("temperature")) {
|
||||
Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
|
||||
if (Temperature->size() > 1) {
|
||||
temperature_ = Temperature->get(0);
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(Logger_, "Failed to parse last stats: " + E.displayText());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
@@ -14,8 +14,10 @@
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
#include <Poco/Data/Session.h>
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include <AP_WS_Reactor_Pool.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -25,16 +27,17 @@ namespace OpenWifi {
|
||||
public:
|
||||
explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response, uint64_t connection_id,
|
||||
Poco::Logger &L, Poco::Net::SocketReactor &R);
|
||||
Poco::Logger &L, std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R);
|
||||
~AP_WS_Connection();
|
||||
|
||||
void EndConnection(bool DeleteSession=true);
|
||||
void EndConnection(bool Clean = true);
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
|
||||
void ProcessIncomingFrame();
|
||||
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
|
||||
|
||||
[[nodiscard]] bool Send(const std::string &Payload);
|
||||
[[nodiscard]] inline bool MustBeSecureRTTY() const { return RTTYMustBeSecure_; }
|
||||
|
||||
bool SendRadiusAuthenticationData(const unsigned char *buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const unsigned char *buffer, std::size_t size);
|
||||
@@ -43,10 +46,7 @@ namespace OpenWifi {
|
||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
|
||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
||||
bool LookForUpgrade(uint64_t UUID, uint64_t &UpgradedUUID);
|
||||
static bool ExtractBase64CompressedData(const std::string &CompressedData,
|
||||
std::string &UnCompressedData,
|
||||
uint64_t compress_sz);
|
||||
bool LookForUpgrade(Poco::Data::Session &Session, uint64_t UUID, uint64_t &UpgradedUUID);
|
||||
void LogException(const Poco::Exception &E);
|
||||
inline Poco::Logger &Logger() { return Logger_; }
|
||||
bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval,
|
||||
@@ -59,82 +59,34 @@ namespace OpenWifi {
|
||||
bool StopKafkaTelemetry(uint64_t RPCID);
|
||||
|
||||
inline void GetLastStats(std::string &LastStats) {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
LastStats = RawLastStats_;
|
||||
}
|
||||
|
||||
inline void SetLastStats(const std::string &LastStats) {
|
||||
std::unique_lock G(ConnectionMutex_);
|
||||
RawLastStats_ = LastStats;
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
|
||||
hasGPS = Stats->isObject("gps");
|
||||
auto Unit = Stats->getObject("unit");
|
||||
auto Memory = Unit->getObject("memory");
|
||||
std::uint64_t TotalMemory = Memory->get("total");
|
||||
std::uint64_t FreeMemory = Memory->get("free");
|
||||
if(TotalMemory>0) {
|
||||
memory_used_ =
|
||||
(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
|
||||
}
|
||||
if(Unit->isArray("load")) {
|
||||
Poco::JSON::Array::Ptr Load = Unit->getArray("load");
|
||||
if(Load->size()>1) {
|
||||
cpu_load_ = Load->get(1);
|
||||
}
|
||||
}
|
||||
if(Unit->isArray("temperature")) {
|
||||
Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
|
||||
if(Temperature->size()>1) {
|
||||
temperature_ = Temperature->get(0);
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
if(!Dead_) {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
LastStats = RawLastStats_;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
|
||||
std::unique_lock G(ConnectionMutex_);
|
||||
RawLastHealthcheck_ = H;
|
||||
}
|
||||
|
||||
inline void GetLastHealthCheck(GWObjects::HealthCheck &H) {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
H = RawLastHealthcheck_;
|
||||
if(!Dead_) {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
H = RawLastHealthcheck_;
|
||||
}
|
||||
}
|
||||
|
||||
inline void GetState(GWObjects::ConnectionState &State) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
State = State_;
|
||||
inline void GetState(GWObjects::ConnectionState &State) {
|
||||
if(!Dead_) {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
State = State_;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool HasGPS() { return hasGPS; }
|
||||
[[nodiscard]] inline bool HasGPS() const { return hasGPS_; }
|
||||
[[nodiscard]] bool ValidatedDevice();
|
||||
|
||||
inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
inline void GetRestrictions(GWObjects::DeviceRestrictions &R) {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
R = Restrictions_;
|
||||
}
|
||||
|
||||
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);
|
||||
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
bool ValidatedDevice();
|
||||
|
||||
inline bool GetTelemetryParameters(bool &Reporting, uint64_t &Interval,
|
||||
uint64_t &WebSocketTimer, uint64_t &KafkaTimer,
|
||||
uint64_t &WebSocketCount, uint64_t &KafkaCount,
|
||||
@@ -153,18 +105,18 @@ namespace OpenWifi {
|
||||
|
||||
friend class AP_WS_Server;
|
||||
|
||||
inline GWObjects::DeviceRestrictions Restrictions() const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
inline GWObjects::DeviceRestrictions Restrictions() {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
return Restrictions_;
|
||||
}
|
||||
|
||||
inline bool MustBeSecureRtty() const { return RttyMustBeSecure_; }
|
||||
void Start();
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex ConnectionMutex_;
|
||||
std::shared_mutex TelemetryMutex_;
|
||||
std::recursive_mutex ConnectionMutex_;
|
||||
std::mutex TelemetryMutex_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::shared_ptr<Poco::Net::SocketReactor> Reactor_;
|
||||
std::shared_ptr<LockedDbSession> DbSession_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
std::string SerialNumber_;
|
||||
uint64_t SerialNumberInt_ = 0;
|
||||
@@ -175,33 +127,56 @@ namespace OpenWifi {
|
||||
uint64_t Errors_ = 0;
|
||||
Poco::Net::IPAddress PeerAddress_;
|
||||
volatile bool TelemetryReporting_ = false;
|
||||
volatile uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
volatile uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
volatile uint64_t TelemetryKafkaTimer_ = 0;
|
||||
volatile uint64_t TelemetryInterval_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketPackets_ = 0;
|
||||
volatile uint64_t TelemetryKafkaPackets_ = 0;
|
||||
std::atomic_uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
std::atomic_uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaTimer_ = 0;
|
||||
std::atomic_uint64_t TelemetryInterval_ = 0;
|
||||
std::atomic_uint64_t TelemetryWebSocketPackets_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaPackets_ = 0;
|
||||
GWObjects::ConnectionState State_;
|
||||
std::string RawLastStats_;
|
||||
Utils::CompressedString RawLastStats_;
|
||||
GWObjects::HealthCheck RawLastHealthcheck_;
|
||||
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};
|
||||
std::atomic_flag Dead_ = false;
|
||||
std::atomic<bool> Dead_ = false;
|
||||
std::atomic_bool DeviceValidated_ = false;
|
||||
std::atomic_bool Valid_ = false;
|
||||
OpenWifi::GWObjects::DeviceRestrictions Restrictions_;
|
||||
bool RttyMustBeSecure_ = false;
|
||||
bool RTTYMustBeSecure_ = false;
|
||||
bool hasGPS_=false;
|
||||
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
|
||||
std::uint64_t uuid_=0;
|
||||
bool Simulated_=false;
|
||||
std::uint64_t LastContact_=0;
|
||||
|
||||
static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
|
||||
|
||||
bool StartTelemetry(uint64_t RPCID, const std::vector<std::string> &TelemetryTypes);
|
||||
bool StopTelemetry(uint64_t RPCID);
|
||||
void UpdateCounts();
|
||||
bool hasGPS=false;
|
||||
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
|
||||
std::uint64_t uuid_=0;
|
||||
static void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid);
|
||||
void SetLastStats(const std::string &LastStats);
|
||||
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);
|
||||
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
|
||||
RawLastHealthcheck_ = H;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace OpenWifi
|
||||
88
src/AP_WS_LookForUpgrade.cpp
Normal file
88
src/AP_WS_LookForUpgrade.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
#include <AP_WS_Connection.h>
|
||||
#include "ConfigurationCache.h"
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
bool AP_WS_Connection::LookForUpgrade(Poco::Data::Session &Session, 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(Session,SerialNumber_, D)) {
|
||||
if(D.pendingUUID!=0 && UUID==D.pendingUUID) {
|
||||
// so we sent an upgrade to a device, and now it is completing now...
|
||||
UpgradedUUID = D.pendingUUID;
|
||||
StorageService()->CompleteDeviceConfigurationChange(Session, SerialNumber_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
Config::Config Cfg(D.Configuration);
|
||||
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.
|
||||
D.UUID = UUID + 2;
|
||||
UpgradedUUID = D.UUID;
|
||||
}
|
||||
|
||||
Cfg.SetUUID(D.UUID);
|
||||
D.Configuration = Cfg.get();
|
||||
State_.PendingUUID = UpgradedUUID = D.UUID;
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroServiceCreateUUID();
|
||||
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()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
|
||||
SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false);
|
||||
|
||||
GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
|
||||
Notification.content.serialNumber = D.SerialNumber;
|
||||
Notification.content.oldUUID = UUID;
|
||||
Notification.content.newUUID = UpgradedUUID;
|
||||
GWWebSocketNotifications::DeviceConfigurationChange(Notification);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -71,9 +71,8 @@ namespace OpenWifi {
|
||||
|
||||
CommandManager()->ClearQueue(SerialNumberInt_);
|
||||
|
||||
AP_WS_Server()->SetSessionDetails(State_.sessionId, SerialNumberInt_);
|
||||
AP_WS_Server()->StartSession(State_.sessionId, SerialNumberInt_);
|
||||
|
||||
std::lock_guard Lock(ConnectionMutex_);
|
||||
Config::Capabilities Caps(Capabilities);
|
||||
|
||||
Compatible_ = Caps.Compatible();
|
||||
@@ -100,36 +99,24 @@ namespace OpenWifi {
|
||||
Restrictions_.from_json(RestrictionObject);
|
||||
}
|
||||
|
||||
if (Capabilities->has("developer")) {
|
||||
if (Capabilities->has("developer") && !Capabilities->isNull("developer")) {
|
||||
Restrictions_.developer = Capabilities->getValue<bool>("developer");
|
||||
}
|
||||
|
||||
if(Capabilities->has("secure-rtty")) {
|
||||
RttyMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty");
|
||||
RTTYMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty");
|
||||
}
|
||||
|
||||
State_.locale = FindCountryFromIP()->Get(IP);
|
||||
GWObjects::Device DeviceInfo;
|
||||
auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
|
||||
std::lock_guard DbSessionLock(DbSession_->Mutex());
|
||||
|
||||
auto DeviceExists = StorageService()->GetDevice(DbSession_->Session(), SerialNumber_, DeviceInfo);
|
||||
if (Daemon()->AutoProvisioning() && !DeviceExists) {
|
||||
// check the firmware version. if this is too old, we cannot let that device connect yet, we must
|
||||
// force a firmware upgrade
|
||||
GWObjects::DefaultFirmware MinimumFirmware;
|
||||
if(FirmwareRevisionCache()->DeviceMustUpgrade(Compatible_, Firmware, MinimumFirmware)) {
|
||||
/*
|
||||
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "upgrade" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
|
||||
"uri" : <URI to download the firmware>,
|
||||
"FWsignature" : <string representation of the signature for the FW> (optional)
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
|
||||
*/
|
||||
Poco::JSON::Object UpgradeCommand, Params;
|
||||
UpgradeCommand.set(uCentralProtocol::JSONRPC,uCentralProtocol::JSONRPC_VERSION);
|
||||
UpgradeCommand.set(uCentralProtocol::METHOD,uCentralProtocol::UPGRADE);
|
||||
@@ -157,7 +144,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
StorageService()->CreateDefaultDevice(
|
||||
StorageService()->CreateDefaultDevice( DbSession_->Session(),
|
||||
SerialNumber_, Caps, Firmware, PeerAddress_,
|
||||
State_.VerifiedCertificate == GWObjects::SIMULATED);
|
||||
}
|
||||
@@ -166,7 +153,7 @@ namespace OpenWifi {
|
||||
poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_));
|
||||
return EndConnection();
|
||||
} else if (DeviceExists) {
|
||||
StorageService()->UpdateDeviceCapabilities(SerialNumber_, Caps);
|
||||
StorageService()->UpdateDeviceCapabilities(DbSession_->Session(), SerialNumber_, Caps);
|
||||
int Updated{0};
|
||||
if (!Firmware.empty()) {
|
||||
if (Firmware != DeviceInfo.Firmware) {
|
||||
@@ -186,6 +173,12 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
if(ParamsObj->has("reason")) {
|
||||
State_.connectReason = ParamsObj->get("reason").toString();
|
||||
DeviceInfo.connectReason = State_.connectReason;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if(DeviceInfo.DevicePassword!=DevicePassword) {
|
||||
DeviceInfo.DevicePassword = DevicePassword.empty() ? "openwifi" : DevicePassword ;
|
||||
++Updated;
|
||||
@@ -226,13 +219,20 @@ namespace OpenWifi {
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (Updated) {
|
||||
StorageService()->UpdateDevice(DeviceInfo);
|
||||
if(DeviceInfo.certificateExpiryDate!=State_.certificateExpiryDate) {
|
||||
DeviceInfo.certificateExpiryDate = State_.certificateExpiryDate;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID = 0;
|
||||
LookForUpgrade(UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
if (Updated) {
|
||||
StorageService()->UpdateDevice(DbSession_->Session(), DeviceInfo);
|
||||
}
|
||||
|
||||
if(!Simulated_) {
|
||||
uint64_t UpgradedUUID = 0;
|
||||
LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
}
|
||||
}
|
||||
|
||||
State_.Compatible = Compatible_;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenWifi {
|
||||
.Recorded = Utils::Now(),
|
||||
.LogType = 1,
|
||||
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace OpenWifi {
|
||||
if (ParamsObj->has("currentPassword")) {
|
||||
auto Password = ParamsObj->get("currentPassword").toString();
|
||||
|
||||
StorageService()->SetDevicePassword(Serial, Password);
|
||||
StorageService()->SetDevicePassword(*DbSession_,Serial, Password);
|
||||
poco_trace(
|
||||
Logger_,
|
||||
fmt::format("DEVICE-UPDATE({}): Device is updating its login password.", Serial));
|
||||
|
||||
@@ -34,8 +34,13 @@ namespace OpenWifi {
|
||||
FullEvent.set("type", EventType);
|
||||
FullEvent.set("timestamp", EventTimeStamp);
|
||||
FullEvent.set("payload", EventPayload);
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
|
||||
FullEvent);
|
||||
if(strncmp(EventType.c_str(),"rrm.",4) == 0 ) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::RRM, SerialNumber_,
|
||||
FullEvent);
|
||||
} else {
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
|
||||
FullEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
@@ -40,10 +41,6 @@ namespace OpenWifi {
|
||||
CId_, UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
|
||||
GWObjects::HealthCheck Check;
|
||||
|
||||
Check.SerialNumber = SerialNumber_;
|
||||
@@ -52,14 +49,14 @@ namespace OpenWifi {
|
||||
Check.Data = CheckData;
|
||||
Check.Sanity = Sanity;
|
||||
|
||||
StorageService()->AddHealthCheckData(Check);
|
||||
StorageService()->AddHealthCheckData(*DbSession_, Check);
|
||||
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, CheckData);
|
||||
}
|
||||
|
||||
SetLastHealthCheck(Check);
|
||||
if (KafkaManager()->Enabled()) {
|
||||
if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableHealthChecks()) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, *ParamsObj);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenWifi {
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 0,
|
||||
.UUID = State_.UUID};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenWifi {
|
||||
.Recorded = ParamsObj->get(uCentralProtocol::DATE),
|
||||
.LogType = 2,
|
||||
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("REBOOT-LOG({}): Missing parameters.", CId_));
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenWifi {
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
|
||||
if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
|
||||
GWObjects::CommandDetails Cmd;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StateUtils.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
@@ -39,15 +40,19 @@ namespace OpenWifi {
|
||||
UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
std::lock_guard Guard(DbSession_->Mutex());
|
||||
if(!Simulated_) {
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
}
|
||||
|
||||
SetLastStats(StateStr);
|
||||
|
||||
GWObjects::Statistics Stats{
|
||||
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
|
||||
Stats.Recorded = Utils::Now();
|
||||
StorageService()->AddStatisticsData(Stats);
|
||||
StorageService()->AddStatisticsData(DbSession_->Session(),Stats);
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, StateStr);
|
||||
}
|
||||
@@ -55,7 +60,7 @@ namespace OpenWifi {
|
||||
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
|
||||
State_.Associations_5G, State_.Associations_6G);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableState()) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, *ParamsObj);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@ namespace OpenWifi {
|
||||
}
|
||||
if (TelemetryWebSocketRefCount_) {
|
||||
if (now < TelemetryWebSocketTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" <<
|
||||
// std::endl;
|
||||
|
||||
TelemetryWebSocketPackets_++;
|
||||
State_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, KafkaPayload);
|
||||
@@ -46,7 +45,6 @@ namespace OpenWifi {
|
||||
}
|
||||
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_,
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit AP_WS_ReactorThreadPool() {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount() * 2;
|
||||
if (NumberOfThreads_ == 0)
|
||||
NumberOfThreads_ = 4;
|
||||
}
|
||||
|
||||
~AP_WS_ReactorThreadPool() { Stop(); }
|
||||
|
||||
void Start() {
|
||||
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
|
||||
auto NewReactor = std::make_unique<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->start(*NewReactor);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for (auto &i : Reactors_)
|
||||
i->stop();
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor &NextReactor() {
|
||||
std::shared_lock Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
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_;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
75
src/AP_WS_Reactor_Pool.h
Normal file
75
src/AP_WS_Reactor_Pool.h
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include <Poco/Data/SessionPool.h>
|
||||
#include "framework/utils.h"
|
||||
#include <StorageService.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit AP_WS_ReactorThreadPool(Poco::Logger &Logger) : Logger_(Logger) {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount() * 4;
|
||||
if (NumberOfThreads_ == 0)
|
||||
NumberOfThreads_ = 8;
|
||||
NumberOfThreads_ = std::min(NumberOfThreads_, (std::uint64_t) 128);
|
||||
}
|
||||
|
||||
~AP_WS_ReactorThreadPool() { Stop(); }
|
||||
|
||||
void Start() {
|
||||
Reactors_.reserve(NumberOfThreads_);
|
||||
DbSessions_.reserve(NumberOfThreads_);
|
||||
Threads_.reserve(NumberOfThreads_);
|
||||
Logger_.information(fmt::format("WebSocket Processor: starting {} threads.", NumberOfThreads_));
|
||||
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
|
||||
auto NewReactor = std::make_shared<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->start(*NewReactor);
|
||||
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));
|
||||
DbSessions_.emplace_back(std::make_shared<LockedDbSession>());
|
||||
}
|
||||
Logger_.information(fmt::format("WebSocket Processor: {} threads started.", NumberOfThreads_));
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for (auto &i : Reactors_)
|
||||
i->stop();
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
DbSessions_.clear();
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession> > NextReactor() {
|
||||
std::lock_guard Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return std::make_pair(Reactors_[NextReactor_], DbSessions_[NextReactor_]);
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
std::vector<std::shared_ptr<Poco::Net::SocketReactor>> Reactors_;
|
||||
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
|
||||
std::vector<std::shared_ptr<LockedDbSession>> DbSessions_;
|
||||
Poco::Logger &Logger_;
|
||||
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
@@ -23,15 +23,47 @@
|
||||
|
||||
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");
|
||||
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t session_id) : Logger_(L),
|
||||
session_id_(session_id) {
|
||||
};
|
||||
|
||||
void handleRequest( Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override {
|
||||
try {
|
||||
auto NewConnection = std::make_shared<AP_WS_Connection>(request, response, session_id_, Logger_,
|
||||
AP_WS_Server()->NextReactor());
|
||||
AP_WS_Server()->AddConnection(NewConnection);
|
||||
NewConnection->Start();
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
std::uint64_t session_id_;
|
||||
};
|
||||
|
||||
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");
|
||||
session_id_++;
|
||||
return new AP_WS_RequestHandler(Logger_, session_id_);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static std::atomic_uint64_t session_id_ = 0;
|
||||
};
|
||||
|
||||
bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
|
||||
@@ -57,7 +89,7 @@ namespace OpenWifi {
|
||||
|
||||
SessionTimeOut_ = MicroServiceConfigGetInt("openwifi.session.timeout", 10*60);
|
||||
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>(Logger());
|
||||
Reactor_pool_->Start();
|
||||
|
||||
for (const auto &Svr : ConfigServersList_) {
|
||||
@@ -107,7 +139,6 @@ namespace OpenWifi {
|
||||
Context->flushSessionCache();
|
||||
Context->enableSessionCache(true);
|
||||
Context->enableExtendedCertificateVerification(false);
|
||||
// Context->disableStatelessSessionResumption();
|
||||
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 |
|
||||
Poco::Net::Context::PROTO_TLSV1_1);
|
||||
|
||||
@@ -136,6 +167,9 @@ namespace OpenWifi {
|
||||
WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
}
|
||||
|
||||
KafkaDisableState_ = MicroServiceConfigGetBool("openwifi.kafka.disablestate", false);
|
||||
KafkaDisableHealthChecks_ = MicroServiceConfigGetBool("openwifi.kafka.disablehealthchecks", false);
|
||||
}
|
||||
|
||||
for (auto &server : WebServers_) {
|
||||
@@ -157,249 +191,345 @@ namespace OpenWifi {
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
|
||||
SimulatorId_ = MicroServiceConfigGetString("simulatorid", "");
|
||||
SimulatorId_ = Poco::toLower(MicroServiceConfigGetString("simulatorid", ""));
|
||||
SimulatorEnabled_ = !SimulatorId_.empty();
|
||||
Utils::SetThreadName(ReactorThread_, "dev:react:head");
|
||||
|
||||
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(
|
||||
*this, &AP_WS_Server::onGarbageCollecting);
|
||||
Timer_.setStartInterval(10 * 1000);
|
||||
Timer_.setPeriodicInterval(10 * 1000); // every minute
|
||||
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
|
||||
|
||||
Running_ = true;
|
||||
GarbageCollector_.setName("ws:garbage");
|
||||
GarbageCollector_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
|
||||
static uint64_t last_log = Utils::Now();
|
||||
auto now = Utils::Now();
|
||||
void AP_WS_Server::run() {
|
||||
uint64_t last_log = Utils::Now(),
|
||||
last_zombie_run = 0,
|
||||
last_garbage_run = 0;
|
||||
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
if (!Garbage_.empty()) {
|
||||
Garbage_.clear();
|
||||
Poco::Logger &LocalLogger = Poco::Logger::create(
|
||||
"WS-Session-Janitor", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel());
|
||||
|
||||
while(Running_) {
|
||||
|
||||
if(!Poco::Thread::trySleep(30000)) {
|
||||
break;
|
||||
}
|
||||
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
uint64_t total_connected_time = 0;
|
||||
LocalLogger.information(fmt::format("Garbage collecting starting run." ));
|
||||
|
||||
auto hint = SerialNumbers_.begin();
|
||||
while (hint != end(SerialNumbers_)) {
|
||||
if (hint->second.second == nullptr) {
|
||||
hint = SerialNumbers_.erase(hint);
|
||||
} else if ((now - hint->second.second->State_.LastContact) > SessionTimeOut_) {
|
||||
hint->second.second->EndConnection(false);
|
||||
poco_information(Logger(),fmt::format("{}: Session seems idle. Controller disconnecting device.", hint->second.second->SerialNumber_));
|
||||
Sessions_.erase(hint->second.second->State_.sessionId);
|
||||
Garbage_.push_back(hint->second.second);
|
||||
hint = SerialNumbers_.erase(hint);
|
||||
} else if (hint->second.second->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time += (now - hint->second.second->State_.started);
|
||||
hint++;
|
||||
uint64_t total_connected_time = 0, now = Utils::Now();
|
||||
|
||||
if(now-last_zombie_run > 60) {
|
||||
try {
|
||||
poco_information(LocalLogger,
|
||||
fmt::format("Garbage collecting zombies... (step 1)"));
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
int waits = 0;
|
||||
for (int hashIndex = 0; hashIndex < MACHash::HashMax(); hashIndex++) {
|
||||
last_zombie_run = now;
|
||||
waits = 0;
|
||||
while (true) {
|
||||
if (SerialNumbersMutex_[hashIndex].try_lock()) {
|
||||
waits = 0;
|
||||
auto hint = SerialNumbers_[hashIndex].begin();
|
||||
while (hint != end(SerialNumbers_[hashIndex])) {
|
||||
|
||||
if (hint->second == nullptr) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("Dead device found in hash index {}", hashIndex));
|
||||
// hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
hint++;
|
||||
continue;
|
||||
}
|
||||
auto Device = hint->second;
|
||||
if(Device->ConnectionMutex_.try_lock()) {
|
||||
auto RightNow = Utils::Now();
|
||||
if (RightNow > Device->LastContact_ &&
|
||||
(RightNow - Device->LastContact_) > SessionTimeOut_) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("{}: Session seems idle. Controller disconnecting device.",
|
||||
Device->SerialNumber_));
|
||||
hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
} else if (Device->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time +=
|
||||
(RightNow - Device->State_.started);
|
||||
++hint;
|
||||
} else {
|
||||
++hint;
|
||||
}
|
||||
Device->ConnectionMutex_.unlock();
|
||||
continue;
|
||||
} else {
|
||||
poco_warning(LocalLogger, fmt::format("Could not lock device mutex for {}",
|
||||
Device->SerialNumber_));
|
||||
}
|
||||
++NumberOfConnectingDevices_;
|
||||
++hint;
|
||||
}
|
||||
SerialNumbersMutex_[hashIndex].unlock();
|
||||
break;
|
||||
} else if (waits < 5) {
|
||||
waits++;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poco_information(LocalLogger,
|
||||
fmt::format("Garbage collecting zombies... (step 2)"));
|
||||
LeftOverSessions_ = 0;
|
||||
for (int i = 0; i < SessionHash::HashMax(); i++) {
|
||||
waits = 0;
|
||||
while (true) {
|
||||
if (SessionMutex_[i].try_lock()) {
|
||||
waits = 0;
|
||||
auto hint = Sessions_[i].begin();
|
||||
auto RightNow = Utils::Now();
|
||||
while (hint != end(Sessions_[i])) {
|
||||
if (hint->second == nullptr) {
|
||||
hint = Sessions_[i].erase(hint);
|
||||
} else if (RightNow > hint->second->LastContact_ &&
|
||||
(RightNow - hint->second->LastContact_) >
|
||||
SessionTimeOut_) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("{}: Session seems idle. Controller disconnecting device.",
|
||||
hint->second->SerialNumber_));
|
||||
hint = Sessions_[i].erase(hint);
|
||||
} else {
|
||||
++LeftOverSessions_;
|
||||
++hint;
|
||||
}
|
||||
}
|
||||
SessionMutex_[i].unlock();
|
||||
break;
|
||||
} else if (waits < 5) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
waits++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ =
|
||||
NumberOfConnectedDevices_ > 0
|
||||
? total_connected_time / NumberOfConnectedDevices_
|
||||
: 0;
|
||||
poco_information(LocalLogger, fmt::format("Garbage collecting zombies done..."));
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(LocalLogger, fmt::format("Poco::Exception: Garbage collecting zombies failed: {}", E.displayText()));
|
||||
} catch (const std::exception &E) {
|
||||
poco_error(LocalLogger, fmt::format("std::exception: Garbage collecting zombies failed: {}", E.what()));
|
||||
} catch (...) {
|
||||
poco_error(LocalLogger, fmt::format("exception:Garbage collecting zombies failed: {}", "unknown"));
|
||||
}
|
||||
|
||||
} else {
|
||||
NumberOfConnectedDevices_=0;
|
||||
for(int i=0;i<MACHash::HashMax();i++) {
|
||||
std::lock_guard Lock(SerialNumbersMutex_[i]);
|
||||
NumberOfConnectedDevices_ += SerialNumbers_[i].size();
|
||||
}
|
||||
if(NumberOfConnectedDevices_) {
|
||||
if (last_garbage_run > 0) {
|
||||
AverageDeviceConnectionTime_ += (now - last_garbage_run);
|
||||
}
|
||||
} else {
|
||||
NumberOfConnectingDevices_++;
|
||||
hint++;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ = NumberOfConnectedDevices_ > 0
|
||||
? total_connected_time / NumberOfConnectedDevices_
|
||||
: 0;
|
||||
if ((now - last_log) > 120) {
|
||||
if ((now - last_log) > 60) {
|
||||
last_log = now;
|
||||
poco_information(Logger(),
|
||||
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
|
||||
poco_information(LocalLogger,
|
||||
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds. Left Over Sessions: {}",
|
||||
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
|
||||
AverageDeviceConnectionTime_));
|
||||
AverageDeviceConnectionTime_, LeftOverSessions_));
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::NumberOfConnection_t Notification;
|
||||
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
|
||||
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
|
||||
GetTotalDataStatistics(Notification.content.tx,Notification.content.rx);
|
||||
GWWebSocketNotifications::NumberOfConnections(Notification);
|
||||
|
||||
Poco::JSON::Object KafkaNotification;
|
||||
Notification.to_json(KafkaNotification);
|
||||
|
||||
Poco::JSON::Object FullEvent;
|
||||
FullEvent.set("type", "load-update");
|
||||
FullEvent.set("timestamp", now);
|
||||
FullEvent.set("payload", KafkaNotification);
|
||||
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
|
||||
LocalLogger.information(fmt::format("Garbage collection finished run." ));
|
||||
last_garbage_run = now;
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::NumberOfConnection_t Notification;
|
||||
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
|
||||
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
|
||||
GetTotalDataStatistics(Notification.content.tx,Notification.content.rx);
|
||||
GWWebSocketNotifications::NumberOfConnections(Notification);
|
||||
|
||||
Poco::JSON::Object KafkaNotification;
|
||||
Notification.to_json(KafkaNotification);
|
||||
|
||||
Poco::JSON::Object FullEvent;
|
||||
FullEvent.set("type", "load-update");
|
||||
FullEvent.set("timestamp", now);
|
||||
FullEvent.set("payload", KafkaNotification);
|
||||
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
|
||||
LocalLogger.information(fmt::format("Garbage collector done for the day." ));
|
||||
}
|
||||
|
||||
void AP_WS_Server::Stop() {
|
||||
poco_information(Logger(), "Stopping...");
|
||||
Running_ = false;
|
||||
|
||||
Timer_.stop();
|
||||
GarbageCollector_.wakeUp();
|
||||
GarbageCollector_.join();
|
||||
|
||||
for (auto &server : WebServers_) {
|
||||
server->stopAll();
|
||||
}
|
||||
|
||||
Reactor_pool_->Stop();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
poco_information(Logger(), "Stopped...");
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
bool AP_WS_Server::GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
|
||||
SerialNumbers.clear();
|
||||
for(int i=0;i<SessionHash::HashMax();i++) {
|
||||
std::lock_guard Lock(SessionMutex_[i]);
|
||||
for (const auto &connection : Sessions_[i]) {
|
||||
if (connection.second->RawLastHealthcheck_.Sanity >= lowLimit &&
|
||||
connection.second->RawLastHealthcheck_.Sanity <= highLimit) {
|
||||
SerialNumbers.push_back(connection.second->SerialNumber_);
|
||||
}
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
}
|
||||
DevicePtr->GetLastStats(Statistics);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
|
||||
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
|
||||
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (Device == SerialNumbers_[hashIndex].end() || Device->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
Device->second->GetLastStats(Statistics);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == SerialNumbers_[hashIndex].end() ||
|
||||
DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->GetState(State);
|
||||
Connection->GetState(State);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber,
|
||||
GWObjects::HealthCheck &CheckData) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
|
||||
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (Device == SerialNumbers_[hashIndex].end() || Device->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
Device->second->GetLastHealthCheck(CheckData);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void AP_WS_Server::StartSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
auto deviceHash = MACHash::Hash(SerialNumber);
|
||||
auto sessionHash = SessionHash::Hash(session_id);
|
||||
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
||||
auto SessionHint = Sessions_[sessionHash].find(session_id);
|
||||
if (SessionHint != end(Sessions_[sessionHash])) {
|
||||
std::lock_guard Lock(SerialNumbersMutex_[deviceHash]);
|
||||
SerialNumbers_[deviceHash][SerialNumber] = SessionHint->second;
|
||||
Sessions_[sessionHash].erase(SessionHint);
|
||||
} else {
|
||||
poco_error(Logger(), fmt::format("StartSession: Could not find session '{}'", session_id));
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto sessionHash = SessionHash::Hash(session_id);
|
||||
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
||||
Sessions_[sessionHash].erase(session_id);
|
||||
}
|
||||
|
||||
{
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == SerialNumbers_[hashIndex].end()
|
||||
|| DeviceHint->second == nullptr
|
||||
|| DeviceHint->second->State_.sessionId != session_id) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
SerialNumbers_[hashIndex].erase(DeviceHint);
|
||||
}
|
||||
DevicePtr->GetLastHealthCheck(CheckData);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Conn = Sessions_.find(connection_id);
|
||||
if (Conn == end(Sessions_))
|
||||
return;
|
||||
|
||||
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
|
||||
if ((CurrentSerialNumber == SerialNumbers_.end()) ||
|
||||
(CurrentSerialNumber->second.first < connection_id)) {
|
||||
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t serial_number) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
|
||||
auto Session = Sessions_.find(session_id);
|
||||
if (Session == end(Sessions_))
|
||||
return false;
|
||||
|
||||
Garbage_.push_back(Session->second);
|
||||
|
||||
auto Device = SerialNumbers_.find(serial_number);
|
||||
if (Device == end(SerialNumbers_)) {
|
||||
Sessions_.erase(Session);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Device->second.first == session_id) {
|
||||
Sessions_.erase(Session);
|
||||
SerialNumbers_.erase(Device);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sessions_.erase(Session);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSessionUnSafe(uint64_t session_id, uint64_t serial_number) {
|
||||
|
||||
auto Session = Sessions_.find(session_id);
|
||||
if (Session == end(Sessions_))
|
||||
return false;
|
||||
|
||||
Garbage_.push_back(Session->second);
|
||||
|
||||
auto Device = SerialNumbers_.find(serial_number);
|
||||
if (Device == end(SerialNumbers_)) {
|
||||
Sessions_.erase(Session);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Device->second.first == session_id) {
|
||||
Sessions_.erase(Session);
|
||||
SerialNumbers_.erase(Device);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sessions_.erase(Session);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::Connected(uint64_t SerialNumber,
|
||||
GWObjects::DeviceRestrictions &Restrictions) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr->GetRestrictions(Restrictions);
|
||||
return DevicePtr->State_.Connected;
|
||||
if(!DeviceHint->second->Dead_) {
|
||||
DeviceHint->second->GetRestrictions(Restrictions);
|
||||
return DeviceHint->second->State_.Connected;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return DevicePtr->State_.Connected;
|
||||
if(!DeviceHint->second->Dead_) {
|
||||
return DeviceHint->second->State_.Connected;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(DeviceHint->second->Dead_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->Send(Payload);
|
||||
return DeviceHint->second->Send(Payload);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'",
|
||||
Utils::IntToSerialNumber(SerialNumber)));
|
||||
@@ -408,61 +538,48 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
|
||||
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_[hashIndex]) || Device->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr->StopWebSocketTelemetry(RPCID);
|
||||
Device->second->StopWebSocketTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void
|
||||
AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
|
||||
uint64_t Interval, uint64_t Lifetime,
|
||||
const std::vector<std::string> &TelemetryTypes) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
DeviceHint->second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
}
|
||||
|
||||
void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
|
||||
uint64_t Interval, uint64_t Lifetime,
|
||||
const std::vector<std::string> &TelemetryTypes) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
DeviceHint->second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
}
|
||||
|
||||
void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr->StopKafkaTelemetry(RPCID);
|
||||
DeviceHint->second->StopKafkaTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void AP_WS_Server::GetTelemetryParameters(
|
||||
@@ -470,16 +587,15 @@ namespace OpenWifi {
|
||||
uint64_t &TelemetryWebSocketTimer, uint64_t &TelemetryKafkaTimer,
|
||||
uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount,
|
||||
uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
|
||||
|
||||
DeviceHint->second->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
|
||||
TelemetryWebSocketTimer, TelemetryKafkaTimer,
|
||||
TelemetryWebSocketCount, TelemetryKafkaCount,
|
||||
TelemetryWebSocketPackets, TelemetryKafkaPackets);
|
||||
@@ -487,18 +603,21 @@ namespace OpenWifi {
|
||||
|
||||
bool AP_WS_Server::SendRadiusAccountingData(const std::string &SerialNumber,
|
||||
const unsigned char *buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
|
||||
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
|
||||
auto hashIndex = MACHash::Hash(IntSerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(DeviceHint->second->Dead_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->SendRadiusAccountingData(buffer, size);
|
||||
return DeviceHint->second->SendRadiusAccountingData(buffer, size);
|
||||
} catch (...) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
@@ -510,18 +629,20 @@ namespace OpenWifi {
|
||||
|
||||
bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber,
|
||||
const unsigned char *buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
|
||||
auto hashIndex = MACHash::Hash(IntSerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(DeviceHint->second->Dead_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->SendRadiusAuthenticationData(buffer, size);
|
||||
return DeviceHint->second->SendRadiusAuthenticationData(buffer, size);
|
||||
} catch (...) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
@@ -533,18 +654,19 @@ namespace OpenWifi {
|
||||
|
||||
bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber,
|
||||
const unsigned char *buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
|
||||
auto hashIndex = MACHash::Hash(IntSerialNumber);
|
||||
std::lock_guard DevicesGuard(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(DeviceHint->second->Dead_) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return DevicePtr->SendRadiusCoAData(buffer, size);
|
||||
return DeviceHint->second->SendRadiusCoAData(buffer, size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),
|
||||
fmt::format(": SendRadiusCoAData: Could not send data to device '{}'",
|
||||
@@ -553,4 +675,32 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::ExtendedAttributes(const std::string &serialNumber,
|
||||
bool & hasGPS,
|
||||
std::uint64_t &Sanity,
|
||||
std::double_t &MemoryUsed,
|
||||
std::double_t &Load,
|
||||
std::double_t &Temperature
|
||||
) {
|
||||
|
||||
auto serialNumberInt = Utils::SerialNumberToInt(serialNumber);
|
||||
auto hashIndex = MACHash::Hash(serialNumberInt);
|
||||
std::lock_guard DevicesGuard(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(Utils::SerialNumberToInt(serialNumber));
|
||||
if(DeviceHint==end(SerialNumbers_[hashIndex])) {
|
||||
return false;
|
||||
}
|
||||
if(DeviceHint->second->Dead_) {
|
||||
return false;
|
||||
}
|
||||
std::lock_guard DeviceGuard(DeviceHint->second->ConnectionMutex_);
|
||||
hasGPS = DeviceHint->second->hasGPS_;
|
||||
Sanity = DeviceHint->second->RawLastHealthcheck_.Sanity;
|
||||
MemoryUsed = DeviceHint->second->memory_used_;
|
||||
Load = DeviceHint->second->cpu_load_;
|
||||
Temperature = DeviceHint->second->temperature_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace OpenWifi
|
||||
@@ -24,46 +24,51 @@
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
#include "AP_WS_Reactor_Pool.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
constexpr uint MACHashMax = 256;
|
||||
constexpr uint MACHashMask = MACHashMax-1;
|
||||
class MACHash {
|
||||
public:
|
||||
explicit AP_WS_RequestHandler(Poco::Logger &L, uint64_t id) : Logger_(L), id_(id){};
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
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;
|
||||
[[nodiscard]] static inline uint16_t Hash(std::uint64_t value) {
|
||||
uint8_t hash = 0, i=6;
|
||||
while(i) {
|
||||
hash ^= (value & MACHashMask) + 1;
|
||||
value >>= 8;
|
||||
--i;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static uint64_t id_ = 1;
|
||||
[[nodiscard]] static inline uint16_t Hash(const std::string & value) {
|
||||
return Hash(Utils::MACToInt(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline uint16_t HashMax() {
|
||||
return MACHashMax;
|
||||
}
|
||||
};
|
||||
|
||||
class AP_WS_Server : public SubSystemServer {
|
||||
constexpr uint SessionHashMax = 256;
|
||||
constexpr uint SessionHashMask = SessionHashMax-1;
|
||||
class SessionHash {
|
||||
public:
|
||||
[[nodiscard]] static inline uint16_t Hash(std::uint64_t value) {
|
||||
return (value & SessionHashMask);
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline uint16_t HashMax() {
|
||||
return SessionHashMax;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class AP_WS_Server : public SubSystemServer, public Poco::Runnable {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new AP_WS_Server;
|
||||
@@ -75,59 +80,49 @@ namespace OpenWifi {
|
||||
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_);
|
||||
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 AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; }
|
||||
|
||||
inline uint64_t MismatchDepth() const { return MismatchDepth_; }
|
||||
|
||||
inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
|
||||
[[nodiscard]] inline Poco::Net::SocketReactor &NextReactor() {
|
||||
void run() override; // Garbage collector thread.
|
||||
[[nodiscard]] inline bool IsSimEnabled() const { return SimulatorEnabled_; }
|
||||
[[nodiscard]] inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; }
|
||||
[[nodiscard]] inline uint64_t MismatchDepth() const { return MismatchDepth_; }
|
||||
[[nodiscard]] inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
[[nodiscard]] inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
[[nodiscard]] inline bool Running() const { return Running_; }
|
||||
[[nodiscard]] inline std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> NextReactor() {
|
||||
return Reactor_pool_->NextReactor();
|
||||
}
|
||||
[[nodiscard]] inline bool Running() const { return Running_; }
|
||||
|
||||
inline void AddConnection(uint64_t session_id,
|
||||
std::shared_ptr<AP_WS_Connection> Connection) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
Sessions_[session_id] = std::move(Connection);
|
||||
inline void AddConnection(std::shared_ptr<AP_WS_Connection> Connection) {
|
||||
std::uint64_t sessionHash = SessionHash::Hash(Connection->State_.sessionId);
|
||||
std::lock_guard Lock(SessionMutex_[sessionHash]);
|
||||
if(Sessions_[sessionHash].find(Connection->State_.sessionId)==end(Sessions_[sessionHash])) {
|
||||
Sessions_[sessionHash][Connection->State_.sessionId] = std::move(Connection);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::shared_ptr<AP_WS_Connection> FindConnection(uint64_t session_id) const {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
[[nodiscard]] inline bool DeviceRequiresSecureRTTY(uint64_t serialNumber) const {
|
||||
auto hashIndex = MACHash::Hash(serialNumber);
|
||||
std::lock_guard G(SerialNumbersMutex_[hashIndex]);
|
||||
|
||||
auto Connection = Sessions_.find(session_id);
|
||||
if (Connection != end(Sessions_))
|
||||
return Connection->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Connection = SerialNumbers_.find(serialNumber);
|
||||
if (Connection==end(SerialNumbers_) || Connection->second.second==nullptr)
|
||||
auto Connection = SerialNumbers_[hashIndex].find(serialNumber);
|
||||
if (Connection==end(SerialNumbers_[hashIndex]) || Connection->second==nullptr)
|
||||
return false;
|
||||
return Connection->second.second->RttyMustBeSecure_;
|
||||
return Connection->second->RTTYMustBeSecure_;
|
||||
}
|
||||
|
||||
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) const;
|
||||
[[nodiscard]] bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const;
|
||||
|
||||
inline bool GetState(const std::string &SerialNumber,
|
||||
GWObjects::ConnectionState &State) const {
|
||||
@@ -143,13 +138,7 @@ namespace OpenWifi {
|
||||
|
||||
bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const;
|
||||
bool Connected(uint64_t SerialNumber) const;
|
||||
|
||||
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) 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,
|
||||
@@ -157,9 +146,8 @@ namespace OpenWifi {
|
||||
bool SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer,
|
||||
std::size_t size);
|
||||
|
||||
void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
|
||||
bool EndSession(uint64_t connection_id, uint64_t serial_number);
|
||||
bool EndSessionUnSafe(uint64_t session_id, uint64_t serial_number);
|
||||
void StartSession(uint64_t session_id, uint64_t SerialNumber);
|
||||
bool EndSession(uint64_t session_id, uint64_t SerialNumber);
|
||||
void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
|
||||
uint64_t Interval, uint64_t Lifetime,
|
||||
const std::vector<std::string> &TelemetryTypes);
|
||||
@@ -176,7 +164,9 @@ namespace OpenWifi {
|
||||
uint64_t &TelemetryWebSocketPackets,
|
||||
uint64_t &TelemetryKafkaPackets);
|
||||
|
||||
void onGarbageCollecting(Poco::Timer &timer);
|
||||
bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers);
|
||||
bool ExtendedAttributes(const std::string &serialNumber, bool & hasGPS, std::uint64_t &Sanity,
|
||||
std::double_t &MemoryUsed, std::double_t &Load, std::double_t &Temperature);
|
||||
|
||||
inline void AverageDeviceStatistics(uint64_t &Connections, uint64_t &AverageConnectionTime,
|
||||
uint64_t &NumberOfConnectingDevices) const {
|
||||
@@ -185,84 +175,60 @@ namespace OpenWifi {
|
||||
NumberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
}
|
||||
|
||||
inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const {
|
||||
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
|
||||
}
|
||||
|
||||
inline void AddRX(std::uint64_t bytes) {
|
||||
std::lock_guard G(StatsMutex_);
|
||||
RX_ += bytes;
|
||||
}
|
||||
|
||||
inline void AddTX(std::uint64_t bytes) {
|
||||
std::lock_guard G(StatsMutex_);
|
||||
TX_ += bytes;
|
||||
}
|
||||
|
||||
inline void GetTotalDataStatistics(std::uint64_t &TX, std::uint64_t &RX) const {
|
||||
std::lock_guard G(StatsMutex_);
|
||||
TX = TX_;
|
||||
RX = RX_;
|
||||
}
|
||||
|
||||
inline bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
|
||||
for(const auto &connection:Sessions_) {
|
||||
if( connection.second->RawLastHealthcheck_.Sanity>=lowLimit &&
|
||||
connection.second->RawLastHealthcheck_.Sanity<=highLimit) {
|
||||
SerialNumbers.push_back(connection.second->SerialNumber_);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExtendedAttributes(const std::string &serialNumber,
|
||||
bool & hasGPS,
|
||||
std::uint64_t &Sanity,
|
||||
std::double_t &MemoryUsed,
|
||||
std::double_t &Load,
|
||||
std::double_t &Temperature
|
||||
) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
auto session_hint = SerialNumbers_.find(Utils::SerialNumberToInt(serialNumber));
|
||||
if(session_hint==end(SerialNumbers_)) {
|
||||
return false;
|
||||
}
|
||||
hasGPS = session_hint->second.second->hasGPS;
|
||||
Sanity = session_hint->second.second->RawLastHealthcheck_.Sanity;
|
||||
MemoryUsed = session_hint->second.second->memory_used_;
|
||||
Load = session_hint->second.second->cpu_load_;
|
||||
Temperature = session_hint->second.second->temperature_;
|
||||
return true;
|
||||
}
|
||||
bool KafkaDisableState() const { return KafkaDisableState_; }
|
||||
bool KafkaDisableHealthChecks() const { return KafkaDisableHealthChecks_; }
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex WSServerMutex_;
|
||||
std::array<std::mutex,SessionHashMax> SessionMutex_;
|
||||
std::array<std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>>,SessionHashMax> Sessions_;
|
||||
using SerialNumberMap = std::map<uint64_t /* serial number */,
|
||||
std::shared_ptr<AP_WS_Connection>>;
|
||||
std::array<SerialNumberMap,MACHashMax> SerialNumbers_;
|
||||
mutable std::array<std::recursive_mutex,MACHashMax> SerialNumbersMutex_;
|
||||
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
|
||||
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
std::string SimulatorId_;
|
||||
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 2, 64};
|
||||
bool LookAtProvisioning_ = false;
|
||||
bool UseDefaultConfig_ = true;
|
||||
bool SimulatorEnabled_ = false;
|
||||
bool AllowSerialNumberMismatch_ = true;
|
||||
|
||||
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
|
||||
std::atomic_bool Running_ = false;
|
||||
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Sessions_;
|
||||
std::map<uint64_t, std::pair<uint64_t, std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
|
||||
std::atomic_bool AllowSerialNumberMismatch_ = true;
|
||||
std::atomic_uint64_t MismatchDepth_ = 2;
|
||||
|
||||
std::uint64_t MismatchDepth_ = 2;
|
||||
std::uint64_t NumberOfConnectedDevices_ = 0;
|
||||
std::uint64_t AverageDeviceConnectionTime_ = 0;
|
||||
std::uint64_t NumberOfConnectingDevices_ = 0;
|
||||
std::uint64_t SessionTimeOut_ = 10*60;
|
||||
mutable std::mutex StatsMutex_;
|
||||
std::uint64_t LeftOverSessions_ = 0;
|
||||
std::atomic_uint64_t TX_=0,RX_=0;
|
||||
|
||||
std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;
|
||||
std::atomic_bool KafkaDisableState_=false,
|
||||
KafkaDisableHealthChecks_=false;
|
||||
|
||||
std::unique_ptr<Poco::TimerCallback<AP_WS_Server>> GarbageCollectorCallback_;
|
||||
Poco::Timer Timer_;
|
||||
Poco::Thread GarbageCollector_;
|
||||
Poco::Thread GarbageCollector_;
|
||||
|
||||
AP_WS_Server() noexcept
|
||||
: SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {}
|
||||
|
||||
@@ -45,11 +45,9 @@ namespace OpenWifi {
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
auto RPC = OutStandingRequests_.find(ID);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
poco_debug(Logger(), fmt::format("({}): RPC {} cannot be found.",
|
||||
SerialNumberStr, ID));
|
||||
} else if (RPC->second.SerialNumber != Resp->SerialNumber_) {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format("({}): RPC {} serial number mismatch {}!={}.",
|
||||
@@ -60,7 +58,6 @@ namespace OpenWifi {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time =
|
||||
std::chrono::high_resolution_clock::now() -
|
||||
RPC->second.submitted;
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): Received RPC answer {}. Command={}",
|
||||
SerialNumberStr, ID,
|
||||
@@ -140,7 +137,6 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
Command.State = 0;
|
||||
|
||||
@@ -163,7 +159,6 @@ namespace OpenWifi {
|
||||
if (Command.rpc_entry) {
|
||||
TmpRpcEntry = Command.rpc_entry;
|
||||
}
|
||||
// std::cout << __LINE__ << " State=" << Command.State << std::endl;
|
||||
if (Command.State == 2) {
|
||||
// look at the payload to see if we should continue or not...
|
||||
if (Payload->has("result")) {
|
||||
@@ -173,12 +168,10 @@ namespace OpenWifi {
|
||||
|
||||
std::uint64_t Error = Status->get("error");
|
||||
if (Error == 0) {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
StorageService()->CommandCompleted(Command.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
Command.State = 1;
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
StorageService()->CommandCompleted(Command.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
std::string ErrorTxt = Status->get("result");
|
||||
@@ -186,14 +179,11 @@ namespace OpenWifi {
|
||||
Command.State = 0;
|
||||
}
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
Command.State = 0;
|
||||
}
|
||||
} else if (Command.State == 1) {
|
||||
// std::cout << "Completing script 2 phase commit." << std::endl;
|
||||
StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true);
|
||||
if (Command.Deferred) {
|
||||
Reply = false;
|
||||
@@ -202,7 +192,6 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if (Command.State == 0) {
|
||||
// std::cout << __LINE__ << " State=" << Command.State << std::endl;
|
||||
OutStandingRequests_.erase(Command.Id);
|
||||
}
|
||||
if (Reply && TmpRpcEntry != nullptr)
|
||||
@@ -262,8 +251,6 @@ namespace OpenWifi {
|
||||
for (auto request = OutStandingRequests_.begin(); request != OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
|
||||
if (delta > 10min) {
|
||||
// std::cout << __LINE__ << " -->> " << request->second.Id <<
|
||||
// std::endl;
|
||||
MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.", request->second.UUID,
|
||||
APCommands::to_string(request->second.Command),
|
||||
Utils::IntToSerialNumber(request->second.SerialNumber)));
|
||||
@@ -275,8 +262,6 @@ namespace OpenWifi {
|
||||
StorageService()->SetCommandTimedOut(request->second.UUID);
|
||||
request = OutStandingRequests_.erase(request);
|
||||
} else {
|
||||
// std::cout << __LINE__ << " -->> " << request->second.Id <<
|
||||
// std::endl;
|
||||
++request;
|
||||
}
|
||||
}
|
||||
@@ -467,4 +452,16 @@ namespace OpenWifi {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CommandManager::FireAndForget(const std::string &SerialNumber, const std::string &Method, const Poco::JSON::Object &Params) {
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, 0);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
std::stringstream ToSend;
|
||||
CompleteRPC.stringify(ToSend);
|
||||
poco_debug(Logger(), fmt::format("{}: Fire and forget command {}.", SerialNumber, Method));
|
||||
return AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())>0;
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
@@ -162,8 +162,10 @@ namespace OpenWifi {
|
||||
inline auto CommandTimeout() const { return commandTimeOut_; }
|
||||
inline auto CommandRetry() const { return commandRetry_; }
|
||||
|
||||
bool FireAndForget(const std::string &SerialNumber, const std::string &Method,
|
||||
const Poco::JSON::Object &Params);
|
||||
private:
|
||||
mutable std::recursive_mutex LocalMutex_;
|
||||
mutable std::mutex LocalMutex_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
std::atomic_uint64_t Id_ = 3; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace OpenWifi {
|
||||
|
||||
void DeviceDashboard::Generate(GWObjects::Dashboard &D, Poco::Logger &Logger) {
|
||||
if (GeneratingDashboard_.load()) {
|
||||
// std::cout << "Trying to generate dashboard but already being generated" << std::endl;
|
||||
while (GeneratingDashboard_.load()) {
|
||||
Poco::Thread::trySleep(100);
|
||||
}
|
||||
@@ -31,7 +30,6 @@ namespace OpenWifi {
|
||||
GeneratingDashboard_ = true;
|
||||
ValidDashboard_ = false;
|
||||
try {
|
||||
// std::cout << "Generating dashboard." << std::endl;
|
||||
poco_information(Logger, "DASHBOARD: Generating a new dashboard.");
|
||||
GWObjects::Dashboard NewData;
|
||||
StorageService()->AnalyzeCommands(NewData.commands);
|
||||
|
||||
@@ -50,17 +50,17 @@ namespace OpenWifi {
|
||||
class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
|
||||
public:
|
||||
DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber,
|
||||
std::uint64_t timestamp, const std::string config)
|
||||
std::uint64_t timestamp, const Poco::JSON::Object::Ptr config)
|
||||
: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
|
||||
}
|
||||
|
||||
~DeviceConfigurationChangeKafkaEvent() {
|
||||
payload_->set("configuration", config_);
|
||||
payload_->set("configuration", *config_);
|
||||
Send();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string config_;
|
||||
Poco::JSON::Object::Ptr config_;
|
||||
};
|
||||
|
||||
class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace OpenWifi {
|
||||
bool Recovered = false;
|
||||
Poco::File OuiFile(CurrentOUIFileName_);
|
||||
if (OuiFile.exists()) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
Recovered = ProcessFile(CurrentOUIFileName_, OUIs_);
|
||||
if (Recovered) {
|
||||
poco_notice(Logger(),
|
||||
@@ -150,7 +150,7 @@ namespace OpenWifi {
|
||||
|
||||
OUIMap TmpOUIs;
|
||||
if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
|
||||
std::unique_lock G(LocalMutex_);
|
||||
std::lock_guard G(LocalMutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
LastUpdate_ = Utils::Now();
|
||||
Poco::File F1(CurrentOUIFileName_);
|
||||
@@ -163,7 +163,7 @@ namespace OpenWifi {
|
||||
} else if (OUIs_.empty()) {
|
||||
if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
|
||||
LastUpdate_ = Utils::Now();
|
||||
std::unique_lock G(LocalMutex_);
|
||||
std::lock_guard G(LocalMutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
}
|
||||
}
|
||||
@@ -173,7 +173,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::string OUIServer::GetManufacturer(const std::string &MAC) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
|
||||
auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
|
||||
if (Manufacturer != OUIs_.end())
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace OpenWifi {
|
||||
[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
|
||||
|
||||
private:
|
||||
std::shared_mutex LocalMutex_;
|
||||
std::mutex LocalMutex_;
|
||||
uint64_t LastUpdate_ = 0;
|
||||
bool Initialized_ = false;
|
||||
OUIMap OUIs_;
|
||||
|
||||
@@ -1753,7 +1753,6 @@ namespace OpenWifi {
|
||||
nlohmann::json new_ie;
|
||||
nlohmann::json content;
|
||||
|
||||
// std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
uint offset = 0;
|
||||
auto sub_ie = data[offset++];
|
||||
switch (sub_ie) {
|
||||
@@ -1788,7 +1787,6 @@ namespace OpenWifi {
|
||||
|
||||
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()) {
|
||||
@@ -1803,8 +1801,6 @@ namespace OpenWifi {
|
||||
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));
|
||||
@@ -1858,18 +1854,12 @@ namespace OpenWifi {
|
||||
} 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 data and type" <<
|
||||
// std::endl;
|
||||
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);
|
||||
}
|
||||
@@ -1877,7 +1867,6 @@ namespace OpenWifi {
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
// std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
}
|
||||
@@ -1886,7 +1875,6 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
Result << to_string(D);
|
||||
// std::cout << "End of parsing wifi" << std::endl;
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger.log(E);
|
||||
|
||||
@@ -177,15 +177,6 @@ namespace OpenWifi {
|
||||
} else {
|
||||
session_hint->second->lastTransaction = Utils::Now();
|
||||
}
|
||||
|
||||
/*
|
||||
if(ap_hint!=AccountingSessions_.end()) {
|
||||
std::cout << "Auth table:" << std::endl;
|
||||
for(const auto &session:ap_hint->second) {
|
||||
std::cout << Notification.SerialNumber_ << ": Index: " << session.first << ": ID: " << session.second->accountingSessionId << " MID:" << session.second->accountingMultiSessionId << std::endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
std::uint32_t GetUiInt32(const std::uint8_t *buf) {
|
||||
@@ -423,15 +414,15 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUSSessionTracker::DisconnectSession(const std::string &SerialNumber) {
|
||||
poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber));
|
||||
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto hint = AccountingSessions_.find(SerialNumber);
|
||||
if(hint==end(AccountingSessions_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber));
|
||||
|
||||
// we need to go through all sessions and send an accounting stop
|
||||
for(const auto &session:hint->second) {
|
||||
poco_debug(Logger(), fmt::format("Stopping accounting for {}:{}", SerialNumber, session.first ));
|
||||
|
||||
740
src/RADIUS_Destination.h
Normal file
740
src/RADIUS_Destination.h
Normal file
@@ -0,0 +1,740 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-08-15.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "RADIUS_helpers.h"
|
||||
#include <RESTObjects/RESTAPI_GWobjects.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RADIUS_Destination : public Poco::Runnable {
|
||||
public:
|
||||
RADIUS_Destination(Poco::Net::SocketReactor &R, const GWObjects::RadiusProxyPool &P)
|
||||
: Reactor_(R),
|
||||
Logger_(Poco::Logger::get(
|
||||
fmt::format("RADSEC: {}", P.name))),
|
||||
Pool_(P)
|
||||
{
|
||||
Type_ = GWObjects::RadiusEndpointType(P.radsecPoolType);
|
||||
Start();
|
||||
}
|
||||
|
||||
~RADIUS_Destination() override { Stop(); }
|
||||
|
||||
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
|
||||
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
|
||||
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
|
||||
const int DEFAULT_RADIUS_CoA_PORT = 3799;
|
||||
|
||||
inline int Start() {
|
||||
ReconnectThread_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() {
|
||||
TryAgain_ = false;
|
||||
Disconnect();
|
||||
ReconnectThread_.wakeUp();
|
||||
ReconnectThread_.join();
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
Poco::Thread::trySleep(5000);
|
||||
std::uint64_t CurrentDelay = 10, maxDelay=300, LastTry=0, LastKeepAlive=0;
|
||||
while (TryAgain_) {
|
||||
if (!Connected_) {
|
||||
if(!LastTry || (Utils::Now()-LastTry)>CurrentDelay) {
|
||||
LastTry = Utils::Now();
|
||||
if (!Connect()) {
|
||||
CurrentDelay *= 2;
|
||||
if(CurrentDelay>maxDelay) CurrentDelay=10;
|
||||
} else {
|
||||
CurrentDelay = 10;
|
||||
}
|
||||
}
|
||||
} else if ((Utils::Now() - LastKeepAlive) > Pool_.radsecKeepAlive) {
|
||||
RADIUS::RadiusOutputPacket P(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
|
||||
P.MakeStatusMessage(Pool_.authConfig.servers[ServerIndex_].name);
|
||||
poco_trace(Logger_, fmt::format("{}: Keep-Alive message.", Pool_.authConfig.servers[ServerIndex_].name));
|
||||
Socket_->sendBytes(P.Data(), P.Len());
|
||||
LastKeepAlive = Utils::Now();
|
||||
}
|
||||
Poco::Thread::trySleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
|
||||
int length) {
|
||||
try {
|
||||
if (Connected_) {
|
||||
RADIUS::RadiusPacket P(buffer, length);
|
||||
int sent_bytes;
|
||||
if (P.VerifyMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret)) {
|
||||
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
sent_bytes = Socket_->sendBytes(buffer, length);
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
P.ComputeMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
|
||||
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
|
||||
}
|
||||
return (sent_bytes == length);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Exception occurred: while sending data.");
|
||||
}
|
||||
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));
|
||||
std::string ReplySource;
|
||||
if (NumberOfReceivedBytes >= 20) {
|
||||
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
|
||||
if (P.IsAuthentication()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(),
|
||||
P.PacketTypeToString(),
|
||||
NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else if(P.IsStatusMessageReply(ReplySource)) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: Keepalive message received.", ReplySource));
|
||||
} else {
|
||||
poco_debug(Logger_, "AUTH packet dropped.");
|
||||
}
|
||||
} else if (P.IsAccounting()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(),
|
||||
P.PacketTypeToString(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_debug(Logger_, "ACCT packet dropped.");
|
||||
}
|
||||
} else if (P.IsAuthority()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(),
|
||||
P.PacketTypeToString(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_debug(Logger_, "CoA/DM packet dropped.");
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
|
||||
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
|
||||
Disconnect();
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Disconnect();
|
||||
} catch (...) {
|
||||
Disconnect();
|
||||
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker error. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void
|
||||
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void OnAccountingSocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger_, "Accounting: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger_, "Accounting: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Accounting Packet Response received for {}", SerialNumber ));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
inline void OnAuthenticationSocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger_, "Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
|
||||
if(Logger_.trace()) {
|
||||
P.Log(std::cout);
|
||||
}
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger_, "Authentication: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
inline void OnCoASocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger_, "CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger_, "CoA/DM: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
static inline bool IsExpired(const Poco::Crypto::X509Certificate &C) {
|
||||
return C.expiresOn().timestamp().epochTime() < (std::time_t)Utils::Now();
|
||||
}
|
||||
|
||||
static inline void Cat(const std::string &F1, const std::string & F2, const std::string &F) {
|
||||
std::ofstream of(F.c_str(),std::ios_base::trunc|std::ios_base::out|std::ios_base::binary);
|
||||
std::ifstream if1(F1.c_str(),std::ios_base::binary|std::ios_base::in);
|
||||
Poco::StreamCopier::copyStream(if1,of);
|
||||
of << std::endl;
|
||||
std::ifstream if2(F2.c_str(),std::ios_base::binary|std::ios_base::in);
|
||||
Poco::StreamCopier::copyStream(if2,of);
|
||||
of << std::endl;
|
||||
of.close();
|
||||
}
|
||||
|
||||
inline bool Connect_GlobalReach() {
|
||||
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile OpenRoamingRootCertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate0(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate1(MicroServiceDataDirectory());
|
||||
|
||||
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
|
||||
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
|
||||
DecodeFile(Intermediate0.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[0]);
|
||||
DecodeFile(Intermediate1.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[1]);
|
||||
|
||||
const static std::string OpenRoamingRootCert{
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIClDCCAhugAwIBAgIUF1f+h+uJNHyr+ZqTpwew8LYRAW0wCgYIKoZIzj0EAwMw\n"
|
||||
"gYkxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNVBAcTBkxvbmRv\n"
|
||||
"bjEsMCoGA1UEChMjR2xvYmFsUmVhY2ggVGVjaG5vbG9neSBFTUVBIExpbWl0ZWQx\n"
|
||||
"KjAoBgNVBAMTIUdsb2JhbFJlYWNoIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0y\n"
|
||||
"MzA3MTQwOTMyMDBaFw00MzA3MDkwOTMyMDBaMIGJMQswCQYDVQQGEwJHQjEPMA0G\n"
|
||||
"A1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xLDAqBgNVBAoTI0dsb2JhbFJl\n"
|
||||
"YWNoIFRlY2hub2xvZ3kgRU1FQSBMaW1pdGVkMSowKAYDVQQDEyFHbG9iYWxSZWFj\n"
|
||||
"aCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARy\n"
|
||||
"f02umFNy5W/TtM5nfMaLhRF61vLxhT8iNQHR1mXiRmNdME3ArForBcAm2eolHPcJ\n"
|
||||
"RH9DcXs59d2zzoPEaBjXADTCjUts3F7G6fjqvfki2e/txx/xfUopQO8G54XcFWqj\n"
|
||||
"QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRS\n"
|
||||
"tNe7MgAFwTaMZKUtS1/8pVoBqjAKBggqhkjOPQQDAwNnADBkAjA7VKHTybtSMBcN\n"
|
||||
"717jGYvkWlcj4c9/LzPtkHO053wGsPigaq+1SjY7tDhS/g9oUQACMA6UqH2e8cfn\n"
|
||||
"cZqmBNVNN3DBjIb4anug7F+FnYOQF36ua6MLBeGn3aKxvu1aO+hjPg==\n"
|
||||
"-----END CERTIFICATE-----\n"};
|
||||
|
||||
std::ofstream ofs{OpenRoamingRootCertFile_.path().c_str(),
|
||||
std::ios_base::trunc | std::ios_base::out |
|
||||
std::ios_base::binary};
|
||||
ofs << OpenRoamingRootCert;
|
||||
ofs.close();
|
||||
|
||||
Poco::Net::Context::Ptr SecureContext = Poco::AutoPtr<Poco::Net::Context>(
|
||||
new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, ""));
|
||||
|
||||
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
SecureContext->usePrivateKey(Poco::Crypto::RSAKey("", KeyFile_.path(), ""));
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if (!IsExpired(Cert)) {
|
||||
SecureContext->useCertificate(Poco::Crypto::X509Certificate(CertFile_.path()));
|
||||
} else {
|
||||
poco_error(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Certificate for {} has expired. We cannot connect to this server.",
|
||||
Pool_.acctConfig.servers[ServerIndex_].name));
|
||||
return false;
|
||||
}
|
||||
|
||||
SecureContext->addCertificateAuthority(
|
||||
Poco::Crypto::X509Certificate(OpenRoamingRootCertFile_.path()));
|
||||
SecureContext->addChainCertificate(
|
||||
Poco::Crypto::X509Certificate(Intermediate0.path()));
|
||||
SecureContext->addChainCertificate(
|
||||
Poco::Crypto::X509Certificate(Intermediate1.path()));
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
ServerIndex_ = 0 ;
|
||||
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
|
||||
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
|
||||
try {
|
||||
poco_information(Logger_, fmt::format("Attempting to connect to {}", CommonName()));
|
||||
Socket_->connect(Destination, Poco::Timespan(20, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
|
||||
*this, &RADIUS_Destination::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADIUS_Destination::onShutdown));
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_, "NetException: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_, "Exception: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Could not connect.");
|
||||
}
|
||||
ServerIndex_++;
|
||||
}
|
||||
}
|
||||
ServerIndex_=0;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Connect_Orion() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
|
||||
|
||||
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
|
||||
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
|
||||
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if(IsExpired(Cert)) {
|
||||
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Pool_.acctConfig.servers[ServerIndex_].name));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &cert : Pool_.acctConfig.servers[ServerIndex_].radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(
|
||||
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
|
||||
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(), ""));
|
||||
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
for (const auto &ca : CaCertFiles_) {
|
||||
Poco::Crypto::X509Certificate cert(ca->path());
|
||||
SecureContext->addCertificateAuthority(cert);
|
||||
}
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
ServerIndex_ = 0 ;
|
||||
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
|
||||
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
|
||||
try {
|
||||
poco_information(Logger_, "Attempting to connect");
|
||||
Socket_->connect(Destination, Poco::Timespan(100, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
|
||||
*this, &RADIUS_Destination::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADIUS_Destination::onShutdown));
|
||||
|
||||
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.");
|
||||
}
|
||||
ServerIndex_++;
|
||||
}
|
||||
}
|
||||
ServerIndex_=0;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Connect_Generic() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
|
||||
|
||||
/*
|
||||
AuthenticationSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
|
||||
Poco::Net::SocketAddress AuthSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
|
||||
*/
|
||||
Reactor_.addEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*CoASocketV4_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
/*
|
||||
Reactor_.addEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*CoASocketV6_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
*/
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Connect_Radsec() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Connect() {
|
||||
switch(Type_) {
|
||||
case GWObjects::RadiusEndpointType::orion: return Connect_Orion();
|
||||
case GWObjects::RadiusEndpointType::globalreach: return Connect_GlobalReach();
|
||||
case GWObjects::RadiusEndpointType::radsec: return Connect_Radsec();
|
||||
default:
|
||||
return Connect_Generic();
|
||||
}
|
||||
}
|
||||
|
||||
inline void Disconnect() {
|
||||
if (Connected_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
if(Type_==GWObjects::RadiusEndpointType::generic) {
|
||||
if(AuthenticationSocketV4_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
AuthenticationSocketV4_->close();
|
||||
AuthenticationSocketV4_.reset();
|
||||
}
|
||||
|
||||
if(AccountingSocketV4_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
AccountingSocketV4_->close();
|
||||
AccountingSocketV4_.reset();
|
||||
}
|
||||
|
||||
if(CoASocketV4_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
CoASocketV4_->close();
|
||||
CoASocketV4_.reset();
|
||||
}
|
||||
|
||||
/* if(AuthenticationSocketV6_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
AuthenticationSocketV6_->close();
|
||||
AuthenticationSocketV6_.reset();
|
||||
}
|
||||
|
||||
if(AccountingSocketV6_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
AccountingSocketV6_->close();
|
||||
AccountingSocketV6_.reset();
|
||||
}
|
||||
|
||||
if(CoASocketV6_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
CoASocketV6_->close();
|
||||
CoASocketV6_.reset();
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
if(Socket_!=nullptr) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::onData));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
|
||||
*this, &RADIUS_Destination::onError));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADIUS_Destination::onShutdown));
|
||||
Socket_->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
Connected_ = false;
|
||||
poco_information(Logger_, "Disconnecting.");
|
||||
}
|
||||
|
||||
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 "";
|
||||
}
|
||||
|
||||
const auto &Pool() const { return Pool_; }
|
||||
auto ServerType() const { return Type_; }
|
||||
|
||||
inline bool SendRadiusDataAuthData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
|
||||
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Auth {} bytes.", serialNumber, size));
|
||||
AuthenticationSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.authConfig.servers[0].ip, Pool_.authConfig.servers[0].port));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SendRadiusDataAcctData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
|
||||
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Acct {} bytes.", serialNumber, size));
|
||||
AccountingSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.acctConfig.servers[0].ip, Pool_.acctConfig.servers[0].port));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SendRadiusDataCoAData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
|
||||
poco_trace(Logger_, fmt::format("{}: Sending RADIUS CoA {} bytes.", serialNumber, size));
|
||||
CoASocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.coaConfig.servers[0].ip, Pool_.coaConfig.servers[0].port));
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex LocalMutex_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
Poco::Logger &Logger_;
|
||||
|
||||
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
|
||||
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
|
||||
|
||||
/* std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
|
||||
*/
|
||||
|
||||
Poco::Thread ReconnectThread_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
|
||||
volatile bool Connected_ = false;
|
||||
volatile bool TryAgain_ = true;
|
||||
enum GWObjects::RadiusEndpointType Type_{GWObjects::RadiusEndpointType::unknown};
|
||||
GWObjects::RadiusProxyPool Pool_;
|
||||
uint64_t ServerIndex_=0;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "Poco/Net/SocketAddress.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include <framework/utils.h>
|
||||
|
||||
namespace OpenWifi::RADIUS {
|
||||
|
||||
// Packet types
|
||||
@@ -407,6 +409,15 @@ namespace OpenWifi::RADIUS {
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
|
||||
|
||||
[[nodiscard]] inline std::string PacketTypeToString() const {
|
||||
|
||||
for(auto const &Name:radius_command_values) {
|
||||
if(Name.cmd == P_.code)
|
||||
return Name.name;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline bool IsAuthentication() {
|
||||
return (P_.code == RADIUS::Access_Request || P_.code == RADIUS::Access_Accept ||
|
||||
P_.code == RADIUS::Access_Challenge || P_.code == RADIUS::Access_Reject ||
|
||||
@@ -427,6 +438,25 @@ namespace OpenWifi::RADIUS {
|
||||
P_.code == RADIUS::CoA_ACK || P_.code == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
inline bool IsStatusMessageReply(std::string &ReplySource) {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == RADIUS::Attributes::PROXY_STATE) {
|
||||
std::string Attr33;
|
||||
// format is statis:server name
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len);
|
||||
auto Parts = Poco::StringTokenizer(Attr33, ":");
|
||||
if(Parts.count() == 2 && Parts[0] == "status") {
|
||||
ReplySource = Parts[1];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DBGLINE
|
||||
return false;
|
||||
}
|
||||
void Log(std::ostream &os) {
|
||||
uint16_t p = 0;
|
||||
|
||||
@@ -663,6 +693,29 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::uint32_t ExtractProxyStateDestinationIPint() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == RADIUS::Attributes::PROXY_STATE && attribute.len > 2) {
|
||||
std::string Attr33;
|
||||
// format is
|
||||
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len);
|
||||
auto Parts = Poco::StringTokenizer(Attr33, "|");
|
||||
if (Parts.count() == 4) {
|
||||
return Utils::IPtoInt(Parts[1]);
|
||||
}
|
||||
Parts = Poco::StringTokenizer(Attr33, ":");
|
||||
if (Parts.count() == 4) {
|
||||
return Utils::IPtoInt(Parts[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string ExtractCallingStationID() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
@@ -962,22 +1015,25 @@ namespace OpenWifi::RADIUS {
|
||||
public:
|
||||
explicit RadiusOutputPacket(const std::string &Secret) : Secret_(Secret) {}
|
||||
|
||||
inline void MakeStatusMessage() {
|
||||
inline void MakeStatusMessage(const std::string &Source) {
|
||||
P_.code = RADIUS::Status_Server;
|
||||
P_.identifier = std::rand() & 0x00ff;
|
||||
MakeRadiusAuthenticator(P_.authenticator);
|
||||
unsigned char MessageAuthenticator[16]{0};
|
||||
std::string FullSource = "status:" + Source;
|
||||
AddAttribute(RADIUS::Attributes::PROXY_STATE, FullSource.size(), (const unsigned char *)FullSource.c_str());
|
||||
AddAttribute(RADIUS::Attributes::MESSAGE_AUTHENTICATOR, sizeof(MessageAuthenticator),
|
||||
MessageAuthenticator);
|
||||
int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
|
||||
// int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16 ;
|
||||
int PktLen = 1 + 1 + 2 + 16 + AttributesLen_;
|
||||
P_.rawlen = htons(PktLen);
|
||||
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(Secret_);
|
||||
H.update((const unsigned char *)&P_, PktLen);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
int p = 0, offset = (int)FullSource.size() + 2 ;
|
||||
for (const auto &i : digest)
|
||||
P_.attributes[1 + 1 + p++] = i;
|
||||
P_.attributes[offset + 1 + 1 + p++] = i;
|
||||
}
|
||||
|
||||
inline void AddAttribute(unsigned char attr, uint8_t len, const unsigned char *data) {
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
|
||||
/*
|
||||
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
|
||||
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
|
||||
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
|
||||
const int DEFAULT_RADIUS_CoA_PORT = 3799;
|
||||
*/
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
@@ -25,7 +27,7 @@ namespace OpenWifi {
|
||||
|
||||
Enabled_ = MicroServiceConfigGetBool("radius.proxy.enable", false);
|
||||
if (!Enabled_ && !Config.exists()) {
|
||||
StopRADSECServers();
|
||||
StopRADIUSDestinations();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,279 +35,81 @@ namespace OpenWifi {
|
||||
|
||||
Enabled_ = true;
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
|
||||
Poco::Net::SocketAddress AuthSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
|
||||
Poco::Net::SocketAddress AcctSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
|
||||
Poco::Net::SocketAddress CoASockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
|
||||
|
||||
RadiusReactor_.reset();
|
||||
RadiusReactor_ = std::make_unique<Poco::Net::SocketReactor>();
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
RadiusReactor_->addEventHandler(
|
||||
*CoASocketV4_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_->addEventHandler(
|
||||
*CoASocketV6_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
ParseConfig();
|
||||
StartRADSECServers();
|
||||
RadiusReactorThread_.start(*RadiusReactor_);
|
||||
StartRADIUSDestinations();
|
||||
RadiusReactorThread_.start(RadiusReactor_);
|
||||
Utils::SetThreadName(RadiusReactorThread_, "rad:reactor");
|
||||
Running_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::Stop() {
|
||||
if (Enabled_ && Running_) {
|
||||
poco_information(Logger(), "Stopping...");
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
AuthenticationSocketV4_->close();
|
||||
AuthenticationSocketV6_->close();
|
||||
AccountingSocketV4_->close();
|
||||
AccountingSocketV6_->close();
|
||||
CoASocketV4_->close();
|
||||
CoASocketV6_->close();
|
||||
|
||||
AuthenticationSocketV4_.reset();
|
||||
AuthenticationSocketV6_.reset();
|
||||
AccountingSocketV4_.reset();
|
||||
AccountingSocketV6_.reset();
|
||||
CoASocketV4_.reset();
|
||||
CoASocketV6_.reset();
|
||||
|
||||
StopRADSECServers();
|
||||
RadiusReactor_->stop();
|
||||
StopRADIUSDestinations();
|
||||
RadiusReactor_.stop();
|
||||
RadiusReactorThread_.join();
|
||||
Running_ = false;
|
||||
poco_information(Logger(), "Stopped...");
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StartRADSECServers() {
|
||||
/* inline static bool isRadsec(const GWObjects::RadiusProxyPool &Cfg) {
|
||||
return Cfg.radsecPoolType=="orion" || Cfg.radsecPoolType=="globalreach" || Cfg.radsecPoolType=="radsec";
|
||||
}
|
||||
*/
|
||||
|
||||
void RADIUS_proxy_server::StartRADIUSDestinations() {
|
||||
std::lock_guard G(Mutex_);
|
||||
for (const auto &pool : PoolList_.pools) {
|
||||
if(pool.enabled) {
|
||||
for (const auto &entry : pool.authConfig.servers) {
|
||||
if (entry.radsec) {
|
||||
RADSECservers_[Poco::Net::SocketAddress(entry.ip, 0)] =
|
||||
std::make_unique<RADSEC_server>(*RadiusReactor_, entry, pool);
|
||||
}
|
||||
}
|
||||
RADIUS_Destinations_[Utils::IPtoInt(pool.poolProxyIp)] =
|
||||
std::make_unique<RADIUS_Destination>(RadiusReactor_, pool);
|
||||
} else {
|
||||
poco_information(Logger(),fmt::format("Pool {} is not enabled.", pool.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StopRADSECServers() {
|
||||
void RADIUS_proxy_server::StopRADIUSDestinations() {
|
||||
std::lock_guard G(Mutex_);
|
||||
RADSECservers_.clear();
|
||||
RADIUS_Destinations_.clear();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAccountingSocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger(), "Accounting: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger(), "Accounting: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"Accounting Packet Response received for {}", SerialNumber ));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnAuthenticationSocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger(), "Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
|
||||
if(Logger().trace()) {
|
||||
P.Log(std::cout);
|
||||
}
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger(), "Authentication: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::OnCoASocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger(), "CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger(), "CoA/DM: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string & secret) {
|
||||
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination,const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string &Secret) {
|
||||
try{
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
// are we sending this to a pool?
|
||||
auto DstParts = Utils::Split(Destination, ':');
|
||||
std::uint32_t DtsIp = Utils::IPtoInt(DstParts[0]);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC, secret);
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if (DestinationServer != end(RADSECservers_)) {
|
||||
|
||||
auto DestinationServer = RADIUS_Destinations_.find(DtsIp);
|
||||
if (DestinationServer != end(RADIUS_Destinations_)) {
|
||||
if(Logger().trace()) {
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
auto SessionID = P.ExtractAccountingSessionID();
|
||||
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
|
||||
Logger().trace(
|
||||
fmt::format("{}: Sending Accounting {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
|
||||
serialNumber, P.Size(),
|
||||
DestinationServer->second->Pool().authConfig.servers[0].ip,
|
||||
CalledStationID, CallingStationID, SessionID, MultiSessionID));
|
||||
}
|
||||
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
|
||||
Secret = DestinationServer->second->Pool().acctConfig.servers[0].secret;
|
||||
if(RecomputeAuthenticator) {
|
||||
P.RecomputeAuthenticator("radsec");
|
||||
P.RecomputeAuthenticator(Secret);
|
||||
}
|
||||
DestinationServer->second->SendData(serialNumber, P.Buffer(), P.Size());
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)P.Buffer(),
|
||||
P.Size());
|
||||
} else {
|
||||
DestinationServer->second->SendRadiusDataAcctData(
|
||||
serialNumber, (const unsigned char *)P.Buffer(), P.Size());
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
|
||||
AccountingSocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
|
||||
AccountingSocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"ACCT: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
if(RecomputeAuthenticator) {
|
||||
P.RecomputeAuthenticator(secret);
|
||||
}
|
||||
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
|
||||
: *AccountingSocketV6_
|
||||
, P.Buffer(), P.Size(), FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),
|
||||
fmt::format("{}: Could not send Accounting packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_debug(Logger(), fmt::format("{}: Sending Accounting Packet to {}, "
|
||||
"CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(),
|
||||
CalledStationID, CallingStationID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -325,8 +129,8 @@ namespace OpenWifi {
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size, std::string & secret) {
|
||||
void RADIUS_proxy_server::SendAccountingData( const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
@@ -334,9 +138,9 @@ namespace OpenWifi {
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, secret);
|
||||
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, secret);
|
||||
|
||||
std::string Secret;
|
||||
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, Secret);
|
||||
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, Secret);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
@@ -351,55 +155,38 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size, std::string & secret) {
|
||||
const char *buffer, std::size_t size) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC, secret);
|
||||
RADIUSSessionTracker()->AddAuthenticationSession(Destination, serialNumber, P, secret);
|
||||
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if (DestinationServer != end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
|
||||
size);
|
||||
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
|
||||
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
|
||||
if (DestinationServer != end(RADIUS_Destinations_)) {
|
||||
if(Logger().trace()) {
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
auto SessionID = P.ExtractAccountingSessionID();
|
||||
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
|
||||
Logger().trace(
|
||||
fmt::format("{}: Sending Authentication {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
|
||||
serialNumber, P.Size(),
|
||||
DestinationServer->second->Pool().authConfig.servers[0].ip,
|
||||
CalledStationID, CallingStationID, SessionID, MultiSessionID));
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
|
||||
AuthenticationSocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
|
||||
AuthenticationSocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"AUTH: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
|
||||
DestinationServer->second->SendData(serialNumber,
|
||||
(const unsigned char *)buffer, size);
|
||||
}
|
||||
else {
|
||||
DestinationServer->second->SendRadiusDataAuthData(
|
||||
serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
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_debug(Logger(), fmt::format("{}: Sending Authentication Packet to {}, "
|
||||
"CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(),
|
||||
CalledStationID, CallingStationID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -410,65 +197,35 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer,
|
||||
std::size_t size, std::string & secret) {
|
||||
std::size_t size) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
|
||||
if (Destination.empty()) {
|
||||
Destination = "0.0.0.0:0";
|
||||
}
|
||||
|
||||
if(Logger().trace()) {
|
||||
P.Log(std::cout);
|
||||
}
|
||||
|
||||
if(Destination.empty()) {
|
||||
poco_warning(Logger(),fmt::format("{}: CoA packet does not have a valid destination.", serialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC, secret);
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if (DestinationServer != end(RADSECservers_)) {
|
||||
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
|
||||
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
|
||||
if (DestinationServer != end(RADIUS_Destinations_)) {
|
||||
poco_trace(Logger(),fmt::format("{}: Sending CoA {} bytes to {}", serialNumber, P.Size(), DestinationServer->second->Pool().coaConfig.servers[0].ip));
|
||||
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
|
||||
size);
|
||||
} else {
|
||||
DestinationServer->second->SendRadiusDataCoAData(
|
||||
serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 && CoASocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 && CoASocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"CoA: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
}
|
||||
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_debug(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
|
||||
FinalDestination.toString()));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("Bad RADIUS CoA/DM Packet from {}. Dropped.", serialNumber));
|
||||
fmt::format("Bad RADIUS AUTH Packet from {}. Dropped.", serialNumber));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +329,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static bool RealmMatch(const std::string &user_realm, const std::string &realm) {
|
||||
if (realm.find_first_of('*') == std::string::npos)
|
||||
return user_realm == realm;
|
||||
@@ -766,7 +524,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
*/
|
||||
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "RADSEC_server.h"
|
||||
#include "RADIUS_Destination.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -28,25 +28,19 @@ namespace OpenWifi {
|
||||
void Stop() final;
|
||||
inline bool Enabled() const { return Enabled_; }
|
||||
|
||||
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
void
|
||||
OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
|
||||
void SendAccountingData(const std::string &serialNumber, const char *buffer,
|
||||
std::size_t size, std::string & secret);
|
||||
void SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
void SendAuthenticationData(const std::string &serialNumber, const char *buffer,
|
||||
std::size_t size, std::string & secret);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size, std::string & secret);
|
||||
std::size_t size);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
|
||||
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string & secret);
|
||||
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string &Secret);
|
||||
|
||||
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
|
||||
void DeleteConfig();
|
||||
void GetConfig(GWObjects::RadiusProxyPoolList &C);
|
||||
|
||||
void StartRADSECServers();
|
||||
void StopRADSECServers();
|
||||
void StartRADIUSDestinations();
|
||||
void StopRADIUSDestinations();
|
||||
|
||||
struct Destination {
|
||||
Poco::Net::SocketAddress Addr;
|
||||
@@ -68,19 +62,13 @@ namespace OpenWifi {
|
||||
inline bool Continue() const { return Running_ && Enabled_ && !Pools_.empty(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
|
||||
std::unique_ptr<Poco::Net::SocketReactor> RadiusReactor_;
|
||||
Poco::Thread RadiusReactorThread_;
|
||||
Poco::Net::SocketReactor RadiusReactor_;
|
||||
Poco::Thread RadiusReactorThread_;
|
||||
|
||||
GWObjects::RadiusProxyPoolList PoolList_;
|
||||
std::string ConfigFilename_;
|
||||
|
||||
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSEC_server>> RADSECservers_;
|
||||
std::map<std::uint32_t, std::unique_ptr<RADIUS_Destination>> RADIUS_Destinations_;
|
||||
|
||||
struct RadiusPool {
|
||||
std::vector<Destination> AuthV4;
|
||||
@@ -105,20 +93,21 @@ namespace OpenWifi {
|
||||
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
|
||||
// Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
|
||||
// const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
|
||||
|
||||
void ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
|
||||
std::vector<Destination> &V4,
|
||||
std::vector<Destination> &V6, bool setAsDefault,
|
||||
const std::string &poolProxyIp);
|
||||
static Poco::Net::SocketAddress
|
||||
/* static Poco::Net::SocketAddress
|
||||
ChooseAddress(std::vector<Destination> &Pool,
|
||||
const Poco::Net::SocketAddress &OriginalAddress, std::string &Secret);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype,
|
||||
const Poco::Net::SocketAddress &RequestedAddress,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
|
||||
std::string &Secret);
|
||||
};
|
||||
*/ };
|
||||
|
||||
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
|
||||
|
||||
|
||||
@@ -1,452 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-08-15.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "RADIUS_helpers.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RADSEC_server : public Poco::Runnable {
|
||||
public:
|
||||
RADSEC_server(Poco::Net::SocketReactor &R, GWObjects::RadiusProxyServerEntry E, const GWObjects::RadiusProxyPool &P)
|
||||
: Reactor_(R), Server_(std::move(E)),
|
||||
Logger_(Poco::Logger::get(
|
||||
fmt::format("RADSEC: {}@{}:{}", Server_.name, Server_.ip, Server_.port))) {
|
||||
KeepAlive_ = P.radsecKeepAlive;
|
||||
Type_ = P.radsecPoolType;
|
||||
Start();
|
||||
}
|
||||
|
||||
~RADSEC_server() { Stop(); }
|
||||
|
||||
inline int Start() {
|
||||
ReconnectThread_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() {
|
||||
TryAgain_ = false;
|
||||
Disconnect();
|
||||
ReconnectThread_.wakeUp();
|
||||
ReconnectThread_.join();
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
Poco::Thread::trySleep(5000);
|
||||
std::uint64_t CurrentDelay = 10, maxDelay=300, LastTry=0, LastKeepAlive=0;
|
||||
while (TryAgain_) {
|
||||
if (!Connected_) {
|
||||
if(!LastTry || (Utils::Now()-LastTry)>CurrentDelay) {
|
||||
LastTry = Utils::Now();
|
||||
if (!Connect()) {
|
||||
CurrentDelay *= 2;
|
||||
if(CurrentDelay>maxDelay) CurrentDelay=10;
|
||||
} else {
|
||||
CurrentDelay = 10;
|
||||
}
|
||||
}
|
||||
} else if ((Utils::Now() - LastKeepAlive) > KeepAlive_) {
|
||||
RADIUS::RadiusOutputPacket P(Server_.radsecSecret);
|
||||
P.MakeStatusMessage();
|
||||
poco_trace(Logger_, fmt::format("{}: Keep-Alive message.", Server_.name));
|
||||
Socket_->sendBytes(P.Data(), P.Len());
|
||||
LastKeepAlive = Utils::Now();
|
||||
}
|
||||
Poco::Thread::trySleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
|
||||
int length) {
|
||||
try {
|
||||
if (Connected_) {
|
||||
RADIUS::RadiusPacket P(buffer, length);
|
||||
int sent_bytes;
|
||||
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
|
||||
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
sent_bytes = Socket_->sendBytes(buffer, length);
|
||||
} else {
|
||||
poco_trace(Logger_, 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 (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Exception occurred: while sending data.");
|
||||
}
|
||||
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 >= 20) {
|
||||
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
|
||||
if (P.IsAuthentication()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_trace(Logger_, "AUTH packet dropped.");
|
||||
}
|
||||
} else if (P.IsAccounting()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_trace(Logger_, "ACCT packet dropped.");
|
||||
}
|
||||
} else if (P.IsAuthority()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_trace(Logger_, "CoA/DM packet dropped.");
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
|
||||
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
|
||||
Disconnect();
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Disconnect();
|
||||
} catch (...) {
|
||||
Disconnect();
|
||||
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker error. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void
|
||||
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
static inline bool IsExpired(const Poco::Crypto::X509Certificate &C) {
|
||||
return C.expiresOn().timestamp().epochTime() < (std::time_t)Utils::Now();
|
||||
}
|
||||
|
||||
inline bool Connect_GlobalReach() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile OpenRoamingRootCertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate0(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate1(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Combined(MicroServiceDataDirectory());
|
||||
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
|
||||
|
||||
DecodeFile(KeyFile_.path(), Server_.radsecKey);
|
||||
DecodeFile(CertFile_.path(), Server_.radsecCert);
|
||||
DecodeFile(Intermediate0.path(), Server_.radsecCacerts[0]);
|
||||
DecodeFile(Intermediate1.path(), Server_.radsecCacerts[1]);
|
||||
|
||||
for (auto &cert : Server_.radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(
|
||||
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
|
||||
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
|
||||
}
|
||||
|
||||
std::string OpenRoamingRootCert{"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIClDCCAhugAwIBAgIUF1f+h+uJNHyr+ZqTpwew8LYRAW0wCgYIKoZIzj0EAwMw\n"
|
||||
"gYkxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNVBAcTBkxvbmRv\n"
|
||||
"bjEsMCoGA1UEChMjR2xvYmFsUmVhY2ggVGVjaG5vbG9neSBFTUVBIExpbWl0ZWQx\n"
|
||||
"KjAoBgNVBAMTIUdsb2JhbFJlYWNoIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0y\n"
|
||||
"MzA3MTQwOTMyMDBaFw00MzA3MDkwOTMyMDBaMIGJMQswCQYDVQQGEwJHQjEPMA0G\n"
|
||||
"A1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xLDAqBgNVBAoTI0dsb2JhbFJl\n"
|
||||
"YWNoIFRlY2hub2xvZ3kgRU1FQSBMaW1pdGVkMSowKAYDVQQDEyFHbG9iYWxSZWFj\n"
|
||||
"aCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARy\n"
|
||||
"f02umFNy5W/TtM5nfMaLhRF61vLxhT8iNQHR1mXiRmNdME3ArForBcAm2eolHPcJ\n"
|
||||
"RH9DcXs59d2zzoPEaBjXADTCjUts3F7G6fjqvfki2e/txx/xfUopQO8G54XcFWqj\n"
|
||||
"QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRS\n"
|
||||
"tNe7MgAFwTaMZKUtS1/8pVoBqjAKBggqhkjOPQQDAwNnADBkAjA7VKHTybtSMBcN\n"
|
||||
"717jGYvkWlcj4c9/LzPtkHO053wGsPigaq+1SjY7tDhS/g9oUQACMA6UqH2e8cfn\n"
|
||||
"cZqmBNVNN3DBjIb4anug7F+FnYOQF36ua6MLBeGn3aKxvu1aO+hjPg==\n"
|
||||
"-----END CERTIFICATE-----\n"};
|
||||
|
||||
std::ofstream ofs{OpenRoamingRootCertFile_.path().c_str(),std::ios_base::trunc|std::ios_base::out|std::ios_base::binary};
|
||||
ofs << OpenRoamingRootCert;
|
||||
ofs.close();
|
||||
|
||||
Poco::Net::Context::Ptr SecureContext =
|
||||
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
|
||||
Poco::Net::Context::TLS_CLIENT_USE, ""));
|
||||
|
||||
if (Server_.allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
SecureContext->usePrivateKey(Poco::Crypto::RSAKey("",KeyFile_.path(),""));
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if(!IsExpired(Cert)) {
|
||||
SecureContext->useCertificate(Poco::Crypto::X509Certificate(CertFile_.path()));
|
||||
} else {
|
||||
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Server_.name));
|
||||
return false;
|
||||
}
|
||||
SecureContext->addCertificateAuthority(Poco::Crypto::X509Certificate(OpenRoamingRootCertFile_.path()));
|
||||
SecureContext->addChainCertificate(Poco::Crypto::X509Certificate(Intermediate0.path()));
|
||||
SecureContext->addChainCertificate(Poco::Crypto::X509Certificate(Intermediate1.path()));
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
|
||||
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(20, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if (!Server_.allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_, "NetException: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_, "Exception: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Could not connect.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Connect_Orion() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
|
||||
|
||||
DecodeFile(CertFile_.path(), Server_.radsecCert);
|
||||
DecodeFile(KeyFile_.path(), Server_.radsecKey);
|
||||
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if(IsExpired(Cert)) {
|
||||
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Server_.name));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &cert : Server_.radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(
|
||||
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
|
||||
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(), ""));
|
||||
if (Server_.allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (!Server_.allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
|
||||
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 bool Connect_Generic() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Connect() {
|
||||
if(Type_=="orion") return Connect_Orion();
|
||||
if(Type_=="globalreach") return Connect_GlobalReach();
|
||||
return Connect_Generic();
|
||||
}
|
||||
|
||||
inline void Disconnect() {
|
||||
if (Connected_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
Socket_->close();
|
||||
Connected_ = false;
|
||||
}
|
||||
poco_information(Logger_, "Disconnecting.");
|
||||
}
|
||||
|
||||
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::recursive_mutex LocalMutex_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
GWObjects::RadiusProxyServerEntry Server_;
|
||||
Poco::Logger &Logger_;
|
||||
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
|
||||
Poco::Thread ReconnectThread_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
|
||||
volatile bool Connected_ = false;
|
||||
volatile bool TryAgain_ = true;
|
||||
std::uint64_t KeepAlive_;
|
||||
std::string Type_;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
@@ -169,10 +169,12 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
|
||||
if (Cmd.ErrorCode == 0 && Cmd.Command == uCentralProtocol::CONFIGURE) {
|
||||
// we need to post a kafka event for this.
|
||||
if (Params.has(uCentralProtocol::CONFIG)) {
|
||||
if (Params.has(uCentralProtocol::CONFIG) && Params.isObject(uCentralProtocol::CONFIG)) {
|
||||
auto Config = Params.get(uCentralProtocol::CONFIG)
|
||||
.extract<Poco::JSON::Object::Ptr>();
|
||||
DeviceConfigurationChangeKafkaEvent KEvent(
|
||||
Utils::SerialNumberToInt(Cmd.SerialNumber), Utils::Now(),
|
||||
Params.get(uCentralProtocol::CONFIG).toString());
|
||||
Config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace OpenWifi {
|
||||
poco_debug(Logger(), fmt::format("BLACKLIST-POST: {}", D.serialNumber));
|
||||
|
||||
Poco::toLowerInPlace(D.serialNumber);
|
||||
if (StorageService()->IsBlackListed(D.serialNumber)) {
|
||||
if (StorageService()->IsBlackListed(Utils::MACToInt(D.serialNumber))) {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberExists);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace OpenWifi {
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Command rtty TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
|
||||
"Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
|
||||
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
|
||||
return Rtty(UUID, RPC, 60000ms, Restrictions);
|
||||
};
|
||||
@@ -163,8 +163,11 @@ namespace OpenWifi {
|
||||
{APCommands::Commands::telemetry, false, true, &RESTAPI_device_commandHandler::Telemetry,
|
||||
30000ms},
|
||||
{APCommands::Commands::ping, false, true, &RESTAPI_device_commandHandler::Ping, 60000ms},
|
||||
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script,
|
||||
300000ms}};
|
||||
{APCommands::Commands::rrm, false, true, &RESTAPI_device_commandHandler::RRM, 60000ms},
|
||||
{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms},
|
||||
{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
|
||||
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 60000ms}
|
||||
};
|
||||
|
||||
void RESTAPI_device_commandHandler::DoPost() {
|
||||
if (!ValidateParameters()) {
|
||||
@@ -1166,7 +1169,7 @@ namespace OpenWifi {
|
||||
|
||||
if (RTTYS_server()->UseInternal()) {
|
||||
std::uint64_t SN = Utils::SerialNumberToInt(SerialNumber_);
|
||||
bool mTLS = AP_WS_Server()->DeviceRequiresSecureRtty(SN);
|
||||
bool mTLS = AP_WS_Server()->DeviceRequiresSecureRTTY(SN);
|
||||
auto Hash = Utils::ComputeHash(UserInfo_.webtoken.refresh_token_, Utils::Now());
|
||||
Rtty.Token = Hash.substr(0, RTTY_DEVICE_TOKEN_LENGTH);
|
||||
if (!RTTYS_server()->CreateEndPoint(Rtty.ConnectionId, Rtty.Token, Requester(),
|
||||
@@ -1339,4 +1342,163 @@ namespace OpenWifi {
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::RRM(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
poco_debug(Logger_, fmt::format("RRM({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(!ParsedBody_->has("actions") || !ParsedBody_->isArray("actions")) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
const auto &Actions = *ParsedBody_->getArray("actions");
|
||||
// perform some validation on the commands.
|
||||
for(const auto &action:Actions) {
|
||||
auto ActionDetails = action.extract<Poco::JSON::Object::Ptr>();
|
||||
if(!ActionDetails->has("action")) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
auto ActionStr = ActionDetails->get("action").toString();
|
||||
if( ActionStr != "kick"
|
||||
&& ActionStr != "channel_switch"
|
||||
&& ActionStr != "tx_power"
|
||||
&& ActionStr != "beacon_request"
|
||||
&& ActionStr != "bss_transition"
|
||||
&& ActionStr != "neighbors" ) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRRMAction);
|
||||
}
|
||||
}
|
||||
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::ACTIONS, Actions);
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::RRM;
|
||||
std::ostringstream os;
|
||||
Params.stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
Cmd.Status= "completed";
|
||||
if(CommandManager()->FireAndForget(SerialNumber_, uCentralProtocol::RRM, Params)) {
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd,
|
||||
Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
Cmd.Status= "completed";
|
||||
return OK();
|
||||
}
|
||||
Cmd.Status= "failed"; // should never happen
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd,
|
||||
Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::Transfer(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
poco_debug(Logger_, fmt::format("TRANSFER({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
GWObjects::DeviceTransferRequest TR;
|
||||
if(!TR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::TRANSFER;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::transfer, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::CertUpdate(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
poco_debug(Logger_, fmt::format("CERTUPDATE({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
GWObjects::DeviceCertificateUpdateRequest CR;
|
||||
if(!CR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::DeviceTransferRequest TR;
|
||||
if(!TR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::CERTUPDATE;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::certupdate, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -62,6 +62,12 @@ namespace OpenWifi {
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void RRM(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void CertUpdate(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void Transfer(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
|
||||
static auto PathName() {
|
||||
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};
|
||||
|
||||
@@ -174,6 +174,15 @@ namespace OpenWifi {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(GetBoolParameter("simulatedDevices",false)) {
|
||||
auto F = []() ->void {
|
||||
StorageService()->DeleteSimulatedDevice("");
|
||||
};
|
||||
std::thread T(F);
|
||||
T.detach();
|
||||
return OK();
|
||||
}
|
||||
|
||||
if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
static bool ValidRadiusPoolServerType(const std::string &T) {
|
||||
static std::set<std::string> Types{ "generic", "orion", "globalreach"};
|
||||
static std::set<std::string> Types{ "radsec", "generic", "orion", "globalreach"};
|
||||
return Types.find(T)!=Types.end();
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "pendingUUID", pendingUUID);
|
||||
field_to_json(Obj, "simulated", simulated);
|
||||
field_to_json(Obj, "lastRecordedContact", lastRecordedContact);
|
||||
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
|
||||
field_to_json(Obj, "connectReason", connectReason);
|
||||
}
|
||||
|
||||
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
|
||||
@@ -122,6 +124,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj, "pendingUUID", pendingUUID);
|
||||
field_from_json(Obj, "simulated", simulated);
|
||||
field_from_json(Obj, "lastRecordedContact", lastRecordedContact);
|
||||
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
|
||||
field_from_json(Obj, "connectReason", connectReason);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -694,4 +698,25 @@ namespace OpenWifi::GWObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceTransferRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serialNumber", serialNumber);
|
||||
field_from_json(Obj, "server", server);
|
||||
field_from_json(Obj, "port", port);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceCertificateUpdateRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serialNumber", serialNumber);
|
||||
field_from_json(Obj, "encodedCertificate", encodedCertificate);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OpenWifi::GWObjects
|
||||
|
||||
@@ -109,7 +109,9 @@ namespace OpenWifi::GWObjects {
|
||||
DeviceRestrictions restrictionDetails;
|
||||
std::uint64_t pendingUUID = 0;
|
||||
bool simulated=false;
|
||||
std::uint64_t lastRecordedContact=0;
|
||||
std::uint64_t lastRecordedContact=0;
|
||||
std::uint64_t certificateExpiryDate = 0;
|
||||
std::string connectReason;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
||||
@@ -452,4 +454,63 @@ namespace OpenWifi::GWObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
enum class RadiusPoolStrategy {
|
||||
round_robin, random, weighted, unknown
|
||||
};
|
||||
|
||||
enum class RadiusEndpointType {
|
||||
generic, radsec, globalreach, orion, unknown
|
||||
};
|
||||
|
||||
static inline RadiusEndpointType RadiusEndpointType(const std::string &T) {
|
||||
if(T=="generic") return RadiusEndpointType::generic;
|
||||
if(T=="radsec") return RadiusEndpointType::radsec;
|
||||
if(T=="globalreach") return RadiusEndpointType::globalreach;
|
||||
if(T=="orion") return RadiusEndpointType::orion;
|
||||
return RadiusEndpointType::unknown;
|
||||
}
|
||||
|
||||
static inline RadiusPoolStrategy RadiusPoolStrategy(const std::string &T) {
|
||||
if(T=="round_robin") return RadiusPoolStrategy::round_robin;
|
||||
if(T=="random") return RadiusPoolStrategy::random;
|
||||
if(T=="weighted") return RadiusPoolStrategy::weighted;
|
||||
return RadiusPoolStrategy::unknown;
|
||||
}
|
||||
|
||||
static inline std::string to_string(enum RadiusEndpointType T) {
|
||||
switch(T) {
|
||||
case RadiusEndpointType::generic: return "generic";
|
||||
case RadiusEndpointType::radsec: return "radsec";
|
||||
case RadiusEndpointType::globalreach: return "globalreach";
|
||||
case RadiusEndpointType::orion: return "orion";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::string to_string(enum RadiusPoolStrategy T) {
|
||||
switch(T) {
|
||||
case RadiusPoolStrategy::round_robin: return "round_robin";
|
||||
case RadiusPoolStrategy::random: return "random";
|
||||
case RadiusPoolStrategy::weighted: return "weighted";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceTransferRequest {
|
||||
std::string serialNumber;
|
||||
std::string server;
|
||||
std::uint64_t port;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceCertificateUpdateRequest {
|
||||
std::string serialNumber;
|
||||
std::string encodedCertificate;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
} // namespace OpenWifi::GWObjects
|
||||
|
||||
@@ -78,21 +78,22 @@ namespace OpenWifi::OWLSObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "simulationId", simulationId);
|
||||
field_to_json(Obj, "state", state);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "msgsTx", msgsTx);
|
||||
field_to_json(Obj, "msgsRx", msgsRx);
|
||||
field_to_json(Obj, "liveDevices", liveDevices);
|
||||
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
|
||||
field_to_json(Obj, "startTime", startTime);
|
||||
field_to_json(Obj, "endTime", endTime);
|
||||
field_to_json(Obj, "errorDevices", errorDevices);
|
||||
field_to_json(Obj, "owner", owner);
|
||||
}
|
||||
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "simulationId", simulationId);
|
||||
field_to_json(Obj, "state", state);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "msgsTx", msgsTx);
|
||||
field_to_json(Obj, "msgsRx", msgsRx);
|
||||
field_to_json(Obj, "liveDevices", liveDevices);
|
||||
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
|
||||
field_to_json(Obj, "startTime", startTime);
|
||||
field_to_json(Obj, "endTime", endTime);
|
||||
field_to_json(Obj, "errorDevices", errorDevices);
|
||||
field_to_json(Obj, "owner", owner);
|
||||
field_to_json(Obj, "expectedDevices", expectedDevices);
|
||||
}
|
||||
|
||||
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {}
|
||||
|
||||
|
||||
@@ -43,23 +43,24 @@ namespace OpenWifi::OWLSObjects {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SimulationStatus {
|
||||
std::string id;
|
||||
std::string simulationId;
|
||||
std::string state;
|
||||
uint64_t tx;
|
||||
uint64_t rx;
|
||||
uint64_t msgsTx;
|
||||
uint64_t msgsRx;
|
||||
uint64_t liveDevices;
|
||||
uint64_t timeToFullDevices;
|
||||
uint64_t startTime;
|
||||
uint64_t endTime;
|
||||
uint64_t errorDevices;
|
||||
std::string owner;
|
||||
struct SimulationStatus {
|
||||
std::string id;
|
||||
std::string simulationId;
|
||||
std::string state;
|
||||
uint64_t tx;
|
||||
uint64_t rx;
|
||||
uint64_t msgsTx;
|
||||
uint64_t msgsRx;
|
||||
uint64_t liveDevices;
|
||||
uint64_t timeToFullDevices;
|
||||
uint64_t startTime;
|
||||
uint64_t endTime;
|
||||
uint64_t errorDevices;
|
||||
std::string owner;
|
||||
uint64_t expectedDevices;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct Dashboard {
|
||||
int O;
|
||||
|
||||
@@ -1194,4 +1194,243 @@ namespace OpenWifi::ProvObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLBLRAccountInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json(Obj, "privateKey", privateKey);
|
||||
field_to_json(Obj, "country", country);
|
||||
field_to_json(Obj, "province", province);
|
||||
field_to_json(Obj, "city", city);
|
||||
field_to_json(Obj, "organization", organization);
|
||||
field_to_json(Obj, "commonName", commonName);
|
||||
field_to_json(Obj, "CSR", CSR);
|
||||
field_to_json(Obj, "CSRPrivateKey", CSRPrivateKey);
|
||||
field_to_json(Obj, "CSRPublicKey", CSRPublicKey);
|
||||
field_to_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
|
||||
}
|
||||
|
||||
bool GLBLRAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
info.from_json(Obj);
|
||||
field_from_json(Obj, "privateKey", privateKey);
|
||||
field_from_json(Obj, "country", country);
|
||||
field_from_json(Obj, "province", province);
|
||||
field_from_json(Obj, "city", city);
|
||||
field_from_json(Obj, "organization", organization);
|
||||
field_from_json(Obj, "commonName", commonName);
|
||||
field_from_json(Obj, "CSR", CSR);
|
||||
field_from_json(Obj, "CSRPrivateKey", CSRPrivateKey);
|
||||
field_from_json(Obj, "CSRPublicKey", CSRPublicKey);
|
||||
field_from_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLBLRCertificateInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "name", name);
|
||||
field_to_json(Obj, "accountId", accountId);
|
||||
field_to_json(Obj, "csr", csr);
|
||||
field_to_json(Obj, "certificate", certificate);
|
||||
field_to_json(Obj, "certificateChain", certificateChain);
|
||||
field_to_json(Obj, "certificateId", certificateId);
|
||||
field_to_json(Obj, "expiresAt", expiresAt);
|
||||
field_to_json(Obj, "created", created);
|
||||
}
|
||||
|
||||
bool GLBLRCertificateInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "name", name);
|
||||
field_from_json(Obj, "accountId", accountId);
|
||||
field_from_json(Obj, "csr", csr);
|
||||
field_from_json(Obj, "certificate", certificate);
|
||||
field_from_json(Obj, "certificateChain", certificateChain);
|
||||
field_from_json(Obj, "certificateId", certificateId);
|
||||
field_from_json(Obj, "expiresAt", expiresAt);
|
||||
field_from_json(Obj, "created", created);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GooglOrionAccountInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json(Obj, "privateKey", privateKey);
|
||||
field_to_json(Obj, "certificate", certificate);
|
||||
field_to_json(Obj, "cacerts", cacerts);
|
||||
}
|
||||
|
||||
bool GooglOrionAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
info.from_json(Obj);
|
||||
field_from_json(Obj, "privateKey", privateKey);
|
||||
field_from_json(Obj, "certificate", certificate);
|
||||
field_from_json(Obj, "cacerts", cacerts);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSServer::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "Hostname", Hostname);
|
||||
field_to_json(Obj, "IP", IP);
|
||||
field_to_json(Obj, "Port", Port);
|
||||
field_to_json(Obj, "Secret", Secret);
|
||||
}
|
||||
|
||||
bool RADIUSServer::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "Hostname", Hostname);
|
||||
field_from_json(Obj, "IP", IP);
|
||||
field_from_json(Obj, "Port", Port);
|
||||
field_from_json(Obj, "Secret", Secret);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndPointRadiusType::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "Authentication", Authentication);
|
||||
field_to_json(Obj, "Accounting", Accounting);
|
||||
field_to_json(Obj, "CoA", CoA);
|
||||
field_to_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
}
|
||||
|
||||
bool RADIUSEndPointRadiusType::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "Authentication", Authentication);
|
||||
field_from_json(Obj, "Accounting", Accounting);
|
||||
field_from_json(Obj, "CoA", CoA);
|
||||
field_from_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndPointRadsecType::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "Hostname", Hostname);
|
||||
field_to_json(Obj, "IP", IP);
|
||||
field_to_json(Obj, "Port", Port);
|
||||
field_to_json(Obj, "Secret", Secret);
|
||||
field_to_json(Obj, "OpenRoamingType", OpenRoamingType);
|
||||
field_to_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
|
||||
field_to_json(Obj, "Weight", Weight);
|
||||
field_to_json(Obj, "Certificate", Certificate);
|
||||
field_to_json(Obj, "PrivateKey", PrivateKey);
|
||||
field_to_json(Obj, "CaCerts", CaCerts);
|
||||
field_to_json(Obj, "AllowSelfSigned", AllowSelfSigned);
|
||||
}
|
||||
|
||||
bool RADIUSEndPointRadsecType::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "Hostname", Hostname);
|
||||
field_from_json(Obj, "IP", IP);
|
||||
field_from_json(Obj, "Port", Port);
|
||||
field_from_json(Obj, "Secret", Secret);
|
||||
field_from_json(Obj, "OpenRoamingType", OpenRoamingType);
|
||||
field_from_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
|
||||
field_from_json(Obj, "Weight", Weight);
|
||||
field_from_json(Obj, "Certificate", Certificate);
|
||||
field_from_json(Obj, "PrivateKey", PrivateKey);
|
||||
field_from_json(Obj, "CaCerts", CaCerts);
|
||||
field_from_json(Obj, "AllowSelfSigned", AllowSelfSigned);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndPoint::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json(Obj, "Type", Type);
|
||||
field_to_json(Obj, "RadsecServers", RadsecServers);
|
||||
field_to_json(Obj, "RadiusServers", RadiusServers);
|
||||
field_to_json(Obj, "PoolStrategy", PoolStrategy);
|
||||
field_to_json(Obj, "Index", Index);
|
||||
field_to_json(Obj, "UsedBy", UsedBy);
|
||||
field_to_json(Obj, "UseGWProxy", UseGWProxy);
|
||||
field_to_json(Obj, "NasIdentifier", NasIdentifier);
|
||||
field_to_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
}
|
||||
|
||||
bool RADIUSEndPoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
info.from_json(Obj);
|
||||
field_from_json(Obj, "Type", Type);
|
||||
field_from_json(Obj, "RadsecServers", RadsecServers);
|
||||
field_from_json(Obj, "RadiusServers", RadiusServers);
|
||||
field_from_json(Obj, "PoolStrategy", PoolStrategy);
|
||||
field_from_json(Obj, "Index", Index);
|
||||
field_from_json(Obj, "UsedBy", UsedBy);
|
||||
field_from_json(Obj, "UseGWProxy", UseGWProxy);
|
||||
field_from_json(Obj, "NasIdentifier", NasIdentifier);
|
||||
field_from_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndpointUpdateStatus::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "lastUpdate", lastUpdate);
|
||||
field_to_json(Obj, "lastConfigurationChange", lastConfigurationChange);
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "lastUpdate", lastUpdate);
|
||||
field_from_json(Obj, "lastConfigurationChange", lastConfigurationChange);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::Read() {
|
||||
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
|
||||
try {
|
||||
if (F.exists()) {
|
||||
Poco::JSON::Parser P;
|
||||
std::ifstream ifs(F.path(), std::ios_base::in | std::ios_base::binary);
|
||||
auto Obj = P.parse(ifs);
|
||||
return from_json(Obj.extract<Poco::JSON::Object::Ptr>());
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::Save() {
|
||||
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
|
||||
try {
|
||||
Poco::JSON::Object Obj;
|
||||
to_json(Obj);
|
||||
std::ofstream O(F.path(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
|
||||
Poco::JSON::Stringifier::stringify(Obj, O);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::ChangeConfiguration() {
|
||||
Read();
|
||||
lastConfigurationChange = Utils::Now();
|
||||
return Save();
|
||||
}
|
||||
|
||||
} // namespace OpenWifi::ProvObjects
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
@@ -38,7 +38,7 @@ namespace OpenWifi {
|
||||
inline int Start() final {
|
||||
poco_notice(Logger(), "Starting...");
|
||||
|
||||
std::shared_lock L(KeyMutex_);
|
||||
std::lock_guard L(KeyMutex_);
|
||||
|
||||
CacheFilename_ = MicroServiceDataDirectory() + "/signature_cache";
|
||||
Poco::File CacheFile(CacheFilename_);
|
||||
@@ -91,7 +91,7 @@ namespace OpenWifi {
|
||||
|
||||
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
|
||||
const std::string &Data) const {
|
||||
std::shared_lock L(KeyMutex_);
|
||||
std::lock_guard L(KeyMutex_);
|
||||
try {
|
||||
if (Restrictions.key_info.algo == "static") {
|
||||
return "aaaaaaaaaa";
|
||||
@@ -120,7 +120,7 @@ namespace OpenWifi {
|
||||
|
||||
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
|
||||
const Poco::URI &uri) {
|
||||
std::shared_lock L(KeyMutex_);
|
||||
std::lock_guard L(KeyMutex_);
|
||||
try {
|
||||
if (Restrictions.key_info.algo == "static") {
|
||||
return "aaaaaaaaaa";
|
||||
@@ -172,7 +172,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex KeyMutex_;
|
||||
mutable std::mutex KeyMutex_;
|
||||
std::map<std::string, Poco::SharedPtr<Poco::Crypto::RSAKey>> Keys_;
|
||||
std::map<std::string, std::string> SignatureCache_;
|
||||
std::string CacheFilename_;
|
||||
|
||||
@@ -16,6 +16,22 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class LockedDbSession {
|
||||
public:
|
||||
explicit LockedDbSession();
|
||||
~LockedDbSession() = default;
|
||||
inline std::mutex &Mutex() { return *Mutex_; };
|
||||
inline Poco::Data::Session &Session() {
|
||||
if(!Session_->isConnected()) {
|
||||
Session_->reconnect();
|
||||
}
|
||||
return *Session_;
|
||||
};
|
||||
private:
|
||||
std::shared_ptr<Poco::Data::Session> Session_;
|
||||
std::shared_ptr<std::mutex> Mutex_;
|
||||
};
|
||||
|
||||
class Storage : public StorageClass {
|
||||
|
||||
public:
|
||||
@@ -90,7 +106,8 @@ namespace OpenWifi {
|
||||
|
||||
// typedef std::map<std::string,std::string> DeviceCapabilitiesCache;
|
||||
|
||||
bool AddLog(const GWObjects::DeviceLog &Log);
|
||||
bool AddLog(LockedDbSession &Session, const GWObjects::DeviceLog &Log);
|
||||
bool AddStatisticsData(Poco::Data::Session &Session, const GWObjects::Statistics &Stats);
|
||||
bool AddStatisticsData(const GWObjects::Statistics &Stats);
|
||||
bool GetStatisticsData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
|
||||
uint64_t Offset, uint64_t HowMany,
|
||||
@@ -102,6 +119,7 @@ namespace OpenWifi {
|
||||
std::vector<GWObjects::Statistics> &Stats);
|
||||
|
||||
bool AddHealthCheckData(const GWObjects::HealthCheck &Check);
|
||||
bool AddHealthCheckData(LockedDbSession &Session, const GWObjects::HealthCheck &Check);
|
||||
bool GetHealthCheckData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
|
||||
uint64_t Offset, uint64_t HowMany,
|
||||
std::vector<GWObjects::HealthCheck> &Checks);
|
||||
@@ -115,13 +133,18 @@ namespace OpenWifi {
|
||||
uint64_t &NewUUID);
|
||||
|
||||
bool RollbackDeviceConfigurationChange(std::string & SerialNumber);
|
||||
bool CompleteDeviceConfigurationChange(Poco::Data::Session &Session, std::string & SerialNumber);
|
||||
bool CompleteDeviceConfigurationChange(std::string & SerialNumber);
|
||||
|
||||
bool CreateDevice(LockedDbSession &Session, GWObjects::Device &);
|
||||
bool CreateDevice(GWObjects::Device &);
|
||||
bool CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
|
||||
bool CreateDefaultDevice(Poco::Data::Session &Session,std::string &SerialNumber,
|
||||
const Config::Capabilities &Caps,
|
||||
std::string &Firmware, const Poco::Net::IPAddress &IPAddress,
|
||||
bool simulated);
|
||||
bool CreateDevice(Poco::Data::Session &Sess, GWObjects::Device &DeviceDetails);
|
||||
|
||||
bool GetDevice(LockedDbSession &Session, std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevice(Poco::Data::Session &Session, std::string &SerialNumber, GWObjects::Device &DeviceDetails);
|
||||
bool GetDevice(std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices,
|
||||
const std::string &orderBy = "");
|
||||
@@ -132,6 +155,8 @@ namespace OpenWifi {
|
||||
bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly);
|
||||
|
||||
bool UpdateDevice(GWObjects::Device &);
|
||||
bool UpdateDevice(LockedDbSession &Session, GWObjects::Device &);
|
||||
bool UpdateDevice(Poco::Data::Session &Sess, GWObjects::Device &NewDeviceDetails);
|
||||
bool DeviceExists(std::string &SerialNumber);
|
||||
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
|
||||
bool GetDeviceCount(uint64_t &Count);
|
||||
@@ -139,7 +164,7 @@ namespace OpenWifi {
|
||||
std::vector<std::string> &SerialNumbers,
|
||||
const std::string &orderBy = "");
|
||||
bool GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy);
|
||||
bool SetDevicePassword(std::string &SerialNumber, std::string &Password);
|
||||
bool SetDevicePassword(LockedDbSession &Session, std::string &SerialNumber, std::string &Password);
|
||||
bool UpdateSerialNumberCache();
|
||||
static void GetDeviceDbFieldList(Types::StringVec &Fields);
|
||||
|
||||
@@ -148,9 +173,11 @@ namespace OpenWifi {
|
||||
|
||||
bool UpdateDeviceCapabilities(std::string &SerialNumber,
|
||||
const Config::Capabilities &Capabilities);
|
||||
bool UpdateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber,
|
||||
const Config::Capabilities &Capabilities);
|
||||
bool GetDeviceCapabilities(std::string &SerialNumber, GWObjects::Capabilities &);
|
||||
bool DeleteDeviceCapabilities(std::string &SerialNumber);
|
||||
bool CreateDeviceCapabilities(std::string &SerialNumber,
|
||||
bool CreateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber,
|
||||
const Config::Capabilities &Capabilities);
|
||||
bool InitCapabilitiesCache();
|
||||
|
||||
@@ -222,28 +249,32 @@ namespace OpenWifi {
|
||||
void RemovedExpiredCommands();
|
||||
void RemoveTimedOutCommands();
|
||||
|
||||
bool RemoveOldCommands(std::string &SerilNumber, std::string &Command);
|
||||
bool RemoveOldCommands(std::string &SerialNumber, std::string &Command);
|
||||
|
||||
bool AddBlackListDevices(std::vector<GWObjects::BlackListedDevice> &Devices);
|
||||
bool AddBlackListDevice(GWObjects::BlackListedDevice &Device);
|
||||
bool GetBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
|
||||
bool DeleteBlackListDevice(std::string &SerialNumber);
|
||||
bool IsBlackListed(const std::string &SerialNumber, std::string &reason,
|
||||
bool IsBlackListed(std::uint64_t SerialNumber, std::string &reason,
|
||||
std::string &author, std::uint64_t &created);
|
||||
bool IsBlackListed(const std::string &SerialNumber);
|
||||
bool IsBlackListed(std::uint64_t SerialNumber);
|
||||
bool InitializeBlackListCache();
|
||||
bool GetBlackListDevices(uint64_t Offset, uint64_t HowMany,
|
||||
std::vector<GWObjects::BlackListedDevice> &Devices);
|
||||
bool UpdateBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
|
||||
uint64_t GetBlackListDeviceCount();
|
||||
|
||||
bool DeleteSimulatedDevice(const std::string &SerialNumber);
|
||||
|
||||
bool RemoveHealthChecksRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveDeviceLogsRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveStatisticsRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveCommandListRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date);
|
||||
|
||||
bool SetDeviceLastRecordedContact(std::string & SeialNumber, std::uint64_t lastRecordedContact);
|
||||
bool SetDeviceLastRecordedContact(LockedDbSession &Session, std::string & SerialNumber, std::uint64_t lastRecordedContact);
|
||||
bool SetDeviceLastRecordedContact(std::string & SerialNumber, std::uint64_t lastRecordedContact);
|
||||
bool SetDeviceLastRecordedContact(Poco::Data::Session & Session, std::string & SerialNumber, std::uint64_t lastRecordedContact);
|
||||
|
||||
int Create_Tables();
|
||||
int Create_Statistics();
|
||||
@@ -263,10 +294,19 @@ namespace OpenWifi {
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
inline Poco::Data::Session StartSession() {
|
||||
return Pool_->get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<OpenWifi::ScriptDB> ScriptDB_;
|
||||
};
|
||||
|
||||
inline auto StorageService() { return Storage::instance(); }
|
||||
|
||||
inline LockedDbSession::LockedDbSession() {
|
||||
Session_ = std::make_shared<Poco::Data::Session>(Poco::Data::Session(StorageService()->StartSession()));
|
||||
Mutex_ = std::make_shared<std::mutex>();
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
#include "AP_WS_Reactor_Pool.h"
|
||||
#include "TelemetryClient.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
// #include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -28,11 +30,11 @@ namespace OpenWifi {
|
||||
if (F.exists()) {
|
||||
std::ostringstream OS;
|
||||
std::ifstream IF(FileName);
|
||||
Poco::StreamCopier::copyStream(IF, OS);
|
||||
Registry_ = nlohmann::json::parse(OS.str());
|
||||
Poco::JSON::Parser P;
|
||||
Registry_ = P.parse(IF).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
} catch (...) {
|
||||
Registry_ = nlohmann::json::parse("{}");
|
||||
Registry_ = Poco::makeShared<Poco::JSON::Object>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,54 +46,47 @@ namespace OpenWifi {
|
||||
inline ~AppServiceRegistry() { Save(); }
|
||||
|
||||
inline void Save() {
|
||||
std::istringstream IS(to_string(Registry_));
|
||||
std::ofstream OF;
|
||||
OF.open(FileName, std::ios::binary | std::ios::trunc);
|
||||
Poco::StreamCopier::copyStream(IS, OF);
|
||||
Registry_->stringify(OF);
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, uint64_t Value) {
|
||||
Registry_[Key] = Value;
|
||||
void Set(const char *key, const std::vector<std::string> &V) {
|
||||
Poco::JSON::Array Arr;
|
||||
for(const auto &s:V) {
|
||||
Arr.add(s);
|
||||
}
|
||||
Registry_->set(key,Arr);
|
||||
Save();
|
||||
}
|
||||
|
||||
template<class T> void Set(const char *key, const T &Value) {
|
||||
Registry_->set(key,Value);
|
||||
Save();
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, const std::string &Value) {
|
||||
Registry_[Key] = Value;
|
||||
Save();
|
||||
}
|
||||
bool Get(const char *key, std::vector<std::string> &Value) {
|
||||
if(Registry_->has(key) && !Registry_->isNull(key) && Registry_->isArray(key)) {
|
||||
auto Arr = Registry_->get(key);
|
||||
for(const auto &v:Arr) {
|
||||
Value.emplace_back(v);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, bool Value) {
|
||||
Registry_[Key] = Value;
|
||||
Save();
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, bool &Value) {
|
||||
if (Registry_[Key].is_boolean()) {
|
||||
Value = Registry_[Key].get<bool>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, uint64_t &Value) {
|
||||
if (Registry_[Key].is_number_unsigned()) {
|
||||
Value = Registry_[Key].get<uint64_t>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, std::string &Value) {
|
||||
if (Registry_[Key].is_string()) {
|
||||
Value = Registry_[Key].get<std::string>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<class T> bool Get(const char *key, T &Value) {
|
||||
if(Registry_->has(key) && !Registry_->isNull(key)) {
|
||||
Value = Registry_->getValue<T>(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string FileName;
|
||||
nlohmann::json Registry_;
|
||||
Poco::JSON::Object::Ptr Registry_;
|
||||
};
|
||||
|
||||
inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); }
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
EventBusManager::EventBusManager(Poco::Logger &L) : Logger_(L) {}
|
||||
|
||||
void EventBusManager::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("fmwk:EventMgr");
|
||||
|
||||
@@ -12,6 +12,16 @@ namespace OpenWifi {
|
||||
|
||||
class EventBusManager : public Poco::Runnable {
|
||||
public:
|
||||
EventBusManager() :
|
||||
Logger_(Poco::Logger::create(
|
||||
"EventBusManager", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel())) {
|
||||
}
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new EventBusManager;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
explicit EventBusManager(Poco::Logger &L);
|
||||
void run() final;
|
||||
void Start();
|
||||
@@ -24,4 +34,6 @@ namespace OpenWifi {
|
||||
Poco::Logger &Logger_;
|
||||
};
|
||||
|
||||
inline auto EventBusManager() { return EventBusManager::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -307,10 +307,8 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
|
||||
return fmt::format( R"lit({{ "system" : {{ "id" : {},
|
||||
"host" : "{}" }},
|
||||
"payload" : {} }})lit", MicroServiceID(),
|
||||
MicroServicePrivateEndPoint(), PayLoad ) ;
|
||||
return fmt::format( R"lit({{ "system" : {{ "id" : {}, "host" : "{}" }}, "payload" : {} }})lit",
|
||||
MicroServiceID(), MicroServicePrivateEndPoint(), PayLoad ) ;
|
||||
}
|
||||
|
||||
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList &partitions) {
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace OpenWifi::KafkaTopics {
|
||||
inline const char * DEVICE_EVENT_QUEUE = "device_event_queue";
|
||||
inline const char * DEVICE_TELEMETRY = "device_telemetry";
|
||||
inline const char * PROVISIONING_CHANGE = "provisioning_change";
|
||||
inline const char * RRM = "rrm";
|
||||
|
||||
namespace ServiceEvents {
|
||||
inline const char * EVENT_JOIN = "join";
|
||||
|
||||
@@ -33,9 +33,23 @@ namespace OpenWifi {
|
||||
|
||||
void MicroService::Exit(int Reason) { std::exit(Reason); }
|
||||
|
||||
static std::string MakeServiceListString(const Types::MicroServiceMetaMap &Services) {
|
||||
std::string SvcList;
|
||||
for (const auto &Svc : Services) {
|
||||
if (SvcList.empty())
|
||||
SvcList = Svc.second.Type;
|
||||
else
|
||||
SvcList += ", " + Svc.second.Type;
|
||||
}
|
||||
return SvcList;
|
||||
}
|
||||
|
||||
void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key,
|
||||
const std::string &Payload) {
|
||||
std::lock_guard G(InfraMutex_);
|
||||
|
||||
Poco::Logger &BusLogger = EventBusManager()->Logger();
|
||||
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Object = P.parse(Payload).extract<Poco::JSON::Object::Ptr>();
|
||||
@@ -55,13 +69,10 @@ namespace OpenWifi {
|
||||
Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) {
|
||||
auto PrivateEndPoint =
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString();
|
||||
if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE &&
|
||||
Services_.find(PrivateEndPoint) != Services_.end()) {
|
||||
Services_[PrivateEndPoint].LastUpdate = Utils::Now();
|
||||
} else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
|
||||
if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
|
||||
Services_.erase(PrivateEndPoint);
|
||||
poco_debug(
|
||||
logger(),
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format(
|
||||
"Service {} ID={} leaving system.",
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
@@ -69,14 +80,7 @@ namespace OpenWifi {
|
||||
ID));
|
||||
} else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN ||
|
||||
Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) {
|
||||
poco_debug(
|
||||
logger(),
|
||||
fmt::format(
|
||||
"Service {} ID={} joining system.",
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
.toString(),
|
||||
ID));
|
||||
Services_[PrivateEndPoint] = Types::MicroServiceMeta{
|
||||
auto ServiceInfo = Types::MicroServiceMeta{
|
||||
.Id = ID,
|
||||
.Type = Poco::toLower(
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::TYPE)
|
||||
@@ -94,20 +98,46 @@ namespace OpenWifi {
|
||||
.toString(),
|
||||
.LastUpdate = Utils::Now()};
|
||||
|
||||
std::string SvcList;
|
||||
for (const auto &Svc : Services_) {
|
||||
if (SvcList.empty())
|
||||
SvcList = Svc.second.Type;
|
||||
else
|
||||
SvcList += ", " + Svc.second.Type;
|
||||
auto s1 = MakeServiceListString(Services_);
|
||||
auto PreviousSize = Services_.size();
|
||||
Services_[PrivateEndPoint] = ServiceInfo;
|
||||
auto CurrentSize = Services_.size();
|
||||
if(Event == KafkaTopics::ServiceEvents::EVENT_JOIN) {
|
||||
if(!s1.empty()) {
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format(
|
||||
"Service {} ID={} is joining the system.",
|
||||
Object
|
||||
->get(
|
||||
KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
.toString(),
|
||||
ID));
|
||||
}
|
||||
std::string SvcList;
|
||||
for (const auto &Svc : Services_) {
|
||||
if (SvcList.empty())
|
||||
SvcList = Svc.second.Type;
|
||||
else
|
||||
SvcList += ", " + Svc.second.Type;
|
||||
}
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format("Current list of microservices: {}", SvcList));
|
||||
} else if(CurrentSize!=PreviousSize) {
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format(
|
||||
"Service {} ID={} is being added back in.",
|
||||
Object
|
||||
->get(KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
.toString(),
|
||||
ID));
|
||||
}
|
||||
poco_information(
|
||||
logger(),
|
||||
fmt::format("Current list of microservices: {}", SvcList));
|
||||
}
|
||||
} else {
|
||||
poco_error(
|
||||
logger(),
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format("KAFKA-MSG: invalid event '{}', missing a field.",
|
||||
Event));
|
||||
}
|
||||
@@ -118,32 +148,39 @@ namespace OpenWifi {
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString());
|
||||
#endif
|
||||
} else {
|
||||
poco_error(
|
||||
logger(),
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format("KAFKA-MSG: invalid event '{}', missing token", Event));
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(),
|
||||
poco_information(BusLogger,
|
||||
fmt::format("Unknown Event: {} Source: {}", Event, ID));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(), "Bad bus message.");
|
||||
std::ostringstream os;
|
||||
Object->stringify(std::cout);
|
||||
std::ostringstream os;
|
||||
Object->stringify(std::cout);
|
||||
poco_error(BusLogger, fmt::format("Bad bus message: {}", os.str()));
|
||||
}
|
||||
|
||||
auto i = Services_.begin();
|
||||
auto ServiceHint = Services_.begin();
|
||||
auto now = Utils::Now();
|
||||
for (; i != Services_.end();) {
|
||||
if ((now - i->second.LastUpdate) > 60) {
|
||||
i = Services_.erase(i);
|
||||
auto si1 = Services_.size();
|
||||
auto ss1 = MakeServiceListString(Services_);
|
||||
while(ServiceHint!=Services_.end()) {
|
||||
if ((now - ServiceHint->second.LastUpdate) > 120) {
|
||||
poco_information(BusLogger, fmt::format("ZombieService: Removing service {}, ", ServiceHint->second.PublicEndPoint));
|
||||
ServiceHint = Services_.erase(ServiceHint);
|
||||
} else
|
||||
++i;
|
||||
++ServiceHint;
|
||||
}
|
||||
if(Services_.size() != si1) {
|
||||
auto ss2 = MakeServiceListString(Services_);
|
||||
poco_information(BusLogger, fmt::format("Current list of microservices: {} -> {}", ss1, ss2));
|
||||
}
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
BusLogger.log(E);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +449,7 @@ namespace OpenWifi {
|
||||
try {
|
||||
DataDir.createDirectory();
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets", "");
|
||||
@@ -530,14 +567,12 @@ namespace OpenWifi {
|
||||
for (auto i : SubSystems_) {
|
||||
i->Start();
|
||||
}
|
||||
EventBusManager_ = std::make_unique<EventBusManager>(Poco::Logger::create(
|
||||
"EventBusManager", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel()));
|
||||
EventBusManager_->Start();
|
||||
EventBusManager()->Start();
|
||||
}
|
||||
|
||||
void MicroService::StopSubSystemServers() {
|
||||
AddActivity("Stopping");
|
||||
EventBusManager_->Stop();
|
||||
EventBusManager()->Stop();
|
||||
for (auto i = SubSystems_.rbegin(); i != SubSystems_.rend(); ++i) {
|
||||
(*i)->Stop();
|
||||
}
|
||||
@@ -697,7 +732,7 @@ namespace OpenWifi {
|
||||
auto APIKEY = Request.get("X-API-KEY");
|
||||
return APIKEY == MyHash_;
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,6 @@ namespace OpenWifi {
|
||||
Poco::JWT::Signer Signer_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::ThreadPool TimerPool_{"timer:pool", 2, 32};
|
||||
std::unique_ptr<EventBusManager> EventBusManager_;
|
||||
};
|
||||
|
||||
inline MicroService *MicroService::instance_ = nullptr;
|
||||
|
||||
@@ -129,4 +129,8 @@ namespace OpenWifi {
|
||||
return ALBHealthCheckServer()->RegisterExtendedHealthMessage(Callback);
|
||||
}
|
||||
|
||||
std::string MicroServiceAccessKey() {
|
||||
return MicroService::instance().Hash();
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace OpenWifi {
|
||||
std::string MicroServicePublicEndPoint();
|
||||
std::string MicroServiceConfigGetString(const std::string &Key,
|
||||
const std::string &DefaultValue);
|
||||
std::string MicroServiceAccessKey();
|
||||
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
|
||||
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue);
|
||||
std::string MicroServicePrivateEndPoint();
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace OpenWifi {
|
||||
|
||||
}
|
||||
|
||||
Poco::Data::SessionPool &Pool() { return *Pool_; }
|
||||
|
||||
private:
|
||||
inline int Setup_SQLite();
|
||||
inline int Setup_MySQL();
|
||||
|
||||
@@ -576,8 +576,8 @@ namespace ORM {
|
||||
bool UpdateRecord(field_name_t FieldName, const T &Value, const RecordType &R) {
|
||||
try {
|
||||
assert(ValidFieldName(FieldName));
|
||||
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Session.begin();
|
||||
Poco::Data::Statement Update(Session);
|
||||
|
||||
RecordTuple RT;
|
||||
@@ -593,6 +593,7 @@ namespace ORM {
|
||||
Update.execute();
|
||||
if (Cache_)
|
||||
Cache_->UpdateCache(R);
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
@@ -662,6 +663,7 @@ namespace ORM {
|
||||
assert(ValidFieldName(FieldName));
|
||||
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Session.begin();
|
||||
Poco::Data::Statement Delete(Session);
|
||||
|
||||
std::string St = "delete from " + TableName_ + " where " + FieldName + "=?";
|
||||
@@ -671,6 +673,7 @@ namespace ORM {
|
||||
Delete.execute();
|
||||
if (Cache_)
|
||||
Cache_->Delete(FieldName, Value);
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
@@ -682,11 +685,13 @@ namespace ORM {
|
||||
try {
|
||||
assert(!WhereClause.empty());
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Session.begin();
|
||||
Poco::Data::Statement Delete(Session);
|
||||
|
||||
std::string St = "delete from " + TableName_ + " where " + WhereClause;
|
||||
Delete << St;
|
||||
Delete.execute();
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
|
||||
@@ -414,10 +414,24 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
};
|
||||
|
||||
static const struct msg DefFirmwareNameExists { 1175, "Firmware name already exists." };
|
||||
|
||||
static const struct msg NotAValidECKey { 1176, "Not a valid Signing Key." };
|
||||
|
||||
static const struct msg NotAValidRadiusPoolType { 1177, "Not a valid RADIUS pool type." };
|
||||
static const struct msg InvalidRadiusTypeEndpoint { 1178, "Invalid RADIUS Server Endpoint type." };
|
||||
static const struct msg InvalidRadiusEndpointPoolStrategy { 1179, "Invalid RADIUS Server Endpoint Pool strategy." };
|
||||
static const struct msg EndpointMustHaveOneTypeOfServers { 1180, "All servers must be either RADIUS or RADSEC." };
|
||||
static const struct msg RadiusEndpointIndexInvalid { 1181, "Index must be an address between 0.0.1.1 and 0.0.2.254" };
|
||||
static const struct msg RadiusEndpointIndexMustBeUnique { 1182, "Index must be unique." };
|
||||
static const struct msg OrionAccountMustExist { 1183, "Orion account must exist." };
|
||||
static const struct msg GlobalReachCertMustExist { 1184, "Global Reach certificate must exist." };
|
||||
static const struct msg InvalidRadsecMainCertificate { 1185, "Invalid Radsec main certificate." };
|
||||
static const struct msg InvalidRadsecCaCertificate { 1186, "Invalid Radsec CA certificates." };
|
||||
static const struct msg InvalidRadsecPrivteKey { 1187, "Invalid Radsec Private key." };
|
||||
static const struct msg InvalidRadsecIPAddress { 1188, "Invalid Radsec IP Address." };
|
||||
static const struct msg InvalidRadsecPort { 1189, "Invalid Radsec Port." };
|
||||
static const struct msg InvalidRadsecSecret { 1190, "Invalid Radsec Secret." };
|
||||
static const struct msg InvalidRadiusServer { 1191, "Invalid Radius Server." };
|
||||
|
||||
static const struct msg InvalidRRMAction { 1192, "Invalid RRM Action." };
|
||||
|
||||
static const struct msg SimulationDoesNotExist {
|
||||
7000, "Simulation Instance ID does not exist."
|
||||
@@ -549,6 +563,10 @@ namespace OpenWifi::RESTAPI::Protocol {
|
||||
static const char *CONTENTDISPOSITION = "Content-Disposition";
|
||||
static const char *CONTENTTYPE = "Content-Type";
|
||||
|
||||
static const char *TRANSFER = "transfer";
|
||||
static const char *CERTUPDATE = "certupdate";
|
||||
static const char *RRM = "rrm";
|
||||
|
||||
static const char *REQUIREMENTS = "requirements";
|
||||
static const char *PASSWORDPATTERN = "passwordPattern";
|
||||
static const char *ACCESSPOLICY = "accessPolicy";
|
||||
@@ -666,6 +684,12 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *RADIUSCOA = "coa";
|
||||
static const char *RADIUSDST = "dst";
|
||||
static const char *IES = "ies";
|
||||
|
||||
static const char *TRANSFER = "transfer";
|
||||
static const char *CERTUPDATE = "certupdate";
|
||||
static const char *RRM = "rrm";
|
||||
static const char *ACTIONS = "actions";
|
||||
|
||||
} // namespace OpenWifi::uCentralProtocol
|
||||
|
||||
namespace OpenWifi::uCentralProtocol::Events {
|
||||
@@ -758,6 +782,9 @@ namespace OpenWifi::APCommands {
|
||||
telemetry,
|
||||
ping,
|
||||
script,
|
||||
rrm,
|
||||
certupdate,
|
||||
transfer,
|
||||
unknown
|
||||
};
|
||||
|
||||
@@ -770,7 +797,10 @@ namespace OpenWifi::APCommands {
|
||||
RESTAPI::Protocol::LEDS, RESTAPI::Protocol::TRACE,
|
||||
RESTAPI::Protocol::REQUEST, RESTAPI::Protocol::WIFISCAN,
|
||||
RESTAPI::Protocol::EVENTQUEUE, RESTAPI::Protocol::TELEMETRY,
|
||||
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT};
|
||||
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT,
|
||||
RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE,
|
||||
RESTAPI::Protocol::TRANSFER
|
||||
};
|
||||
|
||||
inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <resolv.h>
|
||||
|
||||
namespace OpenWifi::Utils {
|
||||
|
||||
bool NormalizeMac(std::string &Mac) {
|
||||
@@ -783,6 +785,10 @@ namespace OpenWifi::Utils {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VerifyPrivateKey(const std::string &key) {
|
||||
return VerifyECKey(key) || VerifyRSAKey(key);
|
||||
}
|
||||
|
||||
bool ValidX509Certificate([[
|
||||
maybe_unused]] const std::string &Cert) {
|
||||
try {
|
||||
@@ -862,4 +868,78 @@ namespace OpenWifi::Utils {
|
||||
return password;
|
||||
}
|
||||
|
||||
// Function to query NAPTR records for a domain and return them in a vector
|
||||
std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain) {
|
||||
std::vector<NAPTRRecord> naptrRecords;
|
||||
|
||||
unsigned char buf[4096];
|
||||
ns_msg handle;
|
||||
ns_initparse(buf, NS_PACKETSZ, &handle);
|
||||
|
||||
// Query NAPTR records for the given domain
|
||||
int response = res_query(domain.c_str(), ns_c_in, ns_t_naptr, buf, sizeof(buf));
|
||||
if (response < 0) {
|
||||
return naptrRecords;
|
||||
}
|
||||
|
||||
if(ns_initparse(buf, response, &handle) < 0) {
|
||||
return naptrRecords;
|
||||
}
|
||||
|
||||
// Iterate through the DNS response and extract NAPTR records
|
||||
int count = ns_msg_count(handle, ns_s_an);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
ns_rr rr;
|
||||
if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
|
||||
char rdata[256];
|
||||
ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
|
||||
NAPTRRecord record;
|
||||
std::istringstream os(rdata);
|
||||
os >> record.name >> record.ttl >> record.rclass >> record.rtype >> record.order >> record.preference >> record.flags
|
||||
>> record.service >> record.regexp >> record.replacement;
|
||||
naptrRecords.push_back(record);
|
||||
}
|
||||
}
|
||||
|
||||
return naptrRecords;
|
||||
}
|
||||
|
||||
std::vector<SrvRecord> getSRVRecords(const std::string& domain) {
|
||||
std::vector<SrvRecord> srvRecords;
|
||||
|
||||
// Buffer to hold the DNS response
|
||||
unsigned char buf[4096];
|
||||
ns_msg handle;
|
||||
ns_initparse(buf, NS_PACKETSZ, &handle);
|
||||
|
||||
// Query NAPTR records for the given domain
|
||||
int response = res_query(domain.c_str(), ns_c_in, ns_t_srv, buf, sizeof(buf));
|
||||
if (response < 0) {
|
||||
std::cerr << "DNS query failed for " << domain << ": " << hstrerror(h_errno) << std::endl;
|
||||
return srvRecords;
|
||||
}
|
||||
|
||||
if(ns_initparse(buf, response, &handle) < 0) {
|
||||
return srvRecords;
|
||||
}
|
||||
|
||||
// Iterate through the DNS response and extract NAPTR records
|
||||
int count = ns_msg_count(handle, ns_s_an);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
ns_rr rr;
|
||||
if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
|
||||
char rdata[256];
|
||||
ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
|
||||
SrvRecord record;
|
||||
std::istringstream os(rdata);
|
||||
os >> record.name >> record.ttl >> record.rclass >> record.rtype >> record.pref >> record.weight >>
|
||||
record.port >> record.srvname ;
|
||||
srvRecords.push_back(record);
|
||||
}
|
||||
}
|
||||
|
||||
return srvRecords;
|
||||
}
|
||||
|
||||
|
||||
} // namespace OpenWifi::Utils
|
||||
|
||||
@@ -247,6 +247,24 @@ namespace OpenWifi::Utils {
|
||||
return count;
|
||||
}
|
||||
|
||||
inline std::uint32_t IPtoInt(const std::string &A) {
|
||||
Poco::Net::IPAddress IP;
|
||||
std::uint32_t Result=0;
|
||||
|
||||
if(Poco::Net::IPAddress::tryParse(A,IP)) {
|
||||
for(const auto i:IP.toBytes()) {
|
||||
Result <<= 8;
|
||||
Result += i;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline bool ValidIP(const std::string &IPstr) {
|
||||
Poco::Net::IPAddress IP;
|
||||
return Poco::Net::IPAddress::tryParse(IPstr,IP);
|
||||
}
|
||||
|
||||
struct CSRCreationParameters {
|
||||
std::string Country, Province, City,
|
||||
Organization, CommonName;
|
||||
@@ -261,7 +279,127 @@ namespace OpenWifi::Utils {
|
||||
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase);
|
||||
bool VerifyECKey(const std::string &key);
|
||||
bool VerifyRSAKey(const std::string &key);
|
||||
bool VerifyPrivateKey(const std::string &key);
|
||||
bool ValidX509Certificate(const std::string &Cert);
|
||||
bool ValidX509Certificate(const std::vector<std::string> &Certs);
|
||||
|
||||
struct NAPTRRecord {
|
||||
std::string name;
|
||||
std::string ttl;
|
||||
std::string rclass;
|
||||
std::string rtype;
|
||||
uint32_t order=0;
|
||||
uint32_t preference=0;
|
||||
std::string flags;
|
||||
std::string service;
|
||||
std::string regexp;
|
||||
std::string replacement;
|
||||
};
|
||||
|
||||
// Function to query NAPTR records for a domain and return them in a vector
|
||||
std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
|
||||
struct SrvRecord {
|
||||
std::string name;
|
||||
std::string ttl;
|
||||
std::string rclass;
|
||||
std::string rtype;
|
||||
uint32_t pref = 0;
|
||||
uint32_t weight = 0;
|
||||
uint32_t port = 0;
|
||||
std::string srvname;
|
||||
};
|
||||
|
||||
std::vector<SrvRecord> getSRVRecords(const std::string& domain);
|
||||
|
||||
struct HostNameServerResult{
|
||||
std::string Hostname;
|
||||
uint32_t Port;
|
||||
};
|
||||
|
||||
class CompressedString {
|
||||
public:
|
||||
CompressedString() {
|
||||
DecompressedSize_ = 0;
|
||||
};
|
||||
|
||||
explicit CompressedString(const std::string &Data) : DecompressedSize_(Data.size()) {
|
||||
CompressIt(Data);
|
||||
}
|
||||
|
||||
CompressedString(const CompressedString &Data) {
|
||||
this->DecompressedSize_ = Data.DecompressedSize_;
|
||||
this->CompressedData_ = Data.CompressedData_;
|
||||
}
|
||||
|
||||
CompressedString& operator=(const CompressedString& rhs) {
|
||||
if (this != &rhs) {
|
||||
this->DecompressedSize_ = rhs.DecompressedSize_;
|
||||
this->CompressedData_ = rhs.CompressedData_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompressedString& operator=(CompressedString&& rhs) {
|
||||
if (this != &rhs) {
|
||||
this->DecompressedSize_ = rhs.DecompressedSize_;
|
||||
this->CompressedData_ = rhs.CompressedData_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~CompressedString() = default;
|
||||
|
||||
operator std::string() const {
|
||||
return DecompressIt();
|
||||
}
|
||||
|
||||
CompressedString &operator=(const std::string &Data) {
|
||||
DecompressedSize_ = Data.size();
|
||||
CompressIt(Data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto CompressedSize() const { return CompressedData_.size(); }
|
||||
auto DecompressedSize() const { return DecompressedSize_; }
|
||||
|
||||
private:
|
||||
std::string CompressedData_;
|
||||
std::size_t DecompressedSize_;
|
||||
|
||||
inline void CompressIt(const std::string &Data) {
|
||||
z_stream strm; // = {0};
|
||||
CompressedData_.resize(Data.size());
|
||||
strm.next_in = (Bytef *)Data.data();
|
||||
strm.avail_in = Data.size();
|
||||
strm.next_out = (Bytef *)CompressedData_.data();
|
||||
strm.avail_out = Data.size();
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
|
||||
deflate(&strm, Z_FINISH);
|
||||
deflateEnd(&strm);
|
||||
CompressedData_.resize(strm.total_out);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string DecompressIt() const {
|
||||
std::string Result;
|
||||
if(DecompressedSize_!=0) {
|
||||
Result.resize(DecompressedSize_);
|
||||
z_stream strm ; //= {0};
|
||||
strm.next_in = (Bytef *)CompressedData_.data();
|
||||
strm.avail_in = CompressedData_.size();
|
||||
strm.next_out = (Bytef *)Result.data();
|
||||
strm.avail_out = Result.size();
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
inflateInit2(&strm, 15 + 32);
|
||||
inflate(&strm, Z_FINISH);
|
||||
inflateEnd(&strm);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace OpenWifi::Utils
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace OpenWifi {
|
||||
|
||||
auto WebClientSecureContext =
|
||||
new Poco::Net::Context(Poco::Net::Context::SERVER_USE, KeyFileName,
|
||||
CertFileName, "", Poco::Net::Context::VERIFY_RELAXED);
|
||||
CertFileName, "", Poco::Net::Context::VERIFY_NONE);
|
||||
Poco::Crypto::X509Certificate WebRoot(RootCaFileName);
|
||||
WebClientSecureContext->addCertificateAuthority(WebRoot);
|
||||
WebClientSecureContext->disableStatelessSessionResumption();
|
||||
|
||||
@@ -56,10 +56,10 @@ namespace OpenWifi {
|
||||
struct DeviceDetails {
|
||||
std::string reason;
|
||||
std::string author;
|
||||
std::uint64_t created;
|
||||
std::uint64_t created=Utils::Now();
|
||||
};
|
||||
|
||||
static std::map<std::string, DeviceDetails> BlackListDevices;
|
||||
static std::map<std::uint64_t , DeviceDetails> BlackListDevices;
|
||||
static std::recursive_mutex BlackListMutex;
|
||||
|
||||
bool Storage::InitializeBlackListCache() {
|
||||
@@ -78,7 +78,7 @@ namespace OpenWifi {
|
||||
auto Reason = RSet[1].convert<std::string>();
|
||||
auto Author = RSet[2].convert<std::string>();
|
||||
auto Created = RSet[3].convert<std::uint64_t>();
|
||||
BlackListDevices[SerialNumber] =
|
||||
BlackListDevices[Utils::MACToInt(SerialNumber)] =
|
||||
DeviceDetails{.reason = Reason, .author = Author, .created = Created};
|
||||
More = RSet.moveNext();
|
||||
}
|
||||
@@ -93,6 +93,7 @@ namespace OpenWifi {
|
||||
bool Storage::AddBlackListDevice(GWObjects::BlackListedDevice &Device) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
std::string St{"INSERT INTO BlackList (" + DB_BlackListDeviceSelectFields + ") " +
|
||||
@@ -102,9 +103,9 @@ namespace OpenWifi {
|
||||
ConvertBlackListDeviceRecord(Device, T);
|
||||
Insert << ConvertParams(St), Poco::Data::Keywords::use(T);
|
||||
Insert.execute();
|
||||
|
||||
Sess.commit();
|
||||
std::lock_guard G(BlackListMutex);
|
||||
BlackListDevices[Device.serialNumber] = DeviceDetails{
|
||||
BlackListDevices[Utils::MACToInt(Device.serialNumber)] = DeviceDetails{
|
||||
.reason = Device.reason, .author = Device.author, .created = Device.created};
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -130,6 +131,7 @@ namespace OpenWifi {
|
||||
bool Storage::DeleteBlackListDevice(std::string &SerialNumber) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St{"DELETE FROM BlackList WHERE SerialNumber=?"};
|
||||
@@ -137,9 +139,9 @@ namespace OpenWifi {
|
||||
Poco::toLowerInPlace(SerialNumber);
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber);
|
||||
Delete.execute();
|
||||
|
||||
Sess.commit();
|
||||
std::lock_guard G(BlackListMutex);
|
||||
BlackListDevices.erase(SerialNumber);
|
||||
BlackListDevices.erase(Utils::MACToInt(SerialNumber));
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -177,6 +179,7 @@ namespace OpenWifi {
|
||||
GWObjects::BlackListedDevice &Device) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string St{"UPDATE BlackList SET " + DB_BlackListDeviceUpdateFields +
|
||||
@@ -187,9 +190,9 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(T),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
|
||||
Sess.commit();
|
||||
std::lock_guard G(BlackListMutex);
|
||||
BlackListDevices[Device.serialNumber] = DeviceDetails{
|
||||
BlackListDevices[Utils::MACToInt(Device.serialNumber)] = DeviceDetails{
|
||||
.reason = Device.reason, .author = Device.author, .created = Device.created};
|
||||
|
||||
return true;
|
||||
@@ -233,10 +236,10 @@ namespace OpenWifi {
|
||||
return BlackListDevices.size();
|
||||
}
|
||||
|
||||
bool Storage::IsBlackListed(const std::string &SerialNumber, std::string &reason,
|
||||
bool Storage::IsBlackListed(std::uint64_t SerialNumber, std::string &reason,
|
||||
std::string &author, std::uint64_t &created) {
|
||||
std::lock_guard G(BlackListMutex);
|
||||
auto DeviceHint = BlackListDevices.find(Poco::toLower(SerialNumber));
|
||||
auto DeviceHint = BlackListDevices.find(SerialNumber);
|
||||
if (DeviceHint == end(BlackListDevices))
|
||||
return false;
|
||||
reason = DeviceHint->second.reason;
|
||||
@@ -245,9 +248,9 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Storage::IsBlackListed(const std::string &SerialNumber) {
|
||||
bool Storage::IsBlackListed(std::uint64_t SerialNumber) {
|
||||
std::lock_guard G(BlackListMutex);
|
||||
auto DeviceHint = BlackListDevices.find(Poco::toLower(SerialNumber));
|
||||
auto DeviceHint = BlackListDevices.find(SerialNumber);
|
||||
return DeviceHint != end(BlackListDevices);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
bool Storage::CreateDeviceCapabilities(std::string &SerialNumber,
|
||||
bool Storage::CreateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber,
|
||||
const Config::Capabilities &Capabilities) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement UpSert(Sess);
|
||||
Session.begin();
|
||||
Poco::Data::Statement UpSert(Session);
|
||||
|
||||
std::string TCaps{Capabilities.AsString()};
|
||||
uint64_t Now = Utils::Now();
|
||||
@@ -33,6 +33,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(TCaps),
|
||||
Poco::Data::Keywords::use(Now);
|
||||
UpSert.execute();
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -41,11 +42,11 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::UpdateDeviceCapabilities(std::string &SerialNumber,
|
||||
bool Storage::UpdateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber,
|
||||
const Config::Capabilities &Caps) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement UpSert(Sess);
|
||||
Session.begin();
|
||||
Poco::Data::Statement UpSert(Session);
|
||||
|
||||
uint64_t Now = Utils::Now();
|
||||
if (!Caps.Compatible().empty() && !Caps.Platform().empty())
|
||||
@@ -61,6 +62,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(TCaps),
|
||||
Poco::Data::Keywords::use(Now);
|
||||
UpSert.execute();
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -99,13 +101,14 @@ namespace OpenWifi {
|
||||
bool Storage::DeleteDeviceCapabilities(std::string &SerialNumber) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St{"DELETE FROM Capabilities WHERE SerialNumber=?"};
|
||||
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber);
|
||||
Delete.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
|
||||
@@ -105,6 +105,7 @@ namespace OpenWifi {
|
||||
bool Storage::RemoveOldCommands(std::string &SerialNumber, std::string &Command) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St{
|
||||
@@ -112,8 +113,7 @@ namespace OpenWifi {
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber),
|
||||
Poco::Data::Keywords::use(Command);
|
||||
Delete.execute();
|
||||
Delete.reset(Sess);
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -146,6 +146,7 @@ namespace OpenWifi {
|
||||
RemoveOldCommands(SerialNumber, Command.Command);
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
std::string St{"INSERT INTO CommandList ( " + DB_Command_SelectFields + " ) VALUES( " +
|
||||
@@ -156,7 +157,7 @@ namespace OpenWifi {
|
||||
|
||||
Insert << ConvertParams(St), Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -215,6 +216,7 @@ namespace OpenWifi {
|
||||
bool Storage::DeleteCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
bool DatesIncluded = (FromDate != 0 || ToDate != 0);
|
||||
@@ -237,8 +239,7 @@ namespace OpenWifi {
|
||||
|
||||
Delete << IntroStatement + DateSelector;
|
||||
Delete.execute();
|
||||
Delete.reset(Sess);
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -274,7 +275,6 @@ namespace OpenWifi {
|
||||
if (Records.size() < HowMany)
|
||||
Done = true;
|
||||
}
|
||||
Select.reset(Sess);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -286,6 +286,7 @@ namespace OpenWifi {
|
||||
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string St{"UPDATE CommandList SET Status=?, Executed=?, Completed=?, "
|
||||
@@ -299,7 +300,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(Command.ErrorCode), Poco::Data::Keywords::use(UUID);
|
||||
|
||||
Update.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -311,6 +312,7 @@ namespace OpenWifi {
|
||||
bool Storage::SetCommandExecuted(std::string &CommandUUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = Utils::Now();
|
||||
@@ -321,6 +323,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(CommandUUID);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -331,6 +334,7 @@ namespace OpenWifi {
|
||||
void Storage::RemovedExpiredCommands() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = Utils::Now(), Window = Now - CommandManager()->CommandTimeout();
|
||||
@@ -341,8 +345,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(Window);
|
||||
Update.execute();
|
||||
Update.reset(Sess);
|
||||
|
||||
Sess.commit();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
@@ -351,6 +354,7 @@ namespace OpenWifi {
|
||||
bool Storage::SetCommandLastTry(std::string &CommandUUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = Utils::Now();
|
||||
@@ -359,6 +363,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(CommandUUID);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -369,6 +374,7 @@ namespace OpenWifi {
|
||||
void Storage::RemoveTimedOutCommands() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = Utils::Now(), Window = Now - CommandManager()->CommandTimeout();
|
||||
@@ -377,7 +383,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Window);
|
||||
Update.execute();
|
||||
Update.reset(Sess);
|
||||
Sess.commit();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
@@ -386,6 +392,7 @@ namespace OpenWifi {
|
||||
bool Storage::SetCommandTimedOut(std::string &CommandUUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = Utils::Now();
|
||||
@@ -395,6 +402,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Status), Poco::Data::Keywords::use(CommandUUID);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -425,6 +433,7 @@ namespace OpenWifi {
|
||||
bool Storage::DeleteCommand(std::string &UUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St{"DELETE FROM CommandList WHERE UUID=?"};
|
||||
@@ -435,8 +444,7 @@ namespace OpenWifi {
|
||||
St = "DELETE FROM FileUploads WHERE UUID=?";
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(UUID);
|
||||
Delete.execute();
|
||||
Delete.reset(Sess);
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -510,6 +518,7 @@ namespace OpenWifi {
|
||||
auto Now = Utils::Now();
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string St{"UPDATE CommandList SET Executed=? WHERE UUID=?"};
|
||||
@@ -518,7 +527,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
|
||||
Update.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -555,6 +564,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Status = to_string(Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
@@ -566,6 +576,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(ResultStr), Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(tET), Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -603,6 +614,7 @@ namespace OpenWifi {
|
||||
bool Storage::CancelWaitFile(std::string &UUID, std::string &ErrorText) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
auto Now = Utils::Now();
|
||||
uint64_t Size = 0, WaitForFile = 0;
|
||||
|
||||
@@ -616,6 +628,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(ErrorText), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -631,6 +644,7 @@ namespace OpenWifi {
|
||||
uint64_t Size = FileContent.str().size();
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Statement(Sess);
|
||||
|
||||
std::string StatementStr;
|
||||
@@ -644,14 +658,14 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Size),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Statement.execute();
|
||||
|
||||
Sess.commit();
|
||||
if (Size < FileUploader()->MaxSize()) {
|
||||
|
||||
Poco::Data::BLOB TheBlob;
|
||||
|
||||
TheBlob.appendRaw((const unsigned char *)FileContent.str().c_str(),
|
||||
FileContent.str().size());
|
||||
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
std::string FileType{Type};
|
||||
|
||||
@@ -662,10 +676,12 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(FileType), Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(TheBlob);
|
||||
Insert.execute();
|
||||
return true;
|
||||
Sess.commit();
|
||||
} else {
|
||||
poco_warning(Logger(), fmt::format("File {} is too large.", UUID));
|
||||
}
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
@@ -712,6 +728,7 @@ namespace OpenWifi {
|
||||
bool Storage::SetCommandResult(std::string &UUID, std::string &Result) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
auto Now = Utils::Now();
|
||||
@@ -722,6 +739,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(Result), Poco::Data::Keywords::use(Status),
|
||||
Poco::Data::Keywords::use(UUID);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -733,13 +751,14 @@ namespace OpenWifi {
|
||||
bool Storage::RemoveAttachedFile(std::string &UUID) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St{"DELETE FROM FileUploads WHERE UUID=?"};
|
||||
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(UUID);
|
||||
Delete.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -751,11 +770,13 @@ namespace OpenWifi {
|
||||
bool Storage::RemoveUploadedFilesRecordsOlderThan(uint64_t Date) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St1{"delete from FileUploads where Created<?"};
|
||||
Delete << ConvertParams(St1), Poco::Data::Keywords::use(Date);
|
||||
Delete.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -766,11 +787,13 @@ namespace OpenWifi {
|
||||
bool Storage::RemoveCommandListRecordsOlderThan(uint64_t Date) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St1{"delete from CommandList where Submitted<?"};
|
||||
Delete << ConvertParams(St1), Poco::Data::Keywords::use(Date);
|
||||
Delete.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace OpenWifi {
|
||||
if (!TmpName.empty())
|
||||
return false;
|
||||
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
std::string St2{"INSERT INTO DefaultFirmwares ( " + DB_DefFirmware_SelectFields +
|
||||
@@ -94,6 +95,7 @@ namespace OpenWifi {
|
||||
Insert << ConvertParams(St2),
|
||||
Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -107,6 +109,7 @@ namespace OpenWifi {
|
||||
try {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
Poco::toLowerInPlace(deviceType);
|
||||
|
||||
@@ -114,7 +117,7 @@ namespace OpenWifi {
|
||||
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(deviceType);
|
||||
Delete.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -125,9 +128,9 @@ namespace OpenWifi {
|
||||
|
||||
bool Storage::UpdateDefaultFirmware(GWObjects::DefaultFirmware &DefFirmware) {
|
||||
try {
|
||||
uint64_t Now = Utils::Now();
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
DefFirmware.LastModified = Now;
|
||||
Poco::toLowerInPlace(DefFirmware.deviceType);
|
||||
@@ -143,7 +146,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Keywords::use(R),
|
||||
Poco::Data::Keywords::use(DefFirmware.deviceType);
|
||||
Update.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
|
||||
@@ -72,6 +72,7 @@ namespace OpenWifi {
|
||||
Config::Config Cfg(DefConfig.Configuration);
|
||||
|
||||
if (Cfg.Valid()) {
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
std::string St{"INSERT INTO DefaultConfigs ( " + DB_DefConfig_SelectFields +
|
||||
@@ -83,6 +84,7 @@ namespace OpenWifi {
|
||||
Convert(DefConfig, R);
|
||||
Insert << ConvertParams(St), Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} else {
|
||||
poco_warning(Logger(), "Cannot create device: invalid configuration.");
|
||||
@@ -99,13 +101,14 @@ namespace OpenWifi {
|
||||
try {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St{"DELETE FROM DefaultConfigs WHERE Name=?"};
|
||||
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(Name);
|
||||
Delete.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -117,9 +120,9 @@ namespace OpenWifi {
|
||||
bool Storage::UpdateDefaultConfiguration(std::string &Name,
|
||||
GWObjects::DefaultConfiguration &DefConfig) {
|
||||
try {
|
||||
uint64_t Now = Utils::Now();
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
DefConfig.LastModified = Now;
|
||||
|
||||
@@ -132,6 +135,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(R),
|
||||
Poco::Data::Keywords::use(Name);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
|
||||
@@ -53,7 +53,9 @@ namespace OpenWifi {
|
||||
"restrictionDetails, "
|
||||
"pendingUUID, "
|
||||
"simulated,"
|
||||
"lastRecordedContact"
|
||||
"lastRecordedContact,"
|
||||
"certificateExpiryDate,"
|
||||
"connectReason "
|
||||
};
|
||||
|
||||
const static std::string DB_DeviceUpdateFields{"SerialNumber=?,"
|
||||
@@ -84,16 +86,20 @@ namespace OpenWifi {
|
||||
"restrictionDetails=?, "
|
||||
"pendingUUID=?, "
|
||||
"simulated=?,"
|
||||
"lastRecordedContact=? "};
|
||||
"lastRecordedContact=?, "
|
||||
"certificateExpiryDate=?,"
|
||||
"connectReason=? "
|
||||
};
|
||||
|
||||
const static std::string DB_DeviceInsertValues{
|
||||
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
|
||||
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
|
||||
|
||||
typedef Poco::Tuple<std::string, std::string, std::string, std::string, std::string,
|
||||
std::string, std::string, std::string, std::string, std::string,
|
||||
std::string, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, std::string,
|
||||
std::string, std::string, std::string, uint64_t, std::string, bool,
|
||||
std::string, std::string, std::string, std::uint64_t, bool, std::uint64_t>
|
||||
std::string, std::string, std::string, std::uint64_t, bool, std::uint64_t,
|
||||
std::uint64_t, std::string>
|
||||
DeviceRecordTuple;
|
||||
typedef std::vector<DeviceRecordTuple> DeviceRecordList;
|
||||
|
||||
@@ -128,6 +134,8 @@ namespace OpenWifi {
|
||||
D.pendingUUID = R.get<26>();
|
||||
D.simulated = R.get<27>();
|
||||
D.lastRecordedContact = R.get<28>();
|
||||
D.certificateExpiryDate = R.get<29>();
|
||||
D.connectReason = R.get<30>();
|
||||
}
|
||||
|
||||
void ConvertDeviceRecord(const GWObjects::Device &D, DeviceRecordTuple &R) {
|
||||
@@ -160,6 +168,8 @@ namespace OpenWifi {
|
||||
R.set<26>(D.pendingUUID);
|
||||
R.set<27>(D.simulated);
|
||||
R.set<28>(D.lastRecordedContact);
|
||||
R.set<29>(D.certificateExpiryDate);
|
||||
R.set<30>(D.connectReason);
|
||||
}
|
||||
|
||||
bool Storage::GetDeviceCount(uint64_t &Count) {
|
||||
@@ -200,7 +210,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::UpdateDeviceConfiguration(std::string &SerialNumber, std::string &Configuration,
|
||||
/* bool Storage::UpdateDeviceConfiguration(std::string &SerialNumber, std::string &Configuration,
|
||||
uint64_t &NewUUID) {
|
||||
try {
|
||||
|
||||
@@ -245,7 +255,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
*/
|
||||
bool Storage::RollbackDeviceConfigurationChange(std::string & SerialNumber) {
|
||||
try {
|
||||
GWObjects::Device D;
|
||||
@@ -258,6 +268,7 @@ namespace OpenWifi {
|
||||
ConfigurationCache().Add(Utils::SerialNumberToInt(SerialNumber), D.UUID);
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
DeviceRecordTuple R;
|
||||
@@ -267,6 +278,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St2), Poco::Data::Keywords::use(R),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -275,6 +287,16 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool Storage::CompleteDeviceConfigurationChange(std::string & SerialNumber) {
|
||||
try {
|
||||
auto Session = Pool_->get();
|
||||
return CompleteDeviceConfigurationChange(Session, SerialNumber);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CompleteDeviceConfigurationChange(Poco::Data::Session & Session, std::string & SerialNumber) {
|
||||
try {
|
||||
GWObjects::Device D;
|
||||
if (!GetDevice(SerialNumber, D))
|
||||
@@ -290,8 +312,8 @@ namespace OpenWifi {
|
||||
|
||||
ConfigurationCache().Add(Utils::SerialNumberToInt(SerialNumber), D.UUID);
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
Session.begin();
|
||||
Poco::Data::Statement Update(Session);
|
||||
|
||||
DeviceRecordTuple R;
|
||||
ConvertDeviceRecord(D, R);
|
||||
@@ -300,6 +322,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St2), Poco::Data::Keywords::use(R),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -318,13 +341,12 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
GWObjects::Device D;
|
||||
if (!GetDevice(SerialNumber, D))
|
||||
return false;
|
||||
|
||||
|
||||
uint64_t Now = time(nullptr);
|
||||
if(NewUUID==0) {
|
||||
D.pendingUUID = NewUUID = (D.LastConfigurationChange == Now ? Now + 1 : Now);
|
||||
@@ -333,6 +355,8 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if (Cfg.SetUUID(NewUUID)) {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
D.pendingConfiguration = Cfg.get();
|
||||
|
||||
@@ -343,6 +367,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St2), Poco::Data::Keywords::use(R),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
poco_information(Logger(),
|
||||
fmt::format("DEVICE-PENDING-CONFIGURATION-UPDATED({}): New UUID is {}",
|
||||
SerialNumber, NewUUID));
|
||||
@@ -356,69 +381,95 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetDeviceLastRecordedContact(std::string &SerialNumber, std::uint64_t lastRecordedContact) {
|
||||
bool Storage::SetDeviceLastRecordedContact(LockedDbSession &Session, std::string &SerialNumber, std::uint64_t lastRecordedContact) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::string St{"UPDATE Devices SET lastRecordedContact=? WHERE SerialNumber=?"};
|
||||
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(lastRecordedContact),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
return true;
|
||||
|
||||
std::lock_guard Lock(Session.Mutex());
|
||||
return SetDeviceLastRecordedContact(Session.Session(), SerialNumber, lastRecordedContact);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CreateDevice(GWObjects::Device &DeviceDetails) {
|
||||
bool Storage::SetDeviceLastRecordedContact(Poco::Data::Session &Session, std::string &SerialNumber, std::uint64_t lastRecordedContact) {
|
||||
try {
|
||||
Session.begin();
|
||||
Poco::Data::Statement Update(Session);
|
||||
std::string St{"UPDATE Devices SET lastRecordedContact=? WHERE SerialNumber=?"};
|
||||
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(lastRecordedContact),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetDeviceLastRecordedContact(std::string &SerialNumber, std::uint64_t lastRecordedContact) {
|
||||
try {
|
||||
auto Session = Pool_->get();
|
||||
return SetDeviceLastRecordedContact(Session, SerialNumber, lastRecordedContact);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CreateDevice(Poco::Data::Session &Sess, GWObjects::Device &DeviceDetails) {
|
||||
std::string SerialNumber;
|
||||
try {
|
||||
Config::Config Cfg(DeviceDetails.Configuration);
|
||||
uint64_t Now = Utils::Now();
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
DeviceDetails.modified = Utils::Now();
|
||||
DeviceDetails.CreationTimestamp = DeviceDetails.LastConfigurationDownload =
|
||||
DeviceDetails.UUID = DeviceDetails.LastConfigurationChange = Now;
|
||||
|
||||
std::string St{"SELECT SerialNumber FROM Devices WHERE SerialNumber=?"};
|
||||
if (Cfg.Valid() && Cfg.SetUUID(DeviceDetails.UUID)) {
|
||||
|
||||
Select << ConvertParams(St), Poco::Data::Keywords::into(SerialNumber),
|
||||
Poco::Data::Keywords::use(DeviceDetails.SerialNumber);
|
||||
Select.execute();
|
||||
DeviceDetails.Configuration = Cfg.get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
if (Select.rowsExtracted() == 0) {
|
||||
Config::Config Cfg(DeviceDetails.Configuration);
|
||||
uint64_t Now = Utils::Now();
|
||||
std::string St2{"INSERT INTO Devices ( " + DB_DeviceSelectFields + " ) " +
|
||||
DB_DeviceInsertValues + " ON CONFLICT (SerialNumber) DO NOTHING"};
|
||||
|
||||
DeviceDetails.modified = Utils::Now();
|
||||
DeviceDetails.CreationTimestamp = DeviceDetails.LastConfigurationDownload =
|
||||
DeviceDetails.UUID = DeviceDetails.LastConfigurationChange = Now;
|
||||
|
||||
if (Cfg.Valid() && Cfg.SetUUID(DeviceDetails.UUID)) {
|
||||
|
||||
DeviceDetails.Configuration = Cfg.get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
std::string St2{"INSERT INTO Devices ( " + DB_DeviceSelectFields + " ) " +
|
||||
DB_DeviceInsertValues};
|
||||
|
||||
SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID);
|
||||
DeviceRecordTuple R;
|
||||
ConvertDeviceRecord(DeviceDetails, R);
|
||||
Insert << ConvertParams(St2), Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID);
|
||||
SerialNumberCache()->AddSerialNumber(DeviceDetails.SerialNumber);
|
||||
return true;
|
||||
} else {
|
||||
poco_warning(Logger(), "Cannot create device: invalid configuration.");
|
||||
return false;
|
||||
}
|
||||
SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID);
|
||||
DeviceRecordTuple R;
|
||||
ConvertDeviceRecord(DeviceDetails, R);
|
||||
Insert << ConvertParams(St2), Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
Sess.commit();
|
||||
SetCurrentConfigurationID(DeviceDetails.SerialNumber, DeviceDetails.UUID);
|
||||
SerialNumberCache()->AddSerialNumber(DeviceDetails.SerialNumber);
|
||||
} else {
|
||||
poco_warning(Logger(), fmt::format("Device {} already exists.", SerialNumber));
|
||||
poco_warning(Logger(), "Cannot create device: invalid configuration.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CreateDevice(LockedDbSession &Session, GWObjects::Device &DeviceDetails) {
|
||||
try {
|
||||
std::lock_guard Lock(Session.Mutex());
|
||||
return CreateDevice(Session.Session(), DeviceDetails);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CreateDevice(GWObjects::Device &DeviceDetails) {
|
||||
try {
|
||||
auto Session = Pool_->get();
|
||||
return CreateDevice(Session, DeviceDetails);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
@@ -447,16 +498,45 @@ namespace OpenWifi {
|
||||
return FoundCountry;
|
||||
}
|
||||
|
||||
#define __DBGLOG__ std::cout << __LINE__ << std::endl;
|
||||
bool Storage::DeleteSimulatedDevice([[maybe_unused]] const std::string &SerialNumber) {
|
||||
|
||||
bool Storage::CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
|
||||
std::vector<std::string> Statements =
|
||||
{
|
||||
"delete from commandlist using devices where commandlist.serialnumber=devices.serialnumber and devices.simulated=true;",
|
||||
"delete from healthchecks using devices where healthchecks.serialnumber=devices.serialnumber and devices.simulated=true;",
|
||||
"delete from statistics using devices where statistics.serialnumber=devices.serialnumber and devices.simulated=true;",
|
||||
"delete from devicelogs using devices where devicelogs.serialnumber=devices.serialnumber and devices.simulated=true;",
|
||||
"delete from capabilities using devices where capabilities.serialnumber=devices.serialnumber and devices.simulated=true;",
|
||||
"delete from devices where devices.simulated=true;"
|
||||
};
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Command(Sess);
|
||||
|
||||
for (const auto &i : Statements) {
|
||||
try {
|
||||
Command << i, Poco::Data::Keywords::now;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
Command.reset(Sess);
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Storage::CreateDefaultDevice(Poco::Data::Session &Session, std::string &SerialNumber, const Config::Capabilities &Caps,
|
||||
std::string &Firmware,
|
||||
const Poco::Net::IPAddress &IPAddress,
|
||||
bool simulated) {
|
||||
|
||||
GWObjects::Device D;
|
||||
poco_information(Logger(), fmt::format("AUTO-CREATION({})", SerialNumber));
|
||||
uint64_t Now = time(nullptr);
|
||||
|
||||
// poco_information(Logger(), fmt::format("AUTO-CREATION({}): Start.", SerialNumber));
|
||||
uint64_t Now = Utils::Now();
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
|
||||
if (!Caps.Platform().empty() && !Caps.Compatible().empty()) {
|
||||
@@ -499,12 +579,13 @@ namespace OpenWifi {
|
||||
D.Notes = SecurityObjects::NoteInfoVec{
|
||||
SecurityObjects::NoteInfo{(uint64_t)Utils::Now(), "", "Auto-provisioned."}};
|
||||
|
||||
CreateDeviceCapabilities(SerialNumber, Caps);
|
||||
|
||||
return CreateDevice(D);
|
||||
CreateDeviceCapabilities(Session, SerialNumber, Caps);
|
||||
auto Result = CreateDevice(Session, D);
|
||||
poco_information(Logger(), fmt::format("AUTO-CREATION({}): Done, Result={}", SerialNumber, Result));
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool Storage::GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy) {
|
||||
/* bool Storage::GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
@@ -519,46 +600,19 @@ namespace OpenWifi {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetDevicePassword(std::string &SerialNumber, std::string &Password) {
|
||||
*/
|
||||
bool Storage::SetDevicePassword(LockedDbSession &Sess, std::string &SerialNumber, std::string &Password) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::lock_guard Lock(Sess.Mutex());
|
||||
Sess.Session().begin();
|
||||
|
||||
Poco::Data::Statement Update(Sess.Session());
|
||||
std::string St{"UPDATE Devices SET DevicePassword=? WHERE SerialNumber=?"};
|
||||
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(Password),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetConnectInfo(std::string &SerialNumber, std::string &Firmware) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
// Get the old version and if they do not match, set the last date
|
||||
std::string St{"SELECT Firmware FROM Devices WHERE SerialNumber=?"};
|
||||
std::string TmpFirmware;
|
||||
Select << ConvertParams(St), Poco::Data::Keywords::into(TmpFirmware),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Select.execute();
|
||||
|
||||
if (TmpFirmware != Firmware) {
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::string St2{
|
||||
"UPDATE Devices SET Firmware=?, LastFWUpdate=? WHERE SerialNumber=?"};
|
||||
uint64_t Now = Utils::Now();
|
||||
|
||||
Update << ConvertParams(St2), Poco::Data::Keywords::use(Firmware),
|
||||
Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
return true;
|
||||
}
|
||||
Sess.Session().commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -574,12 +628,14 @@ namespace OpenWifi {
|
||||
for (const auto &tableName : TableNames) {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St = fmt::format("DELETE FROM {} WHERE SerialNumber='{}'", tableName, SerialNumber);
|
||||
try {
|
||||
Delete << St;
|
||||
Delete.execute();
|
||||
Sess.commit();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
@@ -652,11 +708,9 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetDevice(std::string &SerialNumber, GWObjects::Device &DeviceDetails) {
|
||||
bool Storage::GetDevice(Poco::Data::Session &Session, std::string &SerialNumber, GWObjects::Device &DeviceDetails) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
Poco::Data::Statement Select(Session);
|
||||
std::string St{"SELECT " + DB_DeviceSelectFields +
|
||||
" FROM Devices WHERE SerialNumber=?"};
|
||||
|
||||
@@ -675,6 +729,26 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetDevice(std::string &SerialNumber, GWObjects::Device &DeviceDetails) {
|
||||
try {
|
||||
auto Sess = Pool_->get();
|
||||
return GetDevice(Sess, SerialNumber, DeviceDetails);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetDevice(LockedDbSession &Session, std::string &SerialNumber, GWObjects::Device &DeviceDetails) {
|
||||
try {
|
||||
std::lock_guard Lock(Session.Mutex());
|
||||
return GetDevice(Session.Session(), SerialNumber, DeviceDetails);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::DeviceExists(std::string &SerialNumber) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
@@ -701,6 +775,26 @@ namespace OpenWifi {
|
||||
bool Storage::UpdateDevice(GWObjects::Device &NewDeviceDetails) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
return UpdateDevice(Sess, NewDeviceDetails);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::UpdateDevice(LockedDbSession &Session, GWObjects::Device &NewDeviceDetails) {
|
||||
try {
|
||||
std::lock_guard Lock(Session.Mutex());
|
||||
return UpdateDevice(Session.Session(), NewDeviceDetails);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::UpdateDevice(Poco::Data::Session &Sess, GWObjects::Device &NewDeviceDetails) {
|
||||
try {
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
DeviceRecordTuple R;
|
||||
@@ -713,6 +807,7 @@ namespace OpenWifi {
|
||||
Update << ConvertParams(St2), Poco::Data::Keywords::use(R),
|
||||
Poco::Data::Keywords::use(NewDeviceDetails.SerialNumber);
|
||||
Update.execute();
|
||||
Sess.commit();
|
||||
// GetDevice(NewDeviceDetails.SerialNumber,NewDeviceDetails);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
@@ -35,10 +35,11 @@ namespace OpenWifi {
|
||||
R.set<4>(H.Recorded);
|
||||
}
|
||||
|
||||
bool Storage::AddHealthCheckData(const GWObjects::HealthCheck &Check) {
|
||||
bool Storage::AddHealthCheckData(LockedDbSession &Session, const GWObjects::HealthCheck &Check) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
std::lock_guard Guard(Session.Mutex());
|
||||
Session.Session().begin();
|
||||
Poco::Data::Statement Insert(Session.Session());
|
||||
|
||||
std::string St{"INSERT INTO HealthChecks ( " + DB_HealthCheckSelectFields +
|
||||
" ) VALUES( " + DB_HealthCheckInsertValues + " )"};
|
||||
@@ -47,6 +48,7 @@ namespace OpenWifi {
|
||||
ConvertHealthCheckRecord(Check, R);
|
||||
Insert << ConvertParams(St), Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
Session.Session().commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -134,7 +136,7 @@ namespace OpenWifi {
|
||||
uint64_t ToDate) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
Sess.begin();
|
||||
bool DatesIncluded = (FromDate != 0 || ToDate != 0);
|
||||
|
||||
std::string Prefix{"DELETE FROM HealthChecks "};
|
||||
@@ -158,7 +160,7 @@ namespace OpenWifi {
|
||||
Delete << Statement + DateSelector;
|
||||
|
||||
Delete.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -170,11 +172,13 @@ namespace OpenWifi {
|
||||
bool Storage::RemoveHealthChecksRecordsOlderThan(uint64_t Date) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St1{"delete from HealthChecks where recorded<?"};
|
||||
Delete << ConvertParams(St1), Poco::Data::Keywords::use(Date);
|
||||
Delete.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
|
||||
@@ -39,11 +39,11 @@ namespace OpenWifi {
|
||||
R.set<6>(Log.UUID);
|
||||
}
|
||||
|
||||
bool Storage::AddLog(const GWObjects::DeviceLog &Log) {
|
||||
bool Storage::AddLog(LockedDbSession &Session, const GWObjects::DeviceLog &Log) {
|
||||
try {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
std::lock_guard Guard(Session.Mutex());
|
||||
Session.Session().begin();
|
||||
Poco::Data::Statement Insert(Session.Session());
|
||||
|
||||
std::string St{"INSERT INTO DeviceLogs (" + DB_LogsSelectFields + ") values( " +
|
||||
DB_LogsInsertValues + " )"};
|
||||
@@ -53,6 +53,7 @@ namespace OpenWifi {
|
||||
|
||||
Insert << ConvertParams(St), Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
Session.Session().commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -114,7 +115,7 @@ namespace OpenWifi {
|
||||
uint64_t Type) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
Sess.begin();
|
||||
bool DatesIncluded = (FromDate != 0 || ToDate != 0);
|
||||
bool HasWhere = DatesIncluded || !SerialNumber.empty();
|
||||
|
||||
@@ -141,7 +142,7 @@ namespace OpenWifi {
|
||||
Delete << StatementStr + DateSelector + TypeSelector;
|
||||
|
||||
Delete.execute();
|
||||
Delete.reset(Sess);
|
||||
Sess.commit();
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -183,11 +184,13 @@ namespace OpenWifi {
|
||||
bool Storage::RemoveDeviceLogsRecordsOlderThan(uint64_t Date) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess.begin();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St1{"delete from DeviceLogs where recorded<?"};
|
||||
Delete << ConvertParams(St1), Poco::Data::Keywords::use(Date);
|
||||
Delete.execute();
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -33,10 +32,10 @@ namespace OpenWifi {
|
||||
R.set<3>(Stats.Recorded);
|
||||
}
|
||||
|
||||
bool Storage::AddStatisticsData(const GWObjects::Statistics &Stats) {
|
||||
bool Storage::AddStatisticsData(Poco::Data::Session &Session, const GWObjects::Statistics &Stats) {
|
||||
try {
|
||||
Poco::Data::Session Sess(Pool_->get());
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
Session.begin();
|
||||
Poco::Data::Statement Insert(Session);
|
||||
|
||||
poco_trace(Logger(), fmt::format("{}: Adding stats. Size={}", Stats.SerialNumber,
|
||||
std::to_string(Stats.Data.size())));
|
||||
@@ -46,6 +45,7 @@ namespace OpenWifi {
|
||||
ConvertStatsRecord(Stats, R);
|
||||
Insert << ConvertParams(St), Poco::Data::Keywords::use(R);
|
||||
Insert.execute();
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
@@ -167,7 +167,7 @@ namespace OpenWifi {
|
||||
uint64_t ToDate) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
Sess.begin();
|
||||
bool DatesIncluded = (FromDate != 0 || ToDate != 0);
|
||||
|
||||
std::string Prefix{"DELETE FROM Statistics "};
|
||||
@@ -189,7 +189,7 @@ namespace OpenWifi {
|
||||
Poco::Data::Statement Select(Sess);
|
||||
Select << Statement + DateSelector;
|
||||
Select.execute();
|
||||
|
||||
Sess.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger(), (fmt::format("{}: Failed with: {}", std::string(__func__),
|
||||
|
||||
@@ -40,12 +40,15 @@ namespace OpenWifi {
|
||||
Sess << "CREATE INDEX IF NOT EXISTS StatsSerial ON Statistics (SerialNumber ASC, "
|
||||
"Recorded ASC)",
|
||||
Poco::Data::Keywords::now;
|
||||
Sess << "CREATE INDEX IF NOT EXISTS StatsSerial0 ON Statistics (SerialNumber ASC)",
|
||||
Poco::Data::Keywords::now;
|
||||
} else if (dbType_ == mysql) {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS Statistics ("
|
||||
"SerialNumber VARCHAR(30), "
|
||||
"UUID INTEGER, "
|
||||
"Data TEXT, "
|
||||
"Recorded BIGINT, "
|
||||
"INDEX StatSerial0 (SerialNumber)), ",
|
||||
"INDEX StatSerial (SerialNumber ASC, Recorded ASC))",
|
||||
Poco::Data::Keywords::now;
|
||||
}
|
||||
@@ -90,7 +93,9 @@ namespace OpenWifi {
|
||||
"restrictionDetails TEXT, "
|
||||
"pendingUUID BIGINT, "
|
||||
"simulated BOOLEAN,"
|
||||
"lastRecordedContact BIGINT"
|
||||
"lastRecordedContact BIGINT,"
|
||||
"certificateExpiryDate BIGINT,"
|
||||
"connectReason TEXT"
|
||||
",INDEX DeviceOwner (Owner ASC),"
|
||||
"INDEX LocationIndex (Location ASC))",
|
||||
Poco::Data::Keywords::now;
|
||||
@@ -124,7 +129,9 @@ namespace OpenWifi {
|
||||
"restrictionDetails TEXT,"
|
||||
"pendingUUID BIGINT, "
|
||||
"simulated BOOLEAN, "
|
||||
"lastRecordedContact BIGINT"
|
||||
"lastRecordedContact BIGINT,"
|
||||
"certificateExpiryDate BIGINT,"
|
||||
"connectReason TEXT"
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
Sess << "CREATE INDEX IF NOT EXISTS DeviceOwner ON Devices (Owner ASC)",
|
||||
@@ -145,7 +152,9 @@ namespace OpenWifi {
|
||||
"alter table devices add column restrictionDetails TEXT",
|
||||
"alter table devices add column pendingUUID bigint",
|
||||
"alter table devices add column lastRecordedContact bigint",
|
||||
"alter table devices add column simulated boolean"
|
||||
"alter table devices add column simulated boolean",
|
||||
"alter table devices add column certificateExpiryDate bigint",
|
||||
"alter table devices add column connectReason TEXT"
|
||||
};
|
||||
|
||||
for (const auto &i : Script) {
|
||||
|
||||
@@ -83,82 +83,77 @@ setgateway() {
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
rawurl="$(cat < ${result_file} | jq -r '.endpoints[] | select( .type == "owgw" ) | .uri')"
|
||||
if [[ ! -z "${rawurl}" ]]; then
|
||||
proto="$(echo "$rawurl" | grep :// | sed -e's,^\(.*://\).*,\1,g')"
|
||||
# shellcheck disable=SC2116
|
||||
url="$(echo "${rawurl/$proto/}")"
|
||||
user="$(echo $url | grep @ | cut -d@ -f1)"
|
||||
hostport="$(echo ${url/$user@/} | cut -d/ -f1)"
|
||||
host="$(echo $hostport | sed -e 's,:.*,,g')"
|
||||
port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')"
|
||||
path="$(echo $url | grep / | cut -d/ -f2-)"
|
||||
export OWGW=${url}
|
||||
echo "Using ${OWGW}..."
|
||||
else
|
||||
echo "OWGW endpoint is not found:"
|
||||
jq < ${result_file}
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
export OWGW=${OWGW_OVERRIDE}
|
||||
proto="$(echo "$rawurl" | grep :// | sed -e's,^\(.*://\).*,\1,g')"
|
||||
url="$(echo "${rawurl/$proto/}")"
|
||||
user="$(echo $url | grep @ | cut -d@ -f1)"
|
||||
export OWGW=${url}
|
||||
echo "Using ${OWGW}..."
|
||||
else
|
||||
echo "OWGW endpoint is not found:"
|
||||
jq < ${result_file}
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
export OWGW=${OWGW_OVERRIDE}
|
||||
fi
|
||||
}
|
||||
|
||||
logout() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
rm -rf token.json
|
||||
}
|
||||
|
||||
getdevice() {
|
||||
curl ${FLAGS} -X GET --url "https://${OWGW}/api/v1/device/$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
curl ${FLAGS} -X GET --url "https://${OWGW}/api/v1/device/$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
getcommand() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/command/$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletecommand() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/command/$1" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
}
|
||||
|
||||
listcommands() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/commands?serialNumber=$1&limit=300" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
newestcommands() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/commands?serialNumber=$1&newest=true&limit=50" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletecommands() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/commands?serialNumber=$1" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
}
|
||||
|
||||
getcapabilities() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/device/$1/capabilities" \
|
||||
-H "accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletecapabilities() {
|
||||
@@ -169,42 +164,42 @@ deletecapabilities() {
|
||||
|
||||
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}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletesimdevices() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?simulatedOnly=true&macPattern=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletebulkdevices() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?macPattern=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
listdevicesk() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "X-API-KEY: $1" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "X-API-KEY: $1" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
ldevs() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices?offset=$1&limit=$2" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletedevice() {
|
||||
@@ -660,7 +655,7 @@ validateconfig() {
|
||||
wstest() {
|
||||
echo "Token:${token}"
|
||||
wscat \
|
||||
-c wss://${OWGW}/api/v1/ws
|
||||
-c wss://"${OWGW}"/api/v1/ws
|
||||
}
|
||||
|
||||
telemetry() {
|
||||
@@ -712,7 +707,7 @@ telemetry_to_kafka() {
|
||||
}
|
||||
|
||||
runscript() {
|
||||
scriptcontent=$(base64 -i $3)
|
||||
scriptcontent=$(base64 -i "$3")
|
||||
payload="$(printf '{ "serialNumber": "%s", "type": "%s" , "timeout": 30, "script" : "%s" , "deferred" : false, "when" : 0 }' "$1" "$2" "$scriptcontent" )"
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/script" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -734,61 +729,61 @@ runscriptname() {
|
||||
|
||||
deviceping() {
|
||||
payload="$(printf '{ "serialNumber": "%s" }' "$1" )"
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/ping" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/ping" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
caplist() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/capabilities" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
iptocountry() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/iptocountry?iplist=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
setradiusconfig() {
|
||||
curl ${FLAGS} -X PUT "https://${OWGW}/api/v1/radiusProxyConfig" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-d "@${1}" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-d "@${1}" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
getradiusconfig() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusProxyConfig" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deleteradiusconfig() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/radiusProxyConfig" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
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}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
testtoken() {
|
||||
@@ -836,92 +831,129 @@ stats7count() {
|
||||
|
||||
listscripts() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/scripts" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
getscript() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/script/$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
regulatory() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/regulatory?countries=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
regulatory_reload() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/regulatory?reload=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiussessions() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiussearch() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?userName=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiussearchmac() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?mac=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiusaps() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?serialNumberOnly=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiuscoadm() {
|
||||
payload="$(printf '{ "accountingSessionId": "%s", "accountingMultiSessionId": "%s" , "callingStationId": "%s" }' "$2" "$3" "$4" )"
|
||||
curl ${FLAGS} -X PUT "https://${OWGW}/api/v1/radiusSessions/$1?operation=coadm" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
listdefaultfirmwares() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/default_firmwares" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
getdefaultfirmware() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/default_firmware/$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
transferdevice() {
|
||||
payload="$(printf '{ "serialNumber": "%s", "server": "%s" , "port": %s}' "$1" "$2" "$3")"
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/transfer" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
certupdate() {
|
||||
payload="$(printf '{ "serialNumber": "%s", "encodedCertificate": "%s"}' "$1" "$2")"
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/certupdate" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
rrm_kick() {
|
||||
payload="$(printf '{ "actions" : [{ "action": "kick", "addr": "%s", "reason": %s, "ban_time": %s}] }' "$2" "$3" "$4")"
|
||||
echo "$payload"
|
||||
curl ${FLAGS} -X POST "https://${OWGW}/api/v1/device/$1/rrm" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletesimulateddevices() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?simulatedDevices=true" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}"
|
||||
}
|
||||
|
||||
check_response() {
|
||||
@@ -1210,6 +1242,10 @@ case "$1" in
|
||||
"deletebulkdevices") login; deletebulkdevices "$2"; logout;;
|
||||
"listdefaultfirmwares") login; listdefaultfirmwares; logout;;
|
||||
"getdefaultfirmware") login; getdefaultfirmware "$2"; logout;;
|
||||
"transferdevice") login; transferdevice "$2" "$3" "$4"; logout;;
|
||||
"certupdate") login; certupdate "$2" "$3"; logout;;
|
||||
"rrm_kick") login; rrm_kick "$2" "$3" "$4" "$5"; logout;;
|
||||
"deletesimulateddevices") login; deletesimulateddevices ; logout;;
|
||||
"testtoken") testtoken;;
|
||||
*) help ;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user