mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-11-02 11:47:47 +00:00
Compare commits
188 Commits
v2.9.0-RC3
...
v2.10.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67aef046ac | ||
|
|
ed47e1d7e9 | ||
|
|
abfe38b6fc | ||
|
|
b8673c2dcc | ||
|
|
1974622104 | ||
|
|
13e8ceb7e3 | ||
|
|
6c112c21a7 | ||
|
|
1ca76459fe | ||
|
|
52ebfd30b9 | ||
|
|
44822e5a63 | ||
|
|
2561fb5cd4 | ||
|
|
96f25fd949 | ||
|
|
ccbc6307e6 | ||
|
|
39e625bb34 | ||
|
|
8fd4e57fe8 | ||
|
|
192b2d50b4 | ||
|
|
6dd67a8218 | ||
|
|
3edfb11c33 | ||
|
|
fd607bf963 | ||
|
|
c68cd6aad8 | ||
|
|
f4674e93c7 | ||
|
|
21a4eb2a71 | ||
|
|
ed336bec0c | ||
|
|
b5f8063ab7 | ||
|
|
69dc1b8056 | ||
|
|
a933376bf6 | ||
|
|
21a4245204 | ||
|
|
bcfbc0d2c0 | ||
|
|
f453205a5d | ||
|
|
a8d3ed0dba | ||
|
|
42ab4717d5 | ||
|
|
a36796ab4e | ||
|
|
cd9a4f9902 | ||
|
|
806f39bc88 | ||
|
|
6afeb470d9 | ||
|
|
991d60e019 | ||
|
|
5cebcdd675 | ||
|
|
fdb09654c2 | ||
|
|
a657ce2f52 | ||
|
|
7b17af5575 | ||
|
|
cc2b9e536f | ||
|
|
1a8a0b2ebc | ||
|
|
c808d0146c | ||
|
|
0bb107b48d | ||
|
|
a4f2b8fd5e | ||
|
|
4fd9b4f540 | ||
|
|
d51980e0e5 | ||
|
|
5ece25ebac | ||
|
|
d578174b23 | ||
|
|
08689107da | ||
|
|
0d680934f8 | ||
|
|
907d739943 | ||
|
|
e5665769ef | ||
|
|
8abbc73546 | ||
|
|
0c86ffdfff | ||
|
|
c0f59756ae | ||
|
|
41dd567630 | ||
|
|
6d87fafbc0 | ||
|
|
dddc4f34ac | ||
|
|
9a99bcd2c2 | ||
|
|
e849a3eba0 | ||
|
|
decb2bf8c2 | ||
|
|
0ae5dc5cf9 | ||
|
|
9160497b28 | ||
|
|
9a4e19c651 | ||
|
|
62bfb10ca3 | ||
|
|
9e3d80f1ea | ||
|
|
fc3b516c76 | ||
|
|
ac183fcde6 | ||
|
|
7ebc977601 | ||
|
|
ec94cdb2df | ||
|
|
9c61451f0f | ||
|
|
d08afb6d75 | ||
|
|
087ea5372b | ||
|
|
b882796c90 | ||
|
|
91c6a8fba1 | ||
|
|
2e69ca7444 | ||
|
|
58c08c3ff7 | ||
|
|
737f1146a1 | ||
|
|
0f85f2453b | ||
|
|
a8c4cf1940 | ||
|
|
cf320e63ee | ||
|
|
95a11e8f96 | ||
|
|
bf611d36cc | ||
|
|
b543e03660 | ||
|
|
c1e101366e | ||
|
|
47f21ae17e | ||
|
|
c1dd0151f9 | ||
|
|
80efb654d5 | ||
|
|
2ef9a9220f | ||
|
|
c27edec0f7 | ||
|
|
c8a65d6137 | ||
|
|
f408a44898 | ||
|
|
4f289427ca | ||
|
|
2b89cc187b | ||
|
|
59dc2ad032 | ||
|
|
0d6e2c0e33 | ||
|
|
37a02b699d | ||
|
|
9772e95238 | ||
|
|
f4d86120c4 | ||
|
|
384d11d998 | ||
|
|
5f8ea6a474 | ||
|
|
9769a9fa24 | ||
|
|
4d16155aec | ||
|
|
00ca2a6d92 | ||
|
|
ecddb5ba63 | ||
|
|
6fe5298602 | ||
|
|
1c3c7ec842 | ||
|
|
e547ee40b0 | ||
|
|
81806df5cb | ||
|
|
3b9c574149 | ||
|
|
4159ba4dca | ||
|
|
a1eb8ab3d0 | ||
|
|
2fb316b79e | ||
|
|
ad3319496d | ||
|
|
38a7d35c4b | ||
|
|
3c6e24e50f | ||
|
|
b127f38081 | ||
|
|
82cdc4cc03 | ||
|
|
2566237c91 | ||
|
|
562c952d52 | ||
|
|
23d160cba1 | ||
|
|
8cbe0b7c4f | ||
|
|
d804dad1f0 | ||
|
|
72595922eb | ||
|
|
f1c330eac7 | ||
|
|
f143471723 | ||
|
|
957e6acf03 | ||
|
|
a6bc509c3d | ||
|
|
5fd145c7d6 | ||
|
|
f9b431e566 | ||
|
|
a35acfeb88 | ||
|
|
e028b2dd41 | ||
|
|
69e539ffbe | ||
|
|
4a8506f4fe | ||
|
|
2621e2fdde | ||
|
|
8425632453 | ||
|
|
bce03ee024 | ||
|
|
b6f76b70ab | ||
|
|
30e62dd203 | ||
|
|
ae9179eb0e | ||
|
|
0d59e8b0c2 | ||
|
|
545f787a4e | ||
|
|
64199bbb62 | ||
|
|
1ac4625947 | ||
|
|
b45c16f2c0 | ||
|
|
86a33ed818 | ||
|
|
65c4a96f41 | ||
|
|
b7908816a9 | ||
|
|
dc55a3a180 | ||
|
|
4b953d968b | ||
|
|
81324da9e8 | ||
|
|
54d94eef84 | ||
|
|
397799278c | ||
|
|
d8d0eed1fb | ||
|
|
d1eb584430 | ||
|
|
c76e10299d | ||
|
|
2949231f67 | ||
|
|
d6731e4e5b | ||
|
|
d92b064561 | ||
|
|
ec4a7f64de | ||
|
|
14877301e4 | ||
|
|
d92cba15bb | ||
|
|
33d92c9240 | ||
|
|
737ed24d91 | ||
|
|
670f497af4 | ||
|
|
11ba1cc6e4 | ||
|
|
c69c4754cf | ||
|
|
8478d761db | ||
|
|
500a4dc130 | ||
|
|
c420d9c572 | ||
|
|
c94d90911f | ||
|
|
04fd524b52 | ||
|
|
b49744779e | ||
|
|
60de792147 | ||
|
|
e6d6da53c7 | ||
|
|
cd62cb8b84 | ||
|
|
85eb8546c3 | ||
|
|
bc5a8bbe5b | ||
|
|
d92a93a872 | ||
|
|
0def242b40 | ||
|
|
eeb5e2d3be | ||
|
|
e76132f464 | ||
|
|
ac41327bf8 | ||
|
|
0084b5d21c | ||
|
|
69b4de1b74 | ||
|
|
0c3e8d4630 | ||
|
|
af739bc32b |
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@@ -2,5 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/rapidjson-test" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owgw VERSION 2.9.0)
|
||||
project(owgw VERSION 2.10.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -144,9 +144,14 @@ add_executable( owgw
|
||||
src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h
|
||||
src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
|
||||
src/RESTAPI/RESTAPI_telemetryWebSocket.cpp src/RESTAPI/RESTAPI_telemetryWebSocket.h
|
||||
src/RESTAPI/RESTAPI_scripts_handler.cpp src/RESTAPI/RESTAPI_scripts_handler.h
|
||||
src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h
|
||||
src/RESTAPI/RESTAPI_regulatory.cpp src/RESTAPI/RESTAPI_regulatory.h
|
||||
src/RESTAPI/RESTAPI_radiussessions_handler.cpp src/RESTAPI/RESTAPI_radiussessions_handler.h
|
||||
src/storage/storage_blacklist.cpp src/storage/storage_tables.cpp src/storage/storage_logs.cpp
|
||||
src/storage/storage_command.cpp src/storage/storage_healthcheck.cpp src/storage/storage_statistics.cpp
|
||||
src/storage/storage_device.cpp src/storage/storage_capabilities.cpp src/storage/storage_defconfig.cpp
|
||||
src/storage/storage_scripts.cpp src/storage/storage_scripts.h
|
||||
src/storage/storage_tables.cpp
|
||||
src/RESTAPI/RESTAPI_routers.cpp
|
||||
src/Daemon.cpp src/Daemon.h
|
||||
@@ -195,7 +200,18 @@ add_executable( owgw
|
||||
src/AP_WS_Process_telemetry.cpp
|
||||
src/AP_WS_Process_venuebroadcast.cpp
|
||||
src/RADSEC_server.h
|
||||
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h src/framework/RESTAPI_SystemConfiguration.h src/ScriptManager.cpp src/ScriptManager.h src/RESTAPI/RESTAPI_scripts_handler.cpp src/RESTAPI/RESTAPI_scripts_handler.h src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h src/storage/storage_scripts.cpp src/storage/storage_scripts.h src/SignatureMgr.h src/AP_WS_Process_event.cpp src/AP_WS_Process_wifiscan.cpp src/AP_WS_Process_alarm.cpp src/GWKafkaEvents.cpp src/GWKafkaEvents.h src/RegulatoryInfo.cpp src/RegulatoryInfo.h src/RESTAPI/RESTAPI_regulatory.cpp src/RESTAPI/RESTAPI_regulatory.h)
|
||||
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h
|
||||
src/framework/RESTAPI_SystemConfiguration.h
|
||||
src/ScriptManager.cpp src/ScriptManager.h
|
||||
src/SignatureMgr.h
|
||||
src/AP_WS_Process_event.cpp
|
||||
src/AP_WS_Process_wifiscan.cpp
|
||||
src/AP_WS_Process_alarm.cpp
|
||||
src/GWKafkaEvents.cpp src/GWKafkaEvents.h
|
||||
src/RegulatoryInfo.cpp src/RegulatoryInfo.h
|
||||
src/RADIUSSessionTracker.cpp src/RADIUSSessionTracker.h
|
||||
src/libs/Scheduler.h src/libs/InterruptableSleep.h src/libs/ctpl_stl.h src/libs/Cron.h
|
||||
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
|
||||
|
||||
25
PROTOCOL.md
25
PROTOCOL.md
@@ -149,18 +149,35 @@ The `severity` matches the `syslog` levels. Here are the details:
|
||||
- 7 : LOG_DEBUG 7 /* debug-level messages */
|
||||
|
||||
#### Crash Log event
|
||||
Device may send a crash log event after rebooting after a crash. The event cannot be sent until a connection event has been sent.
|
||||
Device may send a `crash log event` during rebooting after a crash. The event cannot be sent until a connection event has been established.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "crashlog" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"uuid" : <the UUID of the configuration that generated the crash log>,
|
||||
"loglines" : [ an array of strings representing the logs from the log file ]
|
||||
"serial" : <serial number> ,
|
||||
"uuid" : <the UUID of the configuration that generated the crash log>,
|
||||
"loglines" : [ an array of strings representing the logs from the log file ]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Reboot Log event
|
||||
The device may send a `reboot log event` after a reboot. This maybe a scheduled reboot or caused in some other way.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "rebootLog" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"uuid" : <the UUID of the configuration that generated the reboot log>,
|
||||
"date" : <Unix time when this reboot occurred>,
|
||||
"type" : <string>,
|
||||
"info" : [ "info 1", "info 2"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here is a possible list of reboot reasons:
|
||||
|
||||
#### Config change pending event
|
||||
Device sends this message to tell the controller that the device
|
||||
has received a configuration but is still running an older configuration. The controller will not
|
||||
|
||||
@@ -74,6 +74,8 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
|
||||
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
|
||||
CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
|
||||
IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
|
||||
DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
|
||||
envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
|
||||
fi
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owgw:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
|
||||
tag: v2.9.0-RC2
|
||||
tag: v2.10.0
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
|
||||
22213
issues/OWGW Logs.txt
Normal file
22213
issues/OWGW Logs.txt
Normal file
File diff suppressed because it is too large
Load Diff
2158
issues/OWLS Logs.rtf
Normal file
2158
issues/OWLS Logs.rtf
Normal file
File diff suppressed because it is too large
Load Diff
2154
issues/OWLS Logs.txt
Normal file
2154
issues/OWLS Logs.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ openapi: 3.0.1
|
||||
info:
|
||||
title: uCentral gateway API
|
||||
description: A process to manage configuration for devices.
|
||||
version: 2.5.0
|
||||
version: 2.10.0
|
||||
license:
|
||||
name: BSD3
|
||||
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
@@ -152,6 +152,11 @@ components:
|
||||
format: uuid
|
||||
restrictionDetails:
|
||||
$ref: '#/components/schemas/DeviceRestrictions'
|
||||
simulated:
|
||||
type: boolean
|
||||
lastRecordedContact:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
DeviceWithStatus:
|
||||
type: object
|
||||
@@ -260,6 +265,22 @@ components:
|
||||
format: uuid
|
||||
restrictionDetails:
|
||||
$ref: '#/components/schemas/DeviceRestrictions'
|
||||
hasGPS:
|
||||
type: boolean
|
||||
sanity:
|
||||
type: integer
|
||||
format: int64
|
||||
memoryUsed:
|
||||
type: number
|
||||
format: float
|
||||
load:
|
||||
type: number
|
||||
format: float
|
||||
temperature:
|
||||
type: number
|
||||
format: float
|
||||
connectReason:
|
||||
type: string
|
||||
|
||||
DeviceList:
|
||||
type: object
|
||||
@@ -329,6 +350,9 @@ components:
|
||||
associations_5G:
|
||||
type: integer
|
||||
format: int64
|
||||
associations_6G:
|
||||
type: integer
|
||||
format: int64
|
||||
verifiedCertificate:
|
||||
type: string
|
||||
enum:
|
||||
@@ -336,6 +360,7 @@ components:
|
||||
- VALID_CERTIFICATE,
|
||||
- MISMATCH_SERIAL,
|
||||
- VERIFIED
|
||||
- SIMULATED
|
||||
|
||||
DeviceCapabilities:
|
||||
type: object
|
||||
@@ -420,7 +445,7 @@ components:
|
||||
type: string
|
||||
|
||||
CommandSubmitSuccess:
|
||||
description: The command was submitted succesfully.
|
||||
description: The command was submitted successfully.
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
@@ -458,6 +483,10 @@ components:
|
||||
logType:
|
||||
type: integer
|
||||
format: int64
|
||||
example:
|
||||
- 0 normal logs
|
||||
- 1 crash logs
|
||||
- 2 reboot logs
|
||||
UUID:
|
||||
type: integer
|
||||
format: int64
|
||||
@@ -1269,6 +1298,67 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/RadiusProxyPool'
|
||||
|
||||
RadiusSession:
|
||||
type: object
|
||||
properties:
|
||||
started:
|
||||
type: integer
|
||||
format: int64
|
||||
lastTransaction:
|
||||
type: integer
|
||||
format: int64
|
||||
inputPackets:
|
||||
type: integer
|
||||
format: int64
|
||||
outputPackets:
|
||||
type: integer
|
||||
format: int64
|
||||
inputOctets:
|
||||
type: integer
|
||||
format: int64
|
||||
outputOctets:
|
||||
type: integer
|
||||
format: int64
|
||||
inputGigaWords:
|
||||
type: integer
|
||||
format: int64
|
||||
outputGigaWords:
|
||||
type: integer
|
||||
format: int64
|
||||
sessionTime:
|
||||
type: integer
|
||||
format: int64
|
||||
destination:
|
||||
type: string
|
||||
userName:
|
||||
type: string
|
||||
accountingSessionId:
|
||||
type: string
|
||||
accountingMultiSessionId:
|
||||
type: string
|
||||
callingStationId:
|
||||
type: string
|
||||
|
||||
RadiusSessionList:
|
||||
type: object
|
||||
properties:
|
||||
sessions:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RadiusSession'
|
||||
|
||||
RadiusCoADMParameters:
|
||||
type: object
|
||||
properties:
|
||||
accountingSessionId:
|
||||
type: string
|
||||
accountingMultiSessionId:
|
||||
type: string
|
||||
callingStationId:
|
||||
type: string
|
||||
chargeableUserIdentity:
|
||||
type: string
|
||||
|
||||
paths:
|
||||
/devices:
|
||||
get:
|
||||
@@ -1377,6 +1467,54 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- Devices
|
||||
summary: Delete a list of devices matching a criteria
|
||||
description: Delete a list of devices matching a criteria
|
||||
operationId: deleteDeviceList
|
||||
parameters:
|
||||
- in: query
|
||||
description: Supply a list of devices comma separated
|
||||
name: select
|
||||
schema:
|
||||
type: string
|
||||
example: serial1,serial2,serial3
|
||||
required: false
|
||||
- in: query
|
||||
description: Only simulated devices
|
||||
name: simulatedOnly
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
- in: query
|
||||
description: MAC address must match this pattern. Mutually exclusive with oldestContact
|
||||
name: macPattern
|
||||
schema:
|
||||
type: string
|
||||
example:
|
||||
- "aabbcc*"
|
||||
- "*aabbcc*"
|
||||
- "*cccddee"
|
||||
required: false
|
||||
- in: query
|
||||
description: lastRecordedContact older than this value. Mutually exclusive with macPattern
|
||||
name: oldestContact
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
|
||||
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/commands:
|
||||
get:
|
||||
tags:
|
||||
@@ -1775,7 +1913,7 @@ paths:
|
||||
format: int64
|
||||
- in: query
|
||||
name: logType
|
||||
description: 0=any kind of logs (default) 0=normal logs only 1=crash logs only
|
||||
description: 0=any kind of logs (default) 0=normal logs, 1=crash logs, 2=reboot logs only
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
@@ -2113,32 +2251,6 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/command:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Post a command to a device
|
||||
operationId: executeCommand
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Command details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CommandDetails'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/CommandInfo'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/configure:
|
||||
post:
|
||||
tags:
|
||||
@@ -2723,9 +2835,6 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
|
||||
|
||||
/blacklist:
|
||||
get:
|
||||
tags:
|
||||
@@ -2918,6 +3027,82 @@ paths:
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/radiusSessions/{serialNumber}:
|
||||
get:
|
||||
tags:
|
||||
- Radius Sessions
|
||||
summary: Retrieve the RADIUS sessions for a given AP
|
||||
operationId: getAPRadiusSessions
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
example: for searches or listing only serial number, set the serialNumber to 0
|
||||
required: true
|
||||
- in: query
|
||||
name: serialNumberOnly
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: userName
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
- in: query
|
||||
name: mac
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
example: aa:bb:cc:dd:ee:ff
|
||||
responses:
|
||||
200:
|
||||
description: AP List
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/RadiusSessionList'
|
||||
- $ref: '#/components/schemas/SerialNumberList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
put:
|
||||
tags:
|
||||
- Radius Sessions
|
||||
summary: Retrieve the RADIUS sessions for a given AP
|
||||
operationId: putAPRadiusSessions
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: operation
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- coadm
|
||||
requestBody:
|
||||
description: operationParameters
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/RadiusCoADMParameters'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
|
||||
/deviceDashboard:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -85,6 +85,7 @@ iptocountry.ipdata.apikey = ${IPTOCOUNTRY_IPDATA_APIKEY}
|
||||
|
||||
autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
|
||||
|
||||
openwifi.session.timeout = ${DEVICE_SESSION_TIMEOUT}
|
||||
#
|
||||
# rtty
|
||||
#
|
||||
@@ -103,6 +104,12 @@ radius.proxy.accounting.port = ${RADIUS_PROXY_ACCOUNTING_PORT}
|
||||
radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
|
||||
radius.proxy.coa.port = ${RADIUS_PROXY_COA_PORT}
|
||||
|
||||
iptocountry.default = ${IPINFO_DEFAULT_COUNTRY}
|
||||
#iptocountry.provider = ipinfo
|
||||
#iptocountry.provider = ipdata
|
||||
#iptocountry.ipinfo.token =
|
||||
#iptocountry.ipdata.apikey =
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
#############################
|
||||
|
||||
59
src/AP_WS_ConfigAutoUpgrader.cpp
Normal file
59
src/AP_WS_ConfigAutoUpgrader.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-05-23.
|
||||
//
|
||||
|
||||
#include "AP_WS_ConfigAutoUpgrader.h"
|
||||
#include <framework/utils.h>
|
||||
#include <RESTObjects/RESTAPI_GWobjects.h>
|
||||
#include <StorageService.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int AP_WS_ConfigAutoUpgrader::Start() {
|
||||
poco_notice(Logger(), "Starting...");
|
||||
QueueManager_.start(*this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_ConfigAutoUpgrader::Stop() {
|
||||
poco_notice(Logger(), "Stopping...");
|
||||
Running_ = false;
|
||||
Queue_.wakeUpAll();
|
||||
QueueManager_.join();
|
||||
poco_notice(Logger(), "Stopped...");
|
||||
}
|
||||
|
||||
void AP_WS_ConfigAutoUpgrader::run() {
|
||||
Utils::SetThreadName("auto:cfgmgr");
|
||||
Running_ = true;
|
||||
|
||||
while (Running_) {
|
||||
Poco::AutoPtr<Poco::Notification> NextMsg(Queue_.waitDequeueNotification());
|
||||
try {
|
||||
auto Entry = dynamic_cast<CheckConfiguration *>(NextMsg.get());
|
||||
if (Entry != nullptr) {
|
||||
GWObjects::Device DeviceInfo;
|
||||
std::string SerialNumber = Utils::IntToSerialNumber(Entry->serial_);
|
||||
if (StorageService()->GetDevice(SerialNumber, DeviceInfo)) {
|
||||
if(DeviceInfo.pendingUUID!=0 && Entry->uuid_==DeviceInfo.pendingUUID) {
|
||||
StorageService()->CompleteDeviceConfigurationChange(SerialNumber);
|
||||
SetDeviceCacheEntry(Entry->serial_, Utils::Now(), Entry->uuid_, 0);
|
||||
continue;
|
||||
}
|
||||
if(DeviceInfo.UUID==Entry->uuid_) {
|
||||
SetDeviceCacheEntry(Entry->serial_, Utils::Now(), Entry->uuid_, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(), "Exception occurred during run.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
137
src/AP_WS_ConfigAutoUpgrader.h
Normal file
137
src/AP_WS_ConfigAutoUpgrader.h
Normal file
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-05-23.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
#include <framework/SubSystemServer.h>
|
||||
#include <framework/utils.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class CheckConfiguration : public Poco::Notification {
|
||||
public:
|
||||
explicit CheckConfiguration(std::uint64_t s, std::uint64_t c) :
|
||||
serial_(s), uuid_(c) {
|
||||
}
|
||||
std::uint64_t serial_;
|
||||
std::uint64_t uuid_;
|
||||
};
|
||||
|
||||
struct ConfigurationCacheEntry {
|
||||
std::uint64_t last_check_=0;
|
||||
std::uint64_t current_config_=0;
|
||||
std::uint64_t pending_config_=0;
|
||||
};
|
||||
|
||||
class AP_WS_ConfigAutoUpgrader : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
void run() final;
|
||||
|
||||
static auto instance() {
|
||||
static auto instance = new AP_WS_ConfigAutoUpgrader;
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline void AddConfiguration(std::uint64_t serial, std::uint64_t config_uuid) {
|
||||
std::lock_guard Guard(CacheMutex_);
|
||||
auto hint = Cache_.find(serial);
|
||||
if(hint==end(Cache_)) {
|
||||
Cache_[serial] = { Utils::Now(),config_uuid , 0 };
|
||||
return;
|
||||
}
|
||||
if(hint->second.pending_config_==0) {
|
||||
hint->second.last_check_ = Utils::Now();
|
||||
hint->second.current_config_ = config_uuid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inline void AddConfiguration(std::uint64_t serial, std::uint64_t config_uuid, std::uint64_t pending_config_uuid) {
|
||||
std::lock_guard Guard(CacheMutex_);
|
||||
auto hint = Cache_.find(serial);
|
||||
if(hint==end(Cache_)) {
|
||||
Cache_[serial] = { Utils::Now(), config_uuid , pending_config_uuid };
|
||||
return;
|
||||
}
|
||||
if(hint->second.pending_config_==0) {
|
||||
hint->second.last_check_ = Utils::Now();
|
||||
hint->second.current_config_ = config_uuid;
|
||||
hint->second.pending_config_ = pending_config_uuid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline ConfigurationCacheEntry GetSerialInfo(std::uint64_t serial) const {
|
||||
std::lock_guard Guard(CacheMutex_);
|
||||
auto hint = Cache_.find(serial);
|
||||
if(hint==end(Cache_)) {
|
||||
return {0,0,0};
|
||||
}
|
||||
return hint->second;
|
||||
}
|
||||
|
||||
inline bool UpdateConfiguration(std::uint64_t serial, std::uint64_t config) {
|
||||
|
||||
if(serial==0)
|
||||
return false;
|
||||
|
||||
std::lock_guard Guard(CacheMutex_);
|
||||
auto hint = Cache_.find(serial);
|
||||
if(hint!=end(Cache_)) {
|
||||
|
||||
if(hint->second.current_config_==config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(config==hint->second.pending_config_) {
|
||||
Queue_.enqueueNotification(new CheckConfiguration(serial,config));
|
||||
return true;
|
||||
}
|
||||
|
||||
if(config!=hint->second.current_config_ && hint->second.pending_config_==0) {
|
||||
Queue_.enqueueNotification(new CheckConfiguration(serial,config));
|
||||
return true;
|
||||
}
|
||||
|
||||
if((Utils::Now()-hint->second.last_check_)<60*5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(hint->second.pending_config_!=0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void SetDeviceCacheEntry(std::uint64_t serial, std::uint64_t t, std::uint64_t uuid, std::uint64_t pending_uuid) {
|
||||
std::lock_guard Guard(CacheMutex_);
|
||||
Cache_[serial] = { t, uuid, pending_uuid };
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Poco::NotificationQueue Queue_;
|
||||
Poco::Thread QueueManager_;
|
||||
std::atomic_bool Running_=false;
|
||||
|
||||
mutable std::mutex CacheMutex_;
|
||||
std::map<std::uint64_t, ConfigurationCacheEntry> Cache_;
|
||||
|
||||
AP_WS_ConfigAutoUpgrader() noexcept
|
||||
: SubSystemServer("AutoConfigUpgrade", "AUTO-CFG-MGR", "auto.config.updater") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto AP_WS_ConfigAutoUpgrader() { return AP_WS_ConfigAutoUpgrader::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
#include "RADIUSSessionTracker.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -126,7 +127,7 @@ namespace OpenWifi {
|
||||
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_information(Logger_,
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_,
|
||||
State_.sessionId, CN_));
|
||||
|
||||
@@ -138,10 +139,14 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(AP_WS_Server::IsSim(CN_)) {
|
||||
State_.VerifiedCertificate = GWObjects::SIMULATED;
|
||||
}
|
||||
|
||||
std::string reason, author;
|
||||
std::uint64_t created;
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(CN_, reason, author, created)) {
|
||||
DeviceBlacklistedKafkaEvent KE(CN_, Utils::Now(), reason, author, created, CId_);
|
||||
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
@@ -227,7 +232,7 @@ namespace OpenWifi {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(Disconnect, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, std::make_shared<std::string>(OS.str()));
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
@@ -237,10 +242,21 @@ namespace OpenWifi {
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection() {
|
||||
Valid_ = false;
|
||||
void DeviceDisconnectionCleanup(const std::string &SerialNumber) {
|
||||
if (KafkaManager()->Enabled()) {
|
||||
NotifyKafkaDisconnect(SerialNumber);
|
||||
}
|
||||
RADIUSSessionTracker()->DeviceDisconnect(SerialNumber);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection(bool DeleteSession) {
|
||||
Valid_ = false;
|
||||
if (!Dead_.test_and_set()) {
|
||||
|
||||
if(!SerialNumber_.empty() && State_.LastContact!=0) {
|
||||
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
|
||||
}
|
||||
|
||||
if (Registered_) {
|
||||
Registered_ = false;
|
||||
Reactor_.removeEventHandler(
|
||||
@@ -255,14 +271,16 @@ namespace OpenWifi {
|
||||
}
|
||||
WS_->close();
|
||||
|
||||
if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
|
||||
std::string s(SerialNumber_);
|
||||
std::thread t([s]() { NotifyKafkaDisconnect(s); });
|
||||
t.detach();
|
||||
if(!SerialNumber_.empty()) {
|
||||
std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_);
|
||||
Cleanup.detach();
|
||||
}
|
||||
|
||||
auto SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
if (SessionDeleted) {
|
||||
bool SessionDeleted = false;
|
||||
if(DeleteSession)
|
||||
SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
|
||||
if (SessionDeleted || !DeleteSession) {
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
N.content.serialNumber = SerialNumber_;
|
||||
GWWebSocketNotifications::DeviceDisconnected(N);
|
||||
@@ -430,7 +448,7 @@ namespace OpenWifi {
|
||||
std::string reason, author;
|
||||
std::uint64_t created;
|
||||
if (StorageService()->IsBlackListed(Serial, reason, author, created)) {
|
||||
DeviceBlacklistedKafkaEvent KE(CN_, Utils::Now(), reason, author, created, CId_);
|
||||
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
|
||||
Poco::Exception E(
|
||||
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
|
||||
Serial),
|
||||
@@ -495,6 +513,10 @@ namespace OpenWifi {
|
||||
Process_wifiscan(ParamsObj);
|
||||
} break;
|
||||
|
||||
case uCentralProtocol::Events::ET_REBOOTLOG: {
|
||||
Process_rebootLog(ParamsObj);
|
||||
} break;
|
||||
|
||||
// this will never be called but some compilers will complain if we do not have a case for
|
||||
// every single values of an enum
|
||||
case uCentralProtocol::Events::ET_UNKNOWN: {
|
||||
@@ -703,7 +725,7 @@ namespace OpenWifi {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(PingObject, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
@@ -932,22 +954,23 @@ namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
|
||||
if (Doc->has(uCentralProtocol::RADIUSDATA)) {
|
||||
std::string secret;
|
||||
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();
|
||||
if (Type == uCentralProtocol::RADIUSACCT) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAccountingData(SerialNumber_, DecodedData.c_str(),
|
||||
DecodedData.size());
|
||||
DecodedData.size(),secret);
|
||||
} else if (Type == uCentralProtocol::RADIUSAUTH) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_, DecodedData.c_str(),
|
||||
DecodedData.size());
|
||||
DecodedData.size(), secret);
|
||||
} else if (Type == uCentralProtocol::RADIUSCOA) {
|
||||
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
|
||||
auto DecodedData = Base64Decode(Data);
|
||||
RADIUS_proxy_server()->SendCoAData(SerialNumber_, DecodedData.c_str(),
|
||||
DecodedData.size());
|
||||
DecodedData.size(), secret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include <Poco/JSON/Parser.h>
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
@@ -27,7 +28,7 @@ namespace OpenWifi {
|
||||
Poco::Logger &L, Poco::Net::SocketReactor &R);
|
||||
~AP_WS_Connection();
|
||||
|
||||
void EndConnection();
|
||||
void EndConnection(bool DeleteSession=true);
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
|
||||
void ProcessIncomingFrame();
|
||||
@@ -57,7 +58,7 @@ namespace OpenWifi {
|
||||
bool StopWebSocketTelemetry(uint64_t RPCID);
|
||||
bool StopKafkaTelemetry(uint64_t RPCID);
|
||||
|
||||
inline void GetLastStats(std::string &LastStats) const {
|
||||
inline void GetLastStats(std::string &LastStats) {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
LastStats = RawLastStats_;
|
||||
}
|
||||
@@ -65,6 +66,33 @@ namespace OpenWifi {
|
||||
inline void SetLastStats(const std::string &LastStats) {
|
||||
std::unique_lock G(ConnectionMutex_);
|
||||
RawLastStats_ = LastStats;
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
|
||||
hasGPS = Stats->isObject("gps");
|
||||
auto Unit = Stats->getObject("unit");
|
||||
auto Memory = Unit->getObject("memory");
|
||||
std::uint64_t TotalMemory = Memory->get("total");
|
||||
std::uint64_t FreeMemory = Memory->get("free");
|
||||
if(TotalMemory>0) {
|
||||
memory_used_ =
|
||||
(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
|
||||
}
|
||||
if(Unit->isArray("load")) {
|
||||
Poco::JSON::Array::Ptr Load = Unit->getArray("load");
|
||||
if(Load->size()>1) {
|
||||
cpu_load_ = Load->get(1);
|
||||
}
|
||||
}
|
||||
if(Unit->isArray("temperature")) {
|
||||
Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
|
||||
if(Temperature->size()>1) {
|
||||
temperature_ = Temperature->get(0);
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
|
||||
@@ -82,6 +110,8 @@ namespace OpenWifi {
|
||||
State = State_;
|
||||
}
|
||||
|
||||
inline bool HasGPS() { return hasGPS; }
|
||||
|
||||
inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
R = Restrictions_;
|
||||
@@ -101,6 +131,7 @@ namespace OpenWifi {
|
||||
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
bool ValidatedDevice();
|
||||
|
||||
@@ -168,6 +199,8 @@ namespace OpenWifi {
|
||||
bool StartTelemetry(uint64_t RPCID, const std::vector<std::string> &TelemetryTypes);
|
||||
bool StopTelemetry(uint64_t RPCID);
|
||||
void UpdateCounts();
|
||||
bool hasGPS=false;
|
||||
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
|
||||
};
|
||||
|
||||
} // namespace OpenWifi
|
||||
@@ -25,7 +25,7 @@ namespace OpenWifi {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace OpenWifi {
|
||||
Event.set("payload", EventDetails);
|
||||
std::ostringstream OS;
|
||||
Event.stringify(OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace OpenWifi {
|
||||
Event.set("payload", EventDetails);
|
||||
std::ostringstream OS;
|
||||
Event.stringify(OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@ namespace OpenWifi {
|
||||
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
|
||||
CId_ = SerialNumber_ + "@" + CId_;
|
||||
|
||||
if(ParamsObj->has("reason")) {
|
||||
State_.connectReason = ParamsObj->get("reason").toString();
|
||||
}
|
||||
|
||||
auto IP = PeerAddress_.toString();
|
||||
if (IP.substr(0, 7) == "::ffff:") {
|
||||
IP = IP.substr(7);
|
||||
@@ -105,7 +109,7 @@ namespace OpenWifi {
|
||||
GWObjects::Device DeviceInfo;
|
||||
auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
|
||||
if (Daemon()->AutoProvisioning() && !DeviceExists) {
|
||||
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_);
|
||||
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_, State_.VerifiedCertificate==GWObjects::SIMULATED );
|
||||
} else if (!Daemon()->AutoProvisioning() && !DeviceExists) {
|
||||
SendKafkaDeviceNotProvisioned(SerialNumber_, Firmware, Compatible_, CId_);
|
||||
poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_));
|
||||
@@ -115,7 +119,7 @@ namespace OpenWifi {
|
||||
int Updated{0};
|
||||
if (!Firmware.empty()) {
|
||||
if (Firmware != DeviceInfo.Firmware) {
|
||||
DeviceFirmwareChangeKafkaEvent KEvent(SerialNumber_, Utils::Now(),
|
||||
DeviceFirmwareChangeKafkaEvent KEvent(SerialNumberInt_, Utils::Now(),
|
||||
DeviceInfo.Firmware, Firmware);
|
||||
DeviceInfo.Firmware = Firmware;
|
||||
DeviceInfo.LastFWUpdate = Utils::Now();
|
||||
@@ -131,6 +135,21 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
if (DeviceInfo.lastRecordedContact==0) {
|
||||
DeviceInfo.lastRecordedContact = Utils::Now();
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (DeviceInfo.simulated && (State_.VerifiedCertificate!=GWObjects::SIMULATED)) {
|
||||
DeviceInfo.simulated = false;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (!DeviceInfo.simulated && (State_.VerifiedCertificate==GWObjects::SIMULATED)) {
|
||||
DeviceInfo.simulated = true;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (DeviceInfo.locale != State_.locale) {
|
||||
DeviceInfo.locale = State_.locale;
|
||||
++Updated;
|
||||
@@ -193,6 +212,12 @@ namespace OpenWifi {
|
||||
return EndConnection();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poco_information(Logger_,
|
||||
fmt::format("CONNECT({}): Simulator device. "
|
||||
"Session={} ConnectionCompletion Time={}",
|
||||
CId_, State_.sessionId,
|
||||
State_.connectionCompletionTime));
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::SingleDevice_t Notification;
|
||||
@@ -207,7 +232,7 @@ namespace OpenWifi {
|
||||
ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
} else {
|
||||
poco_warning(
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include <GWKafkaEvents.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID)
|
||||
&& ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
poco_trace(Logger_, fmt::format("CRASH-LOG({}): new entry.", CId_));
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
@@ -24,11 +26,11 @@ namespace OpenWifi {
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.Recorded = Utils::Now(),
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace OpenWifi {
|
||||
std::ostringstream OS;
|
||||
FullEvent.stringify(OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
|
||||
OS.str());
|
||||
std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
@@ -19,8 +19,10 @@ namespace OpenWifi {
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::SANITY) &&
|
||||
ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
|
||||
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
|
||||
@@ -62,7 +64,7 @@ namespace OpenWifi {
|
||||
std::ostringstream OS;
|
||||
ParamsObj->set("timestamp", Utils::Now());
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include <GWKafkaEvents.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
@@ -36,6 +37,7 @@ namespace OpenWifi {
|
||||
.LogType = 0,
|
||||
.UUID = State_.UUID};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
return;
|
||||
|
||||
44
src/AP_WS_Process_rebootLog.cpp
Normal file
44
src/AP_WS_Process_rebootLog.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-05-16.
|
||||
//
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include <GWKafkaEvents.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void StripNulls(std::string &S) {
|
||||
for(std::size_t i=0;i<S.size();++i) {
|
||||
if(S[i]==0)
|
||||
S[i]=' ';
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj) {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID)
|
||||
&& ParamsObj->isArray(uCentralProtocol::INFO)
|
||||
&& ParamsObj->has(uCentralProtocol::TYPE)
|
||||
&& ParamsObj->has(uCentralProtocol::DATE) ) {
|
||||
poco_warning(Logger_, fmt::format("REBOOT-LOG({}): new entry.", CId_));
|
||||
|
||||
auto InfoLines = ParamsObj->getArray(uCentralProtocol::INFO);
|
||||
std::ostringstream os;
|
||||
InfoLines->stringify(os);
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
|
||||
.Log = ParamsObj->get(uCentralProtocol::TYPE).toString(),
|
||||
.Data = "{ \"info\" : " + os.str() + "}",
|
||||
.Severity = GWObjects::DeviceLog::LOG_INFO,
|
||||
.Recorded = ParamsObj->get(uCentralProtocol::DATE),
|
||||
.LogType = 2,
|
||||
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("REBOOT-LOG({}): Missing parameters.", CId_));
|
||||
}
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -59,7 +59,7 @@ namespace OpenWifi {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
|
||||
@@ -27,9 +27,10 @@ namespace OpenWifi {
|
||||
std::ostringstream SS;
|
||||
Payload->stringify(SS);
|
||||
auto now = Utils::Now();
|
||||
auto KafkaPayload = std::make_shared<std::string>(SS.str());
|
||||
if (ParamsObj->has("adhoc")) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
|
||||
SS.str());
|
||||
KafkaPayload);
|
||||
return;
|
||||
}
|
||||
if (TelemetryWebSocketRefCount_) {
|
||||
@@ -38,7 +39,7 @@ namespace OpenWifi {
|
||||
// std::endl;
|
||||
TelemetryWebSocketPackets_++;
|
||||
State_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, SS.str());
|
||||
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, *KafkaPayload);
|
||||
} else {
|
||||
StopWebSocketTelemetry(CommandManager()->Next_RPC_ID());
|
||||
}
|
||||
@@ -49,7 +50,7 @@ namespace OpenWifi {
|
||||
TelemetryKafkaPackets_++;
|
||||
State_.kafkaPackets = TelemetryKafkaPackets_;
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
|
||||
SS.str());
|
||||
KafkaPayload);
|
||||
} else {
|
||||
StopKafkaTelemetry(CommandManager()->Next_RPC_ID());
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace OpenWifi {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "fmt/format.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
#include <framework/KafkaManager.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -54,6 +55,8 @@ namespace OpenWifi {
|
||||
MicroServiceConfigGetBool("openwifi.certificates.allowmismatch", true);
|
||||
MismatchDepth_ = MicroServiceConfigGetInt("openwifi.certificates.mismatchdepth", 2);
|
||||
|
||||
SessionTimeOut_ = MicroServiceConfigGetInt("openwifi.session.timeout", 10*60);
|
||||
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
|
||||
Reactor_pool_->Start();
|
||||
|
||||
@@ -161,7 +164,7 @@ namespace OpenWifi {
|
||||
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(
|
||||
*this, &AP_WS_Server::onGarbageCollecting);
|
||||
Timer_.setStartInterval(10 * 1000);
|
||||
Timer_.setPeriodicInterval(5 * 1000); // every minute
|
||||
Timer_.setPeriodicInterval(10 * 1000); // every minute
|
||||
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
|
||||
|
||||
Running_ = true;
|
||||
@@ -169,41 +172,50 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
if (!Garbage_.empty()) {
|
||||
Garbage_.clear();
|
||||
}
|
||||
|
||||
static uint64_t last_log = Utils::Now();
|
||||
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
uint64_t total_connected_time = 0;
|
||||
|
||||
auto now = Utils::Now();
|
||||
for (const auto &connection : SerialNumbers_) {
|
||||
if (connection.second.second == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (connection.second.second->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time += (now - connection.second.second->State_.started);
|
||||
} else {
|
||||
NumberOfConnectingDevices_++;
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ =
|
||||
(NumberOfConnectedDevices_ != 0) ? total_connected_time / NumberOfConnectedDevices_ : 0;
|
||||
if ((now - last_log) > 120) {
|
||||
last_log = now;
|
||||
poco_information(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"Active AP connections: {} Connecting: {} Average connection time: {} seconds",
|
||||
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
|
||||
AverageDeviceConnectionTime_));
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
if (!Garbage_.empty()) {
|
||||
Garbage_.clear();
|
||||
}
|
||||
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
uint64_t total_connected_time = 0;
|
||||
|
||||
auto hint = SerialNumbers_.begin();
|
||||
while (hint != end(SerialNumbers_)) {
|
||||
if (hint->second.second == nullptr) {
|
||||
hint = SerialNumbers_.erase(hint);
|
||||
} else if ((now - hint->second.second->State_.LastContact) > SessionTimeOut_) {
|
||||
hint->second.second->EndConnection(false);
|
||||
poco_information(Logger(),fmt::format("{}: Session seems idle. Controller disconnecting device.", hint->second.second->SerialNumber_));
|
||||
Sessions_.erase(hint->second.second->State_.sessionId);
|
||||
Garbage_.push_back(hint->second.second);
|
||||
hint = SerialNumbers_.erase(hint);
|
||||
} else if (hint->second.second->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time += (now - hint->second.second->State_.started);
|
||||
hint++;
|
||||
} else {
|
||||
NumberOfConnectingDevices_++;
|
||||
hint++;
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ = NumberOfConnectedDevices_ > 0
|
||||
? total_connected_time / NumberOfConnectedDevices_
|
||||
: 0;
|
||||
if ((now - last_log) > 120) {
|
||||
last_log = now;
|
||||
poco_information(Logger(),
|
||||
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
|
||||
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
|
||||
AverageDeviceConnectionTime_));
|
||||
}
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::NumberOfConnection_t Notification;
|
||||
@@ -212,6 +224,19 @@ namespace OpenWifi {
|
||||
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
|
||||
GetTotalDataStatistics(Notification.content.tx,Notification.content.rx);
|
||||
GWWebSocketNotifications::NumberOfConnections(Notification);
|
||||
|
||||
Poco::JSON::Object KafkaNotification;
|
||||
Notification.to_json(KafkaNotification);
|
||||
|
||||
Poco::JSON::Object FullEvent;
|
||||
FullEvent.set("type", "load-update");
|
||||
FullEvent.set("timestamp", now);
|
||||
FullEvent.set("payload", KafkaNotification);
|
||||
|
||||
std::ostringstream OS;
|
||||
FullEvent.stringify(OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system",
|
||||
std::make_shared<std::string>(OS.str()));
|
||||
}
|
||||
|
||||
void AP_WS_Server::Stop() {
|
||||
@@ -309,6 +334,32 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
Sessions_.erase(Session);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSessionUnSafe(uint64_t session_id, uint64_t serial_number) {
|
||||
|
||||
auto Session = Sessions_.find(session_id);
|
||||
if (Session == end(Sessions_))
|
||||
return false;
|
||||
|
||||
Garbage_.push_back(Session->second);
|
||||
|
||||
auto Device = SerialNumbers_.find(serial_number);
|
||||
if (Device == end(SerialNumbers_)) {
|
||||
Sessions_.erase(Session);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Device->second.first == session_id) {
|
||||
Sessions_.erase(Session);
|
||||
SerialNumbers_.erase(Device);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sessions_.erase(Session);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace OpenWifi {
|
||||
|
||||
void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
|
||||
bool EndSession(uint64_t connection_id, uint64_t serial_number);
|
||||
|
||||
bool EndSessionUnSafe(uint64_t session_id, uint64_t serial_number);
|
||||
void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
|
||||
uint64_t Interval, uint64_t Lifetime,
|
||||
const std::vector<std::string> &TelemetryTypes);
|
||||
@@ -212,6 +212,27 @@ namespace OpenWifi {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExtendedAttributes(const std::string &serialNumber,
|
||||
bool & hasGPS,
|
||||
std::uint64_t &Sanity,
|
||||
std::double_t &MemoryUsed,
|
||||
std::double_t &Load,
|
||||
std::double_t &Temperature
|
||||
) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
auto session_hint = SerialNumbers_.find(Utils::SerialNumberToInt(serialNumber));
|
||||
if(session_hint==end(SerialNumbers_)) {
|
||||
return false;
|
||||
}
|
||||
hasGPS = session_hint->second.second->hasGPS;
|
||||
Sanity = session_hint->second.second->RawLastHealthcheck_.Sanity;
|
||||
MemoryUsed = session_hint->second.second->memory_used_;
|
||||
Load = session_hint->second.second->cpu_load_;
|
||||
Temperature = session_hint->second.second->temperature_;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex WSServerMutex_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
@@ -230,10 +251,10 @@ namespace OpenWifi {
|
||||
std::atomic_bool AllowSerialNumberMismatch_ = true;
|
||||
std::atomic_uint64_t MismatchDepth_ = 2;
|
||||
|
||||
std::atomic_uint64_t NumberOfConnectedDevices_ = 0;
|
||||
std::atomic_uint64_t AverageDeviceConnectionTime_ = 0;
|
||||
std::atomic_uint64_t NumberOfConnectingDevices_ = 0;
|
||||
|
||||
std::uint64_t NumberOfConnectedDevices_ = 0;
|
||||
std::uint64_t AverageDeviceConnectionTime_ = 0;
|
||||
std::uint64_t NumberOfConnectingDevices_ = 0;
|
||||
std::uint64_t SessionTimeOut_ = 10*60;
|
||||
mutable std::mutex StatsMutex_;
|
||||
std::atomic_uint64_t TX_=0,RX_=0;
|
||||
|
||||
|
||||
@@ -302,97 +302,116 @@ namespace OpenWifi {
|
||||
StorageService()->RemovedExpiredCommands();
|
||||
StorageService()->RemoveTimedOutCommands();
|
||||
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
|
||||
poco_trace(MyLogger,
|
||||
fmt::format("Scheduler about to process {} commands.", Commands.size()));
|
||||
for (auto &Cmd : Commands) {
|
||||
if (!Running_) {
|
||||
poco_warning(MyLogger, "Scheduler quitting because service is stopping.");
|
||||
break;
|
||||
std::uint64_t offset = 0;
|
||||
bool Done = false;
|
||||
while (!Done) {
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (StorageService()->GetReadyToExecuteCommands(offset, 200, Commands)) {
|
||||
if(Commands.empty()) {
|
||||
Done=true;
|
||||
continue;
|
||||
}
|
||||
poco_trace(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Starting processing.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
try {
|
||||
|
||||
// Skip an already running command
|
||||
if (IsCommandRunning(Cmd.UUID)) {
|
||||
continue;
|
||||
poco_trace(MyLogger, fmt::format("Scheduler about to process {} commands.",
|
||||
Commands.size()));
|
||||
for (auto &Cmd : Commands) {
|
||||
if (!Running_) {
|
||||
poco_warning(MyLogger,
|
||||
"Scheduler quitting because service is stopping.");
|
||||
break;
|
||||
}
|
||||
poco_trace(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Starting processing.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
try {
|
||||
|
||||
auto now = Utils::Now();
|
||||
// 2 hour timeout for commands
|
||||
if ((now - Cmd.Submitted) > commandTimeOut_) {
|
||||
poco_information(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} has expired.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandTimedOut(Cmd.UUID);
|
||||
continue;
|
||||
}
|
||||
// Skip an already running command
|
||||
if (IsCommandRunning(Cmd.UUID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
|
||||
if (!AP_WS_Server()->Connected(SerialNumberInt)) {
|
||||
poco_trace(
|
||||
auto now = Utils::Now();
|
||||
// 2 hour timeout for commands
|
||||
if ((now - Cmd.Submitted) > commandTimeOut_) {
|
||||
poco_information(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandTimedOut(Cmd.UUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
|
||||
if (!AP_WS_Server()->Connected(SerialNumberInt)) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Device is not connected.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandLastTry(Cmd.UUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string ExecutingUUID;
|
||||
APCommands::Commands ExecutingCommand = APCommands::Commands::unknown;
|
||||
if (CommandRunningForDevice(SerialNumberInt, ExecutingUUID,
|
||||
ExecutingCommand)) {
|
||||
poco_trace(
|
||||
MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Device is already busy "
|
||||
"with command {} (Command={}).",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command,
|
||||
ExecutingUUID,
|
||||
APCommands::to_string(ExecutingCommand)));
|
||||
continue;
|
||||
}
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
poco_information(
|
||||
MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Device is not connected.",
|
||||
fmt::format("{}: Serial={} Command={} Preparing execution.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandLastTry(Cmd.UUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string ExecutingUUID;
|
||||
APCommands::Commands ExecutingCommand = APCommands::Commands::unknown;
|
||||
if (CommandRunningForDevice(SerialNumberInt, ExecutingUUID,
|
||||
ExecutingCommand)) {
|
||||
poco_trace(
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk(
|
||||
Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
|
||||
Cmd.SerialNumber, Cmd.Command, *Params, Cmd.UUID, Sent);
|
||||
if (Sent) {
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Sent.", Cmd.UUID,
|
||||
Cmd.SerialNumber, Cmd.Command));
|
||||
} else {
|
||||
poco_debug(
|
||||
MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Re-queued command.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandLastTry(Cmd.UUID);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_debug(
|
||||
MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Device is already busy "
|
||||
"with command {} (Command={}).",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command, ExecutingUUID,
|
||||
APCommands::to_string(ExecutingCommand)));
|
||||
continue;
|
||||
}
|
||||
|
||||
Poco::JSON::Parser P;
|
||||
bool Sent;
|
||||
poco_information(
|
||||
MyLogger, fmt::format("{}: Serial={} Command={} Preparing execution.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Result = PostCommandDisk(
|
||||
Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
|
||||
Cmd.SerialNumber, Cmd.Command, *Params, Cmd.UUID, Sent);
|
||||
if (Sent) {
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Failed. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Sent.", Cmd.UUID,
|
||||
Cmd.SerialNumber, Cmd.Command));
|
||||
} else {
|
||||
poco_debug(MyLogger,
|
||||
fmt::format("{}: Serial={} Command={} Re-queued command.",
|
||||
fmt::format("{}: Serial={} Command={} Hard failure. "
|
||||
"Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandLastTry(Cmd.UUID);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_debug(
|
||||
MyLogger,
|
||||
fmt::format(
|
||||
"{}: Serial={} Command={} Failed. Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
MyLogger.log(E);
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
} catch (...) {
|
||||
poco_debug(MyLogger, fmt::format("{}: Serial={} Command={} Hard failure. "
|
||||
"Command marked as completed.",
|
||||
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
|
||||
StorageService()->SetCommandExecuted(Cmd.UUID);
|
||||
}
|
||||
offset += Commands.size();
|
||||
} else {
|
||||
Done=true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (Poco::Exception &E) {
|
||||
}
|
||||
catch (Poco::Exception &E) {
|
||||
MyLogger.log(E);
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...) {
|
||||
poco_warning(MyLogger, "Exception during command processing.");
|
||||
}
|
||||
poco_trace(MyLogger, "Scheduler done.");
|
||||
|
||||
@@ -11,12 +11,17 @@
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
|
||||
#include <framework/ConfigurationValidator.h>
|
||||
#include <framework/UI_WebSocketClientServer.h>
|
||||
#include <framework/default_device_types.h>
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CommandManager.h"
|
||||
#include "Daemon.h"
|
||||
#include "FileUploader.h"
|
||||
#include "FindCountry.h"
|
||||
#include "OUIServer.h"
|
||||
#include "RADIUSSessionTracker.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "RegulatoryInfo.h"
|
||||
#include "ScriptManager.h"
|
||||
@@ -25,10 +30,10 @@
|
||||
#include "StorageArchiver.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "GenericScheduler.h"
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
#include "VenueBroadcaster.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "framework/UI_WebSocketClientServer.h"
|
||||
#include "AP_WS_ConfigAutoUpgrader.h"
|
||||
#include "rttys/RTTYS_server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -36,52 +41,21 @@ namespace OpenWifi {
|
||||
static Daemon instance(
|
||||
vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, vDAEMON_CONFIG_ENV_VAR,
|
||||
vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
|
||||
SubSystemVec{StorageService(), SerialNumberCache(), ConfigurationValidator(),
|
||||
SubSystemVec{GenericScheduler(), StorageService(), SerialNumberCache(), ConfigurationValidator(),
|
||||
UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(),
|
||||
CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(),
|
||||
RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(),
|
||||
SignatureManager(), AP_WS_Server(),
|
||||
RegulatoryInfo()
|
||||
RegulatoryInfo(),
|
||||
RADIUSSessionTracker(),
|
||||
AP_WS_ConfigAutoUpgrader()
|
||||
});
|
||||
return &instance;
|
||||
}
|
||||
|
||||
static const std::vector<std::pair<std::string, std::string>> DefaultDeviceTypes{
|
||||
{"cig_wf160d", "AP"},
|
||||
{"cig_wf188", "AP"},
|
||||
{"cig_wf188n", "AP"},
|
||||
{"cig_wf194c", "AP"},
|
||||
{"cig_wf194c4", "AP"},
|
||||
{"edgecore_eap101", "AP"},
|
||||
{"edgecore_eap102", "AP"},
|
||||
{"edgecore_ecs4100-12ph", "AP"},
|
||||
{"edgecore_ecw5211", "AP"},
|
||||
{"edgecore_ecw5410", "AP"},
|
||||
{"edgecore_oap100", "AP"},
|
||||
{"edgecore_spw2ac1200", "SWITCH"},
|
||||
{"edgecore_spw2ac1200-lan-poe", "SWITCH"},
|
||||
{"edgecore_ssw2ac2600", "SWITCH"},
|
||||
{"hfcl_ion4", "AP"},
|
||||
{"indio_um-305ac", "AP"},
|
||||
{"linksys_e8450-ubi", "AP"},
|
||||
{"linksys_ea6350", "AP"},
|
||||
{"linksys_ea6350-v4", "AP"},
|
||||
{"linksys_ea8300", "AP"},
|
||||
{"mikrotik_nand", "AP"},
|
||||
{"tp-link_ec420-g1", "AP"},
|
||||
{"tplink_cpe210_v3", "AP"},
|
||||
{"tplink_cpe510_v3", "AP"},
|
||||
{"tplink_eap225_outdoor_v1", "AP"},
|
||||
{"tplink_ec420", "AP"},
|
||||
{"tplink_ex227", "AP"},
|
||||
{"tplink_ex228", "AP"},
|
||||
{"tplink_ex447", "AP"},
|
||||
{"wallys_dr40x9", "AP"}};
|
||||
|
||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning", false);
|
||||
DeviceTypes_ = DefaultDeviceTypes;
|
||||
|
||||
DeviceTypes_ = DefaultDeviceTypeList;
|
||||
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace OpenWifi {
|
||||
Event.set("payload", payload_);
|
||||
std::ostringstream OS;
|
||||
Event.stringify(OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, serialNumber_, OS.str());
|
||||
auto payload = std::make_shared<std::string>(OS.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, Utils::IntToSerialNumber(serialNumber_), payload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,23 +4,26 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Poco/JSON/Object.h>
|
||||
#include <framework/KafkaManager.h>
|
||||
#include <string>
|
||||
|
||||
#include <Poco/JSON/Object.h>
|
||||
#include <RESTObjects/RESTAPI_GWobjects.h>
|
||||
#include <framework/KafkaManager.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class GWKafkaEvents {
|
||||
public:
|
||||
GWKafkaEvents(const std::string &serialNumber, const std::string &type,
|
||||
GWKafkaEvents(std::uint64_t serialNumber, const std::string &type,
|
||||
std::uint64_t timestamp)
|
||||
: serialNumber_(serialNumber), type_(type), timestamp_(timestamp) {}
|
||||
|
||||
inline void SetPayload(Poco::JSON::Object::Ptr payload) { payload_ = std::move(payload); }
|
||||
: serialNumber_(serialNumber), type_(type), timestamp_(timestamp) {
|
||||
payload_ = Poco::SharedPtr<Poco::JSON::Object>(new Poco::JSON::Object);
|
||||
}
|
||||
void Send();
|
||||
[[nodiscard]] inline std::uint64_t Serial() const { return serialNumber_;};
|
||||
|
||||
private:
|
||||
std::string serialNumber_;
|
||||
protected:
|
||||
std::uint64_t serialNumber_;
|
||||
std::string type_;
|
||||
std::uint64_t timestamp_ = 0;
|
||||
Poco::JSON::Object::Ptr payload_;
|
||||
@@ -28,17 +31,15 @@ namespace OpenWifi {
|
||||
|
||||
class DeviceFirmwareChangeKafkaEvent : public GWKafkaEvents {
|
||||
public:
|
||||
DeviceFirmwareChangeKafkaEvent(const std::string &serialNumber, std::uint64_t timestamp,
|
||||
DeviceFirmwareChangeKafkaEvent(std::uint64_t serialNumber, std::uint64_t timestamp,
|
||||
const std::string &oldFirmware,
|
||||
const std::string &newFirmware)
|
||||
: GWKafkaEvents(serialNumber, "unit.firmware_change", timestamp),
|
||||
oldFirmware_(oldFirmware), newFirmware_(newFirmware) {}
|
||||
|
||||
~DeviceFirmwareChangeKafkaEvent() {
|
||||
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
|
||||
payload->set("oldFirmware", oldFirmware_);
|
||||
payload->set("newFirmware", newFirmware_);
|
||||
SetPayload(payload);
|
||||
payload_->set("oldFirmware", oldFirmware_);
|
||||
payload_->set("newFirmware", newFirmware_);
|
||||
Send();
|
||||
}
|
||||
|
||||
@@ -48,15 +49,13 @@ namespace OpenWifi {
|
||||
|
||||
class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
|
||||
public:
|
||||
DeviceConfigurationChangeKafkaEvent(const std::string &serialNumber,
|
||||
DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber,
|
||||
std::uint64_t timestamp, const std::string config)
|
||||
: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
|
||||
}
|
||||
|
||||
~DeviceConfigurationChangeKafkaEvent() {
|
||||
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
|
||||
payload->set("configuration", config_);
|
||||
SetPayload(payload);
|
||||
payload_->set("configuration", config_);
|
||||
Send();
|
||||
}
|
||||
|
||||
@@ -66,7 +65,7 @@ namespace OpenWifi {
|
||||
|
||||
class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {
|
||||
public:
|
||||
explicit DeviceBlacklistedKafkaEvent(const std::string &serialNumber,
|
||||
explicit DeviceBlacklistedKafkaEvent(std::uint64_t serialNumber,
|
||||
std::uint64_t timestamp, const std::string &reason,
|
||||
const std::string &author, std::uint64_t created,
|
||||
std::string &IP)
|
||||
@@ -74,12 +73,10 @@ namespace OpenWifi {
|
||||
author_(author), created_(created), IP_(IP) {}
|
||||
|
||||
~DeviceBlacklistedKafkaEvent() {
|
||||
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
|
||||
payload->set("reason", reason_);
|
||||
payload->set("author", author_);
|
||||
payload->set("created", created_);
|
||||
payload->set("ipaddress", IP_);
|
||||
SetPayload(payload);
|
||||
payload_->set("reason", reason_);
|
||||
payload_->set("author", author_);
|
||||
payload_->set("created", created_);
|
||||
payload_->set("ipaddress", IP_);
|
||||
Send();
|
||||
}
|
||||
|
||||
@@ -89,4 +86,21 @@ namespace OpenWifi {
|
||||
std::string IP_;
|
||||
};
|
||||
|
||||
class DeviceLogKafkaEvent : public GWKafkaEvents {
|
||||
public:
|
||||
explicit DeviceLogKafkaEvent( const GWObjects::DeviceLog &L)
|
||||
: GWKafkaEvents(Utils::MACToInt(L.SerialNumber), "device_log", L.Recorded),
|
||||
DL_(L)
|
||||
{
|
||||
}
|
||||
|
||||
~DeviceLogKafkaEvent() {
|
||||
DL_.to_json(*payload_);
|
||||
Send();
|
||||
}
|
||||
|
||||
private:
|
||||
GWObjects::DeviceLog DL_;
|
||||
};
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
19
src/GenericScheduler.cpp
Normal file
19
src/GenericScheduler.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-19.
|
||||
//
|
||||
|
||||
#include "GenericScheduler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int GenericScheduler::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GenericScheduler::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
37
src/GenericScheduler.h
Normal file
37
src/GenericScheduler.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-19.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <framework/SubSystemServer.h>
|
||||
#include <libs/Scheduler.h>
|
||||
#include <Poco/Environment.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class GenericScheduler : public SubSystemServer {
|
||||
public:
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new GenericScheduler;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
auto & Scheduler() { return Scheduler_; }
|
||||
|
||||
private:
|
||||
GenericScheduler() noexcept
|
||||
: SubSystemServer("Scheduler", "SCHEDULER", "scheduler"),
|
||||
Scheduler_(Poco::Environment::processorCount()*2) {
|
||||
|
||||
}
|
||||
Bosma::Scheduler Scheduler_;
|
||||
};
|
||||
|
||||
inline auto GenericScheduler() { return GenericScheduler::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
407
src/RADIUSSessionTracker.cpp
Normal file
407
src/RADIUSSessionTracker.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-03-19.
|
||||
//
|
||||
|
||||
#include "RADIUSSessionTracker.h"
|
||||
#include <fmt/format.h>
|
||||
#include <framework/utils.h>
|
||||
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int RADIUSSessionTracker::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
QueueManager_.start(*this);
|
||||
GarbageCollectionCallback_ = std::make_unique<Poco::TimerCallback<RADIUSSessionTracker>>(
|
||||
*this, &RADIUSSessionTracker::GarbageCollection);
|
||||
GarbageCollectionTimer_.setStartInterval(10000);
|
||||
GarbageCollectionTimer_.setPeriodicInterval(2*60*1000); // every 2 minutes
|
||||
GarbageCollectionTimer_.start(*GarbageCollectionCallback_, MicroServiceTimerPool());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUSSessionTracker::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
GarbageCollectionTimer_.stop();
|
||||
SessionMessageQueue_.wakeUpAll();
|
||||
QueueManager_.join();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void RADIUSSessionTracker::GarbageCollection([[maybe_unused]] Poco::Timer &timer) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
auto Now = Utils::Now();
|
||||
std::uint64_t active_sessions=0, active_devices=0;
|
||||
for(auto device_it = AccountingSessions_.begin(); device_it != end(AccountingSessions_); ) {
|
||||
auto & serialNumber = device_it->first;
|
||||
auto & session_list = device_it->second;
|
||||
for(auto session_it=session_list.begin();session_it!=end(session_list);) {
|
||||
auto & session_name = session_it->first;
|
||||
auto & session = session_it->second;
|
||||
if((Now-session->lastTransaction)>SessionTimeout_) {
|
||||
poco_debug(Logger(),fmt::format("{}: Session {} timeout for {}", serialNumber, session_name, session->userName));
|
||||
session_it = session_list.erase(session_it);
|
||||
} else {
|
||||
++active_sessions;
|
||||
++session_it;
|
||||
}
|
||||
}
|
||||
if(session_list.empty()) {
|
||||
device_it = AccountingSessions_.erase(device_it);
|
||||
} else {
|
||||
++active_devices;
|
||||
++device_it;
|
||||
}
|
||||
}
|
||||
poco_information(Logger(),fmt::format("{} active sessions on {} devices",active_sessions, active_devices));
|
||||
}
|
||||
|
||||
void RADIUSSessionTracker::run() {
|
||||
Utils::SetThreadName("rad:sessmgr");
|
||||
Running_ = true;
|
||||
|
||||
Poco::AutoPtr<Poco::Notification> NextSession(SessionMessageQueue_.waitDequeueNotification());
|
||||
while (NextSession && Running_) {
|
||||
auto Session = dynamic_cast<SessionNotification *>(NextSession.get());
|
||||
|
||||
try {
|
||||
if (Session != nullptr) {
|
||||
switch(Session->Type_) {
|
||||
case SessionNotification::NotificationType::accounting_session_message: {
|
||||
ProcessAccountingSession(*Session);
|
||||
} break;
|
||||
case SessionNotification::NotificationType::authentication_session_message: {
|
||||
ProcessAuthenticationSession(*Session);
|
||||
} break;
|
||||
case SessionNotification::NotificationType::ap_disconnect: {
|
||||
DisconnectSession(Session->SerialNumber_);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(), "Exception occurred during run.");
|
||||
}
|
||||
NextSession = SessionMessageQueue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger(), "RADIUS session manager stopping.");
|
||||
}
|
||||
|
||||
void RADIUSSessionTracker::ProcessAuthenticationSession([[maybe_unused]] OpenWifi::SessionNotification &Notification) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
std::string CallingStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface, nasId;
|
||||
for (const auto &attribute : Notification.Packet_.Attrs_) {
|
||||
switch (attribute.type) {
|
||||
case RADIUS::Attributes::AUTH_USERNAME: {
|
||||
UserName.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::CALLING_STATION_ID: {
|
||||
CallingStationId.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_SESSION_ID: {
|
||||
AccountingSessionId.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_MULTI_SESSION_ID: {
|
||||
AccountingMultiSessionId.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::CHARGEABLE_USER_IDENTITY:{
|
||||
ChargeableUserIdentity.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::NAS_IDENTIFIER:{
|
||||
nasId.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::PROXY_STATE: {
|
||||
std::string Tmp;
|
||||
Tmp.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
auto ProxyParts = Poco::StringTokenizer(Tmp,":");
|
||||
if(ProxyParts.count()==4)
|
||||
Interface=ProxyParts[3];
|
||||
|
||||
} break;
|
||||
default: {
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
auto ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
|
||||
if(ap_hint==end(AccountingSessions_)) {
|
||||
SessionMap M;
|
||||
AccountingSessions_[Notification.SerialNumber_ ] = M;
|
||||
ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
|
||||
}
|
||||
|
||||
auto Index = CallingStationId; // + AccountingSessionId; // +AccountingMultiSessionId;
|
||||
auto session_hint = ap_hint->second.find(Index);
|
||||
if(session_hint==end(ap_hint->second)) {
|
||||
auto NewSession = std::make_shared<GWObjects::RADIUSSession>();
|
||||
NewSession->serialNumber = Notification.SerialNumber_;
|
||||
NewSession->started = NewSession->lastTransaction = Utils::Now();
|
||||
NewSession->userName = UserName;
|
||||
NewSession->callingStationId = CallingStationId;
|
||||
NewSession->accountingSessionId = AccountingSessionId;
|
||||
NewSession->accountingMultiSessionId = AccountingMultiSessionId;
|
||||
NewSession->chargeableUserIdentity = ChargeableUserIdentity;
|
||||
NewSession->interface = Interface;
|
||||
NewSession->nasId = nasId;
|
||||
NewSession->secret = Notification.Secret_;
|
||||
ap_hint->second[Index] = NewSession;
|
||||
} else {
|
||||
session_hint->second->lastTransaction = Utils::Now();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::uint32_t GetUiInt32(const std::uint8_t *buf) {
|
||||
return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0);
|
||||
}
|
||||
|
||||
/*
|
||||
std::string RADIUSSessionTracker::ComputeSessionIndex(OpenWifi::RADIUSSessionPtr S) {
|
||||
return "";
|
||||
}
|
||||
*/
|
||||
|
||||
void
|
||||
RADIUSSessionTracker::ProcessAccountingSession(OpenWifi::SessionNotification &Notification) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
std::string CallingStationId, AccountingSessionId, AccountingMultiSessionId, UserName, ChargeableUserIdentity, Interface;
|
||||
std::uint8_t AccountingPacketType = 0;
|
||||
std::uint32_t InputOctets=0, OutputOctets=0, InputPackets=0, OutputPackets=0, InputGigaWords=0, OutputGigaWords=0,
|
||||
SessionTime = 0;
|
||||
for (const auto &attribute : Notification.Packet_.Attrs_) {
|
||||
switch (attribute.type) {
|
||||
case RADIUS::Attributes::AUTH_USERNAME: {
|
||||
UserName.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::CALLING_STATION_ID: {
|
||||
CallingStationId.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_SESSION_ID: {
|
||||
AccountingSessionId.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_MULTI_SESSION_ID: {
|
||||
AccountingMultiSessionId.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::CHARGEABLE_USER_IDENTITY:{
|
||||
ChargeableUserIdentity.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_STATUS_TYPE: {
|
||||
AccountingPacketType = Notification.Packet_.P_.attributes[attribute.pos + 3];
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_INPUT_OCTETS: {
|
||||
InputOctets = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_INPUT_PACKETS: {
|
||||
InputPackets = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_INPUT_GIGAWORDS: {
|
||||
InputGigaWords = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_OUTPUT_OCTETS: {
|
||||
OutputOctets = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_OUTPUT_PACKETS: {
|
||||
OutputPackets= GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_OUTPUT_GIGAWORDS: {
|
||||
OutputGigaWords = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
|
||||
} break;
|
||||
case RADIUS::Attributes::ACCT_SESSION_TIME: {
|
||||
SessionTime = GetUiInt32(&Notification.Packet_.P_.attributes[attribute.pos]);
|
||||
} break;
|
||||
case RADIUS::Attributes::PROXY_STATE: {
|
||||
std::string Tmp;
|
||||
Tmp.assign(
|
||||
&Notification.Packet_.P_.attributes[attribute.pos],
|
||||
&Notification.Packet_.P_.attributes[attribute.pos + attribute.len]);
|
||||
auto ProxyParts = Poco::StringTokenizer(Tmp,":");
|
||||
if(ProxyParts.count()==4)
|
||||
Interface=ProxyParts[3];
|
||||
|
||||
} break;
|
||||
default: {
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
auto Index = CallingStationId; // + AccountingSessionId; // +AccountingMultiSessionId;
|
||||
auto ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
|
||||
if(ap_hint==end(AccountingSessions_)) {
|
||||
SessionMap M;
|
||||
AccountingSessions_[Notification.SerialNumber_ ] = M;
|
||||
ap_hint = AccountingSessions_.find(Notification.SerialNumber_);
|
||||
}
|
||||
|
||||
auto session_hint = ap_hint->second.find(Index);
|
||||
if(session_hint==end(ap_hint->second)) {
|
||||
// find the calling_station_id
|
||||
// if we are getting a stop for something we do not know, nothing to do...
|
||||
if( AccountingPacketType!=OpenWifi::RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_START &&
|
||||
AccountingPacketType!=OpenWifi::RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_INTERIM_UPDATE) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto NewSession = std::make_shared<GWObjects::RADIUSSession>();
|
||||
NewSession->serialNumber = Notification.SerialNumber_;
|
||||
NewSession->destination = Notification.Destination_;
|
||||
NewSession->started = NewSession->lastTransaction = Utils::Now();
|
||||
NewSession->userName = UserName;
|
||||
NewSession->callingStationId = CallingStationId;
|
||||
NewSession->accountingSessionId = AccountingSessionId;
|
||||
NewSession->accountingMultiSessionId = AccountingMultiSessionId;
|
||||
NewSession->accountingPacket = Notification.Packet_;
|
||||
NewSession->destination = Notification.Destination_;
|
||||
NewSession->inputOctets = InputOctets;
|
||||
NewSession->inputPackets = InputPackets;
|
||||
NewSession->inputGigaWords = InputGigaWords;
|
||||
NewSession->outputOctets = OutputOctets;
|
||||
NewSession->outputOctets = OutputPackets;
|
||||
NewSession->outputGigaWords = OutputGigaWords;
|
||||
NewSession->sessionTime = SessionTime;
|
||||
NewSession->chargeableUserIdentity = ChargeableUserIdentity;
|
||||
NewSession->interface = Interface;
|
||||
NewSession->secret = Notification.Secret_;
|
||||
|
||||
poco_debug(Logger(),fmt::format("{}: Creating session", CallingStationId));
|
||||
ap_hint->second[Index] = NewSession;
|
||||
|
||||
} else {
|
||||
|
||||
// If we receive a stop, just remove that session
|
||||
if(AccountingPacketType==OpenWifi::RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_STOP) {
|
||||
poco_debug(Logger(),fmt::format("{}: Deleting session", CallingStationId));
|
||||
ap_hint->second.erase(Index);
|
||||
} else {
|
||||
poco_debug(Logger(),fmt::format("{}: Updating session", CallingStationId));
|
||||
session_hint->second->accountingPacket = Notification.Packet_;
|
||||
session_hint->second->destination = Notification.Destination_;
|
||||
session_hint->second->lastTransaction = Utils::Now();
|
||||
session_hint->second->inputOctets = InputOctets;
|
||||
session_hint->second->inputPackets = InputPackets;
|
||||
session_hint->second->inputGigaWords = InputGigaWords;
|
||||
session_hint->second->outputOctets = OutputOctets;
|
||||
session_hint->second->outputOctets = OutputPackets;
|
||||
session_hint->second->outputGigaWords = OutputGigaWords;
|
||||
session_hint->second->sessionTime = SessionTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static void store_packet(const std::string &serialNumber, const char *buffer, std::size_t size, int i) {
|
||||
static std::uint64_t pkt=0;
|
||||
|
||||
std::string filename = MicroServiceDataDirectory() + "/radius." + serialNumber + ".stop." +
|
||||
std::to_string(pkt++) + "." + std::to_string(i) + ".bin";
|
||||
|
||||
std::ofstream ofs(filename,std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);
|
||||
ofs.write(buffer,size);
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
bool RADIUSSessionTracker::SendCoADM(const RADIUSSessionPtr &session) {
|
||||
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
P.PacketType(RADIUS::Disconnect_Request);
|
||||
P.Identifier(std::rand() & 0x00ff);
|
||||
P.AppendAttribute(RADIUS::Attributes::AUTH_USERNAME, session->userName);
|
||||
P.AppendAttribute(RADIUS::Attributes::NAS_IP, (std::uint32_t)(0x7f000001));
|
||||
P.AppendAttribute(RADIUS::Attributes::CALLING_STATION_ID, session->callingStationId);
|
||||
if(!session->accountingSessionId.empty())
|
||||
P.AppendAttribute(RADIUS::Attributes::ACCT_SESSION_ID, session->accountingSessionId);
|
||||
if(!session->accountingMultiSessionId.empty())
|
||||
P.AppendAttribute(RADIUS::Attributes::ACCT_MULTI_SESSION_ID, session->accountingMultiSessionId);
|
||||
if(!session->chargeableUserIdentity.empty())
|
||||
P.AppendAttribute(RADIUS::Attributes::CHARGEABLE_USER_IDENTITY, session->chargeableUserIdentity);
|
||||
if(!session->nasId.empty())
|
||||
P.AppendAttribute(RADIUS::Attributes::NAS_IDENTIFIER, session->nasId);
|
||||
auto ProxyState = session->serialNumber + ":" + "0.0.0.0" + ":" + "3799" + ":" + session->interface;
|
||||
std::cout << "Proxy state: " << ProxyState << " Secret: " << session->secret << std::endl;
|
||||
// P.AppendAttribute(RADIUS::PROXY_STATE, ProxyState);
|
||||
P.RecomputeAuthenticator(session->secret);
|
||||
P.Log(std::cout);
|
||||
AP_WS_Server()->SendRadiusCoAData(session->serialNumber, P.Buffer(), P.Size_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RADIUSSessionTracker::SendCoADM(const std::string &serialNumber, const std::string &sessionId) {
|
||||
poco_information(Logger(),fmt::format("{}: SendCoADM for {}.", serialNumber, sessionId));
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto ap_hint = AccountingSessions_.find(serialNumber);
|
||||
if(ap_hint==end(AccountingSessions_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const auto &[_,session]:ap_hint->second) {
|
||||
if(session->accountingSessionId==sessionId) {
|
||||
SendCoADM(session);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RADIUSSessionTracker::DisconnectSession(const std::string &SerialNumber) {
|
||||
poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber));
|
||||
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto hint = AccountingSessions_.find(SerialNumber);
|
||||
if(hint==end(AccountingSessions_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to go through all sessions and send an accounting stop
|
||||
for(const auto &session:hint->second) {
|
||||
poco_debug(Logger(), fmt::format("Stopping accounting for {}:{}", SerialNumber, session.first ));
|
||||
|
||||
RADIUS::RadiusPacket P(session.second->accountingPacket);
|
||||
|
||||
P.P_.identifier++;
|
||||
P.ReplaceAttribute(RADIUS::Attributes::ACCT_STATUS_TYPE, (std::uint32_t) RADIUS::AccountingPacketTypes::ACCT_STATUS_TYPE_STOP);
|
||||
P.ReplaceOrAdd(RADIUS::Attributes::EVENT_TIMESTAMP, (std::uint32_t) std::time(nullptr));
|
||||
P.AppendAttribute(RADIUS::Attributes::ACCT_TERMINATE_CAUSE, (std::uint32_t) RADIUS::AccountingTerminationReasons::ACCT_TERMINATE_LOST_CARRIER);
|
||||
RADIUS_proxy_server()->RouteAndSendAccountingPacket(session.second->destination, SerialNumber, P, true, session.second->secret);
|
||||
}
|
||||
|
||||
AccountingSessions_.erase(hint);
|
||||
}
|
||||
|
||||
|
||||
} // namespace OpenWifi
|
||||
207
src/RADIUSSessionTracker.h
Normal file
207
src/RADIUSSessionTracker.h
Normal file
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-03-19.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <framework/SubSystemServer.h>
|
||||
#include <Poco/Runnable.h>
|
||||
#include <Poco/Notification.h>
|
||||
#include <Poco/NotificationQueue.h>
|
||||
#include <Poco/JSON/Object.h>
|
||||
#include <Poco/Timer.h>
|
||||
|
||||
#include "RADIUS_helpers.h"
|
||||
|
||||
#include <RESTObjects/RESTAPI_GWobjects.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class SessionNotification : public Poco::Notification {
|
||||
public:
|
||||
|
||||
enum class NotificationType {
|
||||
accounting_session_message,
|
||||
authentication_session_message,
|
||||
ap_disconnect
|
||||
};
|
||||
|
||||
explicit SessionNotification(NotificationType T, const std::string &Destination, const std::string &SerialNumber, const RADIUS::RadiusPacket &P, const std::string &secret)
|
||||
: Type_(T), Destination_(Destination), SerialNumber_(SerialNumber), Packet_(P), Secret_(secret) {
|
||||
}
|
||||
|
||||
explicit SessionNotification(const std::string &SerialNumber)
|
||||
: Type_(NotificationType::ap_disconnect), SerialNumber_(SerialNumber) {
|
||||
|
||||
}
|
||||
|
||||
NotificationType Type_;
|
||||
std::string Destination_;
|
||||
std::string SerialNumber_;
|
||||
RADIUS::RadiusPacket Packet_;
|
||||
std::string Secret_;
|
||||
};
|
||||
|
||||
class TrackerFutureCompletion {
|
||||
public:
|
||||
virtual bool Completed(const RADIUS::RadiusPacket &P) = 0;
|
||||
virtual bool StillValid() = 0;
|
||||
private:
|
||||
};
|
||||
|
||||
class CoADisconnectResponse : public TrackerFutureCompletion {
|
||||
public:
|
||||
CoADisconnectResponse(const std::string &serialNumber, std::uint8_t id, const std::vector<std::uint8_t> &types, const std::string &callingStationId):
|
||||
SerialNumber_(serialNumber),
|
||||
Id_(id),
|
||||
PacketTypes_(types),
|
||||
CallingStationId_(callingStationId) {
|
||||
Created_ = Utils::Now();
|
||||
}
|
||||
|
||||
bool Completed(const RADIUS::RadiusPacket &P) final {
|
||||
if(P.Identifier()==Id_) {
|
||||
if(P.P_.code == RADIUS::Disconnect_ACK) {
|
||||
|
||||
} else if (P.P_.code == RADIUS::Disconnect_NAK) {
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StillValid() final {
|
||||
return (Utils::Now()-Created_) < 20;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string SerialNumber_;
|
||||
std::uint8_t Id_;
|
||||
std::vector<std::uint8_t> PacketTypes_;
|
||||
std::uint64_t Created_;
|
||||
std::string CallingStationId_;
|
||||
};
|
||||
|
||||
using RADIUSSessionPtr = std::shared_ptr<GWObjects::RADIUSSession>;
|
||||
|
||||
class RADIUSSessionTracker : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new RADIUSSessionTracker;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void run() final;
|
||||
|
||||
inline void AddAccountingSession(const std::string &Destination, const std::string &SerialNumber,
|
||||
const RADIUS::RadiusPacket &P, const std::string &secret) {
|
||||
SessionMessageQueue_.enqueueNotification(new SessionNotification(SessionNotification::NotificationType::accounting_session_message, Destination, SerialNumber, P, secret));
|
||||
}
|
||||
|
||||
inline void AddAuthenticationSession(const std::string &Destination, const std::string &SerialNumber,
|
||||
const RADIUS::RadiusPacket &P, const std::string &secret) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto ap_hint = AccountingSessions_.find(SerialNumber);
|
||||
if(AccountingSessions_.find(SerialNumber)!=end(AccountingSessions_)) {
|
||||
// if we have already added the info, do not need to add it again
|
||||
auto CallingStationId = P.ExtractCallingStationID();
|
||||
auto AccountingSessionId = P.ExtractAccountingSessionID();
|
||||
if(ap_hint->second.find(CallingStationId+AccountingSessionId)!=end(ap_hint->second)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SessionMessageQueue_.enqueueNotification(new SessionNotification(SessionNotification::NotificationType::authentication_session_message, Destination, SerialNumber, P, secret));
|
||||
}
|
||||
|
||||
inline void DeviceDisconnect(const std::string &serialNumber) {
|
||||
SessionMessageQueue_.enqueueNotification(new SessionNotification(serialNumber));
|
||||
}
|
||||
|
||||
inline void GetAPList(std::vector<std::string> &SerialNumbers) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
for(const auto &[serialNumber,_]:AccountingSessions_) {
|
||||
SerialNumbers.emplace_back(serialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
inline void GetAPSessions(const std::string &SerialNumber, GWObjects::RADIUSSessionList & list) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
auto ap_hint = AccountingSessions_.find(SerialNumber);
|
||||
if(ap_hint!=end(AccountingSessions_)) {
|
||||
for(const auto &[index,session]:ap_hint->second) {
|
||||
list.sessions.emplace_back(*session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void GetUserNameAPSessions(const std::string &userName, GWObjects::RADIUSSessionList & list) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
for(const auto &[_,sessions]:AccountingSessions_) {
|
||||
for(const auto &[_,session]:sessions) {
|
||||
if(Utils::match(userName.c_str(),session->userName.c_str())) {
|
||||
list.sessions.emplace_back(*session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void GetMACAPSessions(const std::string &mac, GWObjects::RADIUSSessionList & list) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
for(const auto &[_,sessions]:AccountingSessions_) {
|
||||
for(const auto &[_,session]:sessions) {
|
||||
if(Utils::match(mac.c_str(),session->callingStationId.c_str())) {
|
||||
list.sessions.emplace_back(*session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SendCoADM(const std::string &serialNumber, const std::string &sessionId);
|
||||
bool SendCoADM(const RADIUSSessionPtr &session);
|
||||
|
||||
inline std::uint32_t HasSessions(const std::string & serialNumber) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto ap_hint = AccountingSessions_.find(serialNumber);
|
||||
if(ap_hint==end(AccountingSessions_)) {
|
||||
return 0;
|
||||
}
|
||||
return ap_hint->second.size();
|
||||
}
|
||||
|
||||
void GarbageCollection(Poco::Timer &timer);
|
||||
|
||||
private:
|
||||
std::atomic_bool Running_=false;
|
||||
Poco::NotificationQueue SessionMessageQueue_;
|
||||
Poco::Thread QueueManager_;
|
||||
|
||||
using SessionMap = std::map<std::string,RADIUSSessionPtr>; // calling-station-id + accounting-session-id
|
||||
std::map<std::string,SessionMap> AccountingSessions_; // serial-number -> session< accounting-session -> session>
|
||||
|
||||
Poco::Timer GarbageCollectionTimer_;
|
||||
std::unique_ptr<Poco::TimerCallback<RADIUSSessionTracker>> GarbageCollectionCallback_;
|
||||
|
||||
std::uint64_t SessionTimeout_=10*60;
|
||||
|
||||
|
||||
void ProcessAccountingSession(SessionNotification &Notification);
|
||||
void ProcessAuthenticationSession(SessionNotification &Notification);
|
||||
void DisconnectSession(const std::string &SerialNumber);
|
||||
|
||||
RADIUSSessionTracker() noexcept
|
||||
: SubSystemServer("RADIUSSessionTracker", "RADIUS-SESSION", "radius.session") {}
|
||||
|
||||
std::string ComputeSessionIndex(RADIUSSessionPtr S);
|
||||
};
|
||||
|
||||
inline auto RADIUSSessionTracker() { return RADIUSSessionTracker::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -16,246 +16,224 @@
|
||||
|
||||
namespace OpenWifi::RADIUS {
|
||||
|
||||
#define RADCMD_ACCESS_REQ 1 /* Access-Request */
|
||||
#define RADCMD_ACCESS_ACC 2 /* Access-Accept */
|
||||
#define RADCMD_ACCESS_REJ 3 /* Access-Reject */
|
||||
#define RADCMD_ACCOUN_REQ 4 /* Accounting-Request */
|
||||
#define RADCMD_ACCOUN_RES 5 /* Accounting-Response */
|
||||
#define RADCMD_ACCOUN_STATUS 6 /* Accounting-Status */
|
||||
#define RADCMD_PASSWORD_REQUEST 7 /* Password-Request [RFC3575] */
|
||||
#define RADCMD_PASSWORD_ACK 8 /* Password-Ack [RFC3575] */
|
||||
#define RADCMD_PASSWORD_REJECT 9 /* Password-Reject [RFC3575] */
|
||||
#define RADCMD_ACCOUN_MESSAGE 10 /* Accounting-Message [RFC3575] */
|
||||
// Packet types
|
||||
constexpr std::uint8_t Access_Request = 1;
|
||||
constexpr std::uint8_t Access_Accept = 2;
|
||||
constexpr std::uint8_t Access_Reject = 3;
|
||||
constexpr std::uint8_t Accounting_Request = 4;
|
||||
constexpr std::uint8_t Accounting_Response = 5;
|
||||
constexpr std::uint8_t Accounting_Status = 6;
|
||||
constexpr std::uint8_t Password_Request = 7;
|
||||
constexpr std::uint8_t Password_Ack = 8;
|
||||
constexpr std::uint8_t Password_Reject = 9;
|
||||
constexpr std::uint8_t Accounting_Message = 10;
|
||||
constexpr std::uint8_t Access_Challenge = 11;
|
||||
constexpr std::uint8_t Status_Server = 12; /* Status-Server */
|
||||
constexpr std::uint8_t Status_Client = 13; /* Status-Client */
|
||||
constexpr std::uint8_t Disconnect_Request = 40;
|
||||
constexpr std::uint8_t Disconnect_ACK = 41;
|
||||
constexpr std::uint8_t Disconnect_NAK = 42;
|
||||
constexpr std::uint8_t CoA_Request = 43;
|
||||
constexpr std::uint8_t CoA_ACK = 44;
|
||||
constexpr std::uint8_t CoA_NAK = 45;
|
||||
constexpr std::uint8_t Resource_Free_Request = 21;
|
||||
constexpr std::uint8_t Resource_Free_Response = 22;
|
||||
constexpr std::uint8_t Resource_Query_Request = 23;
|
||||
constexpr std::uint8_t Resource_Query_Response = 24;
|
||||
constexpr std::uint8_t Alternate_Resource_Reclaim_Request = 25 ;
|
||||
constexpr std::uint8_t Reserved_Cmd = 255; /* Reserved */
|
||||
|
||||
#define RADCMD_RES_FREE_REQ 21 /* Resource-Free-Request [RFC3575] */
|
||||
#define RADCMD_RES_FREE_RES 22 /* Resource-Free-Response [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_REQ 23 /* Resource-Query-Request [RFC3575] */
|
||||
#define RADCMD_RES_QUERY_RES 24 /* Resource-Query-Response [RFC3575] */
|
||||
#define RADCMD_RES_ALT_RECLAIM_REQ 25 /* Alternate-Resource-Reclaim-Request [RFC3575] */
|
||||
// Some attribute values
|
||||
namespace Attributes {
|
||||
constexpr std::uint8_t AUTH_USERNAME = 1;
|
||||
constexpr std::uint8_t USER_PASSWORD = 2;
|
||||
constexpr std::uint8_t CHAP_PASSWORD = 3;
|
||||
constexpr std::uint8_t NAS_IP = 4;
|
||||
constexpr std::uint8_t CALLED_STATION_ID = 30;
|
||||
constexpr std::uint8_t CALLING_STATION_ID = 31;
|
||||
constexpr std::uint8_t NAS_IDENTIFIER = 32;
|
||||
constexpr std::uint8_t PROXY_STATE = 33;
|
||||
constexpr std::uint8_t ACCT_STATUS_TYPE = 40;
|
||||
constexpr std::uint8_t ACCT_INPUT_OCTETS = 42;
|
||||
constexpr std::uint8_t ACCT_OUTPUT_OCTETS = 43;
|
||||
constexpr std::uint8_t ACCT_SESSION_ID = 44;
|
||||
constexpr std::uint8_t ACCT_AUTHENTIC = 45;
|
||||
constexpr std::uint8_t ACCT_SESSION_TIME = 46;
|
||||
constexpr std::uint8_t ACCT_INPUT_PACKETS = 47;
|
||||
constexpr std::uint8_t ACCT_OUTPUT_PACKETS = 48;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_CAUSE = 49;
|
||||
constexpr std::uint8_t ACCT_MULTI_SESSION_ID = 50;
|
||||
constexpr std::uint8_t ACCT_INPUT_GIGAWORDS = 52;
|
||||
constexpr std::uint8_t ACCT_OUTPUT_GIGAWORDS = 53;
|
||||
constexpr std::uint8_t EVENT_TIMESTAMP = 55;
|
||||
constexpr std::uint8_t MESSAGE_AUTHENTICATOR = 80;
|
||||
constexpr std::uint8_t CHARGEABLE_USER_IDENTITY = 89;
|
||||
};
|
||||
|
||||
#define RADCMD_ACCESS_CHA 11 /* Access-Challenge */
|
||||
#define RADCMD_STATUS_SER 12 /* Status-Server */
|
||||
#define RADCMD_STATUS_CLI 13 /* Status-Client */
|
||||
#define RADCMD_DISCON_REQ 40 /* Disconnect-Request */
|
||||
#define RADCMD_DISCON_ACK 41 /* Disconnect-ACK */
|
||||
#define RADCMD_DISCON_NAK 42 /* Disconnect-NAK */
|
||||
#define RADCMD_COA_REQ 43 /* CoA-Request */
|
||||
#define RADCMD_COA_ACK 44 /* CoA-ACK */
|
||||
#define RADCMD_COA_NAK 45 /* CoA-NAK */
|
||||
#define RADCMD_RESERVED 255 /* Reserved */
|
||||
namespace AccountingPacketTypes {
|
||||
constexpr std::uint8_t ACCT_STATUS_TYPE_START = 1;
|
||||
constexpr std::uint8_t ACCT_STATUS_TYPE_STOP = 2;
|
||||
constexpr std::uint8_t ACCT_STATUS_TYPE_INTERIM_UPDATE = 3;
|
||||
constexpr std::uint8_t ACCT_STATUS_TYPE_ACCOUNTING_ON = 7;
|
||||
constexpr std::uint8_t ACCT_STATUS_TYPE_ACCOUNTING_OFF = 8;
|
||||
constexpr std::uint8_t ACCT_STATUS_TYPE_FAILED = 15;
|
||||
}
|
||||
|
||||
/*
|
||||
21 Resource-Free-Request [RFC3575]
|
||||
22 Resource-Free-Response [RFC3575]
|
||||
23 Resource-Query-Request [RFC3575]
|
||||
24 Resource-Query-Response [RFC3575]
|
||||
25 Alternate-Resource-Reclaim-Request [RFC3575]
|
||||
namespace AccountingTerminationReasons {
|
||||
constexpr std::uint8_t ACCT_TERMINATE_USER_REQUEST = 1;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_LOST_CARRIER = 2;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_LOST_SERVICE = 3;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_IDLE_TIMEOUT = 4;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_SESSION_TIMEOUT = 5;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_ADMIN_RESET = 6;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_ADMIN_REBOOT = 7;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_PORT_ERROR = 8;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_NAS_ERROR = 9;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_NAS_REQUEST = 10;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_PORT_REBOOT = 11;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_PORT_UNNEEDED = 12;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_PORT_PREEMPTED = 13;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_PORT_SUSPEND = 14;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_SERVICE_UNAVAILABLE = 15;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_CALLBACK = 16;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_USER_ERROR = 17;
|
||||
constexpr std::uint8_t ACCT_TERMINATE_HOST_REQUEST = 18;
|
||||
};
|
||||
|
||||
26 NAS-Reboot-Request [RFC3575]
|
||||
27 NAS-Reboot-Response [RFC3575]
|
||||
28 Reserved
|
||||
29 Next-Passcode [RFC3575]
|
||||
30 New-Pin [RFC3575]
|
||||
31 Terminate-Session [RFC3575]
|
||||
32 Password-Expired [RFC3575]
|
||||
33 Event-Request [RFC3575]
|
||||
34 Event-Response [RFC3575]
|
||||
35-39 Unassigned
|
||||
40 Disconnect-Request [RFC3575][RFC5176]
|
||||
41 Disconnect-ACK [RFC3575][RFC5176]
|
||||
42 Disconnect-NAK [RFC3575][RFC5176]
|
||||
43 CoA-Request [RFC3575][RFC5176]
|
||||
44 CoA-ACK [RFC3575][RFC5176]
|
||||
45 CoA-NAK [RFC3575][RFC5176]
|
||||
46-49 Unassigned
|
||||
50 IP-Address-Allocate [RFC3575]
|
||||
51 IP-Address-Release [RFC3575]
|
||||
52 Protocol-Error [RFC7930]
|
||||
53-249 Unassigned
|
||||
250-253 Experimental Use [RFC3575]
|
||||
254 Reserved [RFC3575]
|
||||
255 Reserved [RFC3575]
|
||||
*/
|
||||
namespace AuthenticationTypes {
|
||||
constexpr std::uint8_t ACCT_AUTHENTIC_RADIUS = 1;
|
||||
constexpr std::uint8_t ACCT_AUTHENTIC_LOCAL = 2;
|
||||
constexpr std::uint8_t ACCT_AUTHENTIC_REMOTE = 3;
|
||||
};
|
||||
|
||||
constexpr std::uint32_t TIP_vendor_id = 58888;
|
||||
constexpr std::uint8_t TIP_serial = 1;
|
||||
constexpr std::uint8_t TIP_AAAipaddr = 2;
|
||||
constexpr std::uint8_t TIP_AAAipv6addr = 3;
|
||||
|
||||
struct tok {
|
||||
uint cmd;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Radius commands
|
||||
|
||||
char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
|
||||
"", //!< 0
|
||||
"Access-Request",
|
||||
"Access-Accept",
|
||||
"Access-Reject",
|
||||
"Accounting-Request",
|
||||
"Accounting-Response",
|
||||
"Accounting-Status",
|
||||
"Password-Request",
|
||||
"Password-Accept",
|
||||
"Password-Reject",
|
||||
"Accounting-Message", //!< 10
|
||||
"Access-Challenge",
|
||||
"Status-Server",
|
||||
"Status-Client",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
"18",
|
||||
"19",
|
||||
"20", //!< 20
|
||||
"Resource-Free-Request",
|
||||
"Resource-Free-Response",
|
||||
"Resource-Query-Request",
|
||||
"Resource-Query-Response",
|
||||
"Alternate-Resource-Reclaim-Request",
|
||||
"NAS-Reboot-Request",
|
||||
"NAS-Reboot-Response",
|
||||
"28",
|
||||
"Next-Passcode",
|
||||
"New-Pin", //!< 30
|
||||
"Terminate-Session",
|
||||
"Password-Expired",
|
||||
"Event-Request",
|
||||
"Event-Response",
|
||||
"35",
|
||||
"36",
|
||||
"37",
|
||||
"38",
|
||||
"39",
|
||||
"Disconnect-Request", //!< 40
|
||||
"Disconnect-ACK",
|
||||
"Disconnect-NAK",
|
||||
"CoA-Request",
|
||||
"CoA-ACK",
|
||||
"CoA-NAK",
|
||||
"46",
|
||||
"47",
|
||||
"48",
|
||||
"49",
|
||||
"IP-Address-Allocate",
|
||||
"IP-Address-Release", //!< 50
|
||||
static const struct tok radius_command_values[] = {
|
||||
{Access_Request, "Access-Request"},
|
||||
{Access_Accept, "Access-Accept"},
|
||||
{Access_Reject, "Access-Reject"},
|
||||
{Accounting_Request, "Accounting-Request"},
|
||||
{Accounting_Response, "Accounting-Response"},
|
||||
{Access_Challenge, "Access-Challenge"},
|
||||
{Status_Server, "Status-Server"},
|
||||
{Status_Client, "Status-Client"},
|
||||
{Disconnect_Request, "Disconnect-Request"},
|
||||
{Disconnect_ACK, "Disconnect-ACK"},
|
||||
{Disconnect_NAK, "Disconnect-NAK"},
|
||||
{CoA_Request, "CoA-Request"},
|
||||
{CoA_ACK, "CoA-ACK"},
|
||||
{CoA_NAK, "CoA-NAK"},
|
||||
{Reserved_Cmd, "Reserved"},
|
||||
{Accounting_Status, "Accounting-Status"},
|
||||
{Password_Request, "Password-Request"},
|
||||
{Password_Ack, "Password-Ack"},
|
||||
{Password_Reject, "Password-Reject"},
|
||||
{Accounting_Message, "Accounting-Message"},
|
||||
{Resource_Free_Request, "Resource-Free-Request"},
|
||||
{Resource_Free_Response, "Resource-Free-Response"},
|
||||
{Resource_Query_Request, "Resource-Query-Request"},
|
||||
{Resource_Query_Response, "Resource-Query-Response"},
|
||||
{Alternate_Resource_Reclaim_Request, "Alternate-Resource-Reclaim-Request"},
|
||||
{0, nullptr}
|
||||
};
|
||||
|
||||
static const struct tok radius_attribute_names[] = {
|
||||
{ Attributes::AUTH_USERNAME, "User-Name"},
|
||||
{ Attributes::USER_PASSWORD, "User-Password"},
|
||||
{ Attributes::CHAP_PASSWORD, "CHAP-Password"},
|
||||
{ Attributes::NAS_IP, "NAS-IP Address"},
|
||||
{5, "NAS-Port"},
|
||||
{6, "Service-Type"},
|
||||
{7, "Framed-Protocol"},
|
||||
{8, "Framed-IP-Address"},
|
||||
{9, "Framed-IP-Netmask"},
|
||||
{10, "Framed-Routing"},
|
||||
{11, "Filter-Id"},
|
||||
{12, "Framed-MTU"},
|
||||
{13, "Framed-Compression"},
|
||||
{14, "Login-IP-Host"},
|
||||
{15, "Login-Service"},
|
||||
{16, "Login-TCP-Port"},
|
||||
{18, "Reply-Message"},
|
||||
{19, "Callback-Number"},
|
||||
{20, "Callback-ID"},
|
||||
{22, "Framed-Route"},
|
||||
{23, "Framed-IPX-Network"},
|
||||
{24, "State"},
|
||||
{25, "Class"},
|
||||
{26, "Vendor-Specific"},
|
||||
{27, "Session-Timeout"},
|
||||
{28, "Idle-Timeout"},
|
||||
{29, "Termination-Action"},
|
||||
{ Attributes::CALLED_STATION_ID, "Called-Station-Id"},
|
||||
{ Attributes::CALLING_STATION_ID, "Calling-Station-Id"},
|
||||
{ Attributes::NAS_IDENTIFIER, "NAS-Identifier"},
|
||||
{ Attributes::PROXY_STATE, "Proxy-State"},
|
||||
{34, "Login-LAT-Service"},
|
||||
{35, "Login-LAT-Node"},
|
||||
{36, "Login-LAT-Group"},
|
||||
{37, "Framed-AppleTalk-Link"},
|
||||
{38, "Framed-AppleTalk-Network"},
|
||||
{39, "Framed-AppleTalk-Zone"},
|
||||
{ Attributes::ACCT_STATUS_TYPE, "Acct-Status-Type"},
|
||||
{41, "Acct-Delay-Time"},
|
||||
{ Attributes::ACCT_INPUT_OCTETS, "Acct-Input-Octets"},
|
||||
{ Attributes::ACCT_OUTPUT_OCTETS, "Acct-Output-Octets"},
|
||||
{ Attributes::ACCT_SESSION_ID, "Acct-Session-Id"},
|
||||
{ Attributes::ACCT_AUTHENTIC, "Acct-Authentic"},
|
||||
{ Attributes::ACCT_SESSION_TIME, "Acct-Session-Time"},
|
||||
{ Attributes::ACCT_INPUT_PACKETS, "Acct-Input-Packets"},
|
||||
{ Attributes::ACCT_OUTPUT_PACKETS, "Acct-Output-Packets"},
|
||||
{ Attributes::ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause"},
|
||||
{ Attributes::ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id"},
|
||||
{51, "Acct-Link-Count"},
|
||||
{ Attributes::ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords"},
|
||||
{ Attributes::ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords"},
|
||||
{ Attributes::EVENT_TIMESTAMP, "Event-Timestamp"},
|
||||
{60, "CHAP-Challenge"},
|
||||
{61, "NAS-Port-Type"},
|
||||
{62, "Port-Limit"},
|
||||
{63, "Login-LAT-Port"},
|
||||
{64, "Tunnel-Type3"},
|
||||
{65, "Tunnel-Medium-Type1"},
|
||||
{66, "Tunnel-Client-Endpoint"},
|
||||
{67, "Tunnel-Server-Endpoint1"},
|
||||
{68, "Acct-Tunnel-Connection-ID"},
|
||||
{69, "Tunnel-Password1"},
|
||||
{70, "ARAP-Password"},
|
||||
{71, "ARAP-Features"},
|
||||
{72, "ARAP-Zone-Access"},
|
||||
{73, "ARAP-Security"},
|
||||
{74, "ARAP-Security-Data"},
|
||||
{75, "Password-Retry"},
|
||||
{76, "Prompt"},
|
||||
{77, "Connect-Info"},
|
||||
{78, "Configuration-Token"},
|
||||
{79, "EAP-Message"},
|
||||
{ Attributes::MESSAGE_AUTHENTICATOR, "Message-Authenticator"},
|
||||
{81, "Tunnel-Private-Group-ID"},
|
||||
{82, "Tunnel-Assignment-ID1"},
|
||||
{83, "Tunnel-Preference"},
|
||||
{84, "ARAP-Challenge-Response"},
|
||||
{85, "Acct-Interim-Interval"},
|
||||
{86, "Acct-Tunnel-Packets-Lost"},
|
||||
{87, "NAS-Port-ID"},
|
||||
{88, "Framed-Pool"},
|
||||
{ Attributes::CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity"},
|
||||
{90, "Tunnel-Client-Auth-ID"},
|
||||
{91, "Tunnel-Server-Auth-ID"},
|
||||
{0, nullptr}
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
static const struct tok radius_command_values[] = {
|
||||
{RADCMD_ACCESS_REQ, "Access-Request"},
|
||||
{RADCMD_ACCESS_ACC, "Access-Accept"},
|
||||
{RADCMD_ACCESS_REJ, "Access-Reject"},
|
||||
{RADCMD_ACCOUN_REQ, "Accounting-Request"},
|
||||
{RADCMD_ACCOUN_RES, "Accounting-Response"},
|
||||
{RADCMD_ACCESS_CHA, "Access-Challenge"},
|
||||
{RADCMD_STATUS_SER, "Status-Server"},
|
||||
{RADCMD_STATUS_CLI, "Status-Client"},
|
||||
{RADCMD_DISCON_REQ, "Disconnect-Request"},
|
||||
{RADCMD_DISCON_ACK, "Disconnect-ACK"},
|
||||
{RADCMD_DISCON_NAK, "Disconnect-NAK"},
|
||||
{RADCMD_COA_REQ, "CoA-Request"},
|
||||
{RADCMD_COA_ACK, "CoA-ACK"},
|
||||
{RADCMD_COA_NAK, "CoA-NAK"},
|
||||
{RADCMD_RESERVED, "Reserved"},
|
||||
{RADCMD_ACCOUN_STATUS, "Accounting-Status"},
|
||||
{RADCMD_PASSWORD_REQUEST, "Password-Request"},
|
||||
{RADCMD_PASSWORD_ACK, "Password-Ack"},
|
||||
{RADCMD_PASSWORD_REJECT, "Password-Reject"},
|
||||
{RADCMD_ACCOUN_MESSAGE, "Accounting-Message"},
|
||||
{RADCMD_RES_FREE_REQ, "Resource-Free-Request"},
|
||||
{RADCMD_RES_FREE_RES, "Resource-Free-Response"},
|
||||
{RADCMD_RES_QUERY_REQ, "Resource-Query-Request"},
|
||||
{RADCMD_RES_QUERY_RES, "Resource-Query-Response"},
|
||||
{RADCMD_RES_ALT_RECLAIM_REQ, "Alternate-Resource-Reclaim-Request"},
|
||||
{0, nullptr}};
|
||||
|
||||
static const struct tok radius_attribute_names[] = {{1, "User-Name"},
|
||||
{2, "User-Password"},
|
||||
{3, "CHAP-Password"},
|
||||
{4, "NAS-IP Address"},
|
||||
{5, "NAS-Port"},
|
||||
{6, "Service-Type"},
|
||||
{7, "Framed-Protocol"},
|
||||
{8, "Framed-IP-Address"},
|
||||
{9, "Framed-IP-Netmask"},
|
||||
{10, "Framed-Routing"},
|
||||
{11, "Filter-Id"},
|
||||
{12, "Framed-MTU"},
|
||||
{13, "Framed-Compression"},
|
||||
{14, "Login-IP-Host"},
|
||||
{15, "Login-Service"},
|
||||
{16, "Login-TCP-Port"},
|
||||
{18, "Reply-Message"},
|
||||
{19, "Callback-Number"},
|
||||
{20, "Callback-ID"},
|
||||
{22, "Framed-Route"},
|
||||
{23, "Framed-IPX-Network"},
|
||||
{24, "State"},
|
||||
{25, "Class"},
|
||||
{26, "Vendor-Specific"},
|
||||
{27, "Session-Timeout"},
|
||||
{28, "Idle-Timeout"},
|
||||
{29, "Termination-Action"},
|
||||
{30, "Called-Station-Id"},
|
||||
{31, "Calling-Station-Id"},
|
||||
{32, "NAS-Identifier"},
|
||||
{33, "Proxy-State"},
|
||||
{34, "Login-LAT-Service"},
|
||||
{35, "Login-LAT-Node"},
|
||||
{36, "Login-LAT-Group"},
|
||||
{37, "Framed-AppleTalk-Link"},
|
||||
{38, "Framed-AppleTalk-Network"},
|
||||
{39, "Framed-AppleTalk-Zone"},
|
||||
{40, "Acct-Status-Type"},
|
||||
{41, "Acct-Delay-Time"},
|
||||
{42, "Acct-Input-Octets"},
|
||||
{43, "Acct-Output-Octets"},
|
||||
{44, "Acct-Session-Id"},
|
||||
{45, "Acct-Authentic"},
|
||||
{46, "Acct-Session-Time"},
|
||||
{47, "Acct-Input-Packets"},
|
||||
{48, "Acct-Output-Packets"},
|
||||
{49, "Acct-Terminate-Cause"},
|
||||
{50, "Acct-Multi-Session-Id"},
|
||||
{51, "Acct-Link-Count"},
|
||||
{52, "Acct-Input-Gigawords"},
|
||||
{53, "Acct-Output-Gigawords"},
|
||||
{55, "Event-Timestamp"},
|
||||
{60, "CHAP-Challenge"},
|
||||
{61, "NAS-Port-Type"},
|
||||
{62, "Port-Limit"},
|
||||
{63, "Login-LAT-Port"},
|
||||
{64, "Tunnel-Type3"},
|
||||
{65, "Tunnel-Medium-Type1"},
|
||||
{66, "Tunnel-Client-Endpoint"},
|
||||
{67, "Tunnel-Server-Endpoint1"},
|
||||
{68, "Acct-Tunnel-Connection-ID"},
|
||||
{69, "Tunnel-Password1"},
|
||||
{70, "ARAP-Password"},
|
||||
{71, "ARAP-Features"},
|
||||
{72, "ARAP-Zone-Access"},
|
||||
{73, "ARAP-Security"},
|
||||
{74, "ARAP-Security-Data"},
|
||||
{75, "Password-Retry"},
|
||||
{76, "Prompt"},
|
||||
{77, "Connect-Info"},
|
||||
{78, "Configuration-Token"},
|
||||
{79, "EAP-Message"},
|
||||
{80, "Message-Authenticator"},
|
||||
{81, "Tunnel-Private-Group-ID"},
|
||||
{82, "Tunnel-Assignment-ID1"},
|
||||
{83, "Tunnel-Preference"},
|
||||
{84, "ARAP-Challenge-Response"},
|
||||
{85, "Acct-Interim-Interval"},
|
||||
{86, "Acct-Tunnel-Packets-Lost"},
|
||||
{87, "NAS-Port-ID"},
|
||||
{88, "Framed-Pool"},
|
||||
{90, "Tunnel-Client-Auth-ID"},
|
||||
{91, "Tunnel-Server-Auth-ID"},
|
||||
{0, nullptr}};
|
||||
constexpr std::uint32_t AttributeOffset = 20;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct RadiusAttribute {
|
||||
@@ -272,25 +250,6 @@ namespace OpenWifi::RADIUS {
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr unsigned char Access_Request = 1;
|
||||
constexpr unsigned char Access_Accept = 2;
|
||||
constexpr unsigned char Access_Reject = 3;
|
||||
constexpr unsigned char Access_Challenge = 11;
|
||||
|
||||
constexpr unsigned char Accounting_Request = 4;
|
||||
constexpr unsigned char Accounting_Response = 5;
|
||||
constexpr unsigned char Accounting_Status = 6;
|
||||
constexpr unsigned char Accounting_Message = 10;
|
||||
|
||||
constexpr unsigned char Disconnect_Request = 40;
|
||||
constexpr unsigned char Disconnect_ACK = 41;
|
||||
constexpr unsigned char Disconnect_NAK = 42;
|
||||
constexpr unsigned char CoA_Request = 43;
|
||||
constexpr unsigned char CoA_ACK = 44;
|
||||
constexpr unsigned char CoA_NAK = 45;
|
||||
|
||||
constexpr unsigned char ATTR_MessageAuthenticator = 80;
|
||||
|
||||
inline bool IsAuthentication(unsigned char t) {
|
||||
return (t == RADIUS::Access_Request || t == RADIUS::Access_Accept ||
|
||||
t == RADIUS::Access_Challenge || t == RADIUS::Access_Reject);
|
||||
@@ -333,10 +292,6 @@ namespace OpenWifi::RADIUS {
|
||||
//
|
||||
// From: https://github.com/Telecominfraproject/wlan-dictionary/blob/main/dictionary.tip
|
||||
//
|
||||
static const uint32_t TIP_vendor_id = 58888;
|
||||
static const unsigned char TIP_serial = 1;
|
||||
static const unsigned char TIP_AAAipaddr = 2;
|
||||
static const unsigned char TIP_AAAipv6addr = 3;
|
||||
|
||||
using AttributeList = std::list<RadiusAttribute>;
|
||||
|
||||
@@ -384,7 +339,7 @@ namespace OpenWifi::RADIUS {
|
||||
}
|
||||
memcpy((void *)&P_, Buf.begin(), Buf.size());
|
||||
Size_ = Buf.size();
|
||||
Valid_ = (Size_ == htons(P_.rawlen));
|
||||
Valid_ = (Size_ == ntohs(P_.rawlen));
|
||||
if (Valid_)
|
||||
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
|
||||
}
|
||||
@@ -396,7 +351,7 @@ namespace OpenWifi::RADIUS {
|
||||
}
|
||||
memcpy((void *)&P_, buffer, size);
|
||||
Size_ = size;
|
||||
Valid_ = (Size_ == htons(P_.rawlen));
|
||||
Valid_ = (Size_ == ntohs(P_.rawlen));
|
||||
if (Valid_)
|
||||
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
|
||||
}
|
||||
@@ -408,19 +363,35 @@ namespace OpenWifi::RADIUS {
|
||||
}
|
||||
memcpy((void *)&P_, (const unsigned char *)p.c_str(), p.size());
|
||||
Size_ = p.size();
|
||||
Valid_ = (Size_ == htons(P_.rawlen));
|
||||
Valid_ = (Size_ == ntohs(P_.rawlen));
|
||||
if (Valid_)
|
||||
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
|
||||
}
|
||||
|
||||
explicit RadiusPacket(const RadiusPacket &P) {
|
||||
RadiusPacket(const RadiusPacket &P) {
|
||||
Valid_ = P.Valid_;
|
||||
Size_ = P.Size_;
|
||||
P_ = P.P_;
|
||||
Attrs_ = P.Attrs_;
|
||||
}
|
||||
|
||||
explicit RadiusPacket() = default;
|
||||
void ReParse() {
|
||||
P_.rawlen = htons(Size_);
|
||||
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
|
||||
}
|
||||
|
||||
inline RadiusPacket& operator=(const RadiusPacket& other) {
|
||||
Valid_ = other.Valid_;
|
||||
Size_ = other.Size_;
|
||||
P_ = other.P_;
|
||||
Attrs_ = other.Attrs_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit RadiusPacket() :
|
||||
P_{0}, Size_(AttributeOffset)
|
||||
{
|
||||
};
|
||||
|
||||
unsigned char *Buffer() { return (unsigned char *)&P_; }
|
||||
[[nodiscard]] uint16_t BufferLen() const { return sizeof(P_); }
|
||||
@@ -430,7 +401,7 @@ namespace OpenWifi::RADIUS {
|
||||
Valid_ = ParseRadius(0, (unsigned char *)&P_.attributes[0], Size_ - 20, Attrs_);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t Len() const { return htons(P_.rawlen); }
|
||||
[[nodiscard]] uint16_t Len() const { return ntohs(P_.rawlen); }
|
||||
[[nodiscard]] uint16_t Size() const { return Size_; }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
|
||||
@@ -438,9 +409,9 @@ namespace OpenWifi::RADIUS {
|
||||
inline bool IsAuthentication() {
|
||||
return (P_.code == RADIUS::Access_Request || P_.code == RADIUS::Access_Accept ||
|
||||
P_.code == RADIUS::Access_Challenge || P_.code == RADIUS::Access_Reject ||
|
||||
P_.code == RADCMD_RES_FREE_REQ || P_.code == RADCMD_RES_FREE_RES ||
|
||||
P_.code == RADCMD_RES_QUERY_REQ || P_.code == RADCMD_RES_QUERY_RES ||
|
||||
P_.code == RADCMD_RES_ALT_RECLAIM_REQ);
|
||||
P_.code == RADIUS::Resource_Free_Request || P_.code == RADIUS::Resource_Free_Response ||
|
||||
P_.code == RADIUS::Resource_Query_Request || P_.code == RADIUS::Resource_Query_Response ||
|
||||
P_.code == RADIUS::Alternate_Resource_Reclaim_Request);
|
||||
}
|
||||
|
||||
inline bool IsAccounting() {
|
||||
@@ -475,7 +446,8 @@ namespace OpenWifi::RADIUS {
|
||||
|
||||
inline const char *PacketType() { return CommandName(P_.code); }
|
||||
|
||||
inline int PacketTypeInt() { return (int)(P_.code); }
|
||||
inline std::uint8_t PacketTypeInt() { return P_.code; }
|
||||
inline void PacketType(std::uint8_t T) { P_.code = T; }
|
||||
|
||||
void ComputeMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
@@ -498,9 +470,9 @@ namespace OpenWifi::RADIUS {
|
||||
NewAuthenticator[p++] = i;
|
||||
|
||||
if (memcmp(OldAuthenticator, NewAuthenticator, 16) == 0) {
|
||||
std::cout << "Authenticator match..." << std::endl;
|
||||
// std::cout << "Authenticator match..." << std::endl;
|
||||
} else {
|
||||
std::cout << "Authenticator MIS-match..." << std::endl;
|
||||
// std::cout << "Authenticator MIS-match..." << std::endl;
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 80) {
|
||||
memcpy(&P_.attributes[attr.pos], NewAuthenticator, 16);
|
||||
@@ -510,6 +482,21 @@ namespace OpenWifi::RADIUS {
|
||||
}
|
||||
}
|
||||
|
||||
inline std::uint8_t Identifier(std::uint8_t id) { P_.identifier = id; return id; }
|
||||
inline std::uint8_t Identifier() const { return P_.identifier; }
|
||||
|
||||
void RecomputeAuthenticator(const std::string &secret) {
|
||||
memset(P_.authenticator,0,sizeof(P_.authenticator));
|
||||
Poco::MD5Engine md5;
|
||||
P_.rawlen = htons(Size_);
|
||||
md5.update((const unsigned char *)&P_, Size_);
|
||||
md5.update(secret.c_str(), secret.size());
|
||||
auto digest = md5.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
P_.authenticator[p++] = i;
|
||||
}
|
||||
|
||||
bool VerifyMessageAuthenticator(const std::string &secret) {
|
||||
RawRadiusPacket P = P_;
|
||||
if (P_.code == 1) {
|
||||
@@ -548,6 +535,36 @@ namespace OpenWifi::RADIUS {
|
||||
os << std::dec;
|
||||
}
|
||||
|
||||
void PrintAccount_StatusType(std::ostream &os, const std::string &spaces, const unsigned char *buf, std::uint8_t len) {
|
||||
os << spaces ;
|
||||
if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_START)
|
||||
os << "Start" << std::endl;
|
||||
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_STOP)
|
||||
os << "Stop" << std::endl;
|
||||
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_INTERIM_UPDATE)
|
||||
os << "Interim-Update" << std::endl;
|
||||
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_ACCOUNTING_ON)
|
||||
os << "Accounting-On" << std::endl;
|
||||
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_ACCOUNTING_OFF)
|
||||
os << "Accounting-Off" << std::endl;
|
||||
else if (buf[3]==AccountingPacketTypes::ACCT_STATUS_TYPE_FAILED)
|
||||
os << "Failed" << std::endl;
|
||||
else
|
||||
BufLog(os,"",buf,len);
|
||||
}
|
||||
|
||||
void PrintAccount_AcctAuthentic(std::ostream &os, const std::string &spaces, const unsigned char *buf, std::uint8_t len) {
|
||||
os << spaces ;
|
||||
if (buf[3]==AuthenticationTypes::ACCT_AUTHENTIC_RADIUS)
|
||||
os << "RADIUS" << std::endl;
|
||||
else if (buf[3]==AuthenticationTypes::ACCT_AUTHENTIC_LOCAL)
|
||||
os << "Local" << std::endl;
|
||||
else if (buf[3]==AuthenticationTypes::ACCT_AUTHENTIC_REMOTE)
|
||||
os << "Remote" << std::endl;
|
||||
else
|
||||
BufLog(os,"",buf,len);
|
||||
}
|
||||
|
||||
inline void Print(std::ostream &os) {
|
||||
os << "Packet type: (" << (uint)P_.code << ") " << CommandName(P_.code) << std::endl;
|
||||
os << " Identifier: " << (uint)P_.identifier << std::endl;
|
||||
@@ -558,7 +575,13 @@ namespace OpenWifi::RADIUS {
|
||||
for (const auto &attr : Attrs_) {
|
||||
os << " " << std::setfill(' ') << "(" << std::setw(4) << (uint)attr.type << ") "
|
||||
<< AttributeName(attr.type) << " Len:" << attr.len << std::endl;
|
||||
BufLog(os, " ", &P_.attributes[attr.pos], attr.len);
|
||||
std::string attr_offset = " ";
|
||||
switch(attr.type) {
|
||||
case Attributes::ACCT_STATUS_TYPE: PrintAccount_StatusType(os, attr_offset, &P_.attributes[attr.pos], attr.len); break;
|
||||
case Attributes::ACCT_AUTHENTIC: PrintAccount_AcctAuthentic(os, attr_offset, &P_.attributes[attr.pos], attr.len); break;
|
||||
default:
|
||||
BufLog(os, attr_offset.c_str(), &P_.attributes[attr.pos], attr.len);
|
||||
}
|
||||
}
|
||||
os << std::dec << std::endl << std::endl;
|
||||
}
|
||||
@@ -592,10 +615,10 @@ namespace OpenWifi::RADIUS {
|
||||
return R;
|
||||
}
|
||||
|
||||
std::string ExtractSerialNumberFromProxyState() {
|
||||
std::string ExtractSerialNumberFromProxyState() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == 33) {
|
||||
if (attribute.type == RADIUS::Attributes::PROXY_STATE) {
|
||||
std::string Attr33;
|
||||
// format is serial:IP:port:interface
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
@@ -614,12 +637,13 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractProxyStateDestination() {
|
||||
std::string ExtractProxyStateDestination() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == 33 && attribute.len > 2) {
|
||||
if (attribute.type == RADIUS::Attributes::PROXY_STATE && attribute.len > 2) {
|
||||
std::string Attr33;
|
||||
// format is serial:IP:port:interface
|
||||
// format is
|
||||
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len - 2);
|
||||
auto Parts = Poco::StringTokenizer(Attr33, "|");
|
||||
@@ -638,10 +662,10 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractCallingStationID() {
|
||||
std::string ExtractCallingStationID() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == 31 && attribute.len > 2) {
|
||||
if (attribute.type == RADIUS::Attributes::CALLING_STATION_ID && attribute.len > 2) {
|
||||
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len - 2);
|
||||
return Result;
|
||||
@@ -650,10 +674,22 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractCalledStationID() {
|
||||
std::string ExtractAccountingSessionID() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == 30 && attribute.len > 2) {
|
||||
if (attribute.type == RADIUS::Attributes::ACCT_SESSION_ID && attribute.len > 2) {
|
||||
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len - 2);
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string ExtractCalledStationID() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == RADIUS::Attributes::CALLED_STATION_ID && attribute.len > 2) {
|
||||
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len - 2);
|
||||
return Result;
|
||||
@@ -664,7 +700,7 @@ namespace OpenWifi::RADIUS {
|
||||
|
||||
[[nodiscard]] std::string UserName() const {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if (attr.type == 1) {
|
||||
if (attr.type == RADIUS::Attributes::AUTH_USERNAME) {
|
||||
std::string user_name{(const char *)&P_.attributes[attr.pos], attr.len};
|
||||
return user_name;
|
||||
}
|
||||
@@ -672,10 +708,240 @@ namespace OpenWifi::RADIUS {
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
void ReplaceAttribute(std::uint8_t attribute, std::uint8_t value) {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if(attr.type==attribute) {
|
||||
P_.attributes[attr.pos] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceAttribute(std::uint8_t attribute, std::uint16_t value) {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if(attr.type==attribute) {
|
||||
P_.attributes[attr.pos+0] = value >> 8;
|
||||
P_.attributes[attr.pos+1] = value & 0x00ff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceAttribute(std::uint8_t attribute, std::uint32_t value) {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if(attr.type==attribute) {
|
||||
P_.attributes[attr.pos+0] = (std::uint8_t ) ((value & 0xff000000) >> 24);
|
||||
P_.attributes[attr.pos+1] = (std::uint8_t ) ((value & 0x00ff0000) >> 16);
|
||||
P_.attributes[attr.pos+2] = (std::uint8_t ) ((value & 0x0000ff00) >> 8);
|
||||
P_.attributes[attr.pos+3] = (std::uint8_t ) ((value & 0x000000ff) >> 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceAttribute(std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if(attr.type==attribute) {
|
||||
if(attr.len==attribute_len) {
|
||||
memcpy(&P_.attributes[attr.pos], attribute_value, attribute_len);
|
||||
} else if(attribute_len<attr.len){
|
||||
memcpy(&P_.attributes[attr.pos], attribute_value, attribute_len);
|
||||
P_.attributes[attr.pos-1] = attribute_len + 2;
|
||||
auto Shrink = attr.len - attribute_len;
|
||||
memmove(&P_.attributes[attr.pos+attribute_len], &P_.attributes[attr.pos+attr.len], Size_ - Shrink);
|
||||
Size_ -= Shrink;
|
||||
ReParse();
|
||||
} else {
|
||||
auto Augment = (attribute_len - attr.len);
|
||||
memmove(&P_.attributes[attr.pos+attribute_len], &P_.attributes[attr.pos+attr.len], Size_ + Augment);
|
||||
memcpy(&P_.attributes[attr.pos], attribute_value, attribute_len);
|
||||
P_.attributes[attr.pos-1] = attribute_len+2;
|
||||
Size_ += Augment;
|
||||
ReParse();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceAttribute(std::uint8_t attribute, const std::string &attribute_value) {
|
||||
ReplaceAttribute(attribute,attribute_value.c_str(),attribute_value.size());
|
||||
}
|
||||
|
||||
void RemoveAttribute(std::uint8_t attribute) {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if(attr.type==attribute) {
|
||||
auto Shrink = attr.len+2;
|
||||
memmove(&P_.attributes[attr.pos-2], &P_.attributes[attr.pos+attr.len], Size_ - Shrink);
|
||||
Size_ -= Shrink;
|
||||
ReParse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppendAttribute(std::uint8_t attribute, std::uint8_t value) {
|
||||
if(Size_<AttributeOffset) Size_ = AttributeOffset;
|
||||
auto Pos = Size_ - AttributeOffset;
|
||||
P_.attributes[Pos+0] = attribute;
|
||||
P_.attributes[Pos+1] = 1+2;
|
||||
P_.attributes[Pos+2] = value;
|
||||
Size_+= 3;
|
||||
ReParse();
|
||||
}
|
||||
|
||||
void AppendAttribute(std::uint8_t attribute, std::uint16_t value) {
|
||||
if(Size_<AttributeOffset) Size_ = AttributeOffset;
|
||||
auto Pos = Size_ - AttributeOffset;
|
||||
P_.attributes[Pos+0] = attribute;
|
||||
P_.attributes[Pos+1] = 2+2;
|
||||
P_.attributes[Pos+2] = (value & 0xff00) >> 8;
|
||||
P_.attributes[Pos+3] = (value & 0x00ff) >> 0;
|
||||
Size_+= 4;
|
||||
ReParse();
|
||||
}
|
||||
|
||||
void AppendAttribute(std::uint8_t attribute, std::uint32_t value) {
|
||||
if(Size_<AttributeOffset) Size_ = AttributeOffset;
|
||||
auto Pos = Size_ - AttributeOffset;
|
||||
P_.attributes[Pos+0] = attribute;
|
||||
P_.attributes[Pos+1] = 4+2;
|
||||
P_.attributes[Pos+2] = (value & 0xff000000) >> 24;
|
||||
P_.attributes[Pos+3] = (value & 0x00ff0000) >> 16;
|
||||
P_.attributes[Pos+4] = (value & 0x0000ff00) >> 8;
|
||||
P_.attributes[Pos+5] = (value & 0x000000ff) >> 0;
|
||||
Size_+= 6;
|
||||
ReParse();
|
||||
}
|
||||
|
||||
void AppendAttribute(std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
|
||||
if(Size_<AttributeOffset) Size_ = AttributeOffset;
|
||||
auto Pos = Size_ - AttributeOffset;
|
||||
P_.attributes[Pos+0] = attribute;
|
||||
P_.attributes[Pos+1] = attribute_len+2;
|
||||
memcpy(&P_.attributes[Pos+2],attribute_value,attribute_len);
|
||||
Size_+= 2 + attribute_len;
|
||||
ReParse();
|
||||
}
|
||||
|
||||
void AppendAttribute(std::uint8_t attribute, const std::string &attribute_value) {
|
||||
AppendAttribute(attribute, attribute_value.c_str(), attribute_value.size());
|
||||
}
|
||||
|
||||
void AddAttribute(std::uint8_t location, std::uint8_t attribute, std::uint8_t value) {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if(attr.type==location) {
|
||||
int Augment = 1;
|
||||
memmove(&P_.attributes[attr.pos+attr.len+1+1+Augment], &P_.attributes[attr.pos+attr.len], Size_-(attr.pos+attr.len));
|
||||
P_.attributes[attr.pos+attr.len+0] = attribute;
|
||||
P_.attributes[attr.pos+attr.len+1] = Augment+2;
|
||||
P_.attributes[attr.pos+attr.len+2] = value;
|
||||
Size_+=2+Augment;
|
||||
ReParse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddAttribute(std::uint8_t location, std::uint8_t attribute, std::uint16_t value) {
|
||||
for (const auto &attr : Attrs_) {
|
||||
if(attr.type==location) {
|
||||
int Augment = 2;
|
||||
memmove(&P_.attributes[attr.pos+attr.len+1+1+Augment], &P_.attributes[attr.pos+attr.len], Size_-(attr.pos+attr.len));
|
||||
P_.attributes[attr.pos+attr.len+0] = attribute;
|
||||
P_.attributes[attr.pos+attr.len+1] = Augment+2;
|
||||
P_.attributes[attr.pos+attr.len+2] = (value & 0xff00) >> 8;
|
||||
P_.attributes[attr.pos+attr.len+3] = (value & 0x00ff) >> 0;
|
||||
Size_+=2+Augment;
|
||||
ReParse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddAttribute(std::uint8_t location, std::uint8_t attribute, std::uint32_t value) {
|
||||
for (const auto &attr: Attrs_) {
|
||||
if (attr.type == location) {
|
||||
int Augment = 4;
|
||||
memmove(&P_.attributes[attr.pos + attr.len + 1 + 1 + Augment], &P_.attributes[attr.pos + attr.len],
|
||||
Size_ - (attr.pos + attr.len));
|
||||
P_.attributes[attr.pos + attr.len + 0] = attribute;
|
||||
P_.attributes[attr.pos + attr.len + 1] = Augment+2;
|
||||
P_.attributes[attr.pos + attr.len + 2] = (value & 0xff000000) >> 24;
|
||||
P_.attributes[attr.pos + attr.len + 3] = (value & 0x00ff0000) >> 16;
|
||||
P_.attributes[attr.pos + attr.len + 4] = (value & 0x0000ff00) >> 8;
|
||||
P_.attributes[attr.pos + attr.len + 5] = (value & 0x000000ff) >> 0;
|
||||
Size_ += 2 + Augment;
|
||||
ReParse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AddAttribute(std::uint8_t location, std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
|
||||
for (const auto &attr: Attrs_) {
|
||||
if (attr.type == location) {
|
||||
int Augment = attribute_len;
|
||||
memmove(&P_.attributes[attr.pos + attr.len + 1 + 1 + Augment], &P_.attributes[attr.pos + attr.len],
|
||||
Size_ - (attr.pos + attr.len));
|
||||
P_.attributes[attr.pos + attr.len + 0] = attribute;
|
||||
P_.attributes[attr.pos + attr.len + 1] = Augment+2;
|
||||
memcpy(&P_.attributes[attr.pos + attr.len + 2], attribute_value, attribute_len);
|
||||
Size_ += 2 + Augment;
|
||||
ReParse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddAttribute(std::uint8_t location, std::uint8_t attribute, const std::string &attribute_value) {
|
||||
AddAttribute(location, attribute, attribute_value.c_str(), attribute_value.size());
|
||||
}
|
||||
|
||||
bool HasAttribute(std::uint8_t attribute) const {
|
||||
return std::any_of(Attrs_.begin(),Attrs_.end(),[attribute](const RadiusAttribute &Attr) { return Attr.type ==attribute; });
|
||||
}
|
||||
|
||||
void ReplaceOrAdd(std::uint8_t attribute, std::uint8_t attribute_value) {
|
||||
if(HasAttribute(attribute))
|
||||
ReplaceAttribute(attribute, attribute_value);
|
||||
else
|
||||
AppendAttribute(attribute, attribute_value);
|
||||
}
|
||||
|
||||
void ReplaceOrAdd(std::uint8_t attribute, std::uint16_t attribute_value) {
|
||||
if(HasAttribute(attribute))
|
||||
ReplaceAttribute(attribute, attribute_value);
|
||||
else
|
||||
AppendAttribute(attribute, attribute_value);
|
||||
}
|
||||
|
||||
void ReplaceOrAdd(std::uint8_t attribute, std::uint32_t attribute_value) {
|
||||
if(HasAttribute(attribute))
|
||||
ReplaceAttribute(attribute, attribute_value);
|
||||
else
|
||||
AppendAttribute(attribute, attribute_value);
|
||||
}
|
||||
|
||||
void ReplaceOrAdd(std::uint8_t attribute, const char *attribute_value, std::uint8_t attribute_len) {
|
||||
if(HasAttribute(attribute))
|
||||
ReplaceAttribute(attribute, attribute_value, attribute_len);
|
||||
else
|
||||
AppendAttribute(attribute, attribute_value, attribute_len);
|
||||
}
|
||||
|
||||
void ReplaceOrAdd(std::uint8_t attribute, const std::string & attribute_value) {
|
||||
if(HasAttribute(attribute))
|
||||
ReplaceAttribute(attribute, attribute_value.c_str(), attribute_value.size());
|
||||
else
|
||||
AppendAttribute(attribute, attribute_value.c_str(), attribute_value.size());
|
||||
|
||||
}
|
||||
|
||||
AttributeList Attrs_;
|
||||
RawRadiusPacket P_;
|
||||
uint16_t Size_{0};
|
||||
AttributeList Attrs_;
|
||||
bool Valid_ = false;
|
||||
};
|
||||
|
||||
@@ -684,16 +950,17 @@ namespace OpenWifi::RADIUS {
|
||||
explicit RadiusOutputPacket(const std::string &Secret) : Secret_(Secret) {}
|
||||
|
||||
inline void MakeStatusMessage() {
|
||||
P_.code = RADCMD_STATUS_SER;
|
||||
P_.code = RADIUS::Status_Server;
|
||||
P_.identifier = std::rand() & 0x00ff;
|
||||
MakeRadiusAuthenticator(P_.authenticator);
|
||||
unsigned char MessageAuthenticator[16]{0};
|
||||
AddAttribute(ATTR_MessageAuthenticator, sizeof(MessageAuthenticator),
|
||||
AddAttribute(RADIUS::Attributes::MESSAGE_AUTHENTICATOR, sizeof(MessageAuthenticator),
|
||||
MessageAuthenticator);
|
||||
P_.rawlen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
|
||||
int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
|
||||
P_.rawlen = htons(PktLen);
|
||||
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(Secret_);
|
||||
H.update((const unsigned char *)&P_, P_.rawlen);
|
||||
H.update((const unsigned char *)&P_, PktLen);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
for (const auto &i : digest)
|
||||
@@ -710,7 +977,7 @@ namespace OpenWifi::RADIUS {
|
||||
[[nodiscard]] inline const unsigned char *Data() const {
|
||||
return (const unsigned char *)&P_;
|
||||
}
|
||||
[[nodiscard]] inline std::uint16_t Len() const { return P_.rawlen; }
|
||||
[[nodiscard]] inline std::uint16_t Len() const { return ntohs(P_.rawlen); }
|
||||
|
||||
private:
|
||||
RawRadiusPacket P_;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "RADIUS_helpers.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
|
||||
#include "RADIUSSessionTracker.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -17,6 +18,8 @@ namespace OpenWifi {
|
||||
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
|
||||
const int DEFAULT_RADIUS_CoA_PORT = 3799;
|
||||
|
||||
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
ConfigFilename_ = MicroServiceDataDirectory() + "/radius_pool_config.json";
|
||||
@@ -183,6 +186,7 @@ namespace OpenWifi {
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
// P.Log(std::cout);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger(), "Accounting: missing serial number.");
|
||||
@@ -210,6 +214,7 @@ namespace OpenWifi {
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
// P.Log(std::cout);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger(), "Authentication: missing serial number.");
|
||||
@@ -236,6 +241,8 @@ namespace OpenWifi {
|
||||
poco_warning(Logger(), "CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
// P.Log(std::cout);
|
||||
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (SerialNumber.empty()) {
|
||||
@@ -252,28 +259,23 @@ namespace OpenWifi {
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string & secret) {
|
||||
try{
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC);
|
||||
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC, secret);
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if (DestinationServer != end(RADSECservers_)) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
|
||||
size);
|
||||
if(RecomputeAuthenticator) {
|
||||
P.RecomputeAuthenticator("radsec");
|
||||
}
|
||||
DestinationServer->second->SendData(serialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
|
||||
@@ -287,10 +289,15 @@ namespace OpenWifi {
|
||||
serialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
if(RecomputeAuthenticator) {
|
||||
P.RecomputeAuthenticator(secret);
|
||||
}
|
||||
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
|
||||
: *AccountingSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
: *AccountingSocketV6_
|
||||
, P.Buffer(), P.Size(), FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),
|
||||
fmt::format("{}: Could not send Accounting packet packet to {}.",
|
||||
@@ -309,13 +316,47 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void store_packet(const std::string &serialNumber, const char *buffer, std::size_t size) {
|
||||
static std::uint64_t pkt=0;
|
||||
|
||||
std::string filename = MicroServiceDataDirectory() + "/radius." + serialNumber + "." + std::to_string(pkt++) + ".bin";
|
||||
|
||||
std::ofstream ofs(filename,std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);
|
||||
ofs.write(buffer,size);
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size, std::string & secret) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
|
||||
// P.Log(std::cout);
|
||||
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
// store_packet(serialNumber, buffer, size);
|
||||
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, secret);
|
||||
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, secret);
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("Bad RADIUS ACCT Packet from {}. Dropped.", serialNumber));
|
||||
}
|
||||
}
|
||||
|
||||
bool RADIUS_proxy_server::SendData(Poco::Net::DatagramSocket &Sock, const unsigned char *buf,
|
||||
std::size_t size, const Poco::Net::SocketAddress &S) {
|
||||
return Sock.sendTo(buf, size, S) == (int)size;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size) {
|
||||
const char *buffer, std::size_t size, std::string & secret) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
@@ -327,9 +368,14 @@ namespace OpenWifi {
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
// P.Log(std::cout);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
|
||||
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC, secret);
|
||||
RADIUSSessionTracker()->AddAuthenticationSession(Destination, serialNumber, P, secret);
|
||||
|
||||
// std::cout << "Authentication secret: " << secret << std::endl;
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
@@ -372,7 +418,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer,
|
||||
std::size_t size) {
|
||||
std::size_t size, std::string & secret) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
@@ -385,10 +431,13 @@ namespace OpenWifi {
|
||||
Destination = "0.0.0.0:0";
|
||||
}
|
||||
|
||||
P.Log(std::cout);
|
||||
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
|
||||
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC, secret);
|
||||
std::cout << "CoA secret: " << secret << std::endl;
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
@@ -449,7 +498,8 @@ namespace OpenWifi {
|
||||
.methodParameters = Config.methodParameters,
|
||||
.useAsDefault = setAsDefault,
|
||||
.useRADSEC = server.radsec,
|
||||
.realms = server.radsecRealms};
|
||||
.realms = server.radsecRealms,
|
||||
.secret = server.secret };
|
||||
|
||||
if (setAsDefault && D.useRADSEC)
|
||||
DefaultIsRADSEC_ = true;
|
||||
@@ -530,7 +580,8 @@ namespace OpenWifi {
|
||||
Poco::Net::SocketAddress
|
||||
RADIUS_proxy_server::DefaultRoute(radius_type rtype,
|
||||
const Poco::Net::SocketAddress &RequestedAddress,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
|
||||
std::string &Secret) {
|
||||
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
|
||||
|
||||
// find the realm...
|
||||
@@ -545,7 +596,7 @@ namespace OpenWifi {
|
||||
if (!server.realms.empty()) {
|
||||
for (const auto &realm : server.realms) {
|
||||
if (RealmMatch(UserRealm, realm)) {
|
||||
std::cout << "Realm match..." << std::endl;
|
||||
// std::cout << "Realm match..." << std::endl;
|
||||
UseRADSEC = true;
|
||||
return server.Addr;
|
||||
}
|
||||
@@ -565,18 +616,18 @@ namespace OpenWifi {
|
||||
case radius_type::auth: {
|
||||
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AuthV4
|
||||
: Pools_[DefaultPoolIndex_].AuthV6,
|
||||
RequestedAddress);
|
||||
RequestedAddress, Secret);
|
||||
}
|
||||
case radius_type::acct:
|
||||
default: {
|
||||
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AcctV4
|
||||
: Pools_[DefaultPoolIndex_].AcctV6,
|
||||
RequestedAddress);
|
||||
RequestedAddress, Secret);
|
||||
}
|
||||
case radius_type::coa: {
|
||||
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
|
||||
: Pools_[DefaultPoolIndex_].CoaV6,
|
||||
RequestedAddress);
|
||||
RequestedAddress, Secret);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,7 +635,8 @@ namespace OpenWifi {
|
||||
Poco::Net::SocketAddress
|
||||
RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype,
|
||||
const Poco::Net::SocketAddress &RequestedAddress,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
|
||||
std::string &Secret) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if (Pools_.empty()) {
|
||||
@@ -600,7 +652,7 @@ namespace OpenWifi {
|
||||
Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6);
|
||||
|
||||
if (useDefault) {
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
|
||||
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC, Secret);
|
||||
}
|
||||
|
||||
auto isAddressInPool = [&](const std::vector<Destination> &D, bool &UseRADSEC) -> bool {
|
||||
@@ -616,17 +668,17 @@ namespace OpenWifi {
|
||||
switch (rtype) {
|
||||
case radius_type::coa: {
|
||||
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
|
||||
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress, Secret);
|
||||
}
|
||||
} break;
|
||||
case radius_type::auth: {
|
||||
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
|
||||
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress, Secret);
|
||||
}
|
||||
} break;
|
||||
case radius_type::acct: {
|
||||
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
|
||||
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
|
||||
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress, Secret);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@@ -638,9 +690,11 @@ namespace OpenWifi {
|
||||
|
||||
Poco::Net::SocketAddress
|
||||
RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool,
|
||||
const Poco::Net::SocketAddress &OriginalAddress) {
|
||||
const Poco::Net::SocketAddress &OriginalAddress,
|
||||
std::string &Secret) {
|
||||
|
||||
if (Pool.size() == 1) {
|
||||
Secret = Pool[0].secret;
|
||||
return Pool[0].Addr;
|
||||
}
|
||||
|
||||
@@ -657,6 +711,7 @@ namespace OpenWifi {
|
||||
index = pos;
|
||||
cur_state = i.state;
|
||||
found = true;
|
||||
Secret = i.secret ;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
@@ -664,9 +719,9 @@ namespace OpenWifi {
|
||||
if (!found) {
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
Pool[index].state += Pool[index].step;
|
||||
return Pool[index].Addr;
|
||||
|
||||
} else if (Pool[0].strategy == "round_robin") {
|
||||
bool found = false;
|
||||
uint64_t cur_state = std::numeric_limits<uint64_t>::max();
|
||||
@@ -679,6 +734,7 @@ namespace OpenWifi {
|
||||
if (i.state < cur_state) {
|
||||
index = pos;
|
||||
cur_state = i.state;
|
||||
Secret = i.secret;
|
||||
found = true;
|
||||
}
|
||||
pos++;
|
||||
@@ -692,7 +748,9 @@ namespace OpenWifi {
|
||||
return Pool[index].Addr;
|
||||
} else if (Pool[0].strategy == "random") {
|
||||
if (Pool.size() > 1) {
|
||||
return Pool[std::rand() % Pool.size()].Addr;
|
||||
auto index = std::rand() % Pool.size();
|
||||
Secret = Pool[index].secret;
|
||||
return Pool[index].Addr;
|
||||
} else {
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
@@ -34,10 +34,12 @@ namespace OpenWifi {
|
||||
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
|
||||
void SendAccountingData(const std::string &serialNumber, const char *buffer,
|
||||
std::size_t size);
|
||||
std::size_t size, std::string & secret);
|
||||
void SendAuthenticationData(const std::string &serialNumber, const char *buffer,
|
||||
std::size_t size);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
std::size_t size, std::string & secret);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size, std::string & secret);
|
||||
|
||||
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string & secret);
|
||||
|
||||
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
|
||||
void DeleteConfig();
|
||||
@@ -59,6 +61,7 @@ namespace OpenWifi {
|
||||
bool useAsDefault = false;
|
||||
bool useRADSEC = false;
|
||||
std::vector<std::string> realms;
|
||||
std::string secret;
|
||||
};
|
||||
|
||||
inline bool Continue() const { return Running_ && Enabled_ && !Pools_.empty(); }
|
||||
@@ -102,16 +105,17 @@ namespace OpenWifi {
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
|
||||
void ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
|
||||
std::vector<Destination> &V4, std::vector<Destination> &V6,
|
||||
bool setAsDefault);
|
||||
static Poco::Net::SocketAddress
|
||||
ChooseAddress(std::vector<Destination> &Pool,
|
||||
const Poco::Net::SocketAddress &OriginalAddress);
|
||||
const Poco::Net::SocketAddress &OriginalAddress, std::string &Secret);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype,
|
||||
const Poco::Net::SocketAddress &RequestedAddress,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC);
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
|
||||
std::string &Secret);
|
||||
};
|
||||
|
||||
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
// we need to post a kafka event for this.
|
||||
if (Params.has(uCentralProtocol::CONFIG)) {
|
||||
DeviceConfigurationChangeKafkaEvent KEvent(
|
||||
Cmd.SerialNumber, Utils::Now(),
|
||||
Utils::SerialNumberToInt(Cmd.SerialNumber), Utils::Now(),
|
||||
Params.get(uCentralProtocol::CONFIG).toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ namespace OpenWifi {
|
||||
|
||||
if (AP_WS_Server()->GetState(SerialNumber_, State)) {
|
||||
Poco::JSON::Object RetObject;
|
||||
State.to_json(RetObject);
|
||||
State.to_json(SerialNumber_, RetObject);
|
||||
return ReturnObject(RetObject);
|
||||
} else {
|
||||
Poco::JSON::Object RetObject;
|
||||
@@ -406,6 +406,7 @@ namespace OpenWifi {
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
poco_debug(Logger_, fmt::format("PING({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
|
||||
TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER)) {
|
||||
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
|
||||
@@ -459,6 +460,14 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
bool RESTAPI_device_commandHandler::IsDeviceSimulated(std::string &Serial) {
|
||||
GWObjects::Device Device;
|
||||
if(StorageService()->GetDevice(Serial,Device)) {
|
||||
return Device.simulated;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::CallCanceled(const char *Cmd, const std::string &UUID,
|
||||
uint64_t RPC,
|
||||
const OpenWifi::RESTAPI::Errors::msg &Err) {
|
||||
@@ -474,6 +483,10 @@ namespace OpenWifi {
|
||||
poco_debug(Logger_, fmt::format("SCRIPT({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
GWObjects::ScriptRequest SCR;
|
||||
if (!SCR.from_json(Obj)) {
|
||||
@@ -899,6 +912,10 @@ namespace OpenWifi {
|
||||
poco_debug(Logger_, fmt::format("TRACE({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
|
||||
TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
|
||||
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) &&
|
||||
@@ -956,6 +973,12 @@ namespace OpenWifi {
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
poco_debug(Logger_, fmt::format("WIFISCAN({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
|
||||
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
|
||||
@@ -1001,7 +1024,7 @@ namespace OpenWifi {
|
||||
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::wifiscan, false, Cmd, Params,
|
||||
*Request, *Response, timeout, nullptr, this, Logger_);
|
||||
if (Cmd.ErrorCode == 0) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, Cmd.Results);
|
||||
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, std::make_shared<std::string>(Cmd.Results));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1011,6 +1034,10 @@ namespace OpenWifi {
|
||||
poco_debug(Logger_, fmt::format("EVENT-QUEUE({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->isArray(RESTAPI::Protocol::TYPES)) {
|
||||
|
||||
@@ -1042,7 +1069,7 @@ namespace OpenWifi {
|
||||
Logger_);
|
||||
if (Cmd.ErrorCode == 0) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
|
||||
Cmd.Results);
|
||||
std::make_shared<std::string>(Cmd.Results));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1055,6 +1082,10 @@ namespace OpenWifi {
|
||||
poco_debug(Logger_, fmt::format("FORCE-REQUEST({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(uCentralProtocol::MESSAGE)) {
|
||||
|
||||
@@ -1104,6 +1135,10 @@ namespace OpenWifi {
|
||||
poco_debug(Logger_, fmt::format("RTTY({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
|
||||
TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
if (!Restrictions.developer && Restrictions.rtty) {
|
||||
return BadRequest(RESTAPI::Errors::DeviceIsRestricted);
|
||||
}
|
||||
@@ -1112,6 +1147,11 @@ namespace OpenWifi {
|
||||
GWObjects::Device Device;
|
||||
|
||||
if (StorageService()->GetDevice(SerialNumber_, Device)) {
|
||||
|
||||
if(Device.simulated) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
static std::uint64_t rtty_sid = 0;
|
||||
rtty_sid += std::rand();
|
||||
GWObjects::RttySessionDetails Rtty{
|
||||
@@ -1185,6 +1225,10 @@ namespace OpenWifi {
|
||||
poco_debug(Logger_, fmt::format("TELEMETRY({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
|
||||
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(RESTAPI::Protocol::INTERVAL) &&
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace OpenWifi {
|
||||
void GetChecks();
|
||||
void DeleteChecks();
|
||||
|
||||
bool IsDeviceSimulated(std::string &Serial);
|
||||
|
||||
void Configure(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void Upgrade(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
|
||||
@@ -41,6 +41,10 @@ namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoDelete() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(!RESTAPI_utils::IsRootOrAdmin(UserInfo_.userinfo)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if (!Utils::NormalizeMac(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenWifi {
|
||||
Device.to_json(DeviceInfo);
|
||||
Answer.set("deviceInfo", DeviceInfo);
|
||||
Poco::JSON::Object CSInfo;
|
||||
CS.to_json(CSInfo);
|
||||
CS.to_json(Device.SerialNumber, CSInfo);
|
||||
Answer.set("connectionInfo", CSInfo);
|
||||
Poco::JSON::Object HCInfo;
|
||||
HC.to_json(HCInfo);
|
||||
|
||||
@@ -158,4 +158,54 @@ namespace OpenWifi {
|
||||
}
|
||||
ReturnObject(RetObj);
|
||||
}
|
||||
|
||||
static bool ValidMacPatternOnlyChars(const std::string &s) {
|
||||
return std::for_each(s.begin(),s.end(),[](const char c) {
|
||||
if(c=='%') return true;
|
||||
if(c>='0' && c<='9') return true;
|
||||
if(c>='a' && c<='f') return true;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void RESTAPI_devices_handler::DoDelete() {
|
||||
|
||||
if(!RESTAPI_utils::IsRootOrAdmin(UserInfo_.userinfo)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
if(!QB_.Select.empty()) {
|
||||
for(auto &serialNumber:QB_.Select) {
|
||||
StorageService()->DeleteDevice(serialNumber);
|
||||
}
|
||||
return OK();
|
||||
}
|
||||
|
||||
auto SimulatedOnly = GetBoolParameter("simulatedOnly",false);
|
||||
auto oldestContact = GetParameter("oldestContact",0);
|
||||
if(oldestContact!=0) {
|
||||
StorageService()->DeleteDevices(oldestContact,SimulatedOnly);
|
||||
return OK();
|
||||
}
|
||||
|
||||
auto macPattern = GetParameter("macPattern","");
|
||||
if(macPattern.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
// rules out wrong values.
|
||||
Poco::toLowerInPlace(macPattern);
|
||||
Poco::replaceInPlace(macPattern,"*","%");
|
||||
if(!ValidMacPatternOnlyChars(macPattern)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
StorageService()->DeleteDevices(macPattern, SimulatedOnly);
|
||||
return OK();
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
@@ -18,11 +18,12 @@ namespace OpenWifi {
|
||||
bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal){};
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/devices"}; };
|
||||
void DoGet() final;
|
||||
void DoDelete() final{};
|
||||
void DoDelete() final;
|
||||
void DoPost() final{};
|
||||
void DoPut() final{};
|
||||
};
|
||||
|
||||
129
src/RESTAPI/RESTAPI_radiussessions_handler.cpp
Normal file
129
src/RESTAPI/RESTAPI_radiussessions_handler.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-02.
|
||||
//
|
||||
|
||||
#include "RESTAPI_radiussessions_handler.h"
|
||||
#include <RESTObjects/RESTAPI_GWobjects.h>
|
||||
#include <RADIUSSessionTracker.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
bool MayBeAMAC(const std::string &mac) {
|
||||
return std::all_of(mac.begin(),mac.end(),[](char c)->bool {
|
||||
if ((c>='0' && c<='9') ||
|
||||
(c>='a' && c<='f') ||
|
||||
(c>='A' && c<='F') ||
|
||||
(c==':') ||
|
||||
(c=='-') ||
|
||||
(c=='*')) return true;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
std::string InsertDelimiters(const std::string &mac, int first=1, char delimiter=':') {
|
||||
std::string res;
|
||||
std::size_t index=0;
|
||||
for(auto c:mac) {
|
||||
res += c;
|
||||
index++;
|
||||
if(index<mac.size()) {
|
||||
if (!first)
|
||||
res += delimiter;
|
||||
}
|
||||
first = 1-first;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string StripDelimiters(const std::string &V) {
|
||||
std::string Res;
|
||||
std::for_each(V.begin(),V.end(),[&](char c){ if(c!=':' && c!='-') { Res += c; }});
|
||||
return Res;
|
||||
}
|
||||
|
||||
static std::string ConvertToMac(const std::string & V) {
|
||||
auto res = V;
|
||||
Poco::toUpperInPlace(res);
|
||||
res = StripDelimiters(res);
|
||||
if(res.size()==12) {
|
||||
res = InsertDelimiters(res);
|
||||
} else {
|
||||
if(res.find_first_of('*')==std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
if(res[0]=='*') {
|
||||
res = InsertDelimiters(res, 1 - (res.size() % 2) );
|
||||
} else {
|
||||
res = InsertDelimiters(res);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void RESTAPI_radiussessions_handler::DoGet() {
|
||||
|
||||
if(GetBoolParameter("serialNumberOnly")) {
|
||||
std::vector<std::string> L;
|
||||
RADIUSSessionTracker()->GetAPList(L);
|
||||
return ReturnObject("serialNumbers",L);
|
||||
}
|
||||
|
||||
auto mac = GetParameter("mac","");
|
||||
auto userName = GetParameter("userName","");
|
||||
if(!userName.empty()) {
|
||||
GWObjects::RADIUSSessionList L;
|
||||
Poco::toLowerInPlace(userName);
|
||||
RADIUSSessionTracker()->GetUserNameAPSessions(userName,L);
|
||||
if(L.sessions.empty() && MayBeAMAC(userName)) {
|
||||
mac = ConvertToMac(userName);
|
||||
} else {
|
||||
return ReturnObject("sessions", L.sessions);
|
||||
}
|
||||
}
|
||||
|
||||
if(!mac.empty()) {
|
||||
Poco::toUpperInPlace(mac);
|
||||
Poco::replaceInPlace(mac,":","-");
|
||||
GWObjects::RADIUSSessionList L;
|
||||
RADIUSSessionTracker()->GetMACAPSessions(mac,L);
|
||||
return ReturnObject("sessions",L.sessions);
|
||||
}
|
||||
|
||||
auto SerialNumber = GetBinding("serialNumber","");
|
||||
if(SerialNumber.empty() || !Utils::ValidSerialNumber(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::RADIUSSessionList L;
|
||||
RADIUSSessionTracker()->GetAPSessions(SerialNumber,L);
|
||||
return ReturnObject("sessions",L.sessions);
|
||||
}
|
||||
|
||||
void RESTAPI_radiussessions_handler::DoPut() {
|
||||
auto SerialNumber = GetBinding("serialNumber","");
|
||||
if(SerialNumber.empty() || !Utils::ValidSerialNumber(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::RadiusCoADMParameters Parameters;
|
||||
if(!Parameters.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if(Parameters.callingStationId.empty() || Parameters.accountingSessionId.empty() || Parameters.accountingMultiSessionId.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
auto Command = GetParameter("operation","");
|
||||
|
||||
if(Command=="coadm") {
|
||||
if(RADIUSSessionTracker()->SendCoADM(SerialNumber, Parameters.accountingSessionId)) {
|
||||
return OK();
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
|
||||
}
|
||||
|
||||
return BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
28
src/RESTAPI/RESTAPI_radiussessions_handler.h
Normal file
28
src/RESTAPI/RESTAPI_radiussessions_handler.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-02.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RESTAPI_radiussessions_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_radiussessions_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||
bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal){};
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/radiusSessions/{serialNumber}"}; };
|
||||
void DoGet() final;
|
||||
void DoDelete() final{};
|
||||
void DoPost() final{};
|
||||
void DoPut();
|
||||
};
|
||||
|
||||
} // namespace OpenWifi
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "RESTAPI/RESTAPI_script_handler.h"
|
||||
#include "RESTAPI/RESTAPI_scripts_handler.h"
|
||||
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
|
||||
#include "RESTAPI/RESTAPI_radiussessions_handler.h"
|
||||
|
||||
#include "framework/RESTAPI_SystemCommand.h"
|
||||
#include "framework/RESTAPI_SystemConfiguration.h"
|
||||
@@ -39,7 +40,7 @@ namespace OpenWifi {
|
||||
RESTAPI_system_configuration, RESTAPI_deviceDashboardHandler, RESTAPI_webSocketServer,
|
||||
RESTAPI_blacklist, RESTAPI_blacklist_list, RESTAPI_iptocountry_handler,
|
||||
RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler, RESTAPI_script_handler,
|
||||
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket,
|
||||
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket, RESTAPI_radiussessions_handler,
|
||||
RESTAPI_regulatory>(Path, Bindings, L, S,
|
||||
TransactionId);
|
||||
}
|
||||
@@ -53,7 +54,7 @@ namespace OpenWifi {
|
||||
RESTAPI_default_configurations, RESTAPI_default_configuration, RESTAPI_command,
|
||||
RESTAPI_commands, RESTAPI_ouis, RESTAPI_file, RESTAPI_blacklist,
|
||||
RESTAPI_iptocountry_handler, RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler,
|
||||
RESTAPI_script_handler, RESTAPI_blacklist_list,
|
||||
RESTAPI_script_handler, RESTAPI_blacklist_list, RESTAPI_radiussessions_handler,
|
||||
RESTAPI_regulatory>(Path, Bindings, L, S, TransactionId);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -13,6 +13,7 @@
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#include "RADIUSSessionTracker.h"
|
||||
#endif
|
||||
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
@@ -29,6 +30,7 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "serialNumber", SerialNumber);
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
field_to_json(Obj, "deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible));
|
||||
field_to_json(Obj, "hasRADIUSSessions", RADIUSSessionTracker()->HasSessions(SerialNumber));
|
||||
#endif
|
||||
field_to_json(Obj, "macAddress", MACAddress);
|
||||
field_to_json(Obj, "manufacturer", Manufacturer);
|
||||
@@ -55,6 +57,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd);
|
||||
field_to_json(Obj, "restrictionDetails", restrictionDetails);
|
||||
field_to_json(Obj, "pendingUUID", pendingUUID);
|
||||
field_to_json(Obj, "simulated", simulated);
|
||||
field_to_json(Obj, "lastRecordedContact", lastRecordedContact);
|
||||
}
|
||||
|
||||
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
|
||||
@@ -64,7 +68,7 @@ namespace OpenWifi::GWObjects {
|
||||
ConnectionState ConState;
|
||||
|
||||
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
|
||||
ConState.to_json(Obj);
|
||||
ConState.to_json(SerialNumber,Obj);
|
||||
} else {
|
||||
field_to_json(Obj, "ipAddress", "");
|
||||
field_to_json(Obj, "txBytes", (uint64_t)0);
|
||||
@@ -76,6 +80,13 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "associations_2G", (uint64_t)0);
|
||||
field_to_json(Obj, "associations_5G", (uint64_t)0);
|
||||
field_to_json(Obj, "associations_6G", (uint64_t)0);
|
||||
field_to_json(Obj, "hasRADIUSSessions", false);
|
||||
field_to_json(Obj, "hasGPS", ConState.hasGPS);
|
||||
field_to_json(Obj, "sanity", ConState.sanity);
|
||||
field_to_json(Obj, "memoryUsed", ConState.memoryUsed);
|
||||
field_to_json(Obj, "sanity", ConState.sanity);
|
||||
field_to_json(Obj, "load", ConState.load);
|
||||
field_to_json(Obj, "temperature", ConState.temperature);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -109,6 +120,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd);
|
||||
field_from_json(Obj, "restrictionDetails", restrictionDetails);
|
||||
field_from_json(Obj, "pendingUUID", pendingUUID);
|
||||
field_from_json(Obj, "simulated", simulated);
|
||||
field_from_json(Obj, "lastRecordedContact", lastRecordedContact);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -211,7 +224,7 @@ namespace OpenWifi::GWObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConnectionState::to_json(Poco::JSON::Object &Obj) const {
|
||||
void ConnectionState::to_json([[maybe_unused]] const std::string &SerialNumber, Poco::JSON::Object &Obj) {
|
||||
field_to_json(Obj, "ipAddress", Address);
|
||||
field_to_json(Obj, "txBytes", TX);
|
||||
field_to_json(Obj, "rxBytes", RX);
|
||||
@@ -233,6 +246,22 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
|
||||
field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
|
||||
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
|
||||
field_to_json(Obj, "connectReason", connectReason);
|
||||
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
hasRADIUSSessions = RADIUSSessionTracker()->HasSessions(SerialNumber);
|
||||
AP_WS_Server()->ExtendedAttributes(SerialNumber, hasGPS, sanity,
|
||||
memoryUsed,
|
||||
load,
|
||||
temperature);
|
||||
#endif
|
||||
field_to_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
|
||||
field_to_json(Obj, "hasGPS", hasGPS);
|
||||
field_to_json(Obj, "sanity", sanity);
|
||||
field_to_json(Obj, "memoryUsed", memoryUsed);
|
||||
field_to_json(Obj, "sanity", sanity);
|
||||
field_to_json(Obj, "load", load);
|
||||
field_to_json(Obj, "temperature", temperature);
|
||||
|
||||
switch (VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
@@ -247,6 +276,9 @@ namespace OpenWifi::GWObjects {
|
||||
case VERIFIED:
|
||||
field_to_json(Obj, "verifiedCertificate", "VERIFIED");
|
||||
break;
|
||||
case SIMULATED:
|
||||
field_to_json(Obj, "verifiedCertificate", "SIMULATED");
|
||||
break;
|
||||
default:
|
||||
field_to_json(Obj, "verifiedCertificate", "NO_CERTIFICATE");
|
||||
break;
|
||||
@@ -580,4 +612,43 @@ namespace OpenWifi::GWObjects {
|
||||
(T.commands != commands) || (T.developer != developer) || (T.ssh != ssh) ||
|
||||
(T.key_info != key_info) || (T.country != country));
|
||||
}
|
||||
|
||||
void RADIUSSession::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "started", started);
|
||||
field_to_json(Obj, "lastTransaction", lastTransaction);
|
||||
field_to_json(Obj, "destination", destination);
|
||||
field_to_json(Obj, "serialNumber", serialNumber);
|
||||
field_to_json(Obj, "userName", userName);
|
||||
field_to_json(Obj, "accountingSessionId", accountingSessionId);
|
||||
field_to_json(Obj, "accountingMultiSessionId", accountingMultiSessionId);
|
||||
field_to_json(Obj, "inputPackets", inputPackets);
|
||||
field_to_json(Obj, "outputPackets", outputPackets);
|
||||
field_to_json(Obj, "inputOctets", inputOctets);
|
||||
field_to_json(Obj, "outputOctets", outputOctets);
|
||||
field_to_json(Obj, "inputGigaWords", inputGigaWords);
|
||||
field_to_json(Obj, "outputGigaWords", outputGigaWords);
|
||||
field_to_json(Obj, "sessionTime", sessionTime);
|
||||
field_to_json(Obj, "callingStationId", callingStationId);
|
||||
field_to_json(Obj, "chargeableUserIdentity", chargeableUserIdentity);
|
||||
field_to_json(Obj, "interface", interface);
|
||||
field_to_json(Obj, "secret", secret);
|
||||
field_to_json(Obj, "nasId", nasId);
|
||||
}
|
||||
|
||||
void RADIUSSessionList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "sessions", sessions);
|
||||
}
|
||||
|
||||
bool RadiusCoADMParameters::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "accountingSessionId", accountingSessionId);
|
||||
field_from_json(Obj, "accountingMultiSessionId", accountingMultiSessionId);
|
||||
field_from_json(Obj, "callingStationId", callingStationId);
|
||||
field_from_json(Obj, "chargeableUserIdentity", chargeableUserIdentity);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OpenWifi::GWObjects
|
||||
|
||||
@@ -11,9 +11,13 @@
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
#include <RADIUS_helpers.h>
|
||||
#endif
|
||||
|
||||
namespace OpenWifi::GWObjects {
|
||||
|
||||
enum CertificateValidation { NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED };
|
||||
enum CertificateValidation { NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED, SIMULATED };
|
||||
|
||||
struct ConnectionState {
|
||||
uint64_t MessageCount = 0;
|
||||
@@ -38,8 +42,15 @@ namespace OpenWifi::GWObjects {
|
||||
uint64_t sessionId = 0;
|
||||
double connectionCompletionTime = 0.0;
|
||||
std::uint64_t certificateExpiryDate = 0;
|
||||
std::uint64_t hasRADIUSSessions = 0;
|
||||
bool hasGPS = false;
|
||||
std::uint64_t sanity=0;
|
||||
std::double_t memoryUsed=0.0;
|
||||
std::double_t load=0.0;
|
||||
std::double_t temperature=0.0;
|
||||
std::string connectReason;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void to_json(const std::string &SerialNumber, Poco::JSON::Object &Obj) ;
|
||||
};
|
||||
|
||||
struct DeviceRestrictionsKeyInfo {
|
||||
@@ -97,6 +108,8 @@ namespace OpenWifi::GWObjects {
|
||||
std::string pendingConfigurationCmd;
|
||||
DeviceRestrictions restrictionDetails;
|
||||
std::uint64_t pendingUUID = 0;
|
||||
bool simulated=false;
|
||||
std::uint64_t lastRecordedContact=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
||||
@@ -370,5 +383,46 @@ namespace OpenWifi::GWObjects {
|
||||
|
||||
using RegulatoryInfoCountryMap = std::map<std::string,RegulatoryCountryInfo>;
|
||||
|
||||
struct RADIUSSession {
|
||||
std::uint64_t started=0,
|
||||
lastTransaction=0;
|
||||
std::string serialNumber,
|
||||
destination,
|
||||
userName,
|
||||
accountingSessionId,
|
||||
accountingMultiSessionId,
|
||||
callingStationId,
|
||||
chargeableUserIdentity,
|
||||
secret,
|
||||
interface,
|
||||
nasId;
|
||||
std::uint64_t inputPackets = 0,
|
||||
outputPackets = 0,
|
||||
inputOctets = 0,
|
||||
outputOctets = 0,
|
||||
inputGigaWords = 0,
|
||||
outputGigaWords = 0;
|
||||
std::uint32_t sessionTime = 0;
|
||||
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
RADIUS::RadiusPacket accountingPacket;
|
||||
#endif
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct RADIUSSessionList {
|
||||
std::vector<RADIUSSession> sessions;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct RadiusCoADMParameters {
|
||||
std::string accountingSessionId,
|
||||
accountingMultiSessionId,
|
||||
callingStationId,
|
||||
chargeableUserIdentity;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
} // namespace OpenWifi::GWObjects
|
||||
|
||||
@@ -119,7 +119,8 @@ namespace OpenWifi {
|
||||
|
||||
bool CreateDevice(GWObjects::Device &);
|
||||
bool CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
|
||||
std::string &Firmware, const Poco::Net::IPAddress &IPAddress);
|
||||
std::string &Firmware, const Poco::Net::IPAddress &IPAddress,
|
||||
bool simulated);
|
||||
|
||||
bool GetDevice(std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices,
|
||||
@@ -127,6 +128,9 @@ namespace OpenWifi {
|
||||
// bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select,
|
||||
// std::vector<GWObjects::Device> &Devices, const std::string & orderBy="");
|
||||
bool DeleteDevice(std::string &SerialNumber);
|
||||
bool DeleteDevices(std::string &SerialPattern, bool SimulatedOnly);
|
||||
bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly);
|
||||
|
||||
bool UpdateDevice(GWObjects::Device &);
|
||||
bool DeviceExists(std::string &SerialNumber);
|
||||
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
|
||||
@@ -226,6 +230,8 @@ namespace OpenWifi {
|
||||
bool RemoveCommandListRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date);
|
||||
|
||||
bool SetDeviceLastRecordedContact(std::string & SeialNumber, std::uint64_t lastRecordedContact);
|
||||
|
||||
int Create_Tables();
|
||||
int Create_Statistics();
|
||||
int Create_Devices();
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace OpenWifi::GWWebSocketNotifications {
|
||||
|
||||
struct SingleDevice {
|
||||
std::string serialNumber;
|
||||
inline void to_json(Poco::JSON::Object &Obj) const;
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SingleDeviceConfigurationChange {
|
||||
@@ -20,15 +20,15 @@ namespace OpenWifi::GWWebSocketNotifications {
|
||||
uint64_t oldUUID;
|
||||
uint64_t newUUID;
|
||||
|
||||
inline void to_json(Poco::JSON::Object &Obj) const;
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SingleDeviceFirmwareChange {
|
||||
std::string serialNumber;
|
||||
std::string newFirmware;
|
||||
inline void to_json(Poco::JSON::Object &Obj) const;
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct NumberOfConnection {
|
||||
@@ -38,8 +38,8 @@ namespace OpenWifi::GWWebSocketNotifications {
|
||||
std::uint64_t rx = 0;
|
||||
std::uint64_t tx = 0;
|
||||
|
||||
inline void to_json(Poco::JSON::Object &Obj) const;
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
void Register();
|
||||
|
||||
@@ -37,6 +37,10 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"uuid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"public_ip_lookup": {
|
||||
"type": "string",
|
||||
"format": "uc-fqdn"
|
||||
},
|
||||
"unit": {
|
||||
"$ref": "#/$defs/unit"
|
||||
},
|
||||
@@ -634,26 +638,6 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"type": "string",
|
||||
"format": "uc-timeout",
|
||||
"default": "6h"
|
||||
},
|
||||
"relay-server": {
|
||||
"type": "string",
|
||||
"format": "ipv4",
|
||||
"example": "192.168.2.1"
|
||||
},
|
||||
"circuit-id-format": {
|
||||
"type": "string",
|
||||
"example": [
|
||||
"\\{Interface\\}:\\{VLAN-Id\\}:\\{SSID\\}:\\{Model\\}:\\{Name\\}:\\{AP-MAC\\}:\\{Location\\}",
|
||||
"\\{AP-MAC\\};\\{SSID\\};\\{Crypto\\}",
|
||||
"\\{Name\\} \\{ESSID\\}"
|
||||
]
|
||||
},
|
||||
"remote-id-format": {
|
||||
"type": "string",
|
||||
"example": [
|
||||
"\\{Client-MAC-hex\\} \\{SSID\\}",
|
||||
"\\{AP-MAC-hex\\} \\{SSID\\}"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1232,6 +1216,32 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"secondary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"host": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"examples": [
|
||||
1812
|
||||
]
|
||||
},
|
||||
"secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"request-attribute": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1309,6 +1319,25 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"value": "Example Operator"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"maximum": 255,
|
||||
"minimum": 1
|
||||
},
|
||||
"hex-value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"id": 32,
|
||||
"value": "0a0b0c0d"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1658,6 +1687,236 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.click": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "click-to-continue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.radius": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "radius"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.credentials": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "credentials"
|
||||
},
|
||||
"credentials": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.uam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "uam"
|
||||
},
|
||||
"uam-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 3990
|
||||
},
|
||||
"uam-secret": {
|
||||
"type": "string"
|
||||
},
|
||||
"uam-server": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasid": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasmac": {
|
||||
"type": "string"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"ssid": {
|
||||
"type": "string"
|
||||
},
|
||||
"mac-format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"aabbccddeeff",
|
||||
"aa-bb-cc-dd-ee-ff",
|
||||
"aa:bb:cc:dd:ee:ff",
|
||||
"AABBCCDDEEFF",
|
||||
"AA:BB:CC:DD:EE:FF",
|
||||
"AA-BB-CC-DD-EE-FF"
|
||||
]
|
||||
},
|
||||
"final-redirect-url": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"default",
|
||||
"uam"
|
||||
]
|
||||
},
|
||||
"mac-auth": {
|
||||
"type": "boolean",
|
||||
"default": "default"
|
||||
},
|
||||
"radius-gw-proxy": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive": {
|
||||
"allOf": [
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.click"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.radius"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.credentials"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.uam"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"walled-garden-fqdn": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"walled-garden-ipaddr": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "uc-ip"
|
||||
}
|
||||
},
|
||||
"web-root": {
|
||||
"type": "string",
|
||||
"format": "uc-base64"
|
||||
},
|
||||
"idle-timeout": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"session-timeout": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"interface.ssid": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1710,6 +1969,10 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"isolate-clients": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"strict-forwarding": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"power-save": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -1778,7 +2041,14 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"$ref": "#/$defs/interface.ssid.rate-limit"
|
||||
},
|
||||
"roaming": {
|
||||
"$ref": "#/$defs/interface.ssid.roaming"
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/interface.ssid.roaming"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
},
|
||||
"radius": {
|
||||
"$ref": "#/$defs/interface.ssid.radius"
|
||||
@@ -1795,6 +2065,9 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"access-control-list": {
|
||||
"$ref": "#/$defs/interface.ssid.acl"
|
||||
},
|
||||
"captive": {
|
||||
"$ref": "#/$defs/service.captive"
|
||||
},
|
||||
"hostapd-bss-raw": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -2084,6 +2357,10 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"examples": [
|
||||
"01234567890123456789012345678901"
|
||||
]
|
||||
},
|
||||
"mutual-tls": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2693,236 +2970,6 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.click": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "click-to-continue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.radius": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "radius"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.credentials": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "credentials"
|
||||
},
|
||||
"credentials": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.uam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "uam"
|
||||
},
|
||||
"uam-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 3990
|
||||
},
|
||||
"uam-secret": {
|
||||
"type": "string"
|
||||
},
|
||||
"uam-server": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasid": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasmac": {
|
||||
"type": "string"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"ssid": {
|
||||
"type": "string"
|
||||
},
|
||||
"mac-format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"aabbccddeeff",
|
||||
"aa-bb-cc-dd-ee-ff",
|
||||
"aa:bb:cc:dd:ee:ff",
|
||||
"AABBCCDDEEFF",
|
||||
"AA:BB:CC:DD:EE:FF",
|
||||
"AA-BB-CC-DD-EE-FF"
|
||||
]
|
||||
},
|
||||
"final-redirect-url": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"default",
|
||||
"uam"
|
||||
]
|
||||
},
|
||||
"mac-auth": {
|
||||
"type": "boolean",
|
||||
"default": "default"
|
||||
},
|
||||
"radius-gw-proxy": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive": {
|
||||
"allOf": [
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.click"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.radius"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.credentials"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.uam"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"walled-garden-fqdn": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"walled-garden-ipaddr": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "uc-ip"
|
||||
}
|
||||
},
|
||||
"web-root": {
|
||||
"type": "string",
|
||||
"format": "uc-base64"
|
||||
},
|
||||
"idle-timeout": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"session-timeout": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"service.gps": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2941,6 +2988,32 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.dhcp-relay": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"select-ports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vlans": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vlan": {
|
||||
"type": "number"
|
||||
},
|
||||
"relay-server": {
|
||||
"type": "string",
|
||||
"format": "uc-ip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"service": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -3000,6 +3073,9 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
},
|
||||
"gps": {
|
||||
"$ref": "#/$defs/service.gps"
|
||||
},
|
||||
"dhcp-relay": {
|
||||
"$ref": "#/$defs/service.dhcp-relay"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,18 +14,18 @@ namespace OpenWifi {
|
||||
void EventBusManager::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("fmwk:EventMgr");
|
||||
auto Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
|
||||
auto Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN));
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
|
||||
false);
|
||||
while (Running_) {
|
||||
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
|
||||
if (!Running_)
|
||||
break;
|
||||
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
|
||||
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE));
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(),
|
||||
Msg, false);
|
||||
}
|
||||
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE);
|
||||
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE));
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
|
||||
false);
|
||||
};
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace OpenWifi {
|
||||
Consumer.async_commit(Msg);
|
||||
continue;
|
||||
}
|
||||
KafkaManager()->Dispatch(Msg.get_topic(), Msg.get_key(), Msg.get_payload());
|
||||
KafkaManager()->Dispatch(Msg.get_topic().c_str(), Msg.get_key(), std::make_shared<std::string>(Msg.get_payload()));
|
||||
if (!AutoCommit)
|
||||
Consumer.async_commit(Msg);
|
||||
}
|
||||
@@ -212,8 +212,8 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaProducer::Produce(const std::string &Topic, const std::string &Key,
|
||||
const std::string &Payload) {
|
||||
void KafkaProducer::Produce(const char *Topic, const std::string &Key,
|
||||
const std::shared_ptr<std::string> Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
|
||||
}
|
||||
@@ -275,8 +275,8 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Dispatch(const std::string &Topic, const std::string &Key,
|
||||
const std::string &Payload) {
|
||||
void KafkaDispatcher::Dispatch(const char *Topic, const std::string &Key,
|
||||
const std::shared_ptr<std::string> Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if (It != Notifiers_.end()) {
|
||||
@@ -332,20 +332,21 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::PostMessage(const std::string &topic, const std::string &key,
|
||||
const std::string &PayLoad, bool WrapMessage) {
|
||||
void KafkaManager::PostMessage(const char *topic, const std::string &key,
|
||||
const std::shared_ptr<std::string> PayLoad, bool WrapMessage) {
|
||||
if (KafkaEnabled_) {
|
||||
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::Dispatch(const std::string &Topic, const std::string &Key,
|
||||
const std::string &Payload) {
|
||||
void KafkaManager::Dispatch(const char *Topic, const std::string &Key,
|
||||
const std::shared_ptr<std::string> Payload) {
|
||||
Dispatcher_.Dispatch(Topic, Key, Payload);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string &PayLoad) {
|
||||
return SystemInfoWrapper_ + PayLoad + "}";
|
||||
[[nodiscard]] const std::shared_ptr<std::string> KafkaManager::WrapSystemId(const std::shared_ptr<std::string> PayLoad) {
|
||||
*PayLoad = SystemInfoWrapper_ + *PayLoad + "}";
|
||||
return PayLoad;
|
||||
}
|
||||
|
||||
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic,
|
||||
|
||||
@@ -18,17 +18,17 @@ namespace OpenWifi {
|
||||
|
||||
class KafkaMessage : public Poco::Notification {
|
||||
public:
|
||||
KafkaMessage(const std::string &Topic, const std::string &Key, const std::string &Payload)
|
||||
: Topic_(Topic), Key_(Key), Payload_(Payload) {}
|
||||
KafkaMessage(const char * Topic, const std::string &Key, const std::shared_ptr<std::string> Payload)
|
||||
: Topic_(Topic), Key_(Key), Payload_(std::move(Payload)) {}
|
||||
|
||||
inline const std::string &Topic() { return Topic_; }
|
||||
inline const char * Topic() { return Topic_; }
|
||||
inline const std::string &Key() { return Key_; }
|
||||
inline const std::string &Payload() { return Payload_; }
|
||||
inline const std::string &Payload() { return *Payload_; }
|
||||
|
||||
private:
|
||||
std::string Topic_;
|
||||
const char *Topic_;
|
||||
std::string Key_;
|
||||
std::string Payload_;
|
||||
std::shared_ptr<std::string> Payload_;
|
||||
};
|
||||
|
||||
class KafkaProducer : public Poco::Runnable {
|
||||
@@ -36,7 +36,7 @@ namespace OpenWifi {
|
||||
void run() override;
|
||||
void Start();
|
||||
void Stop();
|
||||
void Produce(const std::string &Topic, const std::string &Key, const std::string &Payload);
|
||||
void Produce(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
@@ -63,7 +63,7 @@ namespace OpenWifi {
|
||||
void Stop();
|
||||
auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
|
||||
void UnregisterTopicWatcher(const std::string &Topic, int Id);
|
||||
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
|
||||
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
|
||||
void run() override;
|
||||
void Topics(std::vector<std::string> &T);
|
||||
|
||||
@@ -91,10 +91,10 @@ namespace OpenWifi {
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
void PostMessage(const std::string &topic, const std::string &key,
|
||||
const std::string &PayLoad, bool WrapMessage = true);
|
||||
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
|
||||
[[nodiscard]] std::string WrapSystemId(const std::string &PayLoad);
|
||||
void PostMessage(const char *topic, const std::string &key,
|
||||
const std::shared_ptr<std::string> PayLoad, bool WrapMessage = true);
|
||||
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
|
||||
[[nodiscard]] const std::shared_ptr<std::string> WrapSystemId(const std::shared_ptr<std::string> PayLoad);
|
||||
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
|
||||
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
|
||||
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);
|
||||
|
||||
@@ -10,32 +10,32 @@
|
||||
|
||||
#include <string>
|
||||
namespace OpenWifi::KafkaTopics {
|
||||
static const std::string HEALTHCHECK{"healthcheck"};
|
||||
static const std::string STATE{"state"};
|
||||
static const std::string CONNECTION{"connection"};
|
||||
static const std::string WIFISCAN{"wifiscan"};
|
||||
static const std::string ALERTS{"alerts"};
|
||||
static const std::string COMMAND{"command"};
|
||||
static const std::string SERVICE_EVENTS{"service_events"};
|
||||
static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"};
|
||||
static const std::string DEVICE_TELEMETRY{"device_telemetry"};
|
||||
static const std::string PROVISIONING_CHANGE{"provisioning_change"};
|
||||
inline const char * HEALTHCHECK = "healthcheck";
|
||||
inline const char * STATE = "state";
|
||||
inline const char * CONNECTION = "connection";
|
||||
inline const char * WIFISCAN = "wifiscan";
|
||||
inline const char * ALERTS = "alerts";
|
||||
inline const char * COMMAND = "command";
|
||||
inline const char * SERVICE_EVENTS = "service_events";
|
||||
inline const char * DEVICE_EVENT_QUEUE = "device_event_queue";
|
||||
inline const char * DEVICE_TELEMETRY = "device_telemetry";
|
||||
inline const char * PROVISIONING_CHANGE = "provisioning_change";
|
||||
|
||||
namespace ServiceEvents {
|
||||
static const std::string EVENT_JOIN{"join"};
|
||||
static const std::string EVENT_LEAVE{"leave"};
|
||||
static const std::string EVENT_KEEP_ALIVE{"keep-alive"};
|
||||
static const std::string EVENT_REMOVE_TOKEN{"remove-token"};
|
||||
inline const char * EVENT_JOIN = "join";
|
||||
inline const char * EVENT_LEAVE = "leave";
|
||||
inline const char * EVENT_KEEP_ALIVE = "keep-alive";
|
||||
inline const char * EVENT_REMOVE_TOKEN = "remove-token";
|
||||
|
||||
namespace Fields {
|
||||
static const std::string EVENT{"event"};
|
||||
static const std::string ID{"id"};
|
||||
static const std::string TYPE{"type"};
|
||||
static const std::string PUBLIC{"publicEndPoint"};
|
||||
static const std::string PRIVATE{"privateEndPoint"};
|
||||
static const std::string KEY{"key"};
|
||||
static const std::string VRSN{"version"};
|
||||
static const std::string TOKEN{"token"};
|
||||
inline const char * EVENT = "event";
|
||||
inline const char * ID = "id";
|
||||
inline const char * TYPE = "type";
|
||||
inline const char * PUBLIC = "publicEndPoint";
|
||||
inline const char * PRIVATE = "privateEndPoint";
|
||||
inline const char * KEY = "key";
|
||||
inline const char * VRSN = "version";
|
||||
inline const char * TOKEN = "token";
|
||||
} // namespace Fields
|
||||
} // namespace ServiceEvents
|
||||
} // namespace OpenWifi::KafkaTopics
|
||||
|
||||
@@ -47,11 +47,11 @@ namespace OpenWifi {
|
||||
|
||||
void MicroServiceReload(const std::string &Type) { MicroService::instance().Reload(Type); }
|
||||
|
||||
const Types::StringVec MicroServiceGetLogLevelNames() {
|
||||
Types::StringVec MicroServiceGetLogLevelNames() {
|
||||
return MicroService::instance().GetLogLevelNames();
|
||||
}
|
||||
|
||||
const Types::StringVec MicroServiceGetSubSystems() {
|
||||
Types::StringVec MicroServiceGetSubSystems() {
|
||||
return MicroService::instance().GetSubSystems();
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace OpenWifi {
|
||||
|
||||
std::string MicroServiceGetUIURI() { return MicroService::instance().GetUIURI(); }
|
||||
|
||||
const SubSystemVec MicroServiceGetFullSubSystems() {
|
||||
SubSystemVec MicroServiceGetFullSubSystems() {
|
||||
return MicroService::instance().GetFullSubSystems();
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace OpenWifi {
|
||||
|
||||
std::uint64_t MicroServiceDaemonBusTimer() { return MicroService::instance().DaemonBusTimer(); }
|
||||
|
||||
std::string MicroServiceMakeSystemEventMessage(const std::string &Type) {
|
||||
std::string MicroServiceMakeSystemEventMessage(const char *Type) {
|
||||
return MicroService::instance().MakeSystemEventMessage(Type);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace OpenWifi {
|
||||
void MicroServiceLoadConfigurationFile();
|
||||
void MicroServiceReload();
|
||||
void MicroServiceReload(const std::string &Type);
|
||||
const Types::StringVec MicroServiceGetLogLevelNames();
|
||||
const Types::StringVec MicroServiceGetSubSystems();
|
||||
Types::StringVec MicroServiceGetLogLevelNames();
|
||||
Types::StringVec MicroServiceGetSubSystems();
|
||||
Types::StringPairVec MicroServiceGetLogLevels();
|
||||
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
|
||||
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer);
|
||||
@@ -40,10 +40,10 @@ namespace OpenWifi {
|
||||
std::uint64_t MicroServiceUptimeTotalSeconds();
|
||||
std::uint64_t MicroServiceStartTimeEpochTime();
|
||||
std::string MicroServiceGetUIURI();
|
||||
const SubSystemVec MicroServiceGetFullSubSystems();
|
||||
SubSystemVec MicroServiceGetFullSubSystems();
|
||||
std::string MicroServiceCreateUUID();
|
||||
std::uint64_t MicroServiceDaemonBusTimer();
|
||||
std::string MicroServiceMakeSystemEventMessage(const std::string &Type);
|
||||
std::string MicroServiceMakeSystemEventMessage(const char *Type);
|
||||
Poco::ThreadPool &MicroServiceTimerPool();
|
||||
std::string MicroServiceConfigPath(const std::string &Key, const std::string &DefaultValue);
|
||||
std::string MicroServiceWWWAssetsDir();
|
||||
|
||||
@@ -14,8 +14,15 @@
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include <RESTObjects/RESTAPI_SecurityObjects.h>
|
||||
|
||||
namespace OpenWifi::RESTAPI_utils {
|
||||
|
||||
inline bool IsRootOrAdmin(const SecurityObjects::UserInfo &UI) {
|
||||
return UI.userRole==SecurityObjects::ROOT ||
|
||||
UI.userRole==SecurityObjects::ADMIN;
|
||||
}
|
||||
|
||||
inline void EmbedDocument(const std::string &ObjName, Poco::JSON::Object &Obj,
|
||||
const std::string &ObjStr) {
|
||||
std::string D = ObjStr.empty() ? "{}" : ObjStr;
|
||||
|
||||
63
src/framework/default_device_types.h
Normal file
63
src/framework/default_device_types.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-19.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace OpenWifi {
|
||||
inline const std::vector<std::pair<std::string, std::string>> DefaultDeviceTypeList{
|
||||
{"actiontec_web7200", "AP"},
|
||||
{"cig_wf186w", "AP"},
|
||||
{"cig_wf188n", "AP"},
|
||||
{"cig_wf194c4", "AP"},
|
||||
{"cig_wf196", "AP"},
|
||||
{"cig_wf196-ca", "AP"},
|
||||
{"cig_wf196-ca-ath12", "AP"},
|
||||
{"cig_wf196-us", "AP"},
|
||||
{"cig_wf610d", "AP"},
|
||||
{"cig_wf660a", "AP"},
|
||||
{"cig_wf808", "AP"},
|
||||
{"cybertan_eww622-a1", "AP"},
|
||||
{"edgecore_eap101", "AP"},
|
||||
{"edgecore_eap101-ath12", "AP"},
|
||||
{"edgecore_eap102", "AP"},
|
||||
{"edgecore_eap104", "AP"},
|
||||
{"edgecore_eap104-ath12", "AP"},
|
||||
{"edgecore_ecs4100-12ph", "AP"},
|
||||
{"edgecore_ecw5211", "AP"},
|
||||
{"edgecore_ecw5410", "AP"},
|
||||
{"edgecore_oap100", "AP"},
|
||||
{"edgecore_spw2ac1200", "SWITCH"},
|
||||
{"edgecore_spw2ac1200-lan-poe", "SWITCH"},
|
||||
{"edgecore_ssw2ac2600", "SWITCH"},
|
||||
{"hfcl_ion4", "AP"},
|
||||
{"hfcl_ion4x", "AP"},
|
||||
{"hfcl_ion4x_2", "AP"},
|
||||
{"hfcl_ion4xe", "AP"},
|
||||
{"hfcl_ion4xi", "AP"},
|
||||
{"indio_um-305ac", "AP"},
|
||||
{"indio_um-305ax", "AP"},
|
||||
{"indio_um-310ax-v1", "AP"},
|
||||
{"indio_um-325ac", "AP"},
|
||||
{"indio_um-510ac-v3", "AP"},
|
||||
{"indio_um-510axm-v1", "AP"},
|
||||
{"indio_um-510axp-v1", "AP"},
|
||||
{"indio_um-550ac", "AP"},
|
||||
{"linksys_e8450-ubi", "AP"},
|
||||
{"linksys_ea6350-v4", "AP"},
|
||||
{"linksys_ea8300", "AP"},
|
||||
{"liteon_wpx8324", "AP"},
|
||||
{"meshpp_s618_cp01", "AP"},
|
||||
{"meshpp_s618_cp03", "AP"},
|
||||
{"udaya_a5-id2", "AP"},
|
||||
{"wallys_dr40x9", "AP"},
|
||||
{"wallys_dr6018", "AP"},
|
||||
{"wallys_dr6018_v4", "AP"},
|
||||
{"x64_vm", "AP"},
|
||||
{"yuncore_ax840", "AP"},
|
||||
{"yuncore_fap640", "AP"},
|
||||
{"yuncore_fap650", "AP"}};
|
||||
}
|
||||
@@ -397,6 +397,18 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
static const struct msg FirmwareBDInProgress {
|
||||
1170, "Firmware DB update already in progress."
|
||||
};
|
||||
static const struct msg SimulatedDeviceNotSupported {
|
||||
1171, "Command not supported on simulated device."
|
||||
};
|
||||
|
||||
static const struct msg SimulationDoesNotExist {
|
||||
7000, "Simulation Instance ID does not exist."
|
||||
};
|
||||
|
||||
static const struct msg SimulationIsAlreadyRunning {
|
||||
7001, "There is an instance of this simulation already running.."
|
||||
};
|
||||
|
||||
|
||||
} // namespace OpenWifi::RESTAPI::Errors
|
||||
|
||||
@@ -554,6 +566,7 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *HEALTHCHECK = "healthcheck";
|
||||
static const char *LOG = "log";
|
||||
static const char *CRASHLOG = "crashlog";
|
||||
static const char *REBOOTLOG = "rebootLog";
|
||||
static const char *PING = "ping";
|
||||
static const char *CFGPENDING = "cfgpending";
|
||||
static const char *RECOVERY = "recovery";
|
||||
@@ -612,6 +625,8 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *DEVICEUPDATE = "deviceupdate";
|
||||
static const char *FWSIGNATURE = "FWsignature";
|
||||
static const char *SIGNATURE = "signature";
|
||||
static const char *INFO = "info";
|
||||
static const char *DATE = "date";
|
||||
|
||||
static const char *SERIALNUMBER = "serialNumber";
|
||||
static const char *COMPATIBLE = "compatible";
|
||||
@@ -642,6 +657,7 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
static const char *HEALTHCHECK = "healthcheck";
|
||||
static const char *LOG = "log";
|
||||
static const char *CRASHLOG = "crashlog";
|
||||
static const char *REBOOTLOG = "rebootLog";
|
||||
static const char *PING = "ping";
|
||||
static const char *CFGPENDING = "cfgpending";
|
||||
static const char *RECOVERY = "recovery";
|
||||
@@ -665,7 +681,8 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
ET_VENUEBROADCAST,
|
||||
ET_EVENT,
|
||||
ET_WIFISCAN,
|
||||
ET_ALARM
|
||||
ET_ALARM,
|
||||
ET_REBOOTLOG
|
||||
};
|
||||
|
||||
inline EVENT_MSG EventFromString(const std::string &Method) {
|
||||
@@ -696,8 +713,10 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
else if (strcmp(WIFISCAN, Method.c_str()) == 0)
|
||||
return ET_WIFISCAN;
|
||||
else if (strcmp(ALARM, Method.c_str()) == 0)
|
||||
return ET_WIFISCAN;
|
||||
return ET_ALARM;
|
||||
return ET_ALARM;
|
||||
else if (strcmp(REBOOTLOG, Method.c_str()) == 0)
|
||||
return ET_REBOOTLOG;
|
||||
return ET_UNKNOWN;
|
||||
};
|
||||
} // namespace OpenWifi::uCentralProtocol::Events
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ namespace OpenWifi::Utils {
|
||||
std::all_of(Serial.begin(), Serial.end(), [](auto i) { return std::isxdigit(i); }));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool ValidSerialNumbers(const std::vector<std::string> &numbers) {
|
||||
return std::all_of(numbers.begin(),numbers.end(),[](auto &number) {return ValidSerialNumber(number);});
|
||||
}
|
||||
|
||||
[[nodiscard]] bool ValidUUID(const std::string &UUID) {
|
||||
if (UUID.size() > 36)
|
||||
return false;
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace OpenWifi::Utils {
|
||||
};
|
||||
|
||||
[[nodiscard]] bool ValidSerialNumber(const std::string &Serial);
|
||||
[[nodiscard]] bool ValidSerialNumbers(const std::vector<std::string> &Serial);
|
||||
[[nodiscard]] bool ValidUUID(const std::string &UUID);
|
||||
[[nodiscard]] bool ValidHostname(const std::string &hostname);
|
||||
|
||||
@@ -146,4 +147,38 @@ namespace OpenWifi::Utils {
|
||||
|
||||
bool ExtractBase64CompressedData(const std::string &CompressedData,
|
||||
std::string &UnCompressedData, uint64_t compress_sz);
|
||||
|
||||
inline bool match(const char* first, const char* second)
|
||||
{
|
||||
// If we reach at the end of both strings, we are done
|
||||
if (*first == '\0' && *second == '\0')
|
||||
return true;
|
||||
|
||||
// Make sure to eliminate consecutive '*'
|
||||
if (*first == '*') {
|
||||
while (*(first + 1) == '*')
|
||||
first++;
|
||||
}
|
||||
|
||||
// Make sure that the characters after '*' are present
|
||||
// in second string. This function assumes that the
|
||||
// first string will not contain two consecutive '*'
|
||||
if (*first == '*' && *(first + 1) != '\0'
|
||||
&& *second == '\0')
|
||||
return false;
|
||||
|
||||
// If the first string contains '?', or current
|
||||
// characters of both strings match
|
||||
if (*first == '?' || *first == *second)
|
||||
return match(first + 1, second + 1);
|
||||
|
||||
// If there is *, then there are two possibilities
|
||||
// a) We consider current character of second string
|
||||
// b) We ignore current character of second string.
|
||||
if (*first == '*')
|
||||
return match(first + 1, second)
|
||||
|| match(first, second + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OpenWifi::Utils
|
||||
|
||||
127
src/libs/Cron.h
Normal file
127
src/libs/Cron.h
Normal file
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-12.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
namespace Bosma {
|
||||
using Clock = std::chrono::system_clock;
|
||||
|
||||
inline void add(std::tm &tm, Clock::duration time) {
|
||||
auto tp = Clock::from_time_t(std::mktime(&tm));
|
||||
auto tp_adjusted = tp + time;
|
||||
auto tm_adjusted = Clock::to_time_t(tp_adjusted);
|
||||
tm = *std::localtime(&tm_adjusted);
|
||||
}
|
||||
|
||||
class BadCronExpression : public std::exception {
|
||||
public:
|
||||
explicit BadCronExpression(std::string msg) : msg_(std::move(msg)) {}
|
||||
|
||||
const char *what() const noexcept override { return (msg_.c_str()); }
|
||||
|
||||
private:
|
||||
std::string msg_;
|
||||
};
|
||||
|
||||
inline void
|
||||
verify_and_set(const std::string &token, const std::string &expression, int &field, const int lower_bound,
|
||||
const int upper_bound, const bool adjust = false) {
|
||||
if (token == "*")
|
||||
field = -1;
|
||||
else {
|
||||
try {
|
||||
field = std::stoi(token);
|
||||
} catch (const std::invalid_argument &) {
|
||||
throw BadCronExpression("malformed cron string (`" + token + "` not an integer or *): " + expression);
|
||||
} catch (const std::out_of_range &) {
|
||||
throw BadCronExpression("malformed cron string (`" + token + "` not convertable to int): " + expression);
|
||||
}
|
||||
if (field < lower_bound || field > upper_bound) {
|
||||
std::ostringstream oss;
|
||||
oss << "malformed cron string ('" << token << "' must be <= " << upper_bound << " and >= " << lower_bound
|
||||
<< "): " << expression;
|
||||
throw BadCronExpression(oss.str());
|
||||
}
|
||||
if (adjust)
|
||||
field--;
|
||||
}
|
||||
}
|
||||
|
||||
class Cron {
|
||||
public:
|
||||
explicit Cron(const std::string &expression) {
|
||||
std::istringstream iss(expression);
|
||||
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
|
||||
std::istream_iterator<std::string>{}};
|
||||
|
||||
if (tokens.size() != 5) throw BadCronExpression("malformed cron string (must be 5 fields): " + expression);
|
||||
|
||||
verify_and_set(tokens[0], expression, minute, 0, 59);
|
||||
verify_and_set(tokens[1], expression, hour, 0, 23);
|
||||
verify_and_set(tokens[2], expression, day, 1, 31);
|
||||
verify_and_set(tokens[3], expression, month, 1, 12, true);
|
||||
verify_and_set(tokens[4], expression, day_of_week, 0, 6);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/a/322058/1284550
|
||||
Clock::time_point cron_to_next(const Clock::time_point from = Clock::now()) const {
|
||||
// get current time as a tm object
|
||||
auto now = Clock::to_time_t(from);
|
||||
std::tm next(*std::localtime(&now));
|
||||
// it will always at least run the next minute
|
||||
next.tm_sec = 0;
|
||||
add(next, std::chrono::minutes(1));
|
||||
while (true) {
|
||||
if (month != -1 && next.tm_mon != month) {
|
||||
// add a month
|
||||
// if this will bring us over a year, increment the year instead and reset the month
|
||||
if (next.tm_mon + 1 > 11) {
|
||||
next.tm_mon = 0;
|
||||
next.tm_year++;
|
||||
} else
|
||||
next.tm_mon++;
|
||||
|
||||
next.tm_mday = 1;
|
||||
next.tm_hour = 0;
|
||||
next.tm_min = 0;
|
||||
continue;
|
||||
}
|
||||
if (day != -1 && next.tm_mday != day) {
|
||||
add(next, std::chrono::hours(24));
|
||||
next.tm_hour = 0;
|
||||
next.tm_min = 0;
|
||||
continue;
|
||||
}
|
||||
if (day_of_week != -1 && next.tm_wday != day_of_week) {
|
||||
add(next, std::chrono::hours(24));
|
||||
next.tm_hour = 0;
|
||||
next.tm_min = 0;
|
||||
continue;
|
||||
}
|
||||
if (hour != -1 && next.tm_hour != hour) {
|
||||
add(next, std::chrono::hours(1));
|
||||
next.tm_min = 0;
|
||||
continue;
|
||||
}
|
||||
if (minute != -1 && next.tm_min != minute) {
|
||||
add(next, std::chrono::minutes(1));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// telling mktime to figure out dst
|
||||
next.tm_isdst = -1;
|
||||
return Clock::from_time_t(std::mktime(&next));
|
||||
}
|
||||
|
||||
int minute, hour, day, month, day_of_week;
|
||||
};
|
||||
}
|
||||
67
src/libs/InterruptableSleep.h
Normal file
67
src/libs/InterruptableSleep.h
Normal file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-12.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
namespace Bosma {
|
||||
class InterruptableSleep {
|
||||
|
||||
using Clock = std::chrono::system_clock;
|
||||
|
||||
// InterruptableSleep offers a sleep that can be interrupted by any thread.
|
||||
// It can be interrupted multiple times
|
||||
// and be interrupted before any sleep is called (the sleep will immediately complete)
|
||||
// Has same interface as condition_variables and futures, except with sleep instead of wait.
|
||||
// For a given object, sleep can be called on multiple threads safely, but is not recommended as behaviour is undefined.
|
||||
|
||||
public:
|
||||
InterruptableSleep() : interrupted(false) {
|
||||
}
|
||||
|
||||
InterruptableSleep(const InterruptableSleep &) = delete;
|
||||
|
||||
InterruptableSleep(InterruptableSleep &&) noexcept = delete;
|
||||
|
||||
~InterruptableSleep() noexcept = default;
|
||||
|
||||
InterruptableSleep &operator=(const InterruptableSleep &) noexcept = delete;
|
||||
|
||||
InterruptableSleep &operator=(InterruptableSleep &&) noexcept = delete;
|
||||
|
||||
void sleep_for(Clock::duration duration) {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
cv.wait_for(ul, duration, [this] { return interrupted; });
|
||||
interrupted = false;
|
||||
}
|
||||
|
||||
void sleep_until(Clock::time_point time) {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
cv.wait_until(ul, time, [this] { return interrupted; });
|
||||
interrupted = false;
|
||||
}
|
||||
|
||||
void sleep() {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
cv.wait(ul, [this] { return interrupted; });
|
||||
interrupted = false;
|
||||
}
|
||||
|
||||
void interrupt() {
|
||||
std::lock_guard<std::mutex> lg(m);
|
||||
interrupted = true;
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
bool interrupted;
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
};
|
||||
}
|
||||
237
src/libs/Scheduler.h
Normal file
237
src/libs/Scheduler.h
Normal file
@@ -0,0 +1,237 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-12.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
|
||||
#include "ctpl_stl.h"
|
||||
|
||||
#include "InterruptableSleep.h"
|
||||
#include "Cron.h"
|
||||
|
||||
namespace Bosma {
|
||||
using Clock = std::chrono::system_clock;
|
||||
|
||||
class Task {
|
||||
public:
|
||||
explicit Task(std::function<void()> &&f, bool recur = false, bool interval = false) :
|
||||
f(std::move(f)), recur(recur), interval(interval) {}
|
||||
|
||||
virtual Clock::time_point get_new_time() const = 0;
|
||||
virtual ~Task() = default;
|
||||
|
||||
std::function<void()> f;
|
||||
|
||||
bool recur;
|
||||
bool interval;
|
||||
};
|
||||
|
||||
class InTask : public Task {
|
||||
public:
|
||||
explicit InTask(std::function<void()> &&f) : Task(std::move(f)) {}
|
||||
|
||||
// dummy time_point because it's not used
|
||||
[[nodiscard]] Clock::time_point get_new_time() const override { return Clock::time_point(Clock::duration(0)); }
|
||||
};
|
||||
|
||||
class EveryTask : public Task {
|
||||
public:
|
||||
EveryTask(Clock::duration time, std::function<void()> &&f, bool interval = false) :
|
||||
Task(std::move(f), true, interval), time(time) {}
|
||||
|
||||
[[nodiscard]] Clock::time_point get_new_time() const override {
|
||||
return Clock::now() + time;
|
||||
};
|
||||
Clock::duration time;
|
||||
};
|
||||
|
||||
class CronTask : public Task {
|
||||
public:
|
||||
CronTask(const std::string &expression, std::function<void()> &&f) : Task(std::move(f), true),
|
||||
cron(expression) {}
|
||||
|
||||
[[nodiscard]] Clock::time_point get_new_time() const override {
|
||||
return cron.cron_to_next();
|
||||
};
|
||||
Cron cron;
|
||||
};
|
||||
|
||||
inline bool try_parse(std::tm &tm, const std::string &expression, const std::string &format) {
|
||||
std::stringstream ss(expression);
|
||||
return !(ss >> std::get_time(&tm, format.c_str())).fail();
|
||||
}
|
||||
|
||||
class Scheduler {
|
||||
public:
|
||||
explicit Scheduler(unsigned int max_n_tasks = 4) : done(false), threads(max_n_tasks + 1) {
|
||||
threads.push([this](int) {
|
||||
while (!done) {
|
||||
Clock::time_point sleep_until_time;
|
||||
if(find_sleep_time(sleep_until_time)) {
|
||||
sleeper.sleep_until(sleep_until_time);
|
||||
} else {
|
||||
sleeper.sleep();
|
||||
}
|
||||
manage_tasks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Scheduler(const Scheduler &) = delete;
|
||||
|
||||
Scheduler(Scheduler &&) noexcept = delete;
|
||||
|
||||
Scheduler &operator=(const Scheduler &) = delete;
|
||||
|
||||
Scheduler &operator=(Scheduler &&) noexcept = delete;
|
||||
|
||||
~Scheduler() {
|
||||
done = true;
|
||||
sleeper.interrupt();
|
||||
}
|
||||
|
||||
template<typename _Callable, typename... _Args>
|
||||
void in(const Clock::time_point time, _Callable &&f, _Args &&... args) {
|
||||
std::shared_ptr<Task> t = std::make_shared<InTask>(
|
||||
std::bind(std::forward<_Callable>(f), std::forward<_Args>(args)...));
|
||||
add_task(time, std::move(t));
|
||||
}
|
||||
|
||||
template<typename _Callable, typename... _Args>
|
||||
void in(const Clock::duration time, _Callable &&f, _Args &&... args) {
|
||||
in(Clock::now() + time, std::forward<_Callable>(f), std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename _Callable, typename... _Args>
|
||||
void at(const std::string &time, _Callable &&f, _Args &&... args) {
|
||||
// get current time as a tm object
|
||||
auto time_now = Clock::to_time_t(Clock::now());
|
||||
std::tm tm = *std::localtime(&time_now);
|
||||
|
||||
// our final time as a time_point
|
||||
Clock::time_point tp;
|
||||
|
||||
if (try_parse(tm, time, "%H:%M:%S")) {
|
||||
// convert tm back to time_t, then to a time_point and assign to final
|
||||
tp = Clock::from_time_t(std::mktime(&tm));
|
||||
|
||||
// if we've already passed this time, the user will mean next day, so add a day.
|
||||
if (Clock::now() >= tp)
|
||||
tp += std::chrono::hours(24);
|
||||
} else if (try_parse(tm, time, "%Y-%m-%d %H:%M:%S")) {
|
||||
tp = Clock::from_time_t(std::mktime(&tm));
|
||||
} else if (try_parse(tm, time, "%Y/%m/%d %H:%M:%S")) {
|
||||
tp = Clock::from_time_t(std::mktime(&tm));
|
||||
} else {
|
||||
// could not parse time
|
||||
throw std::runtime_error("Cannot parse time string: " + time);
|
||||
}
|
||||
|
||||
in(tp, std::forward<_Callable>(f), std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename _Callable, typename... _Args>
|
||||
void every(const Clock::duration time, _Callable &&f, _Args &&... args) {
|
||||
std::shared_ptr<Task> t = std::make_shared<EveryTask>(time, std::bind(std::forward<_Callable>(f),
|
||||
std::forward<_Args>(args)...));
|
||||
auto next_time = t->get_new_time();
|
||||
add_task(next_time, std::move(t));
|
||||
}
|
||||
|
||||
// expression format:
|
||||
// from https://en.wikipedia.org/wiki/Cron#Overview
|
||||
// ┌───────────── minute (0 - 59)
|
||||
// │ ┌───────────── hour (0 - 23)
|
||||
// │ │ ┌───────────── day of month (1 - 31)
|
||||
// │ │ │ ┌───────────── month (1 - 12)
|
||||
// │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
|
||||
// │ │ │ │ │
|
||||
// │ │ │ │ │
|
||||
// * * * * *
|
||||
template<typename _Callable, typename... _Args>
|
||||
void cron(const std::string &expression, _Callable &&f, _Args &&... args) {
|
||||
std::shared_ptr<Task> t = std::make_shared<CronTask>(expression, std::bind(std::forward<_Callable>(f),
|
||||
std::forward<_Args>(args)...));
|
||||
auto next_time = t->get_new_time();
|
||||
add_task(next_time, std::move(t));
|
||||
}
|
||||
|
||||
template<typename _Callable, typename... _Args>
|
||||
void interval(const Clock::duration time, _Callable &&f, _Args &&... args) {
|
||||
std::shared_ptr<Task> t = std::make_shared<EveryTask>(time, std::bind(std::forward<_Callable>(f),
|
||||
std::forward<_Args>(args)...), true);
|
||||
add_task(Clock::now(), std::move(t));
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<bool> done;
|
||||
|
||||
Bosma::InterruptableSleep sleeper;
|
||||
|
||||
std::multimap<Clock::time_point, std::shared_ptr<Task>> tasks;
|
||||
std::mutex lock;
|
||||
ctpl::thread_pool threads;
|
||||
|
||||
void add_task(const Clock::time_point time, std::shared_ptr<Task> t) {
|
||||
std::lock_guard<std::mutex> l(lock);
|
||||
tasks.emplace(time, std::move(t));
|
||||
sleeper.interrupt();
|
||||
}
|
||||
|
||||
bool find_sleep_time(Clock::time_point &sleep_value) {
|
||||
std::lock_guard<std::mutex> l(lock);
|
||||
if(tasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
sleep_value = (*tasks.begin()).first;
|
||||
return true;
|
||||
}
|
||||
|
||||
void manage_tasks() {
|
||||
std::lock_guard<std::mutex> l(lock);
|
||||
|
||||
auto end_of_tasks_to_run = tasks.upper_bound(Clock::now());
|
||||
|
||||
// if there are any tasks to be run and removed
|
||||
if (end_of_tasks_to_run != tasks.begin()) {
|
||||
// keep track of tasks that will be re-added
|
||||
decltype(tasks) recurred_tasks;
|
||||
|
||||
// for all tasks that have been triggered
|
||||
for (auto i = tasks.begin(); i != end_of_tasks_to_run; ++i) {
|
||||
|
||||
auto &task = (*i).second;
|
||||
|
||||
if (task->interval) {
|
||||
// if it's an interval task, only add the task back after f() is completed
|
||||
threads.push([this, task](int) {
|
||||
task->f();
|
||||
// no risk of race-condition,
|
||||
// add_task() will wait for manage_tasks() to release lock
|
||||
add_task(task->get_new_time(), task);
|
||||
});
|
||||
} else {
|
||||
threads.push([task](int) {
|
||||
task->f();
|
||||
});
|
||||
// calculate time of next run and add the new task to the tasks to be recurred
|
||||
if (task->recur)
|
||||
recurred_tasks.emplace(task->get_new_time(), std::move(task));
|
||||
}
|
||||
}
|
||||
|
||||
// remove the completed tasks
|
||||
tasks.erase(tasks.begin(), end_of_tasks_to_run);
|
||||
|
||||
// re-add the tasks that are recurring
|
||||
for (auto &task : recurred_tasks)
|
||||
tasks.emplace(task.first, std::move(task.second));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
253
src/libs/ctpl_stl.h
Normal file
253
src/libs/ctpl_stl.h
Normal file
@@ -0,0 +1,253 @@
|
||||
//
|
||||
// Created by stephane bourque on 2023-04-12.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
/*********************************************************
|
||||
*
|
||||
* Copyright (C) 2014 by Vitaliy Vitsentiy
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
|
||||
|
||||
// thread pool to run user's functors with signature
|
||||
// ret func(int id, other_params)
|
||||
// where id is the index of the thread that runs the functor
|
||||
// ret is some return type
|
||||
|
||||
|
||||
namespace ctpl {
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
class Queue {
|
||||
public:
|
||||
bool push(T const & value) {
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->q.push(value);
|
||||
return true;
|
||||
}
|
||||
// deletes the retrieved element, do not use for non integral types
|
||||
bool pop(T & v) {
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
if (this->q.empty())
|
||||
return false;
|
||||
v = this->q.front();
|
||||
this->q.pop();
|
||||
return true;
|
||||
}
|
||||
bool empty() {
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
return this->q.empty();
|
||||
}
|
||||
private:
|
||||
std::queue<T> q;
|
||||
std::mutex mutex;
|
||||
};
|
||||
}
|
||||
|
||||
class thread_pool {
|
||||
|
||||
public:
|
||||
|
||||
thread_pool() { this->init(); }
|
||||
thread_pool(int nThreads) { this->init(); this->resize(nThreads); }
|
||||
|
||||
// the destructor waits for all the functions in the queue to be finished
|
||||
~thread_pool() {
|
||||
this->stop(true);
|
||||
}
|
||||
|
||||
// get the number of running threads in the pool
|
||||
int size() { return static_cast<int>(this->threads.size()); }
|
||||
|
||||
// number of idle threads
|
||||
int n_idle() { return this->nWaiting; }
|
||||
std::thread & get_thread(int i) { return *this->threads[i]; }
|
||||
|
||||
// change the number of threads in the pool
|
||||
// should be called from one thread, otherwise be careful to not interleave, also with this->stop()
|
||||
// nThreads must be >= 0
|
||||
void resize(int nThreads) {
|
||||
if (!this->isStop && !this->isDone) {
|
||||
int oldNThreads = static_cast<int>(this->threads.size());
|
||||
if (oldNThreads <= nThreads) { // if the number of threads is increased
|
||||
this->threads.resize(nThreads);
|
||||
this->flags.resize(nThreads);
|
||||
|
||||
for (int i = oldNThreads; i < nThreads; ++i) {
|
||||
this->flags[i] = std::make_shared<std::atomic<bool>>(false);
|
||||
this->set_thread(i);
|
||||
}
|
||||
}
|
||||
else { // the number of threads is decreased
|
||||
for (int i = oldNThreads - 1; i >= nThreads; --i) {
|
||||
*this->flags[i] = true; // this thread will finish
|
||||
this->threads[i]->detach();
|
||||
}
|
||||
{
|
||||
// stop the detached threads that were waiting
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->cv.notify_all();
|
||||
}
|
||||
this->threads.resize(nThreads); // safe to delete because the threads are detached
|
||||
this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// empty the queue
|
||||
void clear_queue() {
|
||||
std::function<void(int id)> * _f;
|
||||
while (this->q.pop(_f))
|
||||
delete _f; // empty the queue
|
||||
}
|
||||
|
||||
// pops a functional wrapper to the original function
|
||||
std::function<void(int)> pop() {
|
||||
std::function<void(int id)> * _f = nullptr;
|
||||
this->q.pop(_f);
|
||||
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
|
||||
std::function<void(int)> f;
|
||||
if (_f)
|
||||
f = *_f;
|
||||
return f;
|
||||
}
|
||||
|
||||
// wait for all computing threads to finish and stop all threads
|
||||
// may be called asynchronously to not pause the calling thread while waiting
|
||||
// if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions
|
||||
void stop(bool isWait = false) {
|
||||
if (!isWait) {
|
||||
if (this->isStop)
|
||||
return;
|
||||
this->isStop = true;
|
||||
for (int i = 0, n = this->size(); i < n; ++i) {
|
||||
*this->flags[i] = true; // command the threads to stop
|
||||
}
|
||||
this->clear_queue(); // empty the queue
|
||||
}
|
||||
else {
|
||||
if (this->isDone || this->isStop)
|
||||
return;
|
||||
this->isDone = true; // give the waiting threads a command to finish
|
||||
}
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->cv.notify_all(); // stop all waiting threads
|
||||
}
|
||||
for (int i = 0; i < static_cast<int>(this->threads.size()); ++i) { // wait for the computing threads to finish
|
||||
if (this->threads[i]->joinable())
|
||||
this->threads[i]->join();
|
||||
}
|
||||
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
|
||||
// therefore delete them here
|
||||
this->clear_queue();
|
||||
this->threads.clear();
|
||||
this->flags.clear();
|
||||
}
|
||||
|
||||
template<typename F, typename... Rest>
|
||||
auto push(F && f, Rest&&... rest) ->std::future<decltype(f(0, rest...))> {
|
||||
auto pck = std::make_shared<std::packaged_task<decltype(f(0, rest...))(int)>>(
|
||||
std::bind(std::forward<F>(f), std::placeholders::_1, std::forward<Rest>(rest)...)
|
||||
);
|
||||
auto _f = new std::function<void(int id)>([pck](int id) {
|
||||
(*pck)(id);
|
||||
});
|
||||
this->q.push(_f);
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->cv.notify_one();
|
||||
return pck->get_future();
|
||||
}
|
||||
|
||||
// run the user's function that excepts argument int - id of the running thread. returned value is templatized
|
||||
// operator returns std::future, where the user can get the result and rethrow the catched exceptins
|
||||
template<typename F>
|
||||
auto push(F && f) ->std::future<decltype(f(0))> {
|
||||
auto pck = std::make_shared<std::packaged_task<decltype(f(0))(int)>>(std::forward<F>(f));
|
||||
auto _f = new std::function<void(int id)>([pck](int id) {
|
||||
(*pck)(id);
|
||||
});
|
||||
this->q.push(_f);
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->cv.notify_one();
|
||||
return pck->get_future();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// deleted
|
||||
thread_pool(const thread_pool &);// = delete;
|
||||
thread_pool(thread_pool &&);// = delete;
|
||||
thread_pool & operator=(const thread_pool &);// = delete;
|
||||
thread_pool & operator=(thread_pool &&);// = delete;
|
||||
|
||||
void set_thread(int i) {
|
||||
std::shared_ptr<std::atomic<bool>> flag(this->flags[i]); // a copy of the shared ptr to the flag
|
||||
auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() {
|
||||
std::atomic<bool> & _flag = *flag;
|
||||
std::function<void(int id)> * _f;
|
||||
bool isPop = this->q.pop(_f);
|
||||
while (true) {
|
||||
while (isPop) { // if there is anything in the queue
|
||||
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
|
||||
(*_f)(i);
|
||||
if (_flag)
|
||||
return; // the thread is wanted to stop, return even if the queue is not empty yet
|
||||
else
|
||||
isPop = this->q.pop(_f);
|
||||
}
|
||||
// the queue is empty here, wait for the next command
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
++this->nWaiting;
|
||||
this->cv.wait(lock, [this, &_f, &isPop, &_flag](){ isPop = this->q.pop(_f); return isPop || this->isDone || _flag; });
|
||||
--this->nWaiting;
|
||||
if (!isPop)
|
||||
return; // if the queue is empty and this->isDone == true or *flag then return
|
||||
}
|
||||
};
|
||||
this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique()
|
||||
}
|
||||
|
||||
void init() { this->nWaiting = 0; this->isStop = false; this->isDone = false; }
|
||||
|
||||
std::vector<std::unique_ptr<std::thread>> threads;
|
||||
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
|
||||
detail::Queue<std::function<void(int id)> *> q;
|
||||
std::atomic<bool> isDone;
|
||||
std::atomic<bool> isStop;
|
||||
std::atomic<int> nWaiting; // how many threads are waiting
|
||||
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "Poco/Net/WebSocketImpl.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
#define DBGLINE \
|
||||
@@ -221,7 +222,6 @@ namespace OpenWifi {
|
||||
}
|
||||
NewSocket.close();
|
||||
} catch (const Poco::Exception &E) {
|
||||
std::cout << "Exception onDeviceAccept: " << E.what() << std::endl;
|
||||
Logger().log(E);
|
||||
}
|
||||
}
|
||||
@@ -245,7 +245,7 @@ namespace OpenWifi {
|
||||
void RTTYS_server::AddNewSocket(Poco::Net::StreamSocket &Socket, std::unique_ptr<Poco::Crypto::X509Certificate> P, bool valid, const std::string &cid, const std::string &cn) {
|
||||
Socket.setNoDelay(true);
|
||||
Socket.setKeepAlive(true);
|
||||
Socket.setBlocking(false);
|
||||
Socket.setBlocking(true);
|
||||
Socket.setReceiveBufferSize(RTTY_RECEIVE_BUFFER);
|
||||
Socket.setSendBufferSize(RTTY_RECEIVE_BUFFER);
|
||||
Poco::Timespan TS2(300, 100);
|
||||
@@ -261,10 +261,9 @@ namespace OpenWifi {
|
||||
Poco::NObserver<RTTYS_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RTTYS_server::onConnectedDeviceSocketError));
|
||||
int fd = Socket.impl()->sockfd();
|
||||
Sockets_[fd] = std::make_unique<SecureSocketPair>(SecureSocketPair{Socket, std::move(P), valid, cid, cn});
|
||||
Sockets_[fd] = std::make_unique<SecureSocketPair>(Socket, std::move(P), valid, cid, cn);
|
||||
}
|
||||
|
||||
|
||||
void RTTYS_server::RemoveSocket(const Poco::Net::Socket &Socket) {
|
||||
auto hint = Sockets_.find(Socket.impl()->sockfd());
|
||||
if(hint!=end(Sockets_)) {
|
||||
@@ -295,16 +294,8 @@ namespace OpenWifi {
|
||||
*this, &RTTYS_server::onClientSocketError));
|
||||
}
|
||||
|
||||
int RTTYS_server::SendBytes(int fd, const unsigned char *buffer, std::size_t len) {
|
||||
auto hint = Sockets_.find(fd);
|
||||
if(hint==end(Sockets_)) {
|
||||
poco_error(Logger(),fmt::format("Cannot find this socket: {}",fd));
|
||||
return -1;
|
||||
}
|
||||
return hint->second->socket.impl()->sendBytes(buffer,len);
|
||||
}
|
||||
|
||||
int RTTYS_server::SendBytes(const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len) {
|
||||
int RTTYS_server::SendBytes(const std::shared_ptr<RTTYS_EndPoint> & Conn, const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len) {
|
||||
Conn->tx += len;
|
||||
return Socket.impl()->sendBytes(buffer,len);
|
||||
}
|
||||
|
||||
@@ -318,14 +309,14 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
|
||||
bool RTTYS_server::do_msgTypeRegister(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeRegister(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &Buffer, [[maybe_unused]] std::size_t msg_len) {
|
||||
bool good = true;
|
||||
try {
|
||||
|
||||
auto fd = Socket.impl()->sockfd();
|
||||
std::string id_ = ReadString(Buffer, BufferCurrentSize, BufferPos);
|
||||
std::string desc_ = ReadString(Buffer, BufferCurrentSize, BufferPos);
|
||||
std::string token_ = ReadString(Buffer, BufferCurrentSize, BufferPos);
|
||||
std::string id_ = ReadString(Buffer);
|
||||
std::string desc_ = ReadString(Buffer);
|
||||
std::string token_ = ReadString(Buffer);
|
||||
|
||||
poco_information(Logger(),fmt::format("Device registration: description:{} id:{} token:{}", desc_, id_, token_));
|
||||
if (id_.size() != RTTY_DEVICE_TOKEN_LENGTH ||
|
||||
@@ -380,7 +371,7 @@ namespace OpenWifi {
|
||||
OutBuf[5] = 'K';
|
||||
OutBuf[6] = 0;
|
||||
|
||||
if (SendBytes(Socket,OutBuf, 7) != 7) {
|
||||
if (SendBytes(ConnectionEp,Socket,OutBuf, 7) != 7) {
|
||||
poco_error(
|
||||
Logger(),
|
||||
fmt::format("{}: Description:{} Could not send data to complete registration",
|
||||
@@ -418,19 +409,42 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::EmptyBuffer(int fd, const std::uint8_t *buffer, std::size_t len) {
|
||||
auto EndPoint = Connected_.find(fd);
|
||||
if (EndPoint!=end(Connected_) && EndPoint->second->WSSocket_!= nullptr && EndPoint->second->WSSocket_->impl() != nullptr) {
|
||||
SendToClient(*EndPoint->second->WSSocket_, buffer,
|
||||
len);
|
||||
EndPoint->second->rx += len;
|
||||
// std::cout << "Total: " << EndPoint->second->rx << " bytes now: " << len << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void RTTYS_server::onConnectedDeviceSocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
|
||||
std::shared_ptr<RTTYS_EndPoint> ConnectionPtr;
|
||||
std::lock_guard Lock(ServerMutex_);
|
||||
int fd = pNf->socket().impl()->sockfd();
|
||||
|
||||
try {
|
||||
unsigned char Buffer[RTTY_RECEIVE_BUFFER];
|
||||
std::size_t BufferCurrentSize=0, BufferPos=0;
|
||||
|
||||
auto hint = Sockets_.find(fd);
|
||||
if(hint==end(Sockets_)) {
|
||||
poco_error(Logger(),fmt::format("{}: unknown socket",fd));
|
||||
return;
|
||||
}
|
||||
|
||||
Poco::FIFOBuffer &buffer = *hint->second->buffer;
|
||||
|
||||
int received_bytes=0;
|
||||
std::uint8_t agg_buffer[RTTY_RECEIVE_BUFFER];
|
||||
std::size_t agg_buf_pos=0;
|
||||
|
||||
try {
|
||||
BufferCurrentSize = pNf->socket().impl()->receiveBytes(Buffer, sizeof(Buffer));
|
||||
if(BufferCurrentSize==0) {
|
||||
// std::cout << "Available: " << buffer.available() << " ";
|
||||
Poco::Timespan TS(5,0);
|
||||
received_bytes = hint->second->socket.receiveBytes(buffer);
|
||||
if(received_bytes==0) {
|
||||
// std::cout << hint->second->socket.lastError() << std::endl;
|
||||
poco_warning(Logger(), "Device Closing connection - 0 bytes received.");
|
||||
EndConnection( pNf->socket(), __func__, __LINE__ );
|
||||
return;
|
||||
@@ -447,52 +461,68 @@ namespace OpenWifi {
|
||||
|
||||
bool good = true;
|
||||
|
||||
while (BufferPos<BufferCurrentSize && good) {
|
||||
unsigned char LastCommand=0;
|
||||
std::uint16_t msg_len = 0;
|
||||
if (BufferCurrentSize >= RTTY_HDR_SIZE) {
|
||||
LastCommand = Buffer[BufferPos+0];
|
||||
msg_len = (Buffer[BufferPos+1] << 8) + Buffer[BufferPos+2];
|
||||
BufferPos+=RTTY_HDR_SIZE;
|
||||
} else {
|
||||
good = false;
|
||||
std::cout << "Funky..." << BufferCurrentSize << std::endl;
|
||||
continue;
|
||||
while (!buffer.isEmpty() && good) {
|
||||
|
||||
if(buffer.used() < RTTY_HDR_SIZE) {
|
||||
if(agg_buf_pos>0) {
|
||||
EmptyBuffer(fd, agg_buffer, agg_buf_pos);
|
||||
}
|
||||
// poco_debug(Logger(),fmt::format("Not enough data in the pipe for header",buffer.used()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::uint8_t header[RTTY_HDR_SIZE];
|
||||
buffer.peek((char*)header,RTTY_HDR_SIZE);
|
||||
|
||||
std::uint8_t LastCommand = header[0];
|
||||
std::uint16_t msg_len = (header[1] << 8) + header[2];
|
||||
|
||||
if(buffer.used()<(RTTY_HDR_SIZE+msg_len)) {
|
||||
if(agg_buf_pos>0) {
|
||||
EmptyBuffer(fd, agg_buffer, agg_buf_pos);
|
||||
}
|
||||
// poco_debug(Logger(),fmt::format("Not enough data in the pipe for command data",buffer.used()));
|
||||
return;
|
||||
}
|
||||
|
||||
// std::cout << line++ << " Available: " << buffer.available() << " Cmd: " << (int) LastCommand << " Received: " << received_bytes
|
||||
// << " MsgLen: " << msg_len << " Data in buffer: " << buffer.used() << std::endl;
|
||||
|
||||
buffer.drain(RTTY_HDR_SIZE);
|
||||
|
||||
switch (LastCommand) {
|
||||
case RTTYS_EndPoint::msgTypeRegister: {
|
||||
good = do_msgTypeRegister(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeRegister(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeLogin: {
|
||||
good = do_msgTypeLogin(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeLogin(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeLogout: {
|
||||
good = do_msgTypeLogout(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeLogout(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeTermData: {
|
||||
good = do_msgTypeTermData(pNf->socket(), Buffer, BufferCurrentSize, BufferPos, msg_len);
|
||||
good = do_msgTypeTermData(pNf->socket(), buffer, msg_len, agg_buffer, agg_buf_pos);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeWinsize: {
|
||||
good = do_msgTypeWinsize(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeWinsize(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeCmd: {
|
||||
good = do_msgTypeCmd(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeCmd(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeHeartbeat: {
|
||||
good = do_msgTypeHeartbeat(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeHeartbeat(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeFile: {
|
||||
good = do_msgTypeFile(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeFile(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeHttp: {
|
||||
good = do_msgTypeHttp(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeHttp(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeAck: {
|
||||
good = do_msgTypeAck(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeAck(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
case RTTYS_EndPoint::msgTypeMax: {
|
||||
good = do_msgTypeMax(pNf->socket(), Buffer, BufferCurrentSize, BufferPos);
|
||||
good = do_msgTypeMax(pNf->socket(), buffer, msg_len);
|
||||
} break;
|
||||
default: {
|
||||
poco_warning(Logger(),
|
||||
@@ -503,6 +533,12 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
if(agg_buf_pos>0) {
|
||||
EmptyBuffer(fd, agg_buffer, agg_buf_pos);
|
||||
}
|
||||
|
||||
// std::cout << "Empty: " << buffer.isEmpty() << std::endl;
|
||||
|
||||
if (!good) {
|
||||
EndConnection(pNf->socket(), __func__, __LINE__);
|
||||
}
|
||||
@@ -687,14 +723,20 @@ namespace OpenWifi {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// OK Create and register this WS client
|
||||
try {
|
||||
// EndPoint->second->WSSocket_ = std::make_unique<Poco::Net::WebSocket>(request, response);
|
||||
EndPoint->second->WSSocket_ = std::make_unique<Poco::Net::WebSocket>(request, response);
|
||||
EndPoint->second->ClientConnected_ = std::chrono::high_resolution_clock::now();
|
||||
EndPoint->second->WSSocket_->setBlocking(false);
|
||||
EndPoint->second->WSSocket_->setNoDelay(true);
|
||||
EndPoint->second->WSSocket_->setNoDelay(false);
|
||||
EndPoint->second->WSSocket_->setKeepAlive(true);
|
||||
Poco::Timespan ST(600,0);
|
||||
EndPoint->second->WSSocket_->setSendTimeout(ST);
|
||||
EndPoint->second->WSSocket_->setSendBufferSize(1000000);
|
||||
EndPoint->second->WSSocket_->setReceiveTimeout(ST);
|
||||
EndPoint->second->WSSocket_->setReceiveBufferSize(1000000);
|
||||
AddClientEventHandlers(*EndPoint->second->WSSocket_, EndPoint->second);
|
||||
if (EndPoint->second->DeviceIsAttached_ && !EndPoint->second->completed_) {
|
||||
poco_information(Logger(),fmt::format("CLN{}: Device registered, Client Registered - sending login", EndPoint->second->SerialNumber_));
|
||||
@@ -777,9 +819,8 @@ namespace OpenWifi {
|
||||
} else {
|
||||
EndPoints_.erase(hint->second->Id_);
|
||||
}
|
||||
} else {
|
||||
std::cout << "Cannot find the associated WS..." << std::endl;
|
||||
}
|
||||
|
||||
poco_debug(Logger(),fmt::format("Closing connection at {}:{}", func, Line));
|
||||
}
|
||||
|
||||
@@ -823,7 +864,7 @@ namespace OpenWifi {
|
||||
Conn->small_buf_[3] = Conn->sid_;
|
||||
memcpy(&Conn->small_buf_[RTTY_HDR_SIZE + 1], &buf[1], len - 1);
|
||||
try {
|
||||
auto Sent = SendBytes(Conn->DeviceSocket_, Conn->small_buf_,
|
||||
auto Sent = SendBytes(Conn,Conn->DeviceSocket_, Conn->small_buf_,
|
||||
RTTY_HDR_SIZE + 1 + len - 1);
|
||||
return (Sent == (int)(RTTY_HDR_SIZE + 1 + len - 1));
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -841,7 +882,7 @@ namespace OpenWifi {
|
||||
Msg.get()[3] = Conn->sid_;
|
||||
memcpy((Msg.get() + RTTY_HDR_SIZE + 1), &buf[1], len - 1);
|
||||
try {
|
||||
auto Sent = SendBytes(Conn->DeviceSocket_,Msg.get(),
|
||||
auto Sent = SendBytes(Conn,Conn->DeviceSocket_,Msg.get(),
|
||||
RTTY_HDR_SIZE + 1 + len - 1);
|
||||
return (Sent == (int)(RTTY_HDR_SIZE + 1 + len - 1));
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -866,7 +907,7 @@ namespace OpenWifi {
|
||||
outBuf[RTTY_HDR_SIZE + 2 + 1] = rows >> 8;
|
||||
outBuf[RTTY_HDR_SIZE + 3 + 1] = rows & 0x00ff;
|
||||
try {
|
||||
auto Sent = SendBytes(Conn->DeviceSocket_, outBuf, RTTY_HDR_SIZE + 4 + 1);
|
||||
auto Sent = SendBytes(Conn,Conn->DeviceSocket_, outBuf, RTTY_HDR_SIZE + 4 + 1);
|
||||
return (Sent == (int)(RTTY_HDR_SIZE + 4 + 1));
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -884,7 +925,7 @@ namespace OpenWifi {
|
||||
outBuf[2] = 0;
|
||||
try {
|
||||
poco_debug(Logger(), fmt::format("TID:{} Starting login on device.",Conn->TID_));
|
||||
auto Sent = SendBytes(Socket,outBuf,RTTY_HDR_SIZE);
|
||||
auto Sent = SendBytes(Conn,Socket,outBuf,RTTY_HDR_SIZE);
|
||||
Conn->completed_ = true;
|
||||
return Sent == RTTY_HDR_SIZE;
|
||||
} catch (const Poco::Exception &E) {
|
||||
@@ -903,7 +944,7 @@ namespace OpenWifi {
|
||||
outBuf[3] = Conn->sid_;
|
||||
poco_debug(Logger(), fmt::format("{}: Logout", Conn->TID_));
|
||||
try {
|
||||
auto Sent = SendBytes(Socket, outBuf, RTTY_HDR_SIZE + 1);
|
||||
auto Sent = SendBytes(Conn,Socket, outBuf, RTTY_HDR_SIZE + 1);
|
||||
return Sent == (int)(RTTY_HDR_SIZE + 1);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -927,6 +968,20 @@ namespace OpenWifi {
|
||||
return Res;
|
||||
}
|
||||
|
||||
std::string RTTYS_server::ReadString(Poco::FIFOBuffer &Buffer) {
|
||||
std::string Res;
|
||||
while(Buffer.isReadable()) {
|
||||
auto c = *Buffer.begin();
|
||||
if(c==0) {
|
||||
Buffer.drain(1);
|
||||
break;
|
||||
}
|
||||
Res += c;
|
||||
Buffer.drain(1);
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool RTTYS_server::SendToClient(Poco::Net::WebSocket &WebSocket, const u_char *Buf, int len) {
|
||||
WebSocket.sendFrame(
|
||||
Buf, len, Poco::Net::WebSocket::FRAME_FLAG_FIN | Poco::Net::WebSocket::FRAME_OP_BINARY);
|
||||
@@ -938,15 +993,17 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeLogin(const Poco::Net::Socket &Socket, unsigned char *Buffer, [[maybe_unused]] std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeLogin(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, [[maybe_unused]] std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Asking for login");
|
||||
auto EndPoint = Connected_.find(Socket.impl()->sockfd());
|
||||
if (EndPoint!=end(Connected_) && EndPoint->second->WSSocket_!= nullptr && EndPoint->second->WSSocket_->impl() != nullptr) {
|
||||
try {
|
||||
nlohmann::json doc;
|
||||
unsigned char Error = Buffer[BufferPos++];
|
||||
unsigned char Error = *buffer.begin();
|
||||
buffer.drain(1);
|
||||
if(Error==0) {
|
||||
EndPoint->second->sid_ = Buffer[BufferPos++];
|
||||
EndPoint->second->sid_ = *buffer.begin();
|
||||
buffer.drain(1);
|
||||
} else {
|
||||
poco_error(Logger(),"Device login failed.");
|
||||
return false;
|
||||
@@ -964,85 +1021,86 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeLogout([[maybe_unused]] const Poco::Net::Socket &Socket, unsigned char *Buffer, [[maybe_unused]] std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeLogout([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Logout");
|
||||
[[maybe_unused]] unsigned char logout_session_id = Buffer[BufferPos++];
|
||||
|
||||
// [[maybe_unused]] unsigned char logout_session_id = Buffer[BufferPos];
|
||||
buffer.drain(msg_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeTermData(const Poco::Net::Socket &Socket, unsigned char *Buffer, [[maybe_unused]] std::size_t BufferCurrentSize, std::size_t &BufferPos, std::size_t msg_len) {
|
||||
bool RTTYS_server::do_msgTypeTermData(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len, std::uint8_t *buf, std::size_t &pos) {
|
||||
auto EndPoint = Connected_.find(Socket.impl()->sockfd());
|
||||
if (EndPoint!=end(Connected_) && EndPoint->second->WSSocket_!= nullptr && EndPoint->second->WSSocket_->impl() != nullptr) {
|
||||
try {
|
||||
BufferPos++;
|
||||
buffer.drain(1);
|
||||
msg_len--;
|
||||
auto good = SendToClient(*EndPoint->second->WSSocket_, &Buffer[BufferPos], (int) msg_len );
|
||||
BufferPos += msg_len;
|
||||
return good;
|
||||
buffer.read((char*)&(buf[pos]),msg_len);
|
||||
pos+=msg_len;
|
||||
// auto good = SendToClient(*EndPoint->second->WSSocket_, (unsigned char*) buffer.begin(), (int) msg_len );
|
||||
// buffer.drain(msg_len);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
std::cout << "Failed to send WS stuff" << std::endl;
|
||||
Logger().log(E);
|
||||
return false;
|
||||
} catch (const std::exception &E) {
|
||||
LogStdException(E, "Cannot send data to UI Client");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeWinsize([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer,[[maybe_unused]] std::size_t BufferCurrentSize, [[maybe_unused]] std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeWinsize([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Asking for msgTypeWinsize");
|
||||
BufferPos = BufferCurrentSize;
|
||||
buffer.drain(msg_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeCmd([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer,[[maybe_unused]] std::size_t BufferCurrentSize, [[maybe_unused]] std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeCmd([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Asking for msgTypeCmd");
|
||||
BufferPos = BufferCurrentSize;
|
||||
buffer.drain(msg_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, [[maybe_unused]] Poco::FIFOBuffer &buffer, [[maybe_unused]] std::size_t msg_len) {
|
||||
try {
|
||||
u_char MsgBuf[RTTY_HDR_SIZE + 16]{0};
|
||||
BufferPos = BufferCurrentSize;
|
||||
MsgBuf[0] = RTTYS_EndPoint::msgTypeHeartbeat;
|
||||
MsgBuf[1] = 0;
|
||||
MsgBuf[2] = 0;
|
||||
auto Sent = SendBytes(Socket,MsgBuf, RTTY_HDR_SIZE);
|
||||
return Sent == RTTY_HDR_SIZE;
|
||||
auto hint = Connected_.find(Socket.impl()->sockfd());
|
||||
if(hint!=end(Connected_)) {
|
||||
auto Sent = SendBytes(hint->second,Socket, MsgBuf, RTTY_HDR_SIZE);
|
||||
return Sent == RTTY_HDR_SIZE;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
return false;
|
||||
} catch (const std::exception &E) {
|
||||
LogStdException(E, "Cannot send heartbeat");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeFile([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeFile([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Asking for msgTypeFile");
|
||||
BufferPos = BufferCurrentSize;
|
||||
buffer.drain(msg_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeHttp([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeHttp([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Asking for msgTypeHttp");
|
||||
BufferPos = BufferCurrentSize;
|
||||
buffer.drain(msg_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeAck([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
bool RTTYS_server::do_msgTypeAck([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Asking for msgTypeAck");
|
||||
BufferPos = BufferCurrentSize;
|
||||
buffer.drain(msg_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTTYS_server::do_msgTypeMax([[maybe_unused]] const Poco::Net::Socket &Socket, [[maybe_unused]] unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos) {
|
||||
BufferPos = BufferCurrentSize;
|
||||
bool RTTYS_server::do_msgTypeMax([[maybe_unused]] const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
|
||||
poco_debug(Logger(), "Asking for msgTypeMax");
|
||||
buffer.drain(msg_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
#include "Poco/Timer.h"
|
||||
#include <Poco/FIFOBuffer.h>
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/utils.h"
|
||||
@@ -25,7 +26,7 @@ namespace OpenWifi {
|
||||
constexpr uint RTTY_DEVICE_TOKEN_LENGTH = 32;
|
||||
constexpr std::size_t RTTY_SESSION_ID_LENGTH = 32;
|
||||
constexpr std::size_t RTTY_HDR_SIZE = 3;
|
||||
constexpr std::size_t RTTY_RECEIVE_BUFFER = 64000;
|
||||
constexpr std::size_t RTTY_RECEIVE_BUFFER = 1024 << 10;
|
||||
|
||||
class RTTYS_server;
|
||||
|
||||
@@ -114,6 +115,7 @@ namespace OpenWifi {
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> Created_{0s},
|
||||
DeviceDisconnected_{0s}, ClientDisconnected_{0s}, DeviceConnected_{0s},
|
||||
ClientConnected_{0s};
|
||||
std::uint64_t rx=0,tx=0;
|
||||
};
|
||||
|
||||
class RTTYS_server : public SubSystemServer {
|
||||
@@ -129,6 +131,21 @@ namespace OpenWifi {
|
||||
bool valid=false;
|
||||
std::string cid;
|
||||
std::string cn;
|
||||
std::unique_ptr<Poco::FIFOBuffer> buffer;
|
||||
|
||||
SecureSocketPair(Poco::Net::StreamSocket &S,
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Cert,
|
||||
bool Valid,
|
||||
const std::string & Cid,
|
||||
const std::string & CN) :
|
||||
socket(S),
|
||||
cert(std::move(Cert)),
|
||||
valid(Valid),
|
||||
cid(Cid),
|
||||
cn(CN)
|
||||
{
|
||||
buffer = std::make_unique<Poco::FIFOBuffer>(RTTY_RECEIVE_BUFFER);
|
||||
}
|
||||
};
|
||||
|
||||
int Start() final;
|
||||
@@ -184,8 +201,8 @@ namespace OpenWifi {
|
||||
void SendData(std::shared_ptr<RTTYS_EndPoint> &Connection, const u_char *Buf, size_t len);
|
||||
void SendData(std::shared_ptr<RTTYS_EndPoint> &Connection, const std::string &s);
|
||||
|
||||
int SendBytes(int fd, const unsigned char *buffer, std::size_t len);
|
||||
int SendBytes(const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len);
|
||||
// int SendBytes(int fd, const unsigned char *buffer, std::size_t len);
|
||||
int SendBytes(const std::shared_ptr<RTTYS_EndPoint> & Conn,const Poco::Net::Socket &Socket, const unsigned char *buffer, std::size_t len);
|
||||
|
||||
std::shared_ptr<RTTYS_EndPoint> FindRegisteredEndPoint(const std::string &Id,
|
||||
const std::string &Token);
|
||||
@@ -194,18 +211,19 @@ namespace OpenWifi {
|
||||
void RemoveSocket(const Poco::Net::Socket &Socket);
|
||||
void LogStdException(const std::exception &E, const std::string & msg);
|
||||
|
||||
bool do_msgTypeRegister(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeLogin(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeTermData(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos, std::size_t msl_len);
|
||||
bool do_msgTypeLogout(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeWinsize(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeCmd(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeFile(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeHttp(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeAck(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeMax(const Poco::Net::Socket &Socket, unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
bool do_msgTypeRegister(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeLogin(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeTermData(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len, std::uint8_t *buf, std::size_t &pos);
|
||||
bool do_msgTypeLogout(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeWinsize(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeCmd(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeHeartbeat(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeFile(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeHttp(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeAck(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
bool do_msgTypeMax(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len);
|
||||
|
||||
void EmptyBuffer(int fd, const std::uint8_t *buffer, std::size_t len);
|
||||
bool WindowSize(std::shared_ptr<RTTYS_EndPoint> Conn, int cols, int rows);
|
||||
bool KeyStrokes(std::shared_ptr<RTTYS_EndPoint> Conn, const u_char *buf, size_t len);
|
||||
|
||||
@@ -213,6 +231,7 @@ namespace OpenWifi {
|
||||
bool Logout(const Poco::Net::Socket &Socket, std::shared_ptr<RTTYS_EndPoint> Conn);
|
||||
|
||||
std::string ReadString(unsigned char *Buffer, std::size_t BufferCurrentSize, std::size_t &BufferPos);
|
||||
std::string ReadString(Poco::FIFOBuffer &Buffer);
|
||||
bool SendToClient(Poco::Net::WebSocket &WebSocket, const u_char *Buf, int len);
|
||||
bool SendToClient(Poco::Net::WebSocket &WebSocket, const std::string &s);
|
||||
|
||||
|
||||
@@ -51,7 +51,10 @@ namespace OpenWifi {
|
||||
"pendingConfiguration, "
|
||||
"pendingConfigurationCmd, "
|
||||
"restrictionDetails, "
|
||||
"pendingUUID"};
|
||||
"pendingUUID, "
|
||||
"simulated,"
|
||||
"lastRecordedContact"
|
||||
};
|
||||
|
||||
const static std::string DB_DeviceUpdateFields{"SerialNumber=?,"
|
||||
"DeviceType=?, "
|
||||
@@ -79,16 +82,18 @@ namespace OpenWifi {
|
||||
"pendingConfiguration=?, "
|
||||
"pendingConfigurationCmd=?, "
|
||||
"restrictionDetails=?, "
|
||||
"pendingUUID=?"};
|
||||
"pendingUUID=?, "
|
||||
"simulated=?,"
|
||||
"lastRecordedContact=? "};
|
||||
|
||||
const static std::string DB_DeviceInsertValues{
|
||||
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
|
||||
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "};
|
||||
|
||||
typedef Poco::Tuple<std::string, std::string, std::string, std::string, std::string,
|
||||
std::string, std::string, std::string, std::string, std::string,
|
||||
std::string, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, std::string,
|
||||
std::string, std::string, std::string, uint64_t, std::string, bool,
|
||||
std::string, std::string, std::string, std::uint64_t>
|
||||
std::string, std::string, std::string, std::uint64_t, bool, std::uint64_t>
|
||||
DeviceRecordTuple;
|
||||
typedef std::vector<DeviceRecordTuple> DeviceRecordList;
|
||||
|
||||
@@ -121,6 +126,8 @@ namespace OpenWifi {
|
||||
D.restrictionDetails =
|
||||
RESTAPI_utils::to_object<OpenWifi::GWObjects::DeviceRestrictions>(R.get<25>());
|
||||
D.pendingUUID = R.get<26>();
|
||||
D.simulated = R.get<27>();
|
||||
D.lastRecordedContact = R.get<28>();
|
||||
}
|
||||
|
||||
void ConvertDeviceRecord(const GWObjects::Device &D, DeviceRecordTuple &R) {
|
||||
@@ -151,6 +158,8 @@ namespace OpenWifi {
|
||||
R.set<24>(D.pendingConfigurationCmd);
|
||||
R.set<25>(RESTAPI_utils::to_string(D.restrictionDetails));
|
||||
R.set<26>(D.pendingUUID);
|
||||
R.set<27>(D.simulated);
|
||||
R.set<28>(D.lastRecordedContact);
|
||||
}
|
||||
|
||||
bool Storage::GetDeviceCount(uint64_t &Count) {
|
||||
@@ -347,6 +356,23 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetDeviceLastRecordedContact(std::string &SerialNumber, std::uint64_t lastRecordedContact) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
std::string St{"UPDATE Devices SET lastRecordedContact=? WHERE SerialNumber=?"};
|
||||
|
||||
Update << ConvertParams(St), Poco::Data::Keywords::use(lastRecordedContact),
|
||||
Poco::Data::Keywords::use(SerialNumber);
|
||||
Update.execute();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CreateDevice(GWObjects::Device &DeviceDetails) {
|
||||
std::string SerialNumber;
|
||||
try {
|
||||
@@ -425,7 +451,8 @@ namespace OpenWifi {
|
||||
|
||||
bool Storage::CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
|
||||
std::string &Firmware,
|
||||
const Poco::Net::IPAddress &IPAddress) {
|
||||
const Poco::Net::IPAddress &IPAddress,
|
||||
bool simulated) {
|
||||
|
||||
GWObjects::Device D;
|
||||
poco_information(Logger(), fmt::format("AUTO-CREATION({})", SerialNumber));
|
||||
@@ -468,6 +495,7 @@ namespace OpenWifi {
|
||||
D.MACAddress = Utils::SerialToMAC(SerialNumber);
|
||||
D.Manufacturer = Caps.Model();
|
||||
D.Firmware = Firmware;
|
||||
D.simulated = simulated;
|
||||
D.Notes = SecurityObjects::NoteInfoVec{
|
||||
SecurityObjects::NoteInfo{(uint64_t)Utils::Now(), "", "Auto-provisioned."}};
|
||||
|
||||
@@ -540,17 +568,17 @@ namespace OpenWifi {
|
||||
|
||||
bool Storage::DeleteDevice(std::string &SerialNumber) {
|
||||
try {
|
||||
std::vector<std::string> DBList{"Devices", "Statistics", "CommandList",
|
||||
std::vector<std::string> TableNames{"Devices", "Statistics", "CommandList",
|
||||
"HealthChecks", "Capabilities", "DeviceLogs"};
|
||||
|
||||
for (const auto &i : DBList) {
|
||||
for (const auto &tableName : TableNames) {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St{"DELETE FROM " + i + " WHERE SerialNumber=?"};
|
||||
std::string St = fmt::format("DELETE FROM {} WHERE SerialNumber='{}'", tableName, SerialNumber);
|
||||
try {
|
||||
Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber);
|
||||
Delete << St;
|
||||
Delete.execute();
|
||||
} catch (...) {
|
||||
}
|
||||
@@ -564,7 +592,7 @@ namespace OpenWifi {
|
||||
Message.set("timestamp", Utils::Now());
|
||||
std::ostringstream StrPayload;
|
||||
Message.stringify(StrPayload);
|
||||
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, StrPayload.str());
|
||||
KafkaManager()->PostMessage(KafkaTopics::COMMAND, SerialNumber, std::make_shared<std::string>(StrPayload.str()));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -574,6 +602,58 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void DeleteDeviceList(std::vector<std::string> &SerialNumbers, Poco::Logger &Logger) {
|
||||
for (auto &serialNumber:SerialNumbers) {
|
||||
poco_information(Logger,fmt::format("BATCH-DEVICE_DELETE: deleting {}", serialNumber));
|
||||
StorageService()->DeleteDevice(serialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
bool Storage::DeleteDevices(std::string &SerialPattern, bool SimulatedOnly) {
|
||||
try {
|
||||
std::vector<std::string> SerialNumbers;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement GetSerialNumbers(Sess);
|
||||
|
||||
std::string SelectStatement = SimulatedOnly ?
|
||||
fmt::format("SELECT SerialNumber FROM Devices WHERE simulated and SerialNumber LIKE '{}' limit 10000",SerialPattern) :
|
||||
fmt::format("SELECT SerialNumber FROM Devices WHERE SerialNumber LIKE '{}' limit 10000", SerialPattern);
|
||||
|
||||
GetSerialNumbers << SelectStatement,
|
||||
Poco::Data::Keywords::into(SerialNumbers);
|
||||
GetSerialNumbers.execute();
|
||||
|
||||
poco_information(Logger(),fmt::format("BATCH-DEVICE_DELETE: Found {} devices that match the criteria {} to delete.", SerialNumbers.size(), SerialPattern));
|
||||
DeleteDeviceList(SerialNumbers, Logger());
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly) {
|
||||
try {
|
||||
std::vector<std::string> SerialNumbers;
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement GetSerialNumbers(Sess);
|
||||
|
||||
std::string SelectStatement = SimulatedOnly ?
|
||||
fmt::format("SELECT SerialNumber FROM Devices WHERE simulated and lastRecordedContact!=0 and lastRecordedContact<{} limit 10000",OlderContact) :
|
||||
fmt::format("SELECT SerialNumber FROM Devices lastRecordedContact>0 and lastRecordedContact<{} limit 10000",OlderContact);
|
||||
GetSerialNumbers << SelectStatement,
|
||||
Poco::Data::Keywords::into(SerialNumbers);
|
||||
GetSerialNumbers.execute();
|
||||
|
||||
poco_information(Logger(),fmt::format("BATCH-DEVICE_DELETE: Found {} devices that match with lastRecordedContact older than {} to delete.", SerialNumbers.size(), OlderContact));
|
||||
DeleteDeviceList(SerialNumbers, Logger());
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetDevice(std::string &SerialNumber, GWObjects::Device &DeviceDetails) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
@@ -746,6 +826,8 @@ namespace OpenWifi {
|
||||
return "serial mismatch";
|
||||
case GWObjects::VERIFIED:
|
||||
return "verified";
|
||||
case GWObjects::SIMULATED:
|
||||
return "simulated";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
@@ -87,7 +87,9 @@ namespace OpenWifi {
|
||||
"pendingConfiguration TEXT, "
|
||||
"pendingConfigurationCmd VARCHAR(64), "
|
||||
"restrictionDetails TEXT, "
|
||||
"pendingUUID BIGINT "
|
||||
"pendingUUID BIGINT, "
|
||||
"simulated BOOLEAN,"
|
||||
"lastRecordedContact BIGINT"
|
||||
",INDEX DeviceOwner (Owner ASC),"
|
||||
"INDEX LocationIndex (Location ASC))",
|
||||
Poco::Data::Keywords::now;
|
||||
@@ -119,7 +121,9 @@ namespace OpenWifi {
|
||||
"pendingConfiguration TEXT,"
|
||||
"pendingConfigurationCmd VARCHAR(64), "
|
||||
"restrictionDetails TEXT,"
|
||||
"pendingUUID BIGINT "
|
||||
"pendingUUID BIGINT, "
|
||||
"simulated BOOLEAN, "
|
||||
"lastRecordedContact BIGINT"
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
Sess << "CREATE INDEX IF NOT EXISTS DeviceOwner ON Devices (Owner ASC)",
|
||||
@@ -138,7 +142,10 @@ namespace OpenWifi {
|
||||
"alter table devices add column pendingConfiguration TEXT",
|
||||
"alter table devices add column pendingConfigurationCmd VARCHAR(64)",
|
||||
"alter table devices add column restrictionDetails TEXT",
|
||||
"alter table devices add column pendingUUID bigint"};
|
||||
"alter table devices add column pendingUUID bigint",
|
||||
"alter table devices add column lastRecordedContact bigint",
|
||||
"alter table devices add column simulated boolean"
|
||||
};
|
||||
|
||||
for (const auto &i : Script) {
|
||||
try {
|
||||
|
||||
@@ -175,6 +175,22 @@ listdevices() {
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletesimdevices() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?simulatedOnly=true&macPattern=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
deletebulkdevices() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWGW}/api/v1/devices?macPattern=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
listdevicesk() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/devices" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -842,6 +858,48 @@ regulatory_reload() {
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiussessions() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiussearch() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?userName=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiussearchmac() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?mac=$1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiusaps() {
|
||||
curl ${FLAGS} -X GET "https://${OWGW}/api/v1/radiusSessions/0?serialNumberOnly=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
radiuscoadm() {
|
||||
payload="$(printf '{ "accountingSessionId": "%s", "accountingMultiSessionId": "%s" , "callingStationId": "%s" }' "$2" "$3" "$4" )"
|
||||
curl ${FLAGS} -X PUT "https://${OWGW}/api/v1/radiusSessions/$1?operation=coadm" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-d "$payload" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
check_response() {
|
||||
|
||||
if [ -s "$1" ]; then
|
||||
@@ -1118,7 +1176,14 @@ case "$1" in
|
||||
"regulatory") login; regulatory "$2"; logout;;
|
||||
"regulatory_reload") login; regulatory_reload; logout;;
|
||||
"gethealthrange") login; gethealthrange "$2" "$3"; logout;;
|
||||
"radiussessions") login; radiussessions $2; logout;;
|
||||
"radiusaps") login; radiusaps ; logout;;
|
||||
"radiuscoadm") login; radiuscoadm "$2" "$3" "$4" "$5"; logout;;
|
||||
"radiussearch") login; radiussearch "$2"; logout;;
|
||||
"radiussearchmac") login; radiussearchmac "$2"; logout;;
|
||||
"deletesimdevices") login; deletesimdevices "$2"; logout;;
|
||||
"deletebulkdevices") login; deletebulkdevices "$2"; logout;;
|
||||
"testtoken") testtoken;;
|
||||
*) help ;;
|
||||
*) help ;;
|
||||
esac
|
||||
|
||||
|
||||
Reference in New Issue
Block a user