Compare commits

..

5 Commits

106 changed files with 3078 additions and 35799 deletions

2
.idea/ucentral.iml generated
View File

@@ -2,7 +2,7 @@
<module classpath="CMake" type="CPP_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python facet">
<configuration sdkName="Python 3.9 (wlan-cloud-ucentralgw)" />
<configuration sdkName="Python 3.9 (venv)" />
</facet>
</component>
</module>

1
.idea/vcs.xml generated
View File

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

View File

@@ -24,7 +24,7 @@ sudo apt install librdkafka-dev // default-libmysqlclient-dev
sudo apt install nlohmann-json-dev
cd ~
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
cd poco
mkdir cmake-build
cd cmake-build
@@ -75,7 +75,7 @@ sudo yum install yaml-cpp-devel lua-devel
sudo dnf install postgresql.x86_64 librdkafka-devel
sudo dnf install postgresql-devel json-devel
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
cd poco
mkdir cmake-build
cd cmake-build
@@ -125,7 +125,7 @@ brew install openssl \
nlohmann-json \
fmt
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
pushd poco
mkdir cmake-build
push cmake-build

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 3.0.0)
project(owgw VERSION 2.9.0)
set(CMAKE_CXX_STANDARD 17)
@@ -49,7 +49,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1" -DBOOST_NO_CXX98_FUNCTION_BASE=1)
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
@@ -144,14 +144,9 @@ 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
@@ -199,19 +194,8 @@ add_executable( owgw
src/AP_WS_Process_deviceupdate.cpp
src/AP_WS_Process_telemetry.cpp
src/AP_WS_Process_venuebroadcast.cpp
src/RADIUS_Destination.h
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h
src/framework/RESTAPI_SystemConfiguration.h
src/ScriptManager.cpp src/ScriptManager.h
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 src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h)
src/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)
if(NOT SMALL_BUILD)
@@ -223,17 +207,14 @@ INSTALL(TARGETS owgw
target_link_libraries(owgw PUBLIC
${Poco_LIBRARIES}
${ZLIB_LIBRARIES}
)
${ZLIB_LIBRARIES})
if(NOT SMALL_BUILD)
target_link_libraries(owgw PUBLIC
${MySQL_LIBRARIES}
${ZLIB_LIBRARIES}
CppKafka::cppkafka
fmt::fmt
resolv
)
${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
CppKafka::cppkafka
fmt::fmt
)
if(UNIX AND NOT APPLE)
target_link_libraries(owgw PUBLIC PocoJSON)
endif()

View File

@@ -2,8 +2,6 @@ ARG DEBIAN_VERSION=11.5-slim
ARG POCO_VERSION=poco-tip-v2
ARG CPPKAFKA_VERSION=tip-v1
ARG VALIJASON_VERSION=tip-v1
ARG APP_NAME=owgw
ARG APP_HOME_DIR=/openwifi
FROM debian:$DEBIAN_VERSION AS build-base
@@ -55,14 +53,12 @@ RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS app-build
FROM build-base AS owgw-build
ARG APP_NAME
ADD CMakeLists.txt build /${APP_NAME}/
ADD cmake /${APP_NAME}/cmake
ADD src /${APP_NAME}/src
ADD .git /${APP_NAME}/.git
ADD CMakeLists.txt build /owgw/
ADD cmake /owgw/cmake
ADD src /owgw/src
ADD .git /owgw/.git
COPY --from=poco-build /usr/local/include /usr/local/include
COPY --from=poco-build /usr/local/lib /usr/local/lib
@@ -70,33 +66,23 @@ COPY --from=cppkafka-build /usr/local/include /usr/local/include
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=valijson-build /usr/local/include /usr/local/include
WORKDIR /${APP_NAME}
WORKDIR /owgw
RUN mkdir cmake-build
WORKDIR /${APP_NAME}/cmake-build
WORKDIR /owgw/cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
FROM debian:$DEBIAN_VERSION
ARG APP_NAME
ARG APP_HOME_DIR
ENV OWGW_USER=owgw \
OWGW_ROOT=/owgw-data \
OWGW_CONFIG=/owgw-data
ENV APP_NAME=$APP_NAME \
APP_USER=$APP_NAME \
APP_ROOT=/$APP_NAME-data \
APP_CONFIG=/$APP_NAME-data \
APP_HOME_DIR=$APP_HOME_DIR
RUN useradd "$OWGW_USER"
# This is for legacy
ENV OWGW_USER=$APP_USER \
OWGW_ROOT=$APP_ROOT \
OWGW_CONFIG=$APP_CONFIG
RUN useradd $APP_USER
RUN mkdir $APP_HOME_DIR
RUN mkdir -p $APP_ROOT $APP_CONFIG && \
chown $APP_USER: $APP_ROOT $APP_CONFIG
RUN mkdir /openwifi
RUN mkdir -p "$OWGW_ROOT" "$OWGW_CONFIG" && \
chown "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
RUN apt-get update && apt-get install --no-install-recommends -y \
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
@@ -105,14 +91,14 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
COPY $APP_NAME.properties.tmpl /
COPY owgw.properties.tmpl /
COPY docker-entrypoint.sh /
COPY wait-for-postgres.sh /
COPY rtty_ui /dist/rtty_ui
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
COPY --from=app-build /$APP_NAME/cmake-build/$APP_NAME $APP_HOME_DIR/$APP_NAME
COPY --from=owgw-build /owgw/cmake-build/owgw /openwifi/owgw
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib /usr/local/lib/
COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib/
@@ -121,4 +107,4 @@ RUN ldconfig
EXPOSE 15002 16002 16003 17002 16102
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ${APP_HOME_DIR}/${APP_NAME}
CMD ["/openwifi/owgw"]

View File

@@ -149,35 +149,18 @@ 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` during rebooting after a crash. The event cannot be sent until a connection event has been established.
Device may send a crash log event after rebooting after a crash. The event cannot be sent until a connection event has been sent.
```json
{ "jsonrpc" : "2.0" ,
"method" : "crashlog" ,
"params" : {
"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
@@ -775,146 +758,6 @@ The device should answer:
}
```
#### Controller wants the device to replace its certificates
Controller sends this command to run a predefined script. Extreme care must be taken.
```json
{ "jsonrpc" : "2.0" ,
"method" : "certupdate" ,
"params" : {
"serial" : <serial number>,
"certificates" : <BASE64 encoded tar file of the cert package from the certificate portal>
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
"txt" : <text describing the error or success>
},
"id" : <same number as request>
}
```
#### Controller wants the device to switch to another controller
Controller sends this when the device should change the controller it connects to without looking up a new redirector.
```json
{ "jsonrpc" : "2.0" ,
"method" : "transfer" ,
"params" : {
"serial" : <serial number>,
"server" : <controller hostname>,
"port" : <controller port number (integer)>,
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
"txt" : <text describing the error or success>
},
"id" : <same number as request>
}
```
### RRM AP device commands
The following command is used to send RRM commands to an AP. RRM commands are send to an AP, however the
controller will not or cannot verify if they have been sent or the action was performed.
```json
{ "jsonrpc" : "2.0" ,
"method" : "rrm" ,
"params" : {
"serial" : <serial number>,
"actions" : [ array of actions. Each possible action is defined next]
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
"txt" : <text describing the error or success>
},
"id" : <same number as request>
}
```
#### RRM Roam action
##### Kick
```json
{
"action" : "kick" ,
"addr" : <mac if the client that shall be kicked> ,
"reason": <number>, (default: 5, https://www.cisco.com/assets/sol/sb/WAP371_Emulators/WAP371_Emulator_v1-0-1-5/help/Apx_ReasonCodes2.html)
"ban_time": <number> (seconds, optional)
}
```
##### Channel Switch Announcement
```json
{
"action" : "channel_switch" ,
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
"channel" : <number> (HT/HW mode will be retained upon issuing the CSA)
}
```
##### Change TX-Power
```json
{
"action" : "tx_power" ,
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
"level" : <number> (DBm inside the positive number space)
}
```
##### Beacon Scan
```json
{
"action" : "beacon_request" ,
"addr" : <mac if the client that shall perform the scan> ,
"ssid": <string>, (the SSID the client shall scan for on all frequencies),
"channel": <number> (the channel that shall be scanned)
}
```
##### BSS Transition
```json
{
"action" : "bss_transition" ,
"addr" : <mac if the client that shall perform the roam> ,
"neighbors": [ <string> ], (an array of BSSIDs the client shall consider as roamin candidates)
}
```
##### Update neighbours
```json
{
"action" : "neighbors" ,
"bssid" : <mac of the SSID> , (the SSID of the specific VAP)
"neighbors": [ [ <BSS>, <ssid>, <neighbor report> ] ]
}
```
### `rtty server`
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.

2
build
View File

@@ -1 +1 @@
10
105

View File

@@ -6,35 +6,35 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
fi
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\${APP_ROOT}/certs/root.pem"} \
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\${APP_ROOT}/certs/issuer.pem"} \
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\${APP_ROOT}/certs/websocket-cert.pem"} \
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\${APP_ROOT}/certs/websocket-key.pem"} \
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\${APP_ROOT}/certs/clientcas.pem"} \
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\${APP_ROOT}/certs/cas"} \
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\$OWGW_ROOT/certs/websocket-key.pem"} \
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\$OWGW_ROOT/certs/clientcas.pem"} \
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\$OWGW_ROOT/certs/cas"} \
WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
FILEUPLOADER_HOST_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\${APP_ROOT}/uploads"} \
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\$OWGW_ROOT/uploads"} \
FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
SERVICE_KEY=${SERVICE_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
SERVICE_KEY=${SERVICE_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
SYSTEM_DATA=${SYSTEM_DATA:-"\${APP_ROOT}/data"} \
SYSTEM_DATA=${SYSTEM_DATA:-"\$OWGW_ROOT/data"} \
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
@@ -51,7 +51,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
RTTY_TOKEN=${RTTY_TOKEN:-""} \
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
RTTY_ASSETS=${RTTY_ASSETS:-"\${APP_ROOT}/rtty_ui"} \
RTTY_ASSETS=${RTTY_ASSETS:-"\$OWGW_ROOT/rtty_ui"} \
RADIUS_PROXY_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \
@@ -64,41 +64,39 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \
STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"${APP_USER}"} \
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"${APP_USER}"} \
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"${APP_NAME}"} \
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"${APP_USER}"} \
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"${APP_USER}"} \
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"${APP_NAME}"} \
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owgw"} \
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
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 < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
fi
# Check if rtty_ui directory exists
export RTTY_ASSETS=$(grep 'rtty.assets' "${APP_CONFIG}"/"${APP_NAME}".properties | awk -F '=' '{print $2}' | xargs | envsubst)
export RTTY_ASSETS=$(grep 'rtty.assets' $OWGW_CONFIG/owgw.properties | awk -F '=' '{print $2}' | xargs | envsubst)
if [ -z "$RTTY_ASSETS" ]; then
export RTTY_ASSETS="${APP_ROOT}/rtty_ui"
export RTTY_ASSETS="$OWGW_ROOT/rtty_ui"
fi
if [[ ! -d "$(dirname $RTTY_ASSETS)" ]]; then
mkdir -p "$(dirname $RTTY_ASSETS)"
mkdir -p $(dirname $RTTY_ASSETS)
fi
if [[ ! -d "$RTTY_ASSETS" ]]; then
cp -r /dist/rtty_ui $RTTY_ASSETS
fi
if [ "$1" = "${APP_HOME_DIR}/${APP_NAME}" -a "$(id -u)" = '0' ]; then
if [ "$1" = '/openwifi/owgw' -a "$(id -u)" = '0' ]; then
if [ "$RUN_CHOWN" = 'true' ]; then
chown -R "$APP_USER": "${APP_ROOT}" "$APP_CONFIG"
chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
fi
exec gosu "$APP_USER" "$@"
exec gosu "$OWGW_USER" "$@"
fi
exec "$@"

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ openapi: 3.0.1
info:
title: uCentral gateway API
description: A process to manage configuration for devices.
version: 2.11.0
version: 2.5.0
license:
name: BSD3
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
@@ -152,11 +152,6 @@ components:
format: uuid
restrictionDetails:
$ref: '#/components/schemas/DeviceRestrictions'
simulated:
type: boolean
lastRecordedContact:
type: integer
format: int64
DeviceWithStatus:
type: object
@@ -265,22 +260,6 @@ 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
@@ -350,9 +329,6 @@ components:
associations_5G:
type: integer
format: int64
associations_6G:
type: integer
format: int64
verifiedCertificate:
type: string
enum:
@@ -360,7 +336,6 @@ components:
- VALID_CERTIFICATE,
- MISMATCH_SERIAL,
- VERIFIED
- SIMULATED
DeviceCapabilities:
type: object
@@ -445,7 +420,7 @@ components:
type: string
CommandSubmitSuccess:
description: The command was submitted successfully.
description: The command was submitted succesfully.
properties:
serialNumber:
type: string
@@ -483,10 +458,6 @@ components:
logType:
type: integer
format: int64
example:
- 0 normal logs
- 1 crash logs
- 2 reboot logs
UUID:
type: integer
format: int64
@@ -553,35 +524,6 @@ components:
items:
$ref : '#/components/schemas/DefaultConfiguration'
DefaultFirmware:
type: object
properties:
deviceType:
type: string
description:
type: string
uri:
type: string
revision:
type: string
imageCreationDate:
type: integer
format: int64
created:
type: integer
format: int64
lastModified:
type: integer
format: int64
DefaultFirmwareList:
type: object
properties:
firmwares:
type: array
items:
$ref: '#/components/schemas/DefaultFirmware'
UpgradeRequest:
type: object
properties:
@@ -903,114 +845,6 @@ components:
kafkaClients:
type: integer
RRM_Kick:
type: object
properties:
action:
type: string
enum:
- kick
addr:
type: string
format: mac
reason:
type: integer
default: 5
ban_time:
type: integer
format: int64
RRM_channel_switch:
type: object
properties:
action:
type: string
enum:
- channel_switch
bssid:
type: string
format: mac
channel:
type: integer
RRM_tx_power:
type: object
properties:
action:
type: string
enum:
- tx_power
bssid:
type: string
format: mac
level:
type: integer
RRM_beacon_request:
type: object
properties:
action:
type: string
enum:
- beacon_request
addr:
type: string
format: mac
ssid:
type: string
channel:
type: integer
RRM_bss_transition:
type: object
properties:
action:
type: string
enum:
- bss_transition
addr:
type: string
format: mac
neighbors:
type: array
items:
type: string
format: mac
RRM_neighbors:
type: object
properties:
action:
type: string
enum:
- neighbors
bssid:
type: string
format: mac
neighbors:
type: array
items:
type: string
format: mac
RRM_action:
type: object
oneOf:
- $ref: '#/components/schemas/RRM_Kick'
- $ref: '#/components/schemas/RRM_channel_switch'
- $ref: '#/components/schemas/RRM_tx_power'
- $ref: '#/components/schemas/RRM_beacon_request'
- $ref: '#/components/schemas/RRM_bss_transition'
- $ref: '#/components/schemas/RRM_neighbors'
RRM_actions:
type: object
properties:
actions:
type: array
items:
$ref: '#/components/schemas/RRM_action'
#########################################################################################
##
## These are endpoints that all services in the uCentral stack must provide
@@ -1079,6 +913,12 @@ components:
- $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList'
SystemCommandResults:
type: object
oneOf:
- $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList'
NoteInfo:
type: object
properties:
@@ -1118,33 +958,6 @@ components:
type: integer
format: int64
SystemResources:
type: object
properties:
numberOfFileDescriptors:
type: integer
format: int64
currRealMem:
type: integer
format: int64
peakRealMem:
type: integer
format: int64
currVirtMem:
type: integer
format: int64
peakVirtMem:
type: integer
format: int64
SystemCommandResults:
type: object
oneOf:
- $ref: '#/components/schemas/SystemResources'
- $ref: '#/components/schemas/SystemInfoResults'
- $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList'
SystemCommandSetLogLevel:
type: object
properties:
@@ -1447,30 +1260,6 @@ components:
$ref: '#/components/schemas/RadiusProxyServerConfig'
coaConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig'
radsecPoolType:
type: string
enum:
- generic
- orion
- globalreach
- radsec
default:
generic
poolProxyIp:
type: string
description: This is the fake IP for the entire pool
example:
- These addresses must match the addresses in the AP configuration and must start with 0.0
- 0.0.0.1
- 0.0.1.1
radsecPoolKeepAlive:
type: integer
description: The keep alive value in seconds. Usually 30s or less.
format: int64
default: 25
enabled:
type: boolean
default: true
RadiusProxyPoolList:
type: object
@@ -1480,92 +1269,6 @@ 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
userName:
type: string
DeviceTransferRequest:
type: object
properties:
serialNumber:
type: string
format: uuid
server:
type: string
format: hostname
port:
type: integer
format: int32
DeviceCertificateUpdateRequest:
type: object
properties:
serialNumber:
type: string
encodedCertificate:
type: string
format: base64
description: This is a base64 encoded string of the certificate bundle (the current bundle .tar.gz file from the PKI portal)
paths:
/devices:
get:
@@ -1674,58 +1377,6 @@ 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
- in: query
description: Filter the results
name: simulatedDevices
schema:
type: boolean
required: false
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/commands:
get:
tags:
@@ -1982,123 +1633,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/default_firmwares:
get:
tags:
- Firmware
summary: Retrieve the lists of all default firmwares.
description: Retrieve the lists of all default firmwares.
operationId: getDefaultFirmwares
responses:
200:
description: List of default firmwares
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmwareList'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/default_firmware/{deviceType}:
get:
tags:
- Firmware
summary: Retrieve a default firmware.
description: Retrieve a default firmware.
operationId: getDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
responses:
200:
description: Default firmware included
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmware'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
post:
tags:
- Firmware
summary: Create a default firmware.
description: Create a default firmware.
operationId: createDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
requestBody:
description: Information used to create the new firmware entry
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmware'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- Firmware
summary: Delete a default default firmware
description: Delete a default default firmware
operationId: deleteDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
responses:
204:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- Firmware
summary: Update a default firmware
description: Update a default firmware
operationId: updateDefaultFirmware
parameters:
- in: path
name: deviceType
schema:
type: string
required: true
requestBody:
description: Firmware details
content:
application/json:
schema:
$ref: '#/components/schemas/DefaultFirmware'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}:
get:
tags:
@@ -2241,7 +1775,7 @@ paths:
format: int64
- in: query
name: logType
description: 0=any kind of logs (default) 0=normal logs, 1=crash logs, 2=reboot logs only
description: 0=any kind of logs (default) 0=normal logs only 1=crash logs only
schema:
type: integer
format: int64
@@ -2579,6 +2113,32 @@ 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:
@@ -2710,7 +2270,7 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/script:
/device/{serialNumber}/:
post:
tags:
- Commands
@@ -2924,88 +2484,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/rrm:
post:
tags:
- Commands
summary: Send RRM commands to a device.
operationId: sendRRMcommandsForADevice
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Commands to send
content:
application/json:
schema:
$ref: '#/components/schemas/RRM_actions'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/transfer:
post:
tags:
- Commands
summary: Transfer a device to a new redirector.
operationId: transferDevice
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Transfer details
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DeviceTransferRequest'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/certupdate:
post:
tags:
- Commands
summary: Update the certificates for a device.
operationId: updateCertificates
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Certificate update details
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/DeviceCertificateUpdateRequest'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/ouis:
get:
tags:
@@ -3245,6 +2723,9 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/blacklist:
get:
tags:
@@ -3437,81 +2918,6 @@ 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
- disconnectUser
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:
@@ -3608,12 +3014,16 @@ paths:
type: string
enum:
- info
- extraConfiguration
- resources
required: true
responses:
200:
$ref: '#/components/schemas/SystemCommandResults'
description: Successful command execution
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/SystemInfoResults'
403:
$ref: '#/components/responses/Unauthorized'
404:

View File

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

View File

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

View File

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

View File

@@ -31,7 +31,6 @@
#include "framework/ow_constants.h"
#include "RADIUSSessionTracker.h"
#include "RADIUS_proxy_server.h"
namespace OpenWifi {
@@ -73,7 +72,6 @@ namespace OpenWifi {
*this, &AP_WS_Connection::OnSocketError));
Registered_ = true;
Valid_ = true;
uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
}
bool AP_WS_Connection::ValidatedDevice() {
@@ -128,7 +126,7 @@ namespace OpenWifi {
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
poco_trace(Logger_,
poco_information(Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_,
State_.sessionId, CN_));
@@ -140,15 +138,10 @@ namespace OpenWifi {
return false;
}
if(AP_WS_Server::IsSim(CN_)) {
State_.VerifiedCertificate = GWObjects::SIMULATED;
Simulated_ = true;
}
std::string reason, author;
std::uint64_t created;
if (!CN_.empty() && StorageService()->IsBlackListed(CN_, reason, author, created)) {
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
DeviceBlacklistedKafkaEvent KE(CN_, Utils::Now(), reason, author, created, CId_);
poco_warning(
Logger_,
fmt::format(
@@ -224,15 +217,17 @@ namespace OpenWifi {
return false;
}
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
static void NotifyKafkaDisconnect(const std::string &SerialNumber) {
try {
Poco::JSON::Object Disconnect;
Poco::JSON::Object Details;
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
Details.set(uCentralProtocol::UUID,uuid);
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(Disconnect, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
} catch (...) {
}
}
@@ -242,21 +237,10 @@ namespace OpenWifi {
EndConnection();
}
void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) {
if (KafkaManager()->Enabled()) {
NotifyKafkaDisconnect(SerialNumber, uuid);
}
RADIUSSessionTracker()->DeviceDisconnect(SerialNumber);
}
void AP_WS_Connection::EndConnection(bool DeleteSession) {
Valid_ = false;
void AP_WS_Connection::EndConnection() {
Valid_ = false;
if (!Dead_.test_and_set()) {
if(!SerialNumber_.empty() && State_.LastContact!=0) {
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
}
if (Registered_) {
Registered_ = false;
Reactor_.removeEventHandler(
@@ -271,16 +255,14 @@ namespace OpenWifi {
}
WS_->close();
if(!SerialNumber_.empty()) {
std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_, uuid_);
Cleanup.detach();
if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
std::string s(SerialNumber_);
std::thread t([s]() { NotifyKafkaDisconnect(s); });
t.detach();
}
bool SessionDeleted = false;
if(DeleteSession)
SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
if (SessionDeleted || !DeleteSession) {
auto SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
if (SessionDeleted) {
GWWebSocketNotifications::SingleDevice_t N;
N.content.serialNumber = SerialNumber_;
GWWebSocketNotifications::DeviceDisconnected(N);
@@ -448,7 +430,7 @@ namespace OpenWifi {
std::string reason, author;
std::uint64_t created;
if (StorageService()->IsBlackListed(Serial, reason, author, created)) {
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
DeviceBlacklistedKafkaEvent KE(CN_, Utils::Now(), reason, author, created, CId_);
Poco::Exception E(
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
Serial),
@@ -513,10 +495,6 @@ 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: {
@@ -720,11 +698,12 @@ namespace OpenWifi {
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
PingDetails.set(uCentralProtocol::UUID, uuid_);
PingDetails.set("locale", State_.locale);
PingObject.set(uCentralProtocol::PING, PingDetails);
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(PingObject, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
}
return;
} break;

View File

@@ -4,11 +4,10 @@
#pragma once
#include <mutex>
#include <shared_mutex>
#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"
@@ -28,7 +27,7 @@ namespace OpenWifi {
Poco::Logger &L, Poco::Net::SocketReactor &R);
~AP_WS_Connection();
void EndConnection(bool DeleteSession=true);
void EndConnection();
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
void ProcessIncomingFrame();
@@ -58,62 +57,33 @@ namespace OpenWifi {
bool StopWebSocketTelemetry(uint64_t RPCID);
bool StopKafkaTelemetry(uint64_t RPCID);
inline void GetLastStats(std::string &LastStats) {
std::lock_guard G(ConnectionMutex_);
inline void GetLastStats(std::string &LastStats) const {
std::shared_lock G(ConnectionMutex_);
LastStats = RawLastStats_;
}
inline void SetLastStats(const std::string &LastStats) {
std::lock_guard G(ConnectionMutex_);
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) {
std::lock_guard G(ConnectionMutex_);
std::unique_lock G(ConnectionMutex_);
RawLastHealthcheck_ = H;
}
inline void GetLastHealthCheck(GWObjects::HealthCheck &H) {
std::lock_guard G(ConnectionMutex_);
std::shared_lock G(ConnectionMutex_);
H = RawLastHealthcheck_;
}
inline void GetState(GWObjects::ConnectionState &State) const {
std::lock_guard G(ConnectionMutex_);
std::shared_lock G(ConnectionMutex_);
State = State_;
}
inline bool HasGPS() { return hasGPS; }
inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
std::lock_guard G(ConnectionMutex_);
std::shared_lock G(ConnectionMutex_);
R = Restrictions_;
}
@@ -131,7 +101,6 @@ 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();
@@ -154,15 +123,15 @@ namespace OpenWifi {
friend class AP_WS_Server;
inline GWObjects::DeviceRestrictions Restrictions() const {
std::lock_guard G(ConnectionMutex_);
std::shared_lock G(ConnectionMutex_);
return Restrictions_;
}
inline bool MustBeSecureRtty() const { return RttyMustBeSecure_; }
private:
mutable std::mutex ConnectionMutex_;
std::mutex TelemetryMutex_;
mutable std::shared_mutex ConnectionMutex_;
std::shared_mutex TelemetryMutex_;
Poco::Logger &Logger_;
Poco::Net::SocketReactor &Reactor_;
std::unique_ptr<Poco::Net::WebSocket> WS_;
@@ -199,10 +168,6 @@ 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;
std::uint64_t uuid_=0;
bool Simulated_=false;
};
} // namespace OpenWifi

View File

@@ -21,7 +21,11 @@ namespace OpenWifi {
if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
if (KafkaManager()->Enabled()) {
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, *ParamsObj);
auto Data = ParamsObj->get(uCentralProtocol::DATA);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, OS.str());
}
}
}

View File

@@ -14,8 +14,6 @@
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "firmware_revision_cache.h"
#include "UI_GW_WebSocketNotifications.h"
#include <GWKafkaEvents.h>
@@ -32,7 +30,9 @@ namespace OpenWifi {
Event.set("type", "device.firmware_change");
Event.set("timestamp", Utils::Now());
Event.set("payload", EventDetails);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, Event);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, OS.str());
}
}
@@ -49,7 +49,9 @@ namespace OpenWifi {
Event.set("type", "device.not_provisioned");
Event.set("timestamp", Utils::Now());
Event.set("payload", EventDetails);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, Event);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, OS.str());
}
}
@@ -61,11 +63,6 @@ namespace OpenWifi {
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
auto Capabilities = ParamsObj->getObject(uCentralProtocol::CAPABILITIES);
std::string DevicePassword;
if(ParamsObj->has("password")) {
DevicePassword = ParamsObj->get("password").toString();
}
SerialNumber_ = Serial;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
@@ -84,10 +81,6 @@ 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);
@@ -112,55 +105,7 @@ namespace OpenWifi {
GWObjects::Device DeviceInfo;
auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
if (Daemon()->AutoProvisioning() && !DeviceExists) {
// check the firmware version. if this is too old, we cannot let that device connect yet, we must
// force a firmware upgrade
GWObjects::DefaultFirmware MinimumFirmware;
if(FirmwareRevisionCache()->DeviceMustUpgrade(Compatible_, Firmware, MinimumFirmware)) {
/*
{ "jsonrpc" : "2.0" ,
"method" : "upgrade" ,
"params" : {
"serial" : <serial number> ,
"when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
"uri" : <URI to download the firmware>,
"FWsignature" : <string representation of the signature for the FW> (optional)
},
"id" : <some number>
}
*/
Poco::JSON::Object UpgradeCommand, Params;
UpgradeCommand.set(uCentralProtocol::JSONRPC,uCentralProtocol::JSONRPC_VERSION);
UpgradeCommand.set(uCentralProtocol::METHOD,uCentralProtocol::UPGRADE);
Params.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
Params.set(uCentralProtocol::WHEN, 0);
Params.set(uCentralProtocol::URI, MinimumFirmware.uri);
Params.set(uCentralProtocol::KEEP_REDIRECTOR,1);
UpgradeCommand.set(uCentralProtocol::PARAMS, Params);
UpgradeCommand.set(uCentralProtocol::ID, 1);
std::ostringstream Command;
UpgradeCommand.stringify(Command);
if(Send(Command.str())) {
poco_information(
Logger(),
fmt::format(
"Forcing device {} to upgrade to {} before connection is allowed.",
SerialNumber_, MinimumFirmware.revision));
} else {
poco_error(
Logger(),
fmt::format(
"Could not force device {} to upgrade to {} before connection is allowed.",
SerialNumber_, MinimumFirmware.revision));
}
return;
} else {
StorageService()->CreateDefaultDevice(
SerialNumber_, Caps, Firmware, PeerAddress_,
State_.VerifiedCertificate == GWObjects::SIMULATED);
}
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_);
} 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_));
@@ -170,7 +115,7 @@ namespace OpenWifi {
int Updated{0};
if (!Firmware.empty()) {
if (Firmware != DeviceInfo.Firmware) {
DeviceFirmwareChangeKafkaEvent KEvent(SerialNumberInt_, Utils::Now(),
DeviceFirmwareChangeKafkaEvent KEvent(SerialNumber_, Utils::Now(),
DeviceInfo.Firmware, Firmware);
DeviceInfo.Firmware = Firmware;
DeviceInfo.LastFWUpdate = Utils::Now();
@@ -186,32 +131,6 @@ namespace OpenWifi {
}
}
if(ParamsObj->has("reason")) {
State_.connectReason = ParamsObj->get("reason").toString();
DeviceInfo.connectReason = State_.connectReason;
++Updated;
}
if(DeviceInfo.DevicePassword!=DevicePassword) {
DeviceInfo.DevicePassword = DevicePassword.empty() ? "openwifi" : DevicePassword ;
++Updated;
}
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;
@@ -232,20 +151,13 @@ namespace OpenWifi {
++Updated;
}
if(DeviceInfo.certificateExpiryDate!=State_.certificateExpiryDate) {
DeviceInfo.certificateExpiryDate = State_.certificateExpiryDate;
++Updated;
}
if (Updated) {
StorageService()->UpdateDevice(DeviceInfo);
}
if(!Simulated_) {
uint64_t UpgradedUUID = 0;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
}
uint64_t UpgradedUUID = 0;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
}
State_.Compatible = Compatible_;
@@ -281,12 +193,6 @@ 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;
@@ -294,11 +200,14 @@ namespace OpenWifi {
GWWebSocketNotifications::DeviceConnected(Notification);
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
ParamsObj->set("locale", State_.locale);
ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
ParamsObj->set(uCentralProtocol::UUID, uuid_);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, *ParamsObj);
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
}
} else {
poco_warning(

View File

@@ -7,12 +7,10 @@
#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;
@@ -26,11 +24,11 @@ namespace OpenWifi {
.Log = LogText,
.Data = "",
.Severity = GWObjects::DeviceLog::LOG_EMERG,
.Recorded = Utils::Now(),
.Recorded = (uint64_t)time(nullptr),
.LogType = 1,
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
.UUID = 0};
StorageService()->AddLog(DeviceLog);
DeviceLogKafkaEvent E(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
return;

View File

@@ -24,7 +24,7 @@ namespace OpenWifi {
StorageService()->SetDevicePassword(Serial, Password);
poco_trace(
Logger_,
fmt::format("DEVICE-UPDATE({}): Device is updating its login password.", Serial));
fmt::format("DEVICEUPDATE({}): Device is updating its login password.", Serial));
}
}

View File

@@ -34,13 +34,11 @@ namespace OpenWifi {
FullEvent.set("type", EventType);
FullEvent.set("timestamp", EventTimeStamp);
FullEvent.set("payload", EventPayload);
if(strncmp(EventType.c_str(),"rrm.",4) == 0 ) {
KafkaManager()->PostMessage(KafkaTopics::RRM, SerialNumber_,
FullEvent);
} else {
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
FullEvent);
}
std::ostringstream OS;
FullEvent.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
OS.str());
}
}
} catch (const Poco::Exception &E) {

View File

@@ -19,10 +19,8 @@ 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();
@@ -40,6 +38,10 @@ namespace OpenWifi {
CId_, UUID, request_uuid));
}
uint64_t UpgradedUUID;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
GWObjects::HealthCheck Check;
Check.SerialNumber = SerialNumber_;
@@ -56,7 +58,11 @@ namespace OpenWifi {
SetLastHealthCheck(Check);
if (KafkaManager()->Enabled()) {
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, *ParamsObj);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
ParamsObj->set("timestamp", Utils::Now());
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
}
} else {
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));

View File

@@ -7,7 +7,6 @@
#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) {
@@ -37,7 +36,6 @@ namespace OpenWifi {
.LogType = 0,
.UUID = State_.UUID};
StorageService()->AddLog(DeviceLog);
DeviceLogKafkaEvent E(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
return;

View File

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

View File

@@ -39,11 +39,9 @@ namespace OpenWifi {
UUID, request_uuid));
}
if(!Simulated_) {
uint64_t UpgradedUUID;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
}
uint64_t UpgradedUUID;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
SetLastStats(StateStr);
GWObjects::Statistics Stats{
@@ -58,7 +56,10 @@ namespace OpenWifi {
State_.Associations_5G, State_.Associations_6G);
if (KafkaManager()->Enabled()) {
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, *ParamsObj);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
}
GWWebSocketNotifications::SingleDevice_t N;

View File

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

View File

@@ -21,7 +21,11 @@ namespace OpenWifi {
if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
if (KafkaManager()->Enabled()) {
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, *ParamsObj);
auto Data = ParamsObj->get(uCentralProtocol::DATA);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, OS.str());
}
}
}

View File

@@ -4,7 +4,7 @@
#pragma once
#include <mutex>
#include <shared_mutex>
#include <string>
#include "Poco/Environment.h"
@@ -16,7 +16,7 @@ namespace OpenWifi {
class AP_WS_ReactorThreadPool {
public:
explicit AP_WS_ReactorThreadPool() {
NumberOfThreads_ = Poco::Environment::processorCount() * 4;
NumberOfThreads_ = Poco::Environment::processorCount() * 2;
if (NumberOfThreads_ == 0)
NumberOfThreads_ = 4;
}
@@ -46,14 +46,14 @@ namespace OpenWifi {
}
Poco::Net::SocketReactor &NextReactor() {
std::lock_guard Lock(Mutex_);
std::shared_lock Lock(Mutex_);
NextReactor_++;
NextReactor_ %= NumberOfThreads_;
return *Reactors_[NextReactor_];
}
private:
std::mutex Mutex_;
std::shared_mutex Mutex_;
uint64_t NumberOfThreads_;
uint64_t NextReactor_ = 0;
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;

View File

@@ -19,7 +19,6 @@
#include "fmt/format.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
#include <framework/KafkaManager.h>
namespace OpenWifi {
@@ -55,8 +54,6 @@ 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();
@@ -107,6 +104,7 @@ namespace OpenWifi {
Context->flushSessionCache();
Context->enableSessionCache(true);
Context->enableExtendedCertificateVerification(false);
// Context->disableStatelessSessionResumption();
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 |
Poco::Net::Context::PROTO_TLSV1_1);
@@ -163,7 +161,7 @@ namespace OpenWifi {
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(
*this, &AP_WS_Server::onGarbageCollecting);
Timer_.setStartInterval(10 * 1000);
Timer_.setPeriodicInterval(10 * 1000); // every minute
Timer_.setPeriodicInterval(5 * 1000); // every minute
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
Running_ = true;
@@ -171,80 +169,41 @@ namespace OpenWifi {
}
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
static uint64_t last_log = Utils::Now(), last_zombie_run = 0;
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();
{
{
std::lock_guard SessionLock(SessionMutex_);
if (!Garbage_.empty()) {
Garbage_.clear();
}
for (const auto &connection : SerialNumbers_) {
if (connection.second.second == nullptr) {
continue;
}
uint64_t total_connected_time = 0;
if(now-last_zombie_run > 20) {
poco_information(Logger(), fmt::format("Garbage collecting..."));
std::vector<std::uint64_t> SessionsToRemove;
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
last_zombie_run = now;
for(int hashIndex=0;hashIndex<256;hashIndex++) {
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto hint = SerialNumbers_[hashIndex].begin();
while (hint != end(SerialNumbers_[hashIndex])) {
if (hint->second.second == nullptr) {
hint = SerialNumbers_[hashIndex].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_));
SessionsToRemove.emplace_back(hint->second.first);
Garbage_.push_back(hint->second.second);
hint = SerialNumbers_[hashIndex].erase(hint);
} else if (hint->second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - hint->second.second->State_.started);
hint++;
} else {
NumberOfConnectingDevices_++;
hint++;
}
}
}
if(SessionsToRemove.empty()) {
poco_information(Logger(), fmt::format("Removing {} sessions.", SessionsToRemove.size()));
std::lock_guard Lock(SessionMutex_);
for (const auto &Session : SessionsToRemove) {
Sessions_.erase(Session);
}
}
AverageDeviceConnectionTime_ =
NumberOfConnectedDevices_ > 0 ? total_connected_time / NumberOfConnectedDevices_
: 0;
poco_information(Logger(), fmt::format("Garbage collecting done..."));
if (connection.second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - connection.second.second->State_.started);
} else {
std::lock_guard SessionLock(SessionMutex_);
NumberOfConnectedDevices_ = Sessions_.size();
AverageDeviceConnectionTime_ += 10;
NumberOfConnectingDevices_++;
}
}
if ((now - last_log) > 120) {
last_log = now;
poco_information(Logger(),
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
AverageDeviceConnectionTime_));
}
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;
@@ -253,16 +212,6 @@ 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);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
}
void AP_WS_Server::Stop() {
@@ -281,118 +230,128 @@ namespace OpenWifi {
}
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
Device->second.second->GetLastStats(Statistics);
DevicePtr->GetLastStats(Statistics);
return true;
}
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
Device->second.second->GetState(State);
DevicePtr->GetState(State);
return true;
}
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber,
GWObjects::HealthCheck &CheckData) const {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
Device->second.second->GetLastHealthCheck(CheckData);
DevicePtr->GetLastHealthCheck(CheckData);
return true;
}
void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
std::lock_guard SessionLock(SessionMutex_);
std::lock_guard Lock(WSServerMutex_);
auto Conn = Sessions_.find(connection_id);
if (Conn == end(Sessions_))
return;
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto CurrentSerialNumber = SerialNumbers_[hashIndex].find(SerialNumber);
if ((CurrentSerialNumber == SerialNumbers_[hashIndex].end()) ||
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
if ((CurrentSerialNumber == SerialNumbers_.end()) ||
(CurrentSerialNumber->second.first < connection_id)) {
SerialNumbers_[hashIndex][SerialNumber] = std::make_pair(connection_id, Conn->second);
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second);
return;
}
}
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {
std::lock_guard SessionLock(SessionMutex_);
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t serial_number) {
std::lock_guard G(WSServerMutex_);
auto Session = Sessions_.find(session_id);
if (Session == end(Sessions_))
return false;
Garbage_.push_back(Session->second);
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex])) {
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_[hashIndex].erase(Device);
SerialNumbers_.erase(Device);
return true;
}
Sessions_.erase(Session);
return false;
}
bool AP_WS_Server::Connected(uint64_t SerialNumber,
GWObjects::DeviceRestrictions &Restrictions) const {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
Device->second.second->GetRestrictions(Restrictions);
return Device->second.second->State_.Connected;
DevicePtr->GetRestrictions(Restrictions);
return DevicePtr->State_.Connected;
}
bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
return Device->second.second->State_.Connected;
return DevicePtr->State_.Connected;
}
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return Device->second.second->Send(Payload);
return DevicePtr->Send(Payload);
} catch (...) {
poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'",
Utils::IntToSerialNumber(SerialNumber)));
@@ -401,48 +360,61 @@ namespace OpenWifi {
}
void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
Device->second.second->StopWebSocketTelemetry(RPCID);
DevicePtr->StopWebSocketTelemetry(RPCID);
}
void
AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes) {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
DevicePtr->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
}
void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes) {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
DevicePtr->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
}
void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
Device->second.second->StopKafkaTelemetry(RPCID);
DevicePtr->StopKafkaTelemetry(RPCID);
}
void AP_WS_Server::GetTelemetryParameters(
@@ -450,15 +422,16 @@ namespace OpenWifi {
uint64_t &TelemetryWebSocketTimer, uint64_t &TelemetryKafkaTimer,
uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount,
uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) {
auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
Device->second.second->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
DevicePtr->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
TelemetryWebSocketTimer, TelemetryKafkaTimer,
TelemetryWebSocketCount, TelemetryKafkaCount,
TelemetryWebSocketPackets, TelemetryKafkaPackets);
@@ -466,17 +439,18 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusAccountingData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) {
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return Device->second.second->SendRadiusAccountingData(buffer, size);
return DevicePtr->SendRadiusAccountingData(buffer, size);
} catch (...) {
poco_debug(
Logger(),
@@ -488,16 +462,18 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) {
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return Device->second.second->SendRadiusAuthenticationData(buffer, size);
return DevicePtr->SendRadiusAuthenticationData(buffer, size);
} catch (...) {
poco_debug(
Logger(),
@@ -509,16 +485,18 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) {
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
return false;
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return Device->second.second->SendRadiusCoAData(buffer, size);
return DevicePtr->SendRadiusCoAData(buffer, size);
} catch (...) {
poco_debug(Logger(),
fmt::format(": SendRadiusCoAData: Could not send data to device '{}'",

View File

@@ -75,6 +75,7 @@ namespace OpenWifi {
bool IsCertOk() { return IssuerCert_ != nullptr; }
bool ValidateCertificate(const std::string &ConnectionId,
const Poco::Crypto::X509Certificate &Certificate);
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
inline bool IsSimSerialNumber(const std::string &SerialNumber) const {
return IsSim(Poco::toLower(SerialNumber)) &&
@@ -101,16 +102,24 @@ namespace OpenWifi {
inline void AddConnection(uint64_t session_id,
std::shared_ptr<AP_WS_Connection> Connection) {
std::lock_guard Lock(SessionMutex_);
std::lock_guard Lock(WSServerMutex_);
Sessions_[session_id] = std::move(Connection);
}
inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const {
auto hashIndex = Utils::CalculateMacAddressHash(serialNumber);
std::lock_guard G(SerialNumbersMutex_[hashIndex]);
inline std::shared_ptr<AP_WS_Connection> FindConnection(uint64_t session_id) const {
std::lock_guard Lock(WSServerMutex_);
auto Connection = SerialNumbers_[hashIndex].find(serialNumber);
if (Connection==end(SerialNumbers_[hashIndex]) || Connection->second.second==nullptr)
auto Connection = Sessions_.find(session_id);
if (Connection != end(Sessions_))
return Connection->second;
return nullptr;
}
inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const {
std::lock_guard Lock(WSServerMutex_);
auto Connection = SerialNumbers_.find(serialNumber);
if (Connection==end(SerialNumbers_) || Connection->second.second==nullptr)
return false;
return Connection->second.second->RttyMustBeSecure_;
}
@@ -150,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);
@@ -192,9 +201,9 @@ namespace OpenWifi {
RX = RX_;
}
// TOD: move to hash based map.
inline bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
std::lock_guard Lock(SessionMutex_);
std::lock_guard G(WSServerMutex_);
for(const auto &connection:Sessions_) {
if( connection.second->RawLastHealthcheck_.Sanity>=lowLimit &&
connection.second->RawLastHealthcheck_.Sanity<=highLimit) {
@@ -203,33 +212,8 @@ 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
) {
auto serialNumberInt = Utils::SerialNumberToInt(serialNumber);
auto hashIndex = Utils::CalculateMacAddressHash(serialNumberInt);
std::lock_guard G(SerialNumbersMutex_[hashIndex]);
auto session_hint = SerialNumbers_[hashIndex].find(Utils::SerialNumberToInt(serialNumber));
if(session_hint==end(SerialNumbers_[hashIndex])) {
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::mutex SessionMutex_;
mutable std::mutex StatsMutex_;
mutable std::recursive_mutex WSServerMutex_;
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
Poco::Net::SocketReactor Reactor_;
@@ -242,21 +226,15 @@ namespace OpenWifi {
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
std::atomic_bool Running_ = false;
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Sessions_;
using SerialNumberMap = std::map<uint64_t /* serial number */, std::pair<uint64_t /* session id*/,
std::shared_ptr<AP_WS_Connection>>>;
std::array<SerialNumberMap,256> SerialNumbers_;
mutable std::array<std::mutex,256> SerialNumbersMutex_;
std::map<uint64_t, std::pair<uint64_t, std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
std::atomic_bool AllowSerialNumberMismatch_ = true;
std::atomic_uint64_t MismatchDepth_ = 2;
std::uint64_t NumberOfConnectedDevices_ = 0;
std::uint64_t AverageDeviceConnectionTime_ = 0;
std::uint64_t NumberOfConnectingDevices_ = 0;
std::uint64_t SessionTimeOut_ = 10*60;
std::atomic_uint64_t NumberOfConnectedDevices_ = 0;
std::atomic_uint64_t AverageDeviceConnectionTime_ = 0;
std::atomic_uint64_t NumberOfConnectingDevices_ = 0;
mutable std::mutex StatsMutex_;
std::atomic_uint64_t TX_=0,RX_=0;
std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;

View File

@@ -302,116 +302,97 @@ namespace OpenWifi {
StorageService()->RemovedExpiredCommands();
StorageService()->RemoveTimedOutCommands();
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;
std::vector<GWObjects::CommandDetails> Commands;
if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
poco_trace(MyLogger,
fmt::format("Scheduler about to process {} commands.", Commands.size()));
for (auto &Cmd : Commands) {
if (!Running_) {
poco_warning(MyLogger, "Scheduler quitting because service is stopping.");
break;
}
poco_trace(MyLogger, fmt::format("Scheduler about to process {} commands.",
Commands.size()));
for (auto &Cmd : Commands) {
if (!Running_) {
poco_warning(MyLogger,
"Scheduler quitting because service is stopping.");
break;
poco_trace(MyLogger,
fmt::format("{}: Serial={} Command={} Starting processing.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
try {
// Skip an already running command
if (IsCommandRunning(Cmd.UUID)) {
continue;
}
poco_trace(MyLogger,
fmt::format("{}: Serial={} Command={} Starting processing.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
try {
// Skip an already running command
if (IsCommandRunning(Cmd.UUID)) {
continue;
}
auto now = 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 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(
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
if (!AP_WS_Server()->Connected(SerialNumberInt)) {
poco_trace(
MyLogger,
fmt::format("{}: Serial={} Command={} Preparing execution.",
fmt::format("{}: Serial={} Command={} Device is not connected.",
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) {
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={} 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);
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={} 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) {
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={} 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.");
@@ -467,16 +448,4 @@ namespace OpenWifi {
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID));
return nullptr;
}
bool CommandManager::FireAndForget(const std::string &SerialNumber, const std::string &Method, const Poco::JSON::Object &Params) {
Poco::JSON::Object CompleteRPC;
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
CompleteRPC.set(uCentralProtocol::ID, 0);
CompleteRPC.set(uCentralProtocol::METHOD, Method);
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
std::stringstream ToSend;
CompleteRPC.stringify(ToSend);
poco_debug(Logger(), fmt::format("{}: Fire and forget command {}.", SerialNumber, Method));
return AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())>0;
}
} // namespace OpenWifi

View File

@@ -12,7 +12,7 @@
#include <functional>
#include <future>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <utility>
#include "Poco/JSON/Object.h"
@@ -162,10 +162,8 @@ namespace OpenWifi {
inline auto CommandTimeout() const { return commandTimeOut_; }
inline auto CommandRetry() const { return commandRetry_; }
bool FireAndForget(const std::string &SerialNumber, const std::string &Method,
const Poco::JSON::Object &Params);
private:
mutable std::mutex LocalMutex_;
mutable std::recursive_mutex LocalMutex_;
std::atomic_bool Running_ = false;
Poco::Thread ManagerThread;
std::atomic_uint64_t Id_ = 3; // do not start @1. We ignore ID=1 & 0 is illegal..

View File

@@ -11,17 +11,12 @@
#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"
@@ -30,47 +25,64 @@
#include "StorageArchiver.h"
#include "StorageService.h"
#include "TelemetryStream.h"
#include "GenericScheduler.h"
#include "UI_GW_WebSocketNotifications.h"
#include "VenueBroadcaster.h"
#include "AP_WS_ConfigAutoUpgrader.h"
#include "framework/ConfigurationValidator.h"
#include "framework/UI_WebSocketClientServer.h"
#include "rttys/RTTYS_server.h"
#include "firmware_revision_cache.h"
namespace OpenWifi {
class Daemon *Daemon::instance() {
static Daemon instance(
vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, vDAEMON_CONFIG_ENV_VAR,
vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
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(),
RADIUSSessionTracker(),
AP_WS_ConfigAutoUpgrader(),
FirmwareRevisionCache()
SubSystemVec{StorageService(), SerialNumberCache(), ConfigurationValidator(),
UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(),
CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(),
RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(),
SignatureManager(), AP_WS_Server(),
RegulatoryInfo()
});
return &instance;
}
static std::string ALBHealthCallback() {
uint64_t Connections, AverageConnectionTime, NumberOfConnectingDevices;
AP_WS_Server()->AverageDeviceStatistics(Connections, AverageConnectionTime,
NumberOfConnectingDevices);
std::ostringstream os;
os << "Connections: " << Connections << std::endl <<
"ConnectingDevices: " << NumberOfConnectingDevices << std::endl <<
"ConnectionTime: " << AverageConnectionTime << std::endl;
return os.str();
}
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_ = DefaultDeviceTypeList;
DeviceTypes_ = DefaultDeviceTypes;
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
MicroServiceALBCallback(ALBHealthCallback);
}
[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string &Id) const {

View File

@@ -12,7 +12,9 @@ namespace OpenWifi {
Event.set("type", type_);
Event.set("timestamp", timestamp_);
Event.set("payload", payload_);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, Utils::IntToSerialNumber(serialNumber_), Event);
std::ostringstream OS;
Event.stringify(OS);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, serialNumber_, OS.str());
}
}

View File

@@ -4,26 +4,23 @@
#pragma once
#include <string>
#include <Poco/JSON/Object.h>
#include <RESTObjects/RESTAPI_GWobjects.h>
#include <framework/KafkaManager.h>
#include <string>
namespace OpenWifi {
class GWKafkaEvents {
public:
GWKafkaEvents(std::uint64_t serialNumber, const std::string &type,
GWKafkaEvents(const std::string &serialNumber, const std::string &type,
std::uint64_t timestamp)
: 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_;};
: serialNumber_(serialNumber), type_(type), timestamp_(timestamp) {}
protected:
std::uint64_t serialNumber_;
inline void SetPayload(Poco::JSON::Object::Ptr payload) { payload_ = std::move(payload); }
void Send();
private:
std::string serialNumber_;
std::string type_;
std::uint64_t timestamp_ = 0;
Poco::JSON::Object::Ptr payload_;
@@ -31,15 +28,17 @@ namespace OpenWifi {
class DeviceFirmwareChangeKafkaEvent : public GWKafkaEvents {
public:
DeviceFirmwareChangeKafkaEvent(std::uint64_t serialNumber, std::uint64_t timestamp,
DeviceFirmwareChangeKafkaEvent(const std::string &serialNumber, std::uint64_t timestamp,
const std::string &oldFirmware,
const std::string &newFirmware)
: GWKafkaEvents(serialNumber, "unit.firmware_change", timestamp),
oldFirmware_(oldFirmware), newFirmware_(newFirmware) {}
~DeviceFirmwareChangeKafkaEvent() {
payload_->set("oldFirmware", oldFirmware_);
payload_->set("newFirmware", newFirmware_);
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
payload->set("oldFirmware", oldFirmware_);
payload->set("newFirmware", newFirmware_);
SetPayload(payload);
Send();
}
@@ -49,23 +48,25 @@ namespace OpenWifi {
class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
public:
DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber,
std::uint64_t timestamp, const Poco::JSON::Object::Ptr config)
DeviceConfigurationChangeKafkaEvent(const std::string &serialNumber,
std::uint64_t timestamp, const std::string config)
: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
}
~DeviceConfigurationChangeKafkaEvent() {
payload_->set("configuration", *config_);
Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
payload->set("configuration", config_);
SetPayload(payload);
Send();
}
private:
Poco::JSON::Object::Ptr config_;
std::string config_;
};
class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {
public:
explicit DeviceBlacklistedKafkaEvent(std::uint64_t serialNumber,
explicit DeviceBlacklistedKafkaEvent(const std::string &serialNumber,
std::uint64_t timestamp, const std::string &reason,
const std::string &author, std::uint64_t created,
std::string &IP)
@@ -73,10 +74,12 @@ namespace OpenWifi {
author_(author), created_(created), IP_(IP) {}
~DeviceBlacklistedKafkaEvent() {
payload_->set("reason", reason_);
payload_->set("author", author_);
payload_->set("created", created_);
payload_->set("ipaddress", IP_);
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);
Send();
}
@@ -86,21 +89,4 @@ 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

View File

@@ -1,19 +0,0 @@
//
// 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

View File

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

View File

@@ -28,7 +28,7 @@ namespace OpenWifi {
bool Recovered = false;
Poco::File OuiFile(CurrentOUIFileName_);
if (OuiFile.exists()) {
std::lock_guard Lock(LocalMutex_);
std::unique_lock Lock(LocalMutex_);
Recovered = ProcessFile(CurrentOUIFileName_, OUIs_);
if (Recovered) {
poco_notice(Logger(),
@@ -150,7 +150,7 @@ namespace OpenWifi {
OUIMap TmpOUIs;
if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
std::lock_guard G(LocalMutex_);
std::unique_lock G(LocalMutex_);
OUIs_ = std::move(TmpOUIs);
LastUpdate_ = Utils::Now();
Poco::File F1(CurrentOUIFileName_);
@@ -163,7 +163,7 @@ namespace OpenWifi {
} else if (OUIs_.empty()) {
if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
LastUpdate_ = Utils::Now();
std::lock_guard G(LocalMutex_);
std::unique_lock G(LocalMutex_);
OUIs_ = std::move(TmpOUIs);
}
}
@@ -173,7 +173,7 @@ namespace OpenWifi {
}
std::string OUIServer::GetManufacturer(const std::string &MAC) {
std::lock_guard Lock(LocalMutex_);
std::shared_lock Lock(LocalMutex_);
auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
if (Manufacturer != OUIs_.end())

View File

@@ -4,7 +4,7 @@
#pragma once
#include <mutex>
#include <shared_mutex>
#include "framework/SubSystemServer.h"
@@ -32,7 +32,7 @@ namespace OpenWifi {
[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
private:
std::mutex LocalMutex_;
std::shared_mutex LocalMutex_;
uint64_t LastUpdate_ = 0;
bool Initialized_ = false;
OUIMap OUIs_;

View File

@@ -1,452 +0,0 @@
//
// 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, CalledStationId, 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::CALLED_STATION_ID: {
CalledStationId.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 = 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->calledStationId = CalledStationId;
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();
}
/*
if(ap_hint!=AccountingSessions_.end()) {
std::cout << "Auth table:" << std::endl;
for(const auto &session:ap_hint->second) {
std::cout << Notification.SerialNumber_ << ": Index: " << session.first << ": ID: " << session.second->accountingSessionId << " MID:" << session.second->accountingMultiSessionId << std::endl;
}
}
*/
}
std::uint32_t GetUiInt32(const std::uint8_t *buf) {
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, CalledStationId, 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::CALLED_STATION_ID: {
CalledStationId.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 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 = AccountingSessionId + AccountingMultiSessionId;
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;
}
// std::cout << "ACT -> " << Notification.SerialNumber_ << ": AccountingSessionId: " << AccountingSessionId << " AccountingMultiSessionId: " << AccountingMultiSessionId << std::endl;
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->calledStationId = CalledStationId;
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;
}
}
/* if(ap_hint!=AccountingSessions_.end()) {
std::cout << "Acct table:" << std::endl;
for(const auto &session:ap_hint->second) {
std::cout << Notification.SerialNumber_ << ": Index: " << session.first << ": ID: " << session.second->accountingSessionId << " MID:" << session.second->accountingMultiSessionId << std::endl;
}
}
*/
}
[[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));
if(!session->calledStationId.empty())
P.AppendAttribute(RADIUS::Attributes::CALLED_STATION_ID, session->calledStationId);
if(!session->callingStationId.empty())
P.AppendAttribute(RADIUS::Attributes::CALLING_STATION_ID, session->callingStationId);
if(!session->nasId.empty())
P.AppendAttribute(RADIUS::Attributes::NAS_IDENTIFIER, session->nasId);
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);
auto ProxyState = session->serialNumber + ":" + "0.0.0.0" + ":" + "3799" + ":" + session->interface;
// std::cout << "Proxy state: " << ProxyState << " Secret: " << session->secret << std::endl;
P.AppendAttribute(RADIUS::Attributes::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;
}
auto session_hint = ap_hint->second.find(sessionId);
if(session_hint!=ap_hint->second.end()) {
SendCoADM(session_hint->second);
}
return true;
}
bool RADIUSSessionTracker::DisconnectUser(const std::string &UserName) {
poco_information(Logger(),fmt::format("Disconnect user {}.", UserName));
std::lock_guard Guard(Mutex_);
for(const auto &AP:AccountingSessions_) {
for(const auto &Session:AP.second) {
if(Session.second->userName==UserName) {
SendCoADM(Session.second);
}
}
}
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

View File

@@ -1,208 +0,0 @@
//
// 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);
bool DisconnectUser(const std::string &UserName);
inline std::uint32_t HasSessions(const std::string & serialNumber) {
std::lock_guard G(Mutex_);
auto ap_hint = AccountingSessions_.find(serialNumber);
if(ap_hint==end(AccountingSessions_)) {
return 0;
}
return ap_hint->second.size();
}
void GarbageCollection(Poco::Timer &timer);
private:
std::atomic_bool Running_=false;
Poco::NotificationQueue SessionMessageQueue_;
Poco::Thread QueueManager_;
using SessionMap = std::map<std::string,RADIUSSessionPtr>; // calling-station-id + accounting-session-id
std::map<std::string,SessionMap> AccountingSessions_; // serial-number -> session< accounting-session -> session>
Poco::Timer GarbageCollectionTimer_;
std::unique_ptr<Poco::TimerCallback<RADIUSSessionTracker>> GarbageCollectionCallback_;
std::uint64_t SessionTimeout_=10*60;
void ProcessAccountingSession(SessionNotification &Notification);
void ProcessAuthenticationSession(SessionNotification &Notification);
void DisconnectSession(const std::string &SerialNumber);
RADIUSSessionTracker() noexcept
: SubSystemServer("RADIUSSessionTracker", "RADIUS-SESSION", "radius.session") {}
std::string ComputeSessionIndex(RADIUSSessionPtr S);
};
inline auto RADIUSSessionTracker() { return RADIUSSessionTracker::instance(); }
} // namespace OpenWifi

View File

@@ -1,740 +0,0 @@
//
// Created by stephane bourque on 2022-08-15.
//
#pragma once
#include <fstream>
#include <iostream>
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/TemporaryFile.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
#include "AP_WS_Server.h"
#include "RADIUS_helpers.h"
#include <RESTObjects/RESTAPI_GWobjects.h>
namespace OpenWifi {
class RADIUS_Destination : public Poco::Runnable {
public:
RADIUS_Destination(Poco::Net::SocketReactor &R, const GWObjects::RadiusProxyPool &P)
: Reactor_(R),
Logger_(Poco::Logger::get(
fmt::format("RADSEC: {}", P.name))),
Pool_(P)
{
Type_ = GWObjects::RadiusEndpointType(P.radsecPoolType);
Start();
}
~RADIUS_Destination() override { Stop(); }
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799;
inline int Start() {
ReconnectThread_.start(*this);
return 0;
}
inline void Stop() {
TryAgain_ = false;
Disconnect();
ReconnectThread_.wakeUp();
ReconnectThread_.join();
}
inline void run() final {
Poco::Thread::trySleep(5000);
std::uint64_t CurrentDelay = 10, maxDelay=300, LastTry=0, LastKeepAlive=0;
while (TryAgain_) {
if (!Connected_) {
if(!LastTry || (Utils::Now()-LastTry)>CurrentDelay) {
LastTry = Utils::Now();
if (!Connect()) {
CurrentDelay *= 2;
if(CurrentDelay>maxDelay) CurrentDelay=10;
} else {
CurrentDelay = 10;
}
}
} else if ((Utils::Now() - LastKeepAlive) > Pool_.radsecKeepAlive) {
RADIUS::RadiusOutputPacket P(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
P.MakeStatusMessage(Pool_.authConfig.servers[ServerIndex_].name);
poco_trace(Logger_, fmt::format("{}: Keep-Alive message.", Pool_.authConfig.servers[ServerIndex_].name));
Socket_->sendBytes(P.Data(), P.Len());
LastKeepAlive = Utils::Now();
}
Poco::Thread::trySleep(2000);
}
}
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
int length) {
try {
if (Connected_) {
RADIUS::RadiusPacket P(buffer, length);
int sent_bytes;
if (P.VerifyMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret)) {
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
sent_bytes = Socket_->sendBytes(buffer, length);
} else {
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
P.ComputeMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
}
return (sent_bytes == length);
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_warning(Logger_, "Exception occurred: while sending data.");
}
return false;
}
inline void
onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
unsigned char Buffer[4096];
try {
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer, sizeof(Buffer));
std::string ReplySource;
if (NumberOfReceivedBytes >= 20) {
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
if (P.IsAuthentication()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
P.PacketType(),
P.PacketTypeToString(),
NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else if(P.IsStatusMessageReply(ReplySource)) {
poco_debug(Logger_,
fmt::format("{}: Keepalive message received.", ReplySource));
} else {
poco_debug(Logger_, "AUTH packet dropped.");
}
} else if (P.IsAccounting()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
P.PacketType(),
P.PacketTypeToString(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "ACCT packet dropped.");
}
} else if (P.IsAuthority()) {
auto SerialNumber = P.ExtractSerialNumberTIP();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
P.PacketType(),
P.PacketTypeToString(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "CoA/DM packet dropped.");
}
} else {
poco_warning(Logger_,
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
}
} else {
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
Disconnect();
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
Disconnect();
} catch (...) {
Disconnect();
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
}
}
inline void
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
poco_warning(Logger_, "Socker error. Terminating connection.");
Disconnect();
}
inline void
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
Disconnect();
}
inline void OnAccountingSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger_, "Accounting: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger_, "Accounting: missing serial number. Dropping request.");
return;
}
poco_debug(
Logger_,
fmt::format(
"Accounting Packet Response received for {}", SerialNumber ));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, P.Buffer(), P.Size());
}
inline void OnAuthenticationSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger_, "Authentication: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
if(Logger_.trace()) {
P.Log(std::cout);
}
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger_, "Authentication: missing serial number. Dropping request.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger_,
fmt::format(
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
}
inline void OnCoASocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger_, "CoA/DM: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberTIP();
if (SerialNumber.empty()) {
poco_warning(Logger_, "CoA/DM: missing serial number. Dropping request.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger_,
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
}
static inline bool IsExpired(const Poco::Crypto::X509Certificate &C) {
return C.expiresOn().timestamp().epochTime() < (std::time_t)Utils::Now();
}
static inline void Cat(const std::string &F1, const std::string & F2, const std::string &F) {
std::ofstream of(F.c_str(),std::ios_base::trunc|std::ios_base::out|std::ios_base::binary);
std::ifstream if1(F1.c_str(),std::ios_base::binary|std::ios_base::in);
Poco::StreamCopier::copyStream(if1,of);
of << std::endl;
std::ifstream if2(F2.c_str(),std::ios_base::binary|std::ios_base::in);
Poco::StreamCopier::copyStream(if2,of);
of << std::endl;
of.close();
}
inline bool Connect_GlobalReach() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
Poco::TemporaryFile OpenRoamingRootCertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile Intermediate0(MicroServiceDataDirectory());
Poco::TemporaryFile Intermediate1(MicroServiceDataDirectory());
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
DecodeFile(Intermediate0.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[0]);
DecodeFile(Intermediate1.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[1]);
const static std::string OpenRoamingRootCert{
"-----BEGIN CERTIFICATE-----\n"
"MIIClDCCAhugAwIBAgIUF1f+h+uJNHyr+ZqTpwew8LYRAW0wCgYIKoZIzj0EAwMw\n"
"gYkxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNVBAcTBkxvbmRv\n"
"bjEsMCoGA1UEChMjR2xvYmFsUmVhY2ggVGVjaG5vbG9neSBFTUVBIExpbWl0ZWQx\n"
"KjAoBgNVBAMTIUdsb2JhbFJlYWNoIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0y\n"
"MzA3MTQwOTMyMDBaFw00MzA3MDkwOTMyMDBaMIGJMQswCQYDVQQGEwJHQjEPMA0G\n"
"A1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xLDAqBgNVBAoTI0dsb2JhbFJl\n"
"YWNoIFRlY2hub2xvZ3kgRU1FQSBMaW1pdGVkMSowKAYDVQQDEyFHbG9iYWxSZWFj\n"
"aCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARy\n"
"f02umFNy5W/TtM5nfMaLhRF61vLxhT8iNQHR1mXiRmNdME3ArForBcAm2eolHPcJ\n"
"RH9DcXs59d2zzoPEaBjXADTCjUts3F7G6fjqvfki2e/txx/xfUopQO8G54XcFWqj\n"
"QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRS\n"
"tNe7MgAFwTaMZKUtS1/8pVoBqjAKBggqhkjOPQQDAwNnADBkAjA7VKHTybtSMBcN\n"
"717jGYvkWlcj4c9/LzPtkHO053wGsPigaq+1SjY7tDhS/g9oUQACMA6UqH2e8cfn\n"
"cZqmBNVNN3DBjIb4anug7F+FnYOQF36ua6MLBeGn3aKxvu1aO+hjPg==\n"
"-----END CERTIFICATE-----\n"};
std::ofstream ofs{OpenRoamingRootCertFile_.path().c_str(),
std::ios_base::trunc | std::ios_base::out |
std::ios_base::binary};
ofs << OpenRoamingRootCert;
ofs.close();
Poco::Net::Context::Ptr SecureContext = Poco::AutoPtr<Poco::Net::Context>(
new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, ""));
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
SecureContext->enableExtendedCertificateVerification(false);
}
SecureContext->usePrivateKey(Poco::Crypto::RSAKey("", KeyFile_.path(), ""));
Poco::Crypto::X509Certificate Cert(CertFile_.path());
if (!IsExpired(Cert)) {
SecureContext->useCertificate(Poco::Crypto::X509Certificate(CertFile_.path()));
} else {
poco_error(
Logger_,
fmt::format(
"Certificate for {} has expired. We cannot connect to this server.",
Pool_.acctConfig.servers[ServerIndex_].name));
return false;
}
SecureContext->addCertificateAuthority(
Poco::Crypto::X509Certificate(OpenRoamingRootCertFile_.path()));
SecureContext->addChainCertificate(
Poco::Crypto::X509Certificate(Intermediate0.path()));
SecureContext->addChainCertificate(
Poco::Crypto::X509Certificate(Intermediate1.path()));
SecureContext->enableExtendedCertificateVerification(false);
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
ServerIndex_ = 0 ;
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
try {
poco_information(Logger_, fmt::format("Attempting to connect to {}", CommonName()));
Socket_->connect(Destination, Poco::Timespan(20, 0));
Socket_->completeHandshake();
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
Socket_->verifyPeerCertificate();
}
if (Socket_->havePeerCertificate()) {
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
Socket_->peerCertificate());
}
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::onData));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
*this, &RADIUS_Destination::onError));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
*this, &RADIUS_Destination::onShutdown));
Connected_ = true;
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
return true;
} catch (const Poco::Net::NetException &E) {
poco_warning(Logger_, "NetException: Could not connect.");
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_warning(Logger_, "Exception: Could not connect.");
Logger_.log(E);
} catch (...) {
poco_warning(Logger_, "Could not connect.");
}
ServerIndex_++;
}
}
ServerIndex_=0;
return false;
}
inline bool Connect_Orion() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
Poco::Crypto::X509Certificate Cert(CertFile_.path());
if(IsExpired(Cert)) {
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Pool_.acctConfig.servers[ServerIndex_].name));
return false;
}
for (auto &cert : Pool_.acctConfig.servers[ServerIndex_].radsecCacerts) {
CaCertFiles_.emplace_back(
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
}
Poco::Net::Context::Ptr SecureContext =
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
Poco::Net::Context::TLS_CLIENT_USE, KeyFile_.path(), CertFile_.path(), ""));
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
SecureContext->enableExtendedCertificateVerification(false);
}
for (const auto &ca : CaCertFiles_) {
Poco::Crypto::X509Certificate cert(ca->path());
SecureContext->addCertificateAuthority(cert);
}
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
ServerIndex_ = 0 ;
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
try {
poco_information(Logger_, "Attempting to connect");
Socket_->connect(Destination, Poco::Timespan(100, 0));
Socket_->completeHandshake();
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
Socket_->verifyPeerCertificate();
}
if (Socket_->havePeerCertificate()) {
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
Socket_->peerCertificate());
}
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::onData));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
*this, &RADIUS_Destination::onError));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
*this, &RADIUS_Destination::onShutdown));
Connected_ = true;
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
return true;
} catch (const Poco::Net::NetException &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (...) {
poco_information(Logger_, "Could not connect.");
}
ServerIndex_++;
}
}
ServerIndex_=0;
return false;
}
inline bool Connect_Generic() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::Net::SocketAddress AuthSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
AuthenticationSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
Poco::Net::SocketAddress AcctSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
Poco::Net::SocketAddress CoASockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
/*
AuthenticationSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
Poco::Net::SocketAddress AuthSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
Poco::Net::SocketAddress AcctSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
Poco::Net::SocketAddress CoASockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
*/
Reactor_.addEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
Reactor_.addEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
Reactor_.addEventHandler(
*CoASocketV4_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
/*
Reactor_.addEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
Reactor_.addEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
Reactor_.addEventHandler(
*CoASocketV6_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
*/
}
return true;
}
inline bool Connect_Radsec() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
}
return true;
}
inline bool Connect() {
switch(Type_) {
case GWObjects::RadiusEndpointType::orion: return Connect_Orion();
case GWObjects::RadiusEndpointType::globalreach: return Connect_GlobalReach();
case GWObjects::RadiusEndpointType::radsec: return Connect_Radsec();
default:
return Connect_Generic();
}
}
inline void Disconnect() {
if (Connected_) {
std::lock_guard G(LocalMutex_);
if(Type_==GWObjects::RadiusEndpointType::generic) {
if(AuthenticationSocketV4_) {
Reactor_.removeEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
AuthenticationSocketV4_->close();
AuthenticationSocketV4_.reset();
}
if(AccountingSocketV4_) {
Reactor_.removeEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
AccountingSocketV4_->close();
AccountingSocketV4_.reset();
}
if(CoASocketV4_) {
Reactor_.removeEventHandler(
*CoASocketV4_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
CoASocketV4_->close();
CoASocketV4_.reset();
}
/* if(AuthenticationSocketV6_) {
Reactor_.removeEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
AuthenticationSocketV6_->close();
AuthenticationSocketV6_.reset();
}
if(AccountingSocketV6_) {
Reactor_.removeEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnAccountingSocketReadable));
AccountingSocketV6_->close();
AccountingSocketV6_.reset();
}
if(CoASocketV6_) {
Reactor_.removeEventHandler(
*CoASocketV6_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::OnCoASocketReadable));
CoASocketV6_->close();
CoASocketV6_.reset();
}
*/
} else {
if(Socket_!=nullptr) {
std::lock_guard G(LocalMutex_);
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
*this, &RADIUS_Destination::onData));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
*this, &RADIUS_Destination::onError));
Reactor_.removeEventHandler(
*Socket_,
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
*this, &RADIUS_Destination::onShutdown));
Socket_->close();
}
}
}
Connected_ = false;
poco_information(Logger_, "Disconnecting.");
}
static void DecodeFile(const std::string &filename, const std::string &s) {
std::ofstream sec_file(filename, std::ios_base::out | std::ios_base::trunc |
std::ios_base::binary);
std::stringstream is(s);
Poco::Base64Decoder ds(is);
Poco::StreamCopier::copyStream(ds, sec_file);
sec_file.close();
}
[[nodiscard]] inline std::string CommonName() {
if (Peer_Cert_)
return Peer_Cert_->commonName();
return "";
}
[[nodiscard]] inline std::string IssuerName() {
if (Peer_Cert_)
return Peer_Cert_->issuerName();
return "";
}
[[nodiscard]] inline std::string SubjectName() {
if (Peer_Cert_)
return Peer_Cert_->subjectName();
return "";
}
const auto &Pool() const { return Pool_; }
auto ServerType() const { return Type_; }
inline bool SendRadiusDataAuthData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Auth {} bytes.", serialNumber, size));
AuthenticationSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.authConfig.servers[0].ip, Pool_.authConfig.servers[0].port));
return true;
}
inline bool SendRadiusDataAcctData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Acct {} bytes.", serialNumber, size));
AccountingSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.acctConfig.servers[0].ip, Pool_.acctConfig.servers[0].port));
return true;
}
inline bool SendRadiusDataCoAData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
poco_trace(Logger_, fmt::format("{}: Sending RADIUS CoA {} bytes.", serialNumber, size));
CoASocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.coaConfig.servers[0].ip, Pool_.coaConfig.servers[0].port));
return true;
}
private:
std::recursive_mutex LocalMutex_;
Poco::Net::SocketReactor &Reactor_;
Poco::Logger &Logger_;
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
/* std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
*/
Poco::Thread ReconnectThread_;
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
volatile bool Connected_ = false;
volatile bool TryAgain_ = true;
enum GWObjects::RadiusEndpointType Type_{GWObjects::RadiusEndpointType::unknown};
GWObjects::RadiusProxyPool Pool_;
uint64_t ServerIndex_=0;
};
} // namespace OpenWifi

File diff suppressed because it is too large Load Diff

View File

@@ -8,17 +8,14 @@
#include "RADIUS_helpers.h"
#include "RADIUS_proxy_server.h"
#include "RADIUSSessionTracker.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
/*
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799;
*/
int RADIUS_proxy_server::Start() {
@@ -27,7 +24,7 @@ namespace OpenWifi {
Enabled_ = MicroServiceConfigGetBool("radius.proxy.enable", false);
if (!Enabled_ && !Config.exists()) {
StopRADIUSDestinations();
StopRADSECServers();
return 0;
}
@@ -35,101 +32,227 @@ namespace OpenWifi {
Enabled_ = true;
Poco::Net::SocketAddress AuthSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
AuthenticationSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
Poco::Net::SocketAddress AuthSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.authentication.port",
DEFAULT_RADIUS_AUTHENTICATION_PORT));
AuthenticationSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
Poco::Net::SocketAddress AcctSockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV4_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
Poco::Net::SocketAddress AcctSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV6_ =
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
Poco::Net::SocketAddress CoASockAddrV4(
Poco::Net::AddressFamily::IPv4,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
Poco::Net::SocketAddress CoASockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
RadiusReactor_.reset();
RadiusReactor_ = std::make_unique<Poco::Net::SocketReactor>();
RadiusReactor_->addEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_->addEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_->addEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->addEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->addEventHandler(
*CoASocketV4_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
RadiusReactor_->addEventHandler(
*CoASocketV6_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
ParseConfig();
StartRADIUSDestinations();
RadiusReactorThread_.start(RadiusReactor_);
StartRADSECServers();
RadiusReactorThread_.start(*RadiusReactor_);
Utils::SetThreadName(RadiusReactorThread_, "rad:reactor");
Running_ = true;
return 0;
}
void RADIUS_proxy_server::Stop() {
if (Enabled_ && Running_) {
poco_information(Logger(), "Stopping...");
RadiusReactor_->removeEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_->removeEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
StopRADIUSDestinations();
RadiusReactor_.stop();
RadiusReactor_->removeEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->removeEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_->removeEventHandler(
*CoASocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
RadiusReactor_->removeEventHandler(
*CoASocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
AuthenticationSocketV4_->close();
AuthenticationSocketV6_->close();
AccountingSocketV4_->close();
AccountingSocketV6_->close();
CoASocketV4_->close();
CoASocketV6_->close();
AuthenticationSocketV4_.reset();
AuthenticationSocketV6_.reset();
AccountingSocketV4_.reset();
AccountingSocketV6_.reset();
CoASocketV4_.reset();
CoASocketV6_.reset();
StopRADSECServers();
RadiusReactor_->stop();
RadiusReactorThread_.join();
Running_ = false;
poco_information(Logger(), "Stopped...");
}
}
/* inline static bool isRadsec(const GWObjects::RadiusProxyPool &Cfg) {
return Cfg.radsecPoolType=="orion" || Cfg.radsecPoolType=="globalreach" || Cfg.radsecPoolType=="radsec";
}
*/
void RADIUS_proxy_server::StartRADIUSDestinations() {
void RADIUS_proxy_server::StartRADSECServers() {
std::lock_guard G(Mutex_);
for (const auto &pool : PoolList_.pools) {
if(pool.enabled) {
RADIUS_Destinations_[Utils::IPtoInt(pool.poolProxyIp)] =
std::make_unique<RADIUS_Destination>(RadiusReactor_, pool);
} else {
poco_information(Logger(),fmt::format("Pool {} is not enabled.", pool.name));
for (const auto &entry : pool.authConfig.servers) {
if (entry.radsec) {
RADSECservers_[Poco::Net::SocketAddress(entry.ip, 0)] =
std::make_unique<RADSEC_server>(*RadiusReactor_, entry);
}
}
}
}
void RADIUS_proxy_server::StopRADIUSDestinations() {
void RADIUS_proxy_server::StopRADSECServers() {
std::lock_guard G(Mutex_);
RADIUS_Destinations_.clear();
RADSECservers_.clear();
}
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination,const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string &Secret) {
try{
void RADIUS_proxy_server::OnAccountingSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
// are we sending this to a pool?
auto DstParts = Utils::Split(Destination, ':');
std::uint32_t DtsIp = Utils::IPtoInt(DstParts[0]);
std::lock_guard G(Mutex_);
auto DestinationServer = RADIUS_Destinations_.find(DtsIp);
if (DestinationServer != end(RADIUS_Destinations_)) {
if(Logger().trace()) {
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
auto SessionID = P.ExtractAccountingSessionID();
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
Logger().trace(
fmt::format("{}: Sending Accounting {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
serialNumber, P.Size(),
DestinationServer->second->Pool().authConfig.servers[0].ip,
CalledStationID, CallingStationID, SessionID, MultiSessionID));
}
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
Secret = DestinationServer->second->Pool().acctConfig.servers[0].secret;
if(RecomputeAuthenticator) {
P.RecomputeAuthenticator(Secret);
}
DestinationServer->second->SendData(serialNumber, (const unsigned char *)P.Buffer(),
P.Size());
} else {
DestinationServer->second->SendRadiusDataAcctData(
serialNumber, (const unsigned char *)P.Buffer(), P.Size());
}
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),
fmt::format("Bad RADIUS ACCT Packet from {}. Dropped.", serialNumber));
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(), "Accounting: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger(), "Accounting: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger(),
fmt::format(
"Accounting Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, P.Buffer(), P.Size());
}
void store_packet(const std::string &serialNumber, const char *buffer, std::size_t size) {
static std::uint64_t pkt=0;
void RADIUS_proxy_server::OnAuthenticationSocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
std::string filename = MicroServiceDataDirectory() + "/radius." + serialNumber + "." + std::to_string(pkt++) + ".bin";
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(), "Authentication: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (SerialNumber.empty()) {
poco_warning(Logger(), "Authentication: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
std::ofstream ofs(filename,std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);
ofs.write(buffer,size);
ofs.close();
poco_debug(
Logger(),
fmt::format(
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
}
void RADIUS_proxy_server::SendAccountingData( const std::string &serialNumber,
void RADIUS_proxy_server::OnCoASocketReadable(
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(), "CoA/DM: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberTIP();
if (SerialNumber.empty()) {
poco_warning(Logger(), "CoA/DM: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(
Logger(),
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
}
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
const char *buffer, std::size_t size) {
if (!Continue())
@@ -138,9 +261,46 @@ namespace OpenWifi {
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto Destination = P.ExtractProxyStateDestination();
std::string Secret;
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, Secret);
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, Secret);
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC);
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
size);
}
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
AccountingSocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
AccountingSocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format(
"ACCT: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
}
auto AllSent =
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
: *AccountingSocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(),
fmt::format("{}: Could not send Accounting packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending Accounting Packet to {}, "
"CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(),
CalledStationID, CallingStationID));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
@@ -162,31 +322,46 @@ namespace OpenWifi {
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto Destination = P.ExtractProxyStateDestination();
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
if (DestinationServer != end(RADIUS_Destinations_)) {
if(Logger().trace()) {
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
auto SessionID = P.ExtractAccountingSessionID();
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
Logger().trace(
fmt::format("{}: Sending Authentication {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
serialNumber, P.Size(),
DestinationServer->second->Pool().authConfig.servers[0].ip,
CalledStationID, CallingStationID, SessionID, MultiSessionID));
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
size);
}
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
DestinationServer->second->SendData(serialNumber,
(const unsigned char *)buffer, size);
}
else {
DestinationServer->second->SendRadiusDataAuthData(
serialNumber, (const unsigned char *)buffer, size);
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
AuthenticationSocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
AuthenticationSocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format(
"AUTH: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
}
auto AllSent = SendData(Dst.family() == Poco::Net::SocketAddress::IPv4
? *AuthenticationSocketV4_
: *AuthenticationSocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(),
fmt::format("{}: Could not send Authentication packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending Authentication Packet to {}, "
"CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(),
CalledStationID, CallingStationID));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -204,35 +379,54 @@ namespace OpenWifi {
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
auto Destination = P.ExtractProxyStateDestination();
if (Destination.empty()) {
Destination = "0.0.0.0:0";
}
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
if (DestinationServer != end(RADIUS_Destinations_)) {
poco_trace(Logger(),fmt::format("{}: Sending CoA {} bytes to {}", serialNumber, P.Size(), DestinationServer->second->Pool().coaConfig.servers[0].ip));
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
size);
} else {
DestinationServer->second->SendRadiusDataCoAData(
serialNumber, (const unsigned char *)buffer, size);
}
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 && CoASocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 && CoASocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format(
"CoA: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
}
auto AllSent = SendData(
Dst.family() == Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_ : *CoASocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(), fmt::format("{}: Could not send CoA packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
FinalDestination.toString()));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),
fmt::format("Bad RADIUS AUTH Packet from {}. Dropped.", serialNumber));
fmt::format("Bad RADIUS CoA/DM Packet from {}. Dropped.", serialNumber));
}
}
void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
std::vector<Destination> &V4,
std::vector<Destination> &V6, bool setAsDefault,
const std::string &poolProxyIp) {
std::vector<Destination> &V6, bool setAsDefault) {
uint64_t TotalV4 = 0, TotalV6 = 0;
for (const auto &server : Config.servers) {
@@ -255,9 +449,7 @@ namespace OpenWifi {
.methodParameters = Config.methodParameters,
.useAsDefault = setAsDefault,
.useRADSEC = server.radsec,
.realms = server.radsecRealms,
.secret = server.secret,
.poolProxyIp = poolProxyIp};
.realms = server.radsecRealms};
if (setAsDefault && D.useRADSEC)
DefaultIsRADSEC_ = true;
@@ -306,11 +498,11 @@ namespace OpenWifi {
for (const auto &pool : RPC.pools) {
RadiusPool NewPool;
ParseServerList(pool.authConfig, NewPool.AuthV4, NewPool.AuthV6,
pool.useByDefault, pool.poolProxyIp);
pool.useByDefault);
ParseServerList(pool.acctConfig, NewPool.AcctV4, NewPool.AcctV6,
pool.useByDefault, pool.poolProxyIp);
pool.useByDefault);
ParseServerList(pool.coaConfig, NewPool.CoaV4, NewPool.CoaV6,
pool.useByDefault, pool.poolProxyIp);
pool.useByDefault);
Pools_.push_back(NewPool);
}
} else {
@@ -329,7 +521,6 @@ namespace OpenWifi {
}
}
/*
static bool RealmMatch(const std::string &user_realm, const std::string &realm) {
if (realm.find_first_of('*') == std::string::npos)
return user_realm == realm;
@@ -339,9 +530,7 @@ namespace OpenWifi {
Poco::Net::SocketAddress
RADIUS_proxy_server::DefaultRoute(radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret) {
const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
// find the realm...
@@ -356,6 +545,7 @@ namespace OpenWifi {
if (!server.realms.empty()) {
for (const auto &realm : server.realms) {
if (RealmMatch(UserRealm, realm)) {
std::cout << "Realm match..." << std::endl;
UseRADSEC = true;
return server.Addr;
}
@@ -375,18 +565,18 @@ namespace OpenWifi {
case radius_type::auth: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AuthV4
: Pools_[DefaultPoolIndex_].AuthV6,
RequestedAddress, Secret);
}
case radius_type::coa: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
: Pools_[DefaultPoolIndex_].CoaV6,
RequestedAddress, Secret);
RequestedAddress);
}
case radius_type::acct:
default: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AcctV4
: Pools_[DefaultPoolIndex_].AcctV6,
RequestedAddress, Secret);
RequestedAddress);
}
case radius_type::coa: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
: Pools_[DefaultPoolIndex_].CoaV6,
RequestedAddress);
}
}
}
@@ -394,8 +584,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,
std::string &Secret) {
const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
std::lock_guard G(Mutex_);
if (Pools_.empty()) {
UseRADSEC = false;
@@ -404,47 +594,39 @@ namespace OpenWifi {
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
bool useDefault;
useDefault = IsV4 ? RequestedAddress.host() ==
Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4)
: RequestedAddress.host() ==
Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6);
if (useDefault) {
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC, Secret);
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
}
auto isAddressInPool = [&](const std::vector<Destination> &D, bool &UseRADSEC) -> bool {
for (const auto &entry : D) {
if (!entry.poolProxyIp.empty() &&
entry.poolProxyIp == RequestedAddress.host().toString()) {
UseRADSEC = entry.useRADSEC;
return true;
}
for (const auto &entry : D)
if (entry.Addr.host() == RequestedAddress.host()) {
UseRADSEC = entry.useRADSEC;
return true;
}
}
return false;
};
for (auto &pool : Pools_) {
// try and match the pool's address to the destination
for (auto &i : Pools_) {
switch (rtype) {
case radius_type::coa: {
if (isAddressInPool((IsV4 ? pool.CoaV4 : pool.CoaV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.CoaV4 : pool.CoaV6, RequestedAddress, Secret);
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
}
} break;
case radius_type::auth: {
if (isAddressInPool((IsV4 ? pool.AuthV4 : pool.AuthV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.AuthV4 : pool.AuthV6, RequestedAddress, Secret);
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
}
} break;
case radius_type::acct: {
if (isAddressInPool((IsV4 ? pool.AcctV4 : pool.AcctV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.AcctV4 : pool.AcctV6, RequestedAddress, Secret);
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
}
} break;
}
@@ -456,13 +638,10 @@ namespace OpenWifi {
Poco::Net::SocketAddress
RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool,
const Poco::Net::SocketAddress &OriginalAddress,
std::string &Secret) {
const Poco::Net::SocketAddress &OriginalAddress) {
if (Pool.size() == 1) {
Secret = Pool[0].secret;
auto A = Pool[0].Addr;
return A;
return Pool[0].Addr;
}
if (Pool[0].strategy == "weighted") {
@@ -478,7 +657,6 @@ namespace OpenWifi {
index = pos;
cur_state = i.state;
found = true;
Secret = i.secret ;
}
pos++;
}
@@ -486,9 +664,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();
@@ -501,30 +679,27 @@ namespace OpenWifi {
if (i.state < cur_state) {
index = pos;
cur_state = i.state;
Secret = i.secret;
found = true;
}
pos++;
}
if (!found) {
// return OriginalAddress;
return OriginalAddress;
}
Pool[index].state += 1;
return Pool[index].Addr;
} else if (Pool[0].strategy == "random") {
if (Pool.size() > 1) {
auto index = std::rand() % Pool.size();
Secret = Pool[index].secret;
return Pool[index].Addr;
return Pool[std::rand() % Pool.size()].Addr;
} else {
return OriginalAddress;
}
}
return OriginalAddress;
}
*/
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
std::lock_guard G(Mutex_);

View File

@@ -11,7 +11,7 @@
#include "framework/SubSystemServer.h"
#include "RADIUS_Destination.h"
#include "RADSEC_server.h"
namespace OpenWifi {
@@ -28,19 +28,23 @@ namespace OpenWifi {
void Stop() final;
inline bool Enabled() const { return Enabled_; }
void SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size);
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void
OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void SendAccountingData(const std::string &serialNumber, const char *buffer,
std::size_t size);
void SendAuthenticationData(const std::string &serialNumber, const char *buffer,
std::size_t size);
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string &Secret);
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
void DeleteConfig();
void GetConfig(GWObjects::RadiusProxyPoolList &C);
void StartRADIUSDestinations();
void StopRADIUSDestinations();
void StartRADSECServers();
void StopRADSECServers();
struct Destination {
Poco::Net::SocketAddress Addr;
@@ -55,20 +59,24 @@ namespace OpenWifi {
bool useAsDefault = false;
bool useRADSEC = false;
std::vector<std::string> realms;
std::string secret;
std::string poolProxyIp;
};
inline bool Continue() const { return Running_ && Enabled_ && !Pools_.empty(); }
private:
Poco::Net::SocketReactor RadiusReactor_;
Poco::Thread RadiusReactorThread_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
std::unique_ptr<Poco::Net::SocketReactor> RadiusReactor_;
Poco::Thread RadiusReactorThread_;
GWObjects::RadiusProxyPoolList PoolList_;
std::string ConfigFilename_;
std::map<std::uint32_t, std::unique_ptr<RADIUS_Destination>> RADIUS_Destinations_;
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSEC_server>> RADSECservers_;
struct RadiusPool {
std::vector<Destination> AuthV4;
@@ -93,21 +101,18 @@ namespace OpenWifi {
void ParseConfig();
void ResetConfig();
// Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
// const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
const RADIUS::RadiusPacket &P, bool &UseRADSEC);
void ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
std::vector<Destination> &V4,
std::vector<Destination> &V6, bool setAsDefault,
const std::string &poolProxyIp);
/* static Poco::Net::SocketAddress
std::vector<Destination> &V4, std::vector<Destination> &V6,
bool setAsDefault);
static Poco::Net::SocketAddress
ChooseAddress(std::vector<Destination> &Pool,
const Poco::Net::SocketAddress &OriginalAddress, std::string &Secret);
const Poco::Net::SocketAddress &OriginalAddress);
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
std::string &Secret);
*/ };
const RADIUS::RadiusPacket &P, bool &UseRADSEC);
};
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }

304
src/RADSEC_server.h Normal file
View File

@@ -0,0 +1,304 @@
//
// Created by stephane bourque on 2022-08-15.
//
#pragma once
#include <fstream>
#include <iostream>
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/TemporaryFile.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
#include "AP_WS_Server.h"
#include "RADIUS_helpers.h"
namespace OpenWifi {
class RADSEC_server : public Poco::Runnable {
public:
RADSEC_server(Poco::Net::SocketReactor &R, GWObjects::RadiusProxyServerEntry E)
: Reactor_(R), Server_(std::move(E)),
Logger_(Poco::Logger::get(
fmt::format("RADSEC: {}@{}:{}", Server_.name, Server_.ip, Server_.port))) {
Start();
}
~RADSEC_server() { Stop(); }
inline int Start() {
ReconnectThread_.start(*this);
return 0;
}
inline void Stop() {
TryAgain_ = false;
Disconnect();
ReconnectThread_.wakeUp();
ReconnectThread_.join();
}
inline void run() final {
Poco::Thread::trySleep(3000);
std::uint64_t LastStatus = 0;
auto RadSecKeepAlive = MicroServiceConfigGetInt("radsec.keepalive", 120);
while (TryAgain_) {
if (!Connected_) {
std::lock_guard G(LocalMutex_);
LastStatus = Utils::Now();
Connect();
} else if ((Utils::Now() - LastStatus) > RadSecKeepAlive) {
RADIUS::RadiusOutputPacket P(Server_.radsecSecret);
P.MakeStatusMessage();
poco_information(Logger_, "Keep-Alive message.");
Socket_->sendBytes(P.Data(), P.Len());
LastStatus = Utils::Now();
}
Poco::Thread::trySleep(!Connected_ ? 3000 : 10000);
}
}
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
int length) {
try {
if (Connected_) {
RADIUS::RadiusPacket P(buffer, length);
int sent_bytes;
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
poco_debug(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
sent_bytes = Socket_->sendBytes(buffer, length);
} else {
poco_debug(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
P.ComputeMessageAuthenticator(Server_.radsecSecret);
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
}
return (sent_bytes == length);
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_warning(Logger_, "Exception occurred: while sending data.");
}
return false;
}
inline void
onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
unsigned char Buffer[4096];
try {
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer, sizeof(Buffer));
if (NumberOfReceivedBytes >= 20) {
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
if (P.IsAuthentication()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {} Received {} bytes.", SerialNumber,
P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "AUTH packet dropped.");
}
} else if (P.IsAccounting()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {} Received {} bytes.", SerialNumber,
P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "ACCT packet dropped.");
}
} else if (P.IsAuthority()) {
auto SerialNumber = P.ExtractSerialNumberTIP();
if (!SerialNumber.empty()) {
poco_debug(Logger_,
fmt::format("{}: {} Received {} bytes.", SerialNumber,
P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
NumberOfReceivedBytes);
} else {
poco_debug(Logger_, "CoA/DM packet dropped.");
}
} else {
poco_warning(Logger_,
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
}
} else {
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
Disconnect();
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
Disconnect();
} catch (...) {
Disconnect();
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
}
}
inline void
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
poco_warning(Logger_, "Socker error. Terminating connection.");
Disconnect();
}
inline void
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
Disconnect();
}
inline bool Connect() {
if (TryAgain_) {
std::lock_guard G(LocalMutex_);
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
DecodeFile(CertFile_.path(), Server_.radsecCert);
DecodeFile(KeyFile_.path(), Server_.radsecKey);
for (auto &cert : Server_.radsecCacerts) {
CaCertFiles_.emplace_back(
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
}
Poco::Net::Context::Ptr SecureContext =
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
Poco::Net::Context::TLS_CLIENT_USE, KeyFile_.path(), CertFile_.path(), ""));
if (Server_.allowSelfSigned) {
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
SecureContext->enableExtendedCertificateVerification(false);
}
for (const auto &ca : CaCertFiles_) {
Poco::Crypto::X509Certificate cert(ca->path());
SecureContext->addCertificateAuthority(cert);
}
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
try {
poco_information(Logger_, "Attempting to connect");
Socket_->connect(Destination, Poco::Timespan(100, 0));
Socket_->completeHandshake();
if (!Server_.allowSelfSigned) {
Socket_->verifyPeerCertificate();
}
if (Socket_->havePeerCertificate()) {
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
Socket_->peerCertificate());
}
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
*this, &RADSEC_server::onData));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
*this, &RADSEC_server::onError));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
*this, &RADSEC_server::onShutdown));
Connected_ = true;
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
return true;
} catch (const Poco::Net::NetException &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_information(Logger_, "Could not connect.");
Logger_.log(E);
} catch (...) {
poco_information(Logger_, "Could not connect.");
}
}
return false;
}
inline void Disconnect() {
if (Connected_) {
std::lock_guard G(LocalMutex_);
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
*this, &RADSEC_server::onData));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
*this, &RADSEC_server::onError));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
*this, &RADSEC_server::onShutdown));
Socket_->close();
Connected_ = false;
}
poco_information(Logger_, "Disconnecting.");
}
static void DecodeFile(const std::string &filename, const std::string &s) {
std::ofstream sec_file(filename, std::ios_base::out | std::ios_base::trunc |
std::ios_base::binary);
std::stringstream is(s);
Poco::Base64Decoder ds(is);
Poco::StreamCopier::copyStream(ds, sec_file);
sec_file.close();
}
[[nodiscard]] inline std::string CommonName() {
if (Peer_Cert_)
return Peer_Cert_->commonName();
return "";
}
[[nodiscard]] inline std::string IssuerName() {
if (Peer_Cert_)
return Peer_Cert_->issuerName();
return "";
}
[[nodiscard]] inline std::string SubjectName() {
if (Peer_Cert_)
return Peer_Cert_->subjectName();
return "";
}
private:
std::recursive_mutex LocalMutex_;
Poco::Net::SocketReactor &Reactor_;
GWObjects::RadiusProxyServerEntry Server_;
Poco::Logger &Logger_;
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
Poco::Thread ReconnectThread_;
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
volatile bool Connected_ = false;
volatile bool TryAgain_ = true;
};
} // namespace OpenWifi

View File

@@ -169,12 +169,10 @@ namespace OpenWifi::RESTAPI_RPC {
if (Cmd.ErrorCode == 0 && Cmd.Command == uCentralProtocol::CONFIGURE) {
// we need to post a kafka event for this.
if (Params.has(uCentralProtocol::CONFIG) && Params.isObject(uCentralProtocol::CONFIG)) {
auto Config = Params.get(uCentralProtocol::CONFIG)
.extract<Poco::JSON::Object::Ptr>();
if (Params.has(uCentralProtocol::CONFIG)) {
DeviceConfigurationChangeKafkaEvent KEvent(
Utils::SerialNumberToInt(Cmd.SerialNumber), Utils::Now(),
Config);
Cmd.SerialNumber, Utils::Now(),
Params.get(uCentralProtocol::CONFIG).toString());
}
}

View File

@@ -7,6 +7,7 @@
//
#include "Poco/Array.h"
#include "Poco/JSON/Stringifier.h"
#include "RESTAPI_default_configurations.h"
#include "StorageService.h"

View File

@@ -1,117 +0,0 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by stephane bourque on 2023-07-11.
// Arilia Wireless Inc.
//
#include "RESTAPI/RESTAPI_default_firmware.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "StorageService.h"
#include "framework/orm.h"
#include "framework/ow_constants.h"
#include "framework/utils.h"
namespace OpenWifi {
void RESTAPI_default_firmware::DoGet() {
std::string deviceType = ORM::Escape(GetBinding(RESTAPI::Protocol::DEVICETYPE, ""));
GWObjects::DefaultFirmware Firmware;
if (StorageService()->GetDefaultFirmware(deviceType, Firmware)) {
return Object(Firmware);
}
NotFound();
}
void RESTAPI_default_firmware::DoDelete() {
std::string deviceType = ORM::Escape(GetBinding(RESTAPI::Protocol::DEVICETYPE, ""));
if (deviceType.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if (StorageService()->DeleteDefaultFirmware(deviceType)) {
return OK();
}
BadRequest(RESTAPI::Errors::CouldNotBeDeleted);
}
void RESTAPI_default_firmware::DoPost() {
std::string deviceType = GetBinding(RESTAPI::Protocol::DEVICETYPE, "");
if (deviceType.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if (StorageService()->DefaultFirmwareAlreadyExists(deviceType)) {
return BadRequest(RESTAPI::Errors::DefFirmwareNameExists);
}
const auto &Obj = ParsedBody_;
GWObjects::DefaultFirmware Firmware;
if (!Firmware.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(Firmware.uri.empty() || Firmware.revision.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
try {
Poco::URI FirmwareURI(Firmware.uri);
} catch (...) {
return BadRequest(RESTAPI::Errors::InvalidURI);
}
Firmware.Created = Firmware.LastModified = Utils::Now();
if (StorageService()->CreateDefaultFirmware(Firmware)) {
GWObjects::DefaultFirmware ModifiedFirmware;
StorageService()->GetDefaultFirmware(deviceType, ModifiedFirmware);
return Object(ModifiedFirmware);
}
BadRequest(RESTAPI::Errors::RecordNotCreated);
}
void RESTAPI_default_firmware::DoPut() {
std::string deviceType = GetBinding(RESTAPI::Protocol::DEVICETYPE, "");
const auto &Obj = ParsedBody_;
GWObjects::DefaultFirmware NewFirmware;
if (!NewFirmware.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
GWObjects::DefaultFirmware Existing;
if (!StorageService()->GetDefaultFirmware(deviceType, Existing)) {
return NotFound();
}
Existing.LastModified = Utils::Now();
AssignIfPresent(Obj, "description", Existing.Description);
AssignIfPresent(Obj, "imageCreationDate", Existing.imageCreationDate);
AssignIfPresent(Obj, "revision", Existing.revision);
if (Obj->has("uri")) {
if(NewFirmware.uri.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
try {
Poco::URI FirmwareURI(NewFirmware.uri);
} catch (...) {
return BadRequest(RESTAPI::Errors::InvalidURI);
}
Existing.uri = NewFirmware.uri;
}
if (StorageService()->UpdateDefaultFirmware(Existing)) {
GWObjects::DefaultFirmware ModifiedFirmware;
StorageService()->GetDefaultFirmware(deviceType, ModifiedFirmware);
return Object(ModifiedFirmware);
}
BadRequest(RESTAPI::Errors::RecordNotUpdated);
}
} // namespace OpenWifi

View File

@@ -1,30 +0,0 @@
//
// Created by stephane bourque on 2023-07-11.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
class RESTAPI_default_firmware : public RESTAPIHandler {
public:
RESTAPI_default_firmware(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_POST,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal) {}
static auto PathName() {
return std::list<std::string>{"/api/v1/default_firmware/{deviceType}"};
}
void DoGet() final;
void DoDelete() final;
void DoPost() final;
void DoPut() final;
};
} // namespace OpenWifi

View File

@@ -1,25 +0,0 @@
//
// Created by stephane bourque on 2023-07-11.
//
#include "RESTAPI_default_firmwares.h"
#include "Poco/Array.h"
#include "RESTAPI_default_firmwares.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
namespace OpenWifi {
void RESTAPI_default_firmwares::DoGet() {
if (QB_.CountOnly) {
auto Count = StorageService()->GetDefaultFirmwaresCount();
return ReturnCountOnly(Count);
}
std::vector<GWObjects::DefaultFirmware> Firmwares;
StorageService()->GetDefaultFirmwares(QB_.Offset, QB_.Limit, Firmwares);
return Object(RESTAPI::Protocol::FIRMWARES, Firmwares);
}
} // namespace OpenWifi

View File

@@ -1,25 +0,0 @@
//
// Created by stephane bourque on 2023-07-11.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
class RESTAPI_default_firmwares : public RESTAPIHandler {
public:
RESTAPI_default_firmwares(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_OPTIONS},
Server, TransactionId, Internal){};
static auto PathName() { return std::list<std::string>{"/api/v1/default_firmwares"}; }
void DoGet() final;
void DoDelete() final{};
void DoPost() final{};
void DoPut() final{};
};
} // namespace OpenWifi

View File

@@ -163,11 +163,8 @@ namespace OpenWifi {
{APCommands::Commands::telemetry, false, true, &RESTAPI_device_commandHandler::Telemetry,
30000ms},
{APCommands::Commands::ping, false, true, &RESTAPI_device_commandHandler::Ping, 60000ms},
{APCommands::Commands::rrm, false, true, &RESTAPI_device_commandHandler::RRM, 60000ms},
{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms},
{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 60000ms}
};
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script,
300000ms}};
void RESTAPI_device_commandHandler::DoPost() {
if (!ValidateParameters()) {
@@ -312,7 +309,7 @@ namespace OpenWifi {
if (AP_WS_Server()->GetState(SerialNumber_, State)) {
Poco::JSON::Object RetObject;
State.to_json(SerialNumber_, RetObject);
State.to_json(RetObject);
return ReturnObject(RetObject);
} else {
Poco::JSON::Object RetObject;
@@ -409,7 +406,6 @@ 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();
@@ -463,14 +459,6 @@ 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) {
@@ -486,10 +474,6 @@ 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)) {
@@ -915,10 +899,6 @@ 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) &&
@@ -976,12 +956,6 @@ 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();
@@ -1037,10 +1011,6 @@ 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)) {
@@ -1085,10 +1055,6 @@ 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)) {
@@ -1129,16 +1095,15 @@ namespace OpenWifi {
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
#define DBGLINE \
{ std::cout << __LINE__ << std::endl; }
void RESTAPI_device_commandHandler::Rtty(
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
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);
}
@@ -1147,11 +1112,6 @@ 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{
@@ -1225,10 +1185,6 @@ 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) &&
@@ -1342,163 +1298,4 @@ namespace OpenWifi {
}
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
void RESTAPI_device_commandHandler::RRM(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("RRM({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(!ParsedBody_->has("actions") || !ParsedBody_->isArray("actions")) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
const auto &Actions = *ParsedBody_->getArray("actions");
// perform some validation on the commands.
for(const auto &action:Actions) {
auto ActionDetails = action.extract<Poco::JSON::Object::Ptr>();
if(!ActionDetails->has("action")) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto ActionStr = ActionDetails->get("action").toString();
if( ActionStr != "kick"
&& ActionStr != "channel_switch"
&& ActionStr != "tx_power"
&& ActionStr != "beacon_request"
&& ActionStr != "bss_transition"
&& ActionStr != "neighbors" ) {
return BadRequest(RESTAPI::Errors::InvalidRRMAction);
}
}
Poco::JSON::Object Params;
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
Params.set(uCentralProtocol::ACTIONS, Actions);
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::RRM;
std::ostringstream os;
Params.stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = 0;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
Cmd.Status= "completed";
if(CommandManager()->FireAndForget(SerialNumber_, uCentralProtocol::RRM, Params)) {
StorageService()->AddCommand(SerialNumber_, Cmd,
Storage::CommandExecutionType::COMMAND_COMPLETED);
Cmd.Status= "completed";
return OK();
}
Cmd.Status= "failed"; // should never happen
StorageService()->AddCommand(SerialNumber_, Cmd,
Storage::CommandExecutionType::COMMAND_COMPLETED);
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
}
void RESTAPI_device_commandHandler::Transfer(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
poco_debug(Logger_, fmt::format("TRANSFER({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
GWObjects::DeviceTransferRequest TR;
if(!TR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::TRANSFER;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = 0;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::transfer, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
void RESTAPI_device_commandHandler::CertUpdate(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("CERTUPDATE({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
GWObjects::DeviceCertificateUpdateRequest CR;
if(!CR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::DeviceTransferRequest TR;
if(!TR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::CERTUPDATE;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = 0;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::certupdate, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
} // namespace OpenWifi

View File

@@ -34,8 +34,6 @@ 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,
@@ -62,12 +60,6 @@ namespace OpenWifi {
const GWObjects::DeviceRestrictions &R);
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void RRM(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void CertUpdate(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void Transfer(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
static auto PathName() {
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};

View File

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

View File

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

View File

@@ -158,61 +158,4 @@ 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(GetBoolParameter("simulatedDevices",false)) {
if(StorageService()->DeleteSimulatedDevice("")) {
return OK();
}
return NotFound();
}
if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if(!QB_.Select.empty()) {
for(auto &serialNumber:QB_.Select) {
StorageService()->DeleteDevice(serialNumber);
}
return OK();
}
auto SimulatedOnly = GetBoolParameter("simulatedOnly",false);
auto oldestContact = GetParameter("oldestContact",0);
if(oldestContact!=0) {
StorageService()->DeleteDevices(oldestContact,SimulatedOnly);
return OK();
}
auto macPattern = GetParameter("macPattern","");
if(macPattern.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
// rules out wrong values.
Poco::toLowerInPlace(macPattern);
Poco::replaceInPlace(macPattern,"*","%");
if(!ValidMacPatternOnlyChars(macPattern)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
StorageService()->DeleteDevices(macPattern, SimulatedOnly);
return OK();
}
} // namespace OpenWifi

View File

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

View File

@@ -8,11 +8,6 @@
namespace OpenWifi {
static bool ValidRadiusPoolServerType(const std::string &T) {
static std::set<std::string> Types{ "radsec", "generic", "orion", "globalreach"};
return Types.find(T)!=Types.end();
}
void RESTAPI_radiusProxyConfig_handler::DoGet() {
Logger_.information(fmt::format("GET-RADIUS-PROXY-CONFIG: TID={} user={} thr_id={}",
TransactionId_, Requester(),
@@ -49,22 +44,10 @@ namespace OpenWifi {
}
// Logically validate the config.
for (auto &pool : C.pools) {
for (const auto &pool : C.pools) {
if (pool.name.empty()) {
return BadRequest(RESTAPI::Errors::PoolNameInvalid);
}
if (pool.radsecPoolType.empty()) {
pool.radsecPoolType = "generic";
}
if(!ValidRadiusPoolServerType(pool.radsecPoolType)) {
return BadRequest(RESTAPI::Errors::NotAValidRadiusPoolType);
}
if(pool.radsecKeepAlive==0) {
pool.radsecKeepAlive=25;
}
for (const auto &config : {pool.acctConfig, pool.authConfig, pool.coaConfig}) {
if (config.servers.empty())
continue;

View File

@@ -1,141 +0,0 @@
//
// 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);
}
auto Command = GetParameter("operation","");
if(Command=="coadm") {
if(Parameters.callingStationId.empty() || Parameters.accountingSessionId.empty() || Parameters.accountingMultiSessionId.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto Index = Parameters.accountingSessionId + Parameters.accountingMultiSessionId;
poco_information(Logger(), fmt::format("Disconnecting session {},{}", Parameters.accountingSessionId, Parameters.accountingMultiSessionId ));
if(RADIUSSessionTracker()->SendCoADM(SerialNumber, Index)) {
return OK();
}
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
}
if(Command=="disconnectUser" && !Parameters.userName.empty()) {
if(Parameters.userName.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
poco_information(Logger(), fmt::format("Disconnecting sessions for user: {}", Parameters.userName ));
if(RADIUSSessionTracker()->DisconnectUser(Parameters.userName)) {
return OK();
}
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
}
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
} // namespace OpenWifi

View File

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

View File

@@ -21,9 +21,6 @@
#include "RESTAPI/RESTAPI_script_handler.h"
#include "RESTAPI/RESTAPI_scripts_handler.h"
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
#include "RESTAPI/RESTAPI_radiussessions_handler.h"
#include "RESTAPI/RESTAPI_default_firmware.h"
#include "RESTAPI/RESTAPI_default_firmwares.h"
#include "framework/RESTAPI_SystemCommand.h"
#include "framework/RESTAPI_SystemConfiguration.h"
@@ -42,9 +39,8 @@ 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_radiussessions_handler,
RESTAPI_regulatory, RESTAPI_default_firmwares,
RESTAPI_default_firmware>(Path, Bindings, L, S,
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket,
RESTAPI_regulatory>(Path, Bindings, L, S,
TransactionId);
}
@@ -57,8 +53,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_radiussessions_handler,
RESTAPI_regulatory, RESTAPI_default_firmwares,
RESTAPI_default_firmware>(Path, Bindings, L, S, TransactionId);
RESTAPI_script_handler, RESTAPI_blacklist_list,
RESTAPI_regulatory>(Path, Bindings, L, S, TransactionId);
}
} // namespace OpenWifi

View File

@@ -13,7 +13,6 @@
#ifdef TIP_GATEWAY_SERVICE
#include "AP_WS_Server.h"
#include "CapabilitiesCache.h"
#include "RADIUSSessionTracker.h"
#endif
#include "RESTAPI_GWobjects.h"
@@ -30,7 +29,6 @@ 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);
@@ -57,10 +55,6 @@ 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);
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_to_json(Obj, "connectReason", connectReason);
}
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
@@ -70,7 +64,7 @@ namespace OpenWifi::GWObjects {
ConnectionState ConState;
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
ConState.to_json(SerialNumber,Obj);
ConState.to_json(Obj);
} else {
field_to_json(Obj, "ipAddress", "");
field_to_json(Obj, "txBytes", (uint64_t)0);
@@ -82,13 +76,6 @@ 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
}
@@ -122,10 +109,6 @@ 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);
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_from_json(Obj, "connectReason", connectReason);
return true;
} catch (const Poco::Exception &E) {
}
@@ -175,31 +158,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "lastModified", LastModified);
}
void DefaultFirmware::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "deviceType", deviceType);
field_to_json(Obj, "description", Description);
field_to_json(Obj, "uri", uri);
field_to_json(Obj, "revision", revision);
field_to_json(Obj, "imageCreationDate", imageCreationDate);
field_to_json(Obj, "created", Created);
field_to_json(Obj, "lastModified", LastModified);
}
bool DefaultFirmware::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "deviceType", deviceType);
field_from_json(Obj, "description", Description);
field_from_json(Obj, "uri", uri);
field_from_json(Obj, "revision", revision);
field_from_json(Obj, "imageCreationDate", imageCreationDate);
field_from_json(Obj, "created", Created);
field_from_json(Obj, "lastModified", LastModified);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void CommandDetails::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("details", Obj, Details);
EmbedDocument("results", Obj, Results);
@@ -253,7 +211,7 @@ namespace OpenWifi::GWObjects {
return false;
}
void ConnectionState::to_json([[maybe_unused]] const std::string &SerialNumber, Poco::JSON::Object &Obj) {
void ConnectionState::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "ipAddress", Address);
field_to_json(Obj, "txBytes", TX);
field_to_json(Obj, "rxBytes", RX);
@@ -275,22 +233,6 @@ 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:
@@ -305,9 +247,6 @@ 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;
@@ -434,10 +373,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "acctConfig", acctConfig);
field_to_json(Obj, "coaConfig", coaConfig);
field_to_json(Obj, "useByDefault", useByDefault);
field_to_json(Obj, "radsecKeepAlive", radsecKeepAlive);
field_to_json(Obj, "poolProxyIp", poolProxyIp);
field_to_json(Obj, "radsecPoolType", radsecPoolType);
field_to_json(Obj, "enabled", enabled);
}
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -448,10 +383,6 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj, "acctConfig", acctConfig);
field_from_json(Obj, "coaConfig", coaConfig);
field_from_json(Obj, "useByDefault", useByDefault);
field_from_json(Obj, "radsecKeepAlive", radsecKeepAlive);
field_from_json(Obj, "poolProxyIp", poolProxyIp);
field_from_json(Obj, "radsecPoolType", radsecPoolType);
field_from_json(Obj, "enabled", enabled);
return true;
} catch (const Poco::Exception &E) {
}
@@ -649,74 +580,4 @@ 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);
field_to_json(Obj, "calledStationId", calledStationId);
}
void RADIUSSessionList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "sessions", sessions);
}
void RadiusCoADMParameters::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "accountingSessionId", accountingSessionId);
field_to_json(Obj, "accountingMultiSessionId", accountingMultiSessionId);
field_to_json(Obj, "callingStationId", callingStationId);
field_to_json(Obj, "chargeableUserIdentity", chargeableUserIdentity);
field_to_json(Obj, "userName", userName);
}
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);
field_from_json(Obj, "userName", userName);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool DeviceTransferRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber", serialNumber);
field_from_json(Obj, "server", server);
field_from_json(Obj, "port", port);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool DeviceCertificateUpdateRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber", serialNumber);
field_from_json(Obj, "encodedCertificate", encodedCertificate);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
} // namespace OpenWifi::GWObjects

View File

@@ -11,13 +11,9 @@
#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, SIMULATED };
enum CertificateValidation { NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED };
struct ConnectionState {
uint64_t MessageCount = 0;
@@ -42,15 +38,8 @@ 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(const std::string &SerialNumber, Poco::JSON::Object &Obj) ;
void to_json(Poco::JSON::Object &Obj) const;
};
struct DeviceRestrictionsKeyInfo {
@@ -108,10 +97,6 @@ namespace OpenWifi::GWObjects {
std::string pendingConfigurationCmd;
DeviceRestrictions restrictionDetails;
std::uint64_t pendingUUID = 0;
bool simulated=false;
std::uint64_t lastRecordedContact=0;
std::uint64_t certificateExpiryDate = 0;
std::string connectReason;
void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const;
@@ -184,26 +169,6 @@ namespace OpenWifi::GWObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DefaultFirmware {
std::string deviceType;
std::string Description;
std::string uri;
std::string revision;
uint64_t imageCreationDate;
uint64_t Created;
uint64_t LastModified;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DefaultFirmwareList {
std::vector<DefaultFirmware> firmwares;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct CommandDetails {
std::string UUID;
std::string SerialNumber;
@@ -362,10 +327,6 @@ namespace OpenWifi::GWObjects {
RadiusProxyServerConfig acctConfig;
RadiusProxyServerConfig coaConfig;
bool useByDefault = false;
std::string radsecPoolType;
std::string poolProxyIp;
std::uint64_t radsecKeepAlive=25;
bool enabled=true;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -409,108 +370,5 @@ 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;
std::string calledStationId;
#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,
userName;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const;
};
enum class RadiusPoolStrategy {
round_robin, random, weighted, unknown
};
enum class RadiusEndpointType {
generic, radsec, globalreach, orion, unknown
};
static inline RadiusEndpointType RadiusEndpointType(const std::string &T) {
if(T=="generic") return RadiusEndpointType::generic;
if(T=="radsec") return RadiusEndpointType::radsec;
if(T=="globalreach") return RadiusEndpointType::globalreach;
if(T=="orion") return RadiusEndpointType::orion;
return RadiusEndpointType::unknown;
}
static inline RadiusPoolStrategy RadiusPoolStrategy(const std::string &T) {
if(T=="round_robin") return RadiusPoolStrategy::round_robin;
if(T=="random") return RadiusPoolStrategy::random;
if(T=="weighted") return RadiusPoolStrategy::weighted;
return RadiusPoolStrategy::unknown;
}
static inline std::string to_string(enum RadiusEndpointType T) {
switch(T) {
case RadiusEndpointType::generic: return "generic";
case RadiusEndpointType::radsec: return "radsec";
case RadiusEndpointType::globalreach: return "globalreach";
case RadiusEndpointType::orion: return "orion";
default:
return "unknown";
}
}
static inline std::string to_string(enum RadiusPoolStrategy T) {
switch(T) {
case RadiusPoolStrategy::round_robin: return "round_robin";
case RadiusPoolStrategy::random: return "random";
case RadiusPoolStrategy::weighted: return "weighted";
default:
return "unknown";
}
}
struct DeviceTransferRequest {
std::string serialNumber;
std::string server;
std::uint64_t port;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceCertificateUpdateRequest {
std::string serialNumber;
std::string encodedCertificate;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
} // namespace OpenWifi::GWObjects

View File

@@ -78,22 +78,21 @@ namespace OpenWifi::OWLSObjects {
return false;
}
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "simulationId", simulationId);
field_to_json(Obj, "state", state);
field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx);
field_to_json(Obj, "msgsTx", msgsTx);
field_to_json(Obj, "msgsRx", msgsRx);
field_to_json(Obj, "liveDevices", liveDevices);
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
field_to_json(Obj, "startTime", startTime);
field_to_json(Obj, "endTime", endTime);
field_to_json(Obj, "errorDevices", errorDevices);
field_to_json(Obj, "owner", owner);
field_to_json(Obj, "expectedDevices", expectedDevices);
}
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "simulationId", simulationId);
field_to_json(Obj, "state", state);
field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx);
field_to_json(Obj, "msgsTx", msgsTx);
field_to_json(Obj, "msgsRx", msgsRx);
field_to_json(Obj, "liveDevices", liveDevices);
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
field_to_json(Obj, "startTime", startTime);
field_to_json(Obj, "endTime", endTime);
field_to_json(Obj, "errorDevices", errorDevices);
field_to_json(Obj, "owner", owner);
}
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {}

View File

@@ -43,24 +43,23 @@ namespace OpenWifi::OWLSObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationStatus {
std::string id;
std::string simulationId;
std::string state;
uint64_t tx;
uint64_t rx;
uint64_t msgsTx;
uint64_t msgsRx;
uint64_t liveDevices;
uint64_t timeToFullDevices;
uint64_t startTime;
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
uint64_t expectedDevices;
struct SimulationStatus {
std::string id;
std::string simulationId;
std::string state;
uint64_t tx;
uint64_t rx;
uint64_t msgsTx;
uint64_t msgsRx;
uint64_t liveDevices;
uint64_t timeToFullDevices;
uint64_t startTime;
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
void to_json(Poco::JSON::Object &Obj) const;
};
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
int O;

View File

@@ -1194,243 +1194,4 @@ namespace OpenWifi::ProvObjects {
return false;
}
void GLBLRAccountInfo::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj, "privateKey", privateKey);
field_to_json(Obj, "country", country);
field_to_json(Obj, "province", province);
field_to_json(Obj, "city", city);
field_to_json(Obj, "organization", organization);
field_to_json(Obj, "commonName", commonName);
field_to_json(Obj, "CSR", CSR);
field_to_json(Obj, "CSRPrivateKey", CSRPrivateKey);
field_to_json(Obj, "CSRPublicKey", CSRPublicKey);
field_to_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
}
bool GLBLRAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj, "privateKey", privateKey);
field_from_json(Obj, "country", country);
field_from_json(Obj, "province", province);
field_from_json(Obj, "city", city);
field_from_json(Obj, "organization", organization);
field_from_json(Obj, "commonName", commonName);
field_from_json(Obj, "CSR", CSR);
field_from_json(Obj, "CSRPrivateKey", CSRPrivateKey);
field_from_json(Obj, "CSRPublicKey", CSRPublicKey);
field_from_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void GLBLRCertificateInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "name", name);
field_to_json(Obj, "accountId", accountId);
field_to_json(Obj, "csr", csr);
field_to_json(Obj, "certificate", certificate);
field_to_json(Obj, "certificateChain", certificateChain);
field_to_json(Obj, "certificateId", certificateId);
field_to_json(Obj, "expiresAt", expiresAt);
field_to_json(Obj, "created", created);
}
bool GLBLRCertificateInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "id", id);
field_from_json(Obj, "name", name);
field_from_json(Obj, "accountId", accountId);
field_from_json(Obj, "csr", csr);
field_from_json(Obj, "certificate", certificate);
field_from_json(Obj, "certificateChain", certificateChain);
field_from_json(Obj, "certificateId", certificateId);
field_from_json(Obj, "expiresAt", expiresAt);
field_from_json(Obj, "created", created);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void GooglOrionAccountInfo::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj, "privateKey", privateKey);
field_to_json(Obj, "certificate", certificate);
field_to_json(Obj, "cacerts", cacerts);
}
bool GooglOrionAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj, "privateKey", privateKey);
field_from_json(Obj, "certificate", certificate);
field_from_json(Obj, "cacerts", cacerts);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSServer::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "Hostname", Hostname);
field_to_json(Obj, "IP", IP);
field_to_json(Obj, "Port", Port);
field_to_json(Obj, "Secret", Secret);
}
bool RADIUSServer::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "Hostname", Hostname);
field_from_json(Obj, "IP", IP);
field_from_json(Obj, "Port", Port);
field_from_json(Obj, "Secret", Secret);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndPointRadiusType::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "Authentication", Authentication);
field_to_json(Obj, "Accounting", Accounting);
field_to_json(Obj, "CoA", CoA);
field_to_json(Obj, "AccountingInterval", AccountingInterval);
}
bool RADIUSEndPointRadiusType::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "Authentication", Authentication);
field_from_json(Obj, "Accounting", Accounting);
field_from_json(Obj, "CoA", CoA);
field_from_json(Obj, "AccountingInterval", AccountingInterval);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndPointRadsecType::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "Hostname", Hostname);
field_to_json(Obj, "IP", IP);
field_to_json(Obj, "Port", Port);
field_to_json(Obj, "Secret", Secret);
field_to_json(Obj, "OpenRoamingType", OpenRoamingType);
field_to_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
field_to_json(Obj, "Weight", Weight);
field_to_json(Obj, "Certificate", Certificate);
field_to_json(Obj, "PrivateKey", PrivateKey);
field_to_json(Obj, "CaCerts", CaCerts);
field_to_json(Obj, "AllowSelfSigned", AllowSelfSigned);
}
bool RADIUSEndPointRadsecType::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "Hostname", Hostname);
field_from_json(Obj, "IP", IP);
field_from_json(Obj, "Port", Port);
field_from_json(Obj, "Secret", Secret);
field_from_json(Obj, "OpenRoamingType", OpenRoamingType);
field_from_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
field_from_json(Obj, "Weight", Weight);
field_from_json(Obj, "Certificate", Certificate);
field_from_json(Obj, "PrivateKey", PrivateKey);
field_from_json(Obj, "CaCerts", CaCerts);
field_from_json(Obj, "AllowSelfSigned", AllowSelfSigned);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndPoint::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj, "Type", Type);
field_to_json(Obj, "RadsecServers", RadsecServers);
field_to_json(Obj, "RadiusServers", RadiusServers);
field_to_json(Obj, "PoolStrategy", PoolStrategy);
field_to_json(Obj, "Index", Index);
field_to_json(Obj, "UsedBy", UsedBy);
field_to_json(Obj, "UseGWProxy", UseGWProxy);
field_to_json(Obj, "NasIdentifier", NasIdentifier);
field_to_json(Obj, "AccountingInterval", AccountingInterval);
}
bool RADIUSEndPoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj, "Type", Type);
field_from_json(Obj, "RadsecServers", RadsecServers);
field_from_json(Obj, "RadiusServers", RadiusServers);
field_from_json(Obj, "PoolStrategy", PoolStrategy);
field_from_json(Obj, "Index", Index);
field_from_json(Obj, "UsedBy", UsedBy);
field_from_json(Obj, "UseGWProxy", UseGWProxy);
field_from_json(Obj, "NasIdentifier", NasIdentifier);
field_from_json(Obj, "AccountingInterval", AccountingInterval);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RADIUSEndpointUpdateStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "lastUpdate", lastUpdate);
field_to_json(Obj, "lastConfigurationChange", lastConfigurationChange);
}
bool RADIUSEndpointUpdateStatus::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "lastUpdate", lastUpdate);
field_from_json(Obj, "lastConfigurationChange", lastConfigurationChange);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool RADIUSEndpointUpdateStatus::Read() {
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
try {
if (F.exists()) {
Poco::JSON::Parser P;
std::ifstream ifs(F.path(), std::ios_base::in | std::ios_base::binary);
auto Obj = P.parse(ifs);
return from_json(Obj.extract<Poco::JSON::Object::Ptr>());
}
} catch (...) {
}
return false;
}
bool RADIUSEndpointUpdateStatus::Save() {
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
try {
Poco::JSON::Object Obj;
to_json(Obj);
std::ofstream O(F.path(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
Poco::JSON::Stringifier::stringify(Obj, O);
return true;
} catch (...) {
}
return false;
}
bool RADIUSEndpointUpdateStatus::ChangeConfiguration() {
Read();
lastConfigurationChange = Utils::Now();
return Save();
}
} // namespace OpenWifi::ProvObjects

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
#pragma once
#include <fstream>
#include <mutex>
#include <shared_mutex>
#include "framework/MicroServiceFuncs.h"
#include "framework/SubSystemServer.h"
@@ -38,7 +38,7 @@ namespace OpenWifi {
inline int Start() final {
poco_notice(Logger(), "Starting...");
std::lock_guard L(KeyMutex_);
std::shared_lock L(KeyMutex_);
CacheFilename_ = MicroServiceDataDirectory() + "/signature_cache";
Poco::File CacheFile(CacheFilename_);
@@ -91,7 +91,7 @@ namespace OpenWifi {
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
const std::string &Data) const {
std::lock_guard L(KeyMutex_);
std::shared_lock L(KeyMutex_);
try {
if (Restrictions.key_info.algo == "static") {
return "aaaaaaaaaa";
@@ -120,7 +120,7 @@ namespace OpenWifi {
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
const Poco::URI &uri) {
std::lock_guard L(KeyMutex_);
std::shared_lock L(KeyMutex_);
try {
if (Restrictions.key_info.algo == "static") {
return "aaaaaaaaaa";
@@ -172,7 +172,7 @@ namespace OpenWifi {
}
private:
mutable std::mutex KeyMutex_;
mutable std::shared_mutex KeyMutex_;
std::map<std::string, Poco::SharedPtr<Poco::Crypto::RSAKey>> Keys_;
std::map<std::string, std::string> SignatureCache_;
std::string CacheFilename_;

View File

@@ -119,8 +119,7 @@ namespace OpenWifi {
bool CreateDevice(GWObjects::Device &);
bool CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
std::string &Firmware, const Poco::Net::IPAddress &IPAddress,
bool simulated);
std::string &Firmware, const Poco::Net::IPAddress &IPAddress);
bool GetDevice(std::string &SerialNumber, GWObjects::Device &);
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices,
@@ -128,9 +127,6 @@ 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);
@@ -175,19 +171,6 @@ namespace OpenWifi {
uint64_t GetDefaultConfigurationsCount();
bool DefaultConfigurationAlreadyExists(std::string &Name);
bool UpdateDefaultFirmware(GWObjects::DefaultFirmware &DefFirmware);
bool CreateDefaultFirmware(GWObjects::DefaultFirmware &DefConfig);
bool DeleteDefaultFirmware(std::string &name);
bool GetDefaultFirmware(std::string &name, GWObjects::DefaultFirmware &DefConfig);
bool GetDefaultFirmwares(uint64_t From, uint64_t HowMany,
std::vector<GWObjects::DefaultFirmware> &Devices);
bool FindDefaultFirmwareForModel(const std::string &Model,
GWObjects::DefaultFirmware &DefConfig);
uint64_t GetDefaultFirmwaresCount();
bool DefaultFirmwareAlreadyExists(std::string &Name);
bool AddCommand(std::string &SerialNumber, GWObjects::CommandDetails &Command,
CommandExecutionType Type);
bool GetCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
@@ -237,16 +220,12 @@ namespace OpenWifi {
bool UpdateBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
uint64_t GetBlackListDeviceCount();
bool DeleteSimulatedDevice(const std::string &SerialNumber);
bool RemoveHealthChecksRecordsOlderThan(uint64_t Date);
bool RemoveDeviceLogsRecordsOlderThan(uint64_t Date);
bool RemoveStatisticsRecordsOlderThan(uint64_t Date);
bool RemoveCommandListRecordsOlderThan(uint64_t Date);
bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date);
bool SetDeviceLastRecordedContact(std::string & SeialNumber, std::uint64_t lastRecordedContact);
int Create_Tables();
int Create_Statistics();
int Create_Devices();
@@ -257,7 +236,6 @@ namespace OpenWifi {
int Create_CommandList();
int Create_BlackList();
int Create_FileUploads();
int Create_DefaultFirmwares();
bool AnalyzeCommands(Types::CountedMap &R);
bool AnalyzeDevices(GWObjects::Dashboard &D);

View File

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

View File

@@ -1,66 +0,0 @@
//
// Created by stephane bourque on 2023-07-12.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "Poco/ExpireLRUCache.h"
#include "sdks/sdk_fms.h"
namespace OpenWifi {
class FirmwareRevisionCache : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new FirmwareRevisionCache;
return instance_;
}
inline int Start() override {
poco_notice(Logger(), "Starting...");
return 0;
}
inline void Stop() override {
poco_notice(Logger(), "Stopping...");
poco_notice(Logger(), "Stopped...");
}
inline bool DeviceMustUpgrade([[maybe_unused]] std::string &deviceType,
[[maybe_unused]] const std::string &firmware_string,
[[maybe_unused]] GWObjects::DefaultFirmware &Firmware) {
return false;
if(StorageService()->GetDefaultFirmware(deviceType,Firmware)) {
std::string key{ deviceType + Firmware.revision };
if(!Cache_.has(key)) {
FMSObjects::FirmwareAgeDetails FAD;
if(SDK::FMS::GetFirmwareAge(deviceType,Firmware.revision,FAD,Logger())) {
Cache_.add(key,FAD);
} else {
// if we cannot establish the age of the currently running firmware,
// then we assume it is too old.
return true;
}
}
auto FAD = Cache_.get(key);
if(FAD->imageDate < Firmware.imageCreationDate) {
return true;
}
}
return false;
}
private:
Poco::ExpireLRUCache<std::string, FMSObjects::FirmwareAgeDetails> Cache_{
512, 1200000};
FirmwareRevisionCache() noexcept
: SubSystemServer("FirmwareRevisionCache", "FWCACHE-SVR", "firmwarecache") {
}
};
inline auto FirmwareRevisionCache() { return FirmwareRevisionCache::instance(); }
} // namespace OpenWifi

View File

@@ -26,7 +26,7 @@ namespace OpenWifi {
Response.set("Connection", "keep-alive");
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
std::ostream &Answer = Response.send();
Answer << ALBHealthCheckServer()->CallbackText();
Answer << "process Alive and kicking!";
} catch (...) {
}
}

View File

@@ -37,8 +37,6 @@ namespace OpenWifi {
inline static std::atomic_uint64_t req_id_ = 1;
};
typedef std::string ALBHealthMessageCallback();
class ALBHealthCheckServer : public SubSystemServer {
public:
ALBHealthCheckServer();
@@ -50,22 +48,10 @@ namespace OpenWifi {
int Start() override;
void Stop() override;
inline void RegisterExtendedHealthMessage(ALBHealthMessageCallback *F) {
Callback_=F;
};
inline std::string CallbackText() {
if(Callback_== nullptr) {
return "process Alive and kicking!";
} else {
return Callback_();
}
}
private:
std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
ALBHealthMessageCallback *Callback_= nullptr;
int Port_ = 0;
mutable std::atomic_bool Running_ = false;
};

View File

@@ -11,12 +11,10 @@
#include "Poco/File.h"
#include "Poco/StreamCopier.h"
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#include "framework/MicroServiceFuncs.h"
// #include "nlohmann/json.hpp"
#include "nlohmann/json.hpp"
namespace OpenWifi {
@@ -30,11 +28,11 @@ namespace OpenWifi {
if (F.exists()) {
std::ostringstream OS;
std::ifstream IF(FileName);
Poco::JSON::Parser P;
Registry_ = P.parse(IF).extract<Poco::JSON::Object::Ptr>();
Poco::StreamCopier::copyStream(IF, OS);
Registry_ = nlohmann::json::parse(OS.str());
}
} catch (...) {
Registry_ = Poco::makeShared<Poco::JSON::Object>();
Registry_ = nlohmann::json::parse("{}");
}
}
@@ -46,47 +44,54 @@ namespace OpenWifi {
inline ~AppServiceRegistry() { Save(); }
inline void Save() {
std::istringstream IS(to_string(Registry_));
std::ofstream OF;
OF.open(FileName, std::ios::binary | std::ios::trunc);
Registry_->stringify(OF);
Poco::StreamCopier::copyStream(IS, OF);
}
void Set(const char *key, const std::vector<std::string> &V) {
Poco::JSON::Array Arr;
for(const auto &s:V) {
Arr.add(s);
}
Registry_->set(key,Arr);
Save();
}
template<class T> void Set(const char *key, const T &Value) {
Registry_->set(key,Value);
inline void Set(const char *Key, uint64_t Value) {
Registry_[Key] = Value;
Save();
}
bool Get(const char *key, std::vector<std::string> &Value) {
if(Registry_->has(key) && !Registry_->isNull(key) && Registry_->isArray(key)) {
auto Arr = Registry_->get(key);
for(const auto &v:Arr) {
Value.emplace_back(v);
}
return true;
}
return false;
}
inline void Set(const char *Key, const std::string &Value) {
Registry_[Key] = Value;
Save();
}
template<class T> bool Get(const char *key, T &Value) {
if(Registry_->has(key) && !Registry_->isNull(key)) {
Value = Registry_->getValue<T>(key);
return true;
}
return false;
}
inline void Set(const char *Key, bool Value) {
Registry_[Key] = Value;
Save();
}
inline bool Get(const char *Key, bool &Value) {
if (Registry_[Key].is_boolean()) {
Value = Registry_[Key].get<bool>();
return true;
}
return false;
}
inline bool Get(const char *Key, uint64_t &Value) {
if (Registry_[Key].is_number_unsigned()) {
Value = Registry_[Key].get<uint64_t>();
return true;
}
return false;
}
inline bool Get(const char *Key, std::string &Value) {
if (Registry_[Key].is_string()) {
Value = Registry_[Key].get<std::string>();
return true;
}
return false;
}
private:
std::string FileName;
Poco::JSON::Object::Ptr Registry_;
nlohmann::json Registry_;
};
inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); }

View File

@@ -34,17 +34,9 @@ static std::string DefaultUCentralSchema = R"foo(
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"strict": {
"type": "boolean",
"default": false
},
"uuid": {
"type": "integer"
},
"public_ip_lookup": {
"type": "string",
"format": "uc-fqdn"
},
"unit": {
"$ref": "#/$defs/unit"
},
@@ -118,20 +110,6 @@ static std::string DefaultUCentralSchema = R"foo(
"random-password": {
"type": "boolean",
"default": false
},
"beacon-advertisement": {
"type": "object",
"properties": {
"device-name": {
"type": "boolean"
},
"device-serial": {
"type": "boolean"
},
"network-id": {
"type": "integer"
}
}
}
}
},
@@ -240,52 +218,6 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"interface.ssid.encryption": {
"type": "object",
"properties": {
"proto": {
"type": "string",
"enum": [
"none",
"owe",
"owe-transition",
"psk",
"psk2",
"psk-mixed",
"psk2-radius",
"wpa",
"wpa2",
"wpa-mixed",
"sae",
"sae-mixed",
"wpa3",
"wpa3-192",
"wpa3-mixed"
],
"examples": [
"psk2"
]
},
"key": {
"type": "string",
"maxLength": 63,
"minLength": 8
},
"ieee80211w": {
"type": "string",
"enum": [
"disabled",
"optional",
"required"
],
"default": "disabled"
},
"key-caching": {
"type": "boolean",
"default": true
}
}
},
"definitions": {
"type": "object",
"properties": {
@@ -702,6 +634,26 @@ 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\\}"
]
}
}
},
@@ -780,8 +732,7 @@ static std::string DefaultUCentralSchema = R"foo(
"type": "string",
"enum": [
"dynamic",
"static",
"none"
"static"
],
"examples": [
"static"
@@ -1071,6 +1022,52 @@ static std::string DefaultUCentralSchema = R"foo(
}
]
},
"interface.ssid.encryption": {
"type": "object",
"properties": {
"proto": {
"type": "string",
"enum": [
"none",
"owe",
"owe-transition",
"psk",
"psk2",
"psk-mixed",
"psk2-radius",
"wpa",
"wpa2",
"wpa-mixed",
"sae",
"sae-mixed",
"wpa3",
"wpa3-192",
"wpa3-mixed"
],
"examples": [
"psk2"
]
},
"key": {
"type": "string",
"maxLength": 63,
"minLength": 8
},
"ieee80211w": {
"type": "string",
"enum": [
"disabled",
"optional",
"required"
],
"default": "disabled"
},
"key-caching": {
"type": "boolean",
"default": true
}
}
},
"interface.ssid.multi-psk": {
"type": "object",
"properties": {
@@ -1235,32 +1232,6 @@ 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": {
@@ -1338,25 +1309,6 @@ 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"
}
]
}
]
}
@@ -1706,236 +1658,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"
}
}
}
]
},
"interface.ssid": {
"type": "object",
"properties": {
@@ -1988,10 +1710,6 @@ static std::string DefaultUCentralSchema = R"foo(
"isolate-clients": {
"type": "boolean"
},
"strict-forwarding": {
"type": "boolean",
"default": false
},
"power-save": {
"type": "boolean"
},
@@ -2039,11 +1757,6 @@ static std::string DefaultUCentralSchema = R"foo(
"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.",
"type": "string"
},
"tip-information-element": {
"decription": "The device will broadcast the TIP vendor IE inside its beacons if this option is enabled.",
"type": "boolean",
"default": true
},
"fils-discovery-interval": {
"type": "integer",
"default": 20,
@@ -2065,14 +1778,7 @@ static std::string DefaultUCentralSchema = R"foo(
"$ref": "#/$defs/interface.ssid.rate-limit"
},
"roaming": {
"anyOf": [
{
"$ref": "#/$defs/interface.ssid.roaming"
},
{
"type": "boolean"
}
]
"$ref": "#/$defs/interface.ssid.roaming"
},
"radius": {
"$ref": "#/$defs/interface.ssid.radius"
@@ -2089,9 +1795,6 @@ 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": {
@@ -2259,17 +1962,6 @@ static std::string DefaultUCentralSchema = R"foo(
]
}
},
"vlan-awareness": {
"type": "object",
"properties": {
"first": {
"type": "integer"
},
"last": {
"type": "integer"
}
}
},
"vlan": {
"$ref": "#/$defs/interface.vlan"
},
@@ -2392,10 +2084,6 @@ static std::string DefaultUCentralSchema = R"foo(
"examples": [
"01234567890123456789012345678901"
]
},
"mutual-tls": {
"type": "boolean",
"default": true
}
}
},
@@ -2467,24 +2155,6 @@ static std::string DefaultUCentralSchema = R"foo(
"type": "boolean",
"default": false
},
"mode": {
"type": "string",
"enum": [
"radius",
"user"
]
},
"port-filter": {
"type": "array",
"items": {
"type": "string",
"examples": [
{
"LAN1": null
}
]
}
},
"server-certificate": {
"type": "string"
},
@@ -2496,77 +2166,6 @@ static std::string DefaultUCentralSchema = R"foo(
"items": {
"$ref": "#/$defs/interface.ssid.radius.local-user"
}
},
"radius": {
"type": "object",
"properties": {
"nas-identifier": {
"type": "string"
},
"auth-server-addr": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"auth-server-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"examples": [
1812
]
},
"auth-server-secret": {
"type": "string",
"examples": [
"secret"
]
},
"acct-server-addr": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"acct-server-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"examples": [
1813
]
},
"acct-server-secret": {
"type": "string",
"examples": [
"secret"
]
},
"coa-server-addr": {
"type": "string",
"format": "uc-host",
"examples": [
"192.168.1.10"
]
},
"coa-server-port": {
"type": "integer",
"maximum": 65535,
"minimum": 1024,
"examples": [
1814
]
},
"coa-server-secret": {
"type": "string",
"examples": [
"secret"
]
}
}
}
}
},
@@ -2890,12 +2489,6 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"services": {
"type": "array",
"items": {
"type": "string"
}
},
"classifier": {
"type": "array",
"items": {
@@ -3100,6 +2693,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"
}
}
}
]
},
"service.gps": {
"type": "object",
"properties": {
@@ -3118,50 +2941,6 @@ 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"
},
"circuit-id-format": {
"type": "string",
"enum": [
"vlan-id",
"ap-mac",
"ssid"
],
"default": "vlan-id"
},
"remote-id-format": {
"type": "string",
"enum": [
"vlan-id",
"ap-mac",
"ssid"
],
"default": "ap-mac"
}
}
}
}
}
},
"service": {
"type": "object",
"properties": {
@@ -3221,9 +3000,6 @@ static std::string DefaultUCentralSchema = R"foo(
},
"gps": {
"$ref": "#/$defs/service.gps"
},
"dhcp-relay": {
"$ref": "#/$defs/service.dhcp-relay"
}
}
},

View File

@@ -14,18 +14,18 @@ namespace OpenWifi {
void EventBusManager::run() {
Running_ = true;
Utils::SetThreadName("fmwk:EventMgr");
auto Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN));
auto Msg = 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 = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(),
Msg, false);
}
Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE));
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
false);
};

View File

@@ -6,7 +6,6 @@
#include "fmt/format.h"
#include "framework/MicroServiceFuncs.h"
#include "cppkafka/utils/consumer_dispatcher.h"
namespace OpenWifi {
@@ -100,12 +99,9 @@ namespace OpenWifi {
try {
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
if (Msg != nullptr) {
auto NewMessage = cppkafka::MessageBuilder(Msg->Topic());
NewMessage.key(Msg->Key());
NewMessage.partition(0);
NewMessage.payload(Msg->Payload());
Producer.produce(NewMessage);
Producer.flush();
Producer.produce(cppkafka::MessageBuilder(Msg->Topic())
.key(Msg->Key())
.payload(Msg->Payload()));
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,
@@ -160,49 +156,43 @@ namespace OpenWifi {
}
});
// bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false);
// auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 100);
bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false);
auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 20);
Types::StringVec Topics;
std::for_each(Topics_.begin(),Topics_.end(),
[&](const std::string & T) { Topics.emplace_back(T); });
KafkaManager()->Topics(Topics);
Consumer.subscribe(Topics);
Running_ = true;
std::vector<cppkafka::Message> MsgVec;
Dispatcher_ = std::make_unique<cppkafka::ConsumerDispatcher>(Consumer);
Dispatcher_->run(
// Callback executed whenever a new message is consumed
[&](cppkafka::Message msg) {
// Print the key (if any)
std::lock_guard G(ConsumerMutex_);
auto It = Notifiers_.find(msg.get_topic());
if (It != Notifiers_.end()) {
const auto &FL = It->second;
for (const auto &[CallbackFunc, _] : FL) {
try {
CallbackFunc(msg.get_key(), msg.get_payload());
} catch(const Poco::Exception &E) {
} catch(...) {
while (Running_) {
try {
std::vector<cppkafka::Message> MsgVec =
Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100));
for (auto const &Msg : MsgVec) {
if (!Msg)
continue;
if (Msg.get_error()) {
if (!Msg.is_eof()) {
poco_error(Logger_,
fmt::format("Error: {}", Msg.get_error().to_string()));
}
if (!AutoCommit)
Consumer.async_commit(Msg);
continue;
}
KafkaManager()->Dispatch(Msg.get_topic(), Msg.get_key(), Msg.get_payload());
if (!AutoCommit)
Consumer.async_commit(Msg);
}
Consumer.commit(msg);
},
// Whenever there's an error (other than the EOF soft error)
[&Logger_](cppkafka::Error error) {
poco_warning(Logger_,fmt::format("Error: {}", error.to_string()));
},
// Whenever EOF is reached on a partition, print this
[&Logger_](cppkafka::ConsumerDispatcher::EndOfFile, const cppkafka::TopicPartition& topic_partition) {
poco_debug(Logger_,fmt::format("Partition {} EOF", topic_partition.get_partition()));
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,
fmt::format("Caught a Kafka exception (consumer): {}", E.what()));
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_error(Logger_, "std::exception");
}
);
}
Consumer.unsubscribe();
poco_information(Logger_, "Stopped...");
}
@@ -222,7 +212,7 @@ namespace OpenWifi {
}
}
void KafkaProducer::Produce(const char *Topic, const std::string &Key,
void KafkaProducer::Produce(const std::string &Topic, const std::string &Key,
const std::string &Payload) {
std::lock_guard G(Mutex_);
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
@@ -230,6 +220,7 @@ namespace OpenWifi {
void KafkaConsumer::Start() {
if (!Running_) {
Running_ = true;
Worker_.start(*this);
}
}
@@ -237,16 +228,29 @@ namespace OpenWifi {
void KafkaConsumer::Stop() {
if (Running_) {
Running_ = false;
if(Dispatcher_) {
Dispatcher_->stop();
}
Worker_.wakeUp();
Worker_.join();
}
}
std::uint64_t KafkaConsumer::RegisterTopicWatcher(const std::string &Topic,
void KafkaDispatcher::Start() {
if (!Running_) {
Running_ = true;
Worker_.start(*this);
}
}
void KafkaDispatcher::Stop() {
if (Running_) {
Running_ = false;
Queue_.wakeUpAll();
Worker_.join();
}
}
auto KafkaDispatcher::RegisterTopicWatcher(const std::string &Topic,
Types::TopicNotifyFunction &F) {
std::lock_guard G(ConsumerMutex_);
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if (It == Notifiers_.end()) {
Types::TopicNotifyFunctionList L;
@@ -255,12 +259,11 @@ namespace OpenWifi {
} else {
It->second.emplace(It->second.end(), std::make_pair(F, FunctionId_));
}
Topics_.insert(Topic);
return FunctionId_++;
}
void KafkaConsumer::UnregisterTopicWatcher(const std::string &Topic, int Id) {
std::lock_guard G(ConsumerMutex_);
void KafkaDispatcher::UnregisterTopicWatcher(const std::string &Topic, int Id) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if (It != Notifiers_.end()) {
Types::TopicNotifyFunctionList &L = It->second;
@@ -272,17 +275,56 @@ namespace OpenWifi {
}
}
void KafkaDispatcher::Dispatch(const std::string &Topic, const std::string &Key,
const std::string &Payload) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if (It != Notifiers_.end()) {
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
}
}
void KafkaDispatcher::run() {
Poco::Logger &Logger_ =
Poco::Logger::create("KAFKA-DISPATCHER", KafkaManager()->Logger().getChannel());
poco_information(Logger_, "Starting...");
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
Utils::SetThreadName("kafka:dispatch");
while (Note && Running_) {
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
if (Msg != nullptr) {
auto It = Notifiers_.find(Msg->Topic());
if (It != Notifiers_.end()) {
const auto &FL = It->second;
for (const auto &[CallbackFunc, _] : FL) {
CallbackFunc(Msg->Key(), Msg->Payload());
}
}
}
Note = Queue_.waitDequeueNotification();
}
poco_information(Logger_, "Stopped...");
}
void KafkaDispatcher::Topics(std::vector<std::string> &T) {
T.clear();
for (const auto &[TopicName, _] : Notifiers_)
T.push_back(TopicName);
}
int KafkaManager::Start() {
if (!KafkaEnabled_)
return 0;
ConsumerThr_.Start();
ProducerThr_.Start();
Dispatcher_.Start();
return 0;
}
void KafkaManager::Stop() {
if (KafkaEnabled_) {
poco_information(Logger(), "Stopping...");
Dispatcher_.Stop();
ProducerThr_.Stop();
ConsumerThr_.Stop();
poco_information(Logger(), "Stopped...");
@@ -290,27 +332,39 @@ namespace OpenWifi {
}
}
void KafkaManager::PostMessage(const char *topic, const std::string &key,
const std::string & PayLoad, bool WrapMessage) {
void KafkaManager::PostMessage(const std::string &topic, const std::string &key,
const std::string &PayLoad, bool WrapMessage) {
if (KafkaEnabled_) {
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
}
}
void KafkaManager::PostMessage(const char *topic, const std::string &key,
const Poco::JSON::Object &Object, bool WrapMessage) {
void KafkaManager::Dispatch(const std::string &Topic, const std::string &Key,
const std::string &Payload) {
Dispatcher_.Dispatch(Topic, Key, Payload);
}
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string &PayLoad) {
return SystemInfoWrapper_ + PayLoad + "}";
}
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic,
Types::TopicNotifyFunction &F) {
if (KafkaEnabled_) {
std::ostringstream ObjectStr;
Object.stringify(ObjectStr);
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(ObjectStr.str()) : ObjectStr.str());
return Dispatcher_.RegisterTopicWatcher(Topic, F);
} else {
return 0;
}
}
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
return fmt::format( R"lit({{ "system" : {{ "id" : {}, "host" : "{}" }}, "payload" : {} }})lit",
MicroServiceID(), MicroServicePrivateEndPoint(), PayLoad ) ;
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
if (KafkaEnabled_) {
Dispatcher_.UnregisterTopicWatcher(Topic, Id);
}
}
void KafkaManager::Topics(std::vector<std::string> &T) { Dispatcher_.Topics(T); }
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList &partitions) {
poco_information(
Logger(), fmt::format("Partition assigned: {}...", partitions.front().get_partition()));

View File

@@ -6,7 +6,7 @@
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
#include "Poco/JSON/Object.h"
#include "framework/KafkaTopics.h"
#include "framework/OpenWifiTypes.h"
#include "framework/SubSystemServer.h"
@@ -18,15 +18,15 @@ namespace OpenWifi {
class KafkaMessage : public Poco::Notification {
public:
KafkaMessage(const char * Topic, const std::string &Key, const std::string &Payload)
KafkaMessage(const std::string &Topic, const std::string &Key, const std::string &Payload)
: Topic_(Topic), Key_(Key), Payload_(Payload) {}
inline const char * Topic() { return Topic_; }
inline const std::string &Topic() { return Topic_; }
inline const std::string &Key() { return Key_; }
inline const std::string &Payload() { return Payload_; }
private:
const char *Topic_;
std::string Topic_;
std::string Key_;
std::string Payload_;
};
@@ -36,10 +36,10 @@ namespace OpenWifi {
void run() override;
void Start();
void Stop();
void Produce(const char *Topic, const std::string &Key, const std::string & Payload);
void Produce(const std::string &Topic, const std::string &Key, const std::string &Payload);
private:
std::mutex Mutex_;
std::recursive_mutex Mutex_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_ = false;
Poco::NotificationQueue Queue_;
@@ -47,22 +47,33 @@ namespace OpenWifi {
class KafkaConsumer : public Poco::Runnable {
public:
void run() override;
void Start();
void Stop();
private:
std::mutex ConsumerMutex_;
Types::NotifyTable Notifiers_;
Poco::Thread Worker_;
std::recursive_mutex Mutex_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_ = false;
uint64_t FunctionId_ = 1;
std::unique_ptr<cppkafka::ConsumerDispatcher> Dispatcher_;
std::set<std::string> Topics_;
};
void run() override;
friend class KafkaManager;
std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
class KafkaDispatcher : public Poco::Runnable {
public:
void Start();
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 run() override;
void Topics(std::vector<std::string> &T);
private:
std::recursive_mutex Mutex_;
Types::NotifyTable Notifiers_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_ = false;
uint64_t FunctionId_ = 1;
Poco::NotificationQueue Queue_;
};
class KafkaManager : public SubSystemServer {
@@ -80,25 +91,21 @@ namespace OpenWifi {
int Start() override;
void Stop() override;
void PostMessage(const char *topic, const std::string &key,
void PostMessage(const std::string &topic, const std::string &key,
const std::string &PayLoad, bool WrapMessage = true);
void PostMessage(const char *topic, const std::string &key,
const Poco::JSON::Object &Object, bool WrapMessage = true);
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
[[nodiscard]] std::string WrapSystemId(const std::string &PayLoad);
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
inline std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
return ConsumerThr_.RegisterTopicWatcher(Topic,F);
}
inline void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
return ConsumerThr_.UnregisterTopicWatcher(Topic,Id);
}
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);
void Topics(std::vector<std::string> &T);
private:
bool KafkaEnabled_ = false;
std::string SystemInfoWrapper_;
KafkaProducer ProducerThr_;
KafkaConsumer ConsumerThr_;
KafkaDispatcher Dispatcher_;
void PartitionAssignment(const cppkafka::TopicPartitionList &partitions);
void PartitionRevocation(const cppkafka::TopicPartitionList &partitions);

View File

@@ -10,33 +10,32 @@
#include <string>
namespace OpenWifi::KafkaTopics {
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";
inline const char * RRM = "rrm";
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"};
namespace ServiceEvents {
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";
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"};
namespace Fields {
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";
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"};
} // namespace Fields
} // namespace ServiceEvents
} // namespace OpenWifi::KafkaTopics

View File

@@ -129,8 +129,6 @@ namespace OpenWifi {
}
} else {
poco_error(logger(), "Bad bus message.");
std::ostringstream os;
Object->stringify(std::cout);
}
auto i = Services_.begin();

View File

@@ -5,8 +5,6 @@
#include "framework/MicroServiceFuncs.h"
#include "framework/MicroService.h"
#include "framework/ALBserver.h"
namespace OpenWifi {
const std::string &MicroServiceDataDirectory() { return MicroService::instance().DataDir(); }
@@ -49,11 +47,11 @@ namespace OpenWifi {
void MicroServiceReload(const std::string &Type) { MicroService::instance().Reload(Type); }
Types::StringVec MicroServiceGetLogLevelNames() {
const Types::StringVec MicroServiceGetLogLevelNames() {
return MicroService::instance().GetLogLevelNames();
}
Types::StringVec MicroServiceGetSubSystems() {
const Types::StringVec MicroServiceGetSubSystems() {
return MicroService::instance().GetSubSystems();
}
@@ -81,7 +79,7 @@ namespace OpenWifi {
std::string MicroServiceGetUIURI() { return MicroService::instance().GetUIURI(); }
SubSystemVec MicroServiceGetFullSubSystems() {
const SubSystemVec MicroServiceGetFullSubSystems() {
return MicroService::instance().GetFullSubSystems();
}
@@ -89,7 +87,7 @@ namespace OpenWifi {
std::uint64_t MicroServiceDaemonBusTimer() { return MicroService::instance().DaemonBusTimer(); }
std::string MicroServiceMakeSystemEventMessage(const char *Type) {
std::string MicroServiceMakeSystemEventMessage(const std::string &Type) {
return MicroService::instance().MakeSystemEventMessage(Type);
}
@@ -125,12 +123,4 @@ namespace OpenWifi {
return MicroService::instance().AllowExternalMicroServices();
}
void MicroServiceALBCallback( std::string Callback()) {
return ALBHealthCheckServer()->RegisterExtendedHealthMessage(Callback);
}
std::string MicroServiceAccessKey() {
return MicroService::instance().Hash();
}
} // namespace OpenWifi

View File

@@ -22,7 +22,6 @@ namespace OpenWifi {
std::string MicroServicePublicEndPoint();
std::string MicroServiceConfigGetString(const std::string &Key,
const std::string &DefaultValue);
std::string MicroServiceAccessKey();
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue);
std::string MicroServicePrivateEndPoint();
@@ -32,8 +31,8 @@ namespace OpenWifi {
void MicroServiceLoadConfigurationFile();
void MicroServiceReload();
void MicroServiceReload(const std::string &Type);
Types::StringVec MicroServiceGetLogLevelNames();
Types::StringVec MicroServiceGetSubSystems();
const Types::StringVec MicroServiceGetLogLevelNames();
const Types::StringVec MicroServiceGetSubSystems();
Types::StringPairVec MicroServiceGetLogLevels();
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer);
@@ -41,10 +40,10 @@ namespace OpenWifi {
std::uint64_t MicroServiceUptimeTotalSeconds();
std::uint64_t MicroServiceStartTimeEpochTime();
std::string MicroServiceGetUIURI();
SubSystemVec MicroServiceGetFullSubSystems();
const SubSystemVec MicroServiceGetFullSubSystems();
std::string MicroServiceCreateUUID();
std::uint64_t MicroServiceDaemonBusTimer();
std::string MicroServiceMakeSystemEventMessage(const char *Type);
std::string MicroServiceMakeSystemEventMessage(const std::string &Type);
Poco::ThreadPool &MicroServiceTimerPool();
std::string MicroServiceConfigPath(const std::string &Key, const std::string &DefaultValue);
std::string MicroServiceWWWAssetsDir();
@@ -54,5 +53,4 @@ namespace OpenWifi {
std::string MicroServiceGetPublicAPIEndPoint();
void MicroServiceDeleteOverrideConfiguration();
bool AllowExternalMicroServices();
void MicroServiceALBCallback( std::string Callback());
} // namespace OpenWifi

View File

@@ -28,9 +28,6 @@ namespace OpenWifi::Types {
typedef std::string UUID_t;
typedef std::vector<UUID_t> UUIDvec_t;
typedef std::map<std::string, std::map<uint32_t, uint64_t>> Counted3DMapSII;
typedef std::vector<int64_t> IntList;
typedef std::vector<uint64_t> UIntList;
typedef std::vector<double> DoubleList;
struct MicroServiceMeta {
uint64_t Id = 0;

View File

@@ -574,37 +574,7 @@ namespace OpenWifi {
Poco::JSON::Stringifier::stringify(Object, Answer);
}
inline void ReturnObject(const std::vector<std::string> &Strings) {
Poco::JSON::Array Arr;
for(const auto &String:Strings) {
Arr.add(String);
}
std::ostringstream os;
Arr.stringify(os);
return ReturnRawJSON(os.str());
}
template<class T> void ReturnObject(const std::vector<T> &Objects) {
Poco::JSON::Array Arr;
for(const auto &Object:Objects) {
Poco::JSON::Object O;
Object.to_json(O);
Arr.add(O);
}
std::ostringstream os;
Arr.stringify(os);
return ReturnRawJSON(os.str());
}
template<class T> void ReturnObject(const T &Object) {
Poco::JSON::Object O;
Object.to_json(O);
std::ostringstream os;
O.stringify(os);
return ReturnRawJSON(os.str());
}
inline void ReturnRawJSON(const std::string &json_doc) {
inline void ReturnRawJSON(const std::string &json_doc) {
PrepareResponse();
if (Request != nullptr) {
// can we compress ???

View File

@@ -24,63 +24,50 @@ namespace OpenWifi {
Server, TransactionId, Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/system"}; }
inline void DoGet() final {
inline void DoGet() {
std::string Arg;
if (HasParameter("command", Arg)) {
if (Arg == "info") {
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
if (HasParameter("command", Arg) && Arg == "info") {
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
Poco::JSON::Array Certificates;
auto SubSystems = MicroServiceGetFullSubSystems();
std::set<std::string> CertNames;
Poco::JSON::Array Certificates;
auto SubSystems = MicroServiceGetFullSubSystems();
std::set<std::string> CertNames;
for (const auto &i : SubSystems) {
auto Hosts = i->HostSize();
for (uint64_t j = 0; j < Hosts; ++j) {
auto CertFileName = i->Host(j).CertFile();
if (!CertFileName.empty()) {
Poco::File F1(CertFileName);
if (F1.exists()) {
auto InsertResult = CertNames.insert(CertFileName);
if (InsertResult.second) {
Poco::JSON::Object Inner;
Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
Certificates.add(Inner);
}
for (const auto &i : SubSystems) {
auto Hosts = i->HostSize();
for (uint64_t j = 0; j < Hosts; ++j) {
auto CertFileName = i->Host(j).CertFile();
if (!CertFileName.empty()) {
Poco::File F1(CertFileName);
if (F1.exists()) {
auto InsertResult = CertNames.insert(CertFileName);
if (InsertResult.second) {
Poco::JSON::Object Inner;
Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
Certificates.add(Inner);
}
}
}
}
Answer.set("certificates", Certificates);
return ReturnObject(Answer);
}
if (Arg == "extraConfiguration") {
Poco::JSON::Object Answer;
MicroServiceGetExtraConfiguration(Answer);
return ReturnObject(Answer);
}
if (Arg == "resources") {
Poco::JSON::Object Answer;
Answer.set("numberOfFileDescriptors", Utils::get_open_fds());
std::uint64_t currRealMem, peakRealMem, currVirtMem, peakVirtMem;
Utils::getMemory(currRealMem, peakRealMem, currVirtMem, peakVirtMem);
Answer.set("currRealMem", currRealMem);
Answer.set("peakRealMem", peakRealMem);
Answer.set("currVirtMem", currVirtMem);
Answer.set("peakVirtMem", peakVirtMem);
return ReturnObject(Answer);
}
Answer.set("certificates", Certificates);
return ReturnObject(Answer);
}
if (GetBoolParameter("extraConfiguration")) {
Poco::JSON::Object Answer;
MicroServiceGetExtraConfiguration(Answer);
return ReturnObject(Answer);
}
BadRequest(RESTAPI::Errors::InvalidCommand);
}

View File

@@ -14,15 +14,8 @@
#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;
@@ -102,20 +95,6 @@ namespace OpenWifi::RESTAPI_utils {
Obj.set(Field, A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::DoubleList &V) {
Poco::JSON::Array A;
for (const auto &i : V)
A.add(i);
Obj.set(Field, A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::IntList &V) {
Poco::JSON::Array A;
for (const auto &i : V)
A.add(i);
Obj.set(Field, A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::TagList &V) {
Poco::JSON::Array A;
for (const auto &i : V)
@@ -298,28 +277,6 @@ namespace OpenWifi::RESTAPI_utils {
}
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
Types::DoubleList &Value) {
if (Obj->isArray(Field) && !Obj->isNull(Field)) {
Value.clear();
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
for (const auto &i : *A) {
Value.push_back(i);
}
}
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
Types::IntList &Value) {
if (Obj->isArray(Field) && !Obj->isNull(Field)) {
Value.clear();
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
for (const auto &i : *A) {
Value.push_back(i);
}
}
}
template <class T>
void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
std::vector<T> &Value) {

View File

@@ -22,8 +22,9 @@ namespace OpenWifi {
class StorageClass : public SubSystemServer {
public:
StorageClass() noexcept : SubSystemServer("StorageClass", "STORAGE-SVR", "storage") {}
inline int Start() override {
int Start() override {
std::lock_guard Guard(Mutex_);
Logger().notice("Starting.");
@@ -39,22 +40,17 @@ namespace OpenWifi {
return 0;
}
inline void Stop() override { Pool_->shutdown(); }
void Stop() override { Pool_->shutdown(); }
DBType Type() const { return dbType_; };
StorageClass() noexcept : SubSystemServer("StorageClass", "STORAGE-SVR", "storage") {
}
private:
inline int Setup_SQLite();
inline int Setup_MySQL();
inline int Setup_PostgreSQL();
protected:
std::shared_ptr<Poco::Data::SessionPool> Pool_;
protected:
std::unique_ptr<Poco::Data::SessionPool> Pool_;
Poco::Data::SQLite::Connector SQLiteConn_;
Poco::Data::PostgreSQL::Connector PostgresConn_;
Poco::Data::MySQL::Connector MySQLConn_;
@@ -85,7 +81,7 @@ namespace OpenWifi {
// Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8,
// (int)NumSessions,
// (int)IdleTime));
Pool_ = std::make_shared<Poco::Data::SessionPool>(SQLiteConn_.name(), DBName, 8,
Pool_ = std::make_unique<Poco::Data::SessionPool>(SQLiteConn_.name(), DBName, 8,
(int)NumSessions, (int)IdleTime);
return 0;
}
@@ -106,7 +102,7 @@ namespace OpenWifi {
";compress=true;auto-reconnect=true";
Poco::Data::MySQL::Connector::registerConnector();
Pool_ = std::make_shared<Poco::Data::SessionPool>(MySQLConn_.name(), ConnectionStr, 8,
Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_.name(), ConnectionStr, 8,
NumSessions, IdleTime);
return 0;
@@ -130,7 +126,7 @@ namespace OpenWifi {
" connect_timeout=" + ConnectionTimeout;
Poco::Data::PostgreSQL::Connector::registerConnector();
Pool_ = std::make_shared<Poco::Data::SessionPool>(PostgresConn_.name(), ConnectionStr, 8,
Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_.name(), ConnectionStr, 8,
NumSessions, IdleTime);
return 0;

View File

@@ -37,7 +37,6 @@ namespace OpenWifi {
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
P.caLocation = cas_;
// P.securityLevel =
auto Context = Poco::AutoPtr<Poco::Net::Context>(
new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
@@ -54,6 +53,7 @@ namespace OpenWifi {
Context->useCertificate(Cert);
Context->addChainCertificate(Root);
Context->addCertificateAuthority(Root);
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
@@ -76,18 +76,18 @@ namespace OpenWifi {
L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_));
}
SSL_CTX_set_verify(SSLCtx, level_==Poco::Net::Context::VERIFY_NONE ? SSL_VERIFY_NONE : SSL_VERIFY_PEER, nullptr);
SSL_CTX_set_verify(SSLCtx, SSL_VERIFY_PEER, nullptr);
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
SSL_CTX_set_client_CA_list(SSLCtx, SSL_load_client_CA_file(client_cas_.c_str()));
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
}
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
SSL_CTX_dane_enable(SSLCtx);
Context->enableSessionCache();
Context->setSessionCacheSize(0);
Context->setSessionTimeout(60);
Context->enableExtendedCertificateVerification( level_!= Poco::Net::Context::VERIFY_NONE );
Context->enableExtendedCertificateVerification(true);
Context->disableStatelessSessionResumption();
}

View File

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

View File

@@ -40,7 +40,6 @@ namespace OpenWifi {
};
}
#define DBGLINE std::cout << __LINE__ << ":" << __FILE__ << ", " << __func__ << std::endl;
namespace OpenWifi::RESTAPI::Errors {
struct msg {
uint64_t err_num;
@@ -398,49 +397,6 @@ 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 VenuesNameAlreadyExists {
1172, "The venue name already exists."
};
static const struct msg InvalidGlobalReachAccount {
1173, "Invalid Global Reach account information."
};
static const struct msg CannotCreateCSR {
1174, "Cannot create a CSR certificate."
};
static const struct msg DefFirmwareNameExists { 1175, "Firmware name already exists." };
static const struct msg NotAValidECKey { 1176, "Not a valid Signing Key." };
static const struct msg NotAValidRadiusPoolType { 1177, "Not a valid RADIUS pool type." };
static const struct msg InvalidRadiusTypeEndpoint { 1178, "Invalid RADIUS Server Endpoint type." };
static const struct msg InvalidRadiusEndpointPoolStrategy { 1179, "Invalid RADIUS Server Endpoint Pool strategy." };
static const struct msg EndpointMustHaveOneTypeOfServers { 1180, "All servers must be either RADIUS or RADSEC." };
static const struct msg RadiusEndpointIndexInvalid { 1181, "Index must be an address between 0.0.1.1 and 0.0.2.254" };
static const struct msg RadiusEndpointIndexMustBeUnique { 1182, "Index must be unique." };
static const struct msg OrionAccountMustExist { 1183, "Orion account must exist." };
static const struct msg GlobalReachCertMustExist { 1184, "Global Reach certificate must exist." };
static const struct msg InvalidRadsecMainCertificate { 1185, "Invalid Radsec main certificate." };
static const struct msg InvalidRadsecCaCertificate { 1186, "Invalid Radsec CA certificates." };
static const struct msg InvalidRadsecPrivteKey { 1187, "Invalid Radsec Private key." };
static const struct msg InvalidRadsecIPAddress { 1188, "Invalid Radsec IP Address." };
static const struct msg InvalidRadsecPort { 1189, "Invalid Radsec Port." };
static const struct msg InvalidRadsecSecret { 1190, "Invalid Radsec Secret." };
static const struct msg InvalidRadiusServer { 1191, "Invalid Radius Server." };
static const struct msg InvalidRRMAction { 1192, "Invalid RRM Action." };
static const struct msg SimulationDoesNotExist {
7000, "Simulation Instance ID does not exist."
};
static const struct msg SimulationIsAlreadyRunning {
7001, "There is an instance of this simulation already running.."
};
} // namespace OpenWifi::RESTAPI::Errors
@@ -563,10 +519,6 @@ namespace OpenWifi::RESTAPI::Protocol {
static const char *CONTENTDISPOSITION = "Content-Disposition";
static const char *CONTENTTYPE = "Content-Type";
static const char *TRANSFER = "transfer";
static const char *CERTUPDATE = "certupdate";
static const char *RRM = "rrm";
static const char *REQUIREMENTS = "requirements";
static const char *PASSWORDPATTERN = "passwordPattern";
static const char *ACCESSPOLICY = "accessPolicy";
@@ -602,7 +554,6 @@ 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";
@@ -661,8 +612,6 @@ 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";
@@ -684,12 +633,6 @@ namespace OpenWifi::uCentralProtocol {
static const char *RADIUSCOA = "coa";
static const char *RADIUSDST = "dst";
static const char *IES = "ies";
static const char *TRANSFER = "transfer";
static const char *CERTUPDATE = "certupdate";
static const char *RRM = "rrm";
static const char *ACTIONS = "actions";
} // namespace OpenWifi::uCentralProtocol
namespace OpenWifi::uCentralProtocol::Events {
@@ -699,7 +642,6 @@ 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";
@@ -723,8 +665,7 @@ namespace OpenWifi::uCentralProtocol::Events {
ET_VENUEBROADCAST,
ET_EVENT,
ET_WIFISCAN,
ET_ALARM,
ET_REBOOTLOG
ET_ALARM
};
inline EVENT_MSG EventFromString(const std::string &Method) {
@@ -755,10 +696,8 @@ 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_ALARM;
else if (strcmp(REBOOTLOG, Method.c_str()) == 0)
return ET_REBOOTLOG;
return ET_UNKNOWN;
return ET_WIFISCAN;
return ET_ALARM;
};
} // namespace OpenWifi::uCentralProtocol::Events
@@ -782,9 +721,6 @@ namespace OpenWifi::APCommands {
telemetry,
ping,
script,
rrm,
certupdate,
transfer,
unknown
};
@@ -797,10 +733,7 @@ namespace OpenWifi::APCommands {
RESTAPI::Protocol::LEDS, RESTAPI::Protocol::TRACE,
RESTAPI::Protocol::REQUEST, RESTAPI::Protocol::WIFISCAN,
RESTAPI::Protocol::EVENTQUEUE, RESTAPI::Protocol::TELEMETRY,
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT,
RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE,
RESTAPI::Protocol::TRANSFER
};
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT};
inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }

View File

@@ -3,19 +3,10 @@
//
#include "Poco/Path.h"
#include "Poco/TemporaryFile.h"
#include "Poco/Crypto/ECKey.h"
#include "framework/AppServiceRegistry.h"
#include "framework/utils.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <algorithm>
#include <resolv.h>
namespace OpenWifi::Utils {
bool NormalizeMac(std::string &Mac) {
@@ -36,10 +27,6 @@ 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;
@@ -141,15 +128,6 @@ namespace OpenWifi::Utils {
return std::regex_match(Hostname, HostNameRegex);
}
[[nodiscard]] bool ValidNumber(const std::string &number, bool isSigned)
{
static std::regex IntRegex("^-?[0-9]\\d*(\\.\\d+)?$");
if(!isSigned) {
IntRegex = "^[0-9]\\d*(\\.\\d+)?$";
}
return std::regex_match(number, IntRegex);
}
[[nodiscard]] std::string ToHex(const std::vector<unsigned char> &B) {
std::string R;
R.reserve(B.size() * 2);
@@ -617,329 +595,4 @@ namespace OpenWifi::Utils {
return DT.timestamp().epochTime();
}
static std::string FileToString(const std::string &Filename) {
std::ifstream ifs(Filename.c_str(),std::ios_base::in|std::ios_base::binary);
std::ostringstream os;
Poco::StreamCopier::copyStream(ifs,os);
return os.str();
}
bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results) {
int ret = 0;
RSA *r = nullptr;
BIGNUM *bne = nullptr;
int nVersion = 0;
unsigned long e = RSA_F4;
X509_REQ *x509_req = nullptr;
X509_NAME *x509_name = nullptr;
EVP_PKEY *pKey = nullptr;
// RSA *tem = nullptr;
// BIO *bio_err = nullptr;
const char *szCountry = Parameters.Country.c_str();
const char *szProvince = Parameters.Province.c_str();
const char *szCity = Parameters.City.c_str();
const char *szOrganization = Parameters.Organization.c_str();
const char *szCommon = Parameters.CommonName.c_str();
Poco::TemporaryFile CsrPath, PubKey, PrivateKey;
std::string Result;
std::ifstream ifs;
std::ostringstream ss;
BIO *bp_public = nullptr,
*bp_private = nullptr,
*bp_csr = nullptr;
// 1. generate rsa key
bne = BN_new();
ret = BN_set_word(bne,e);
if(ret != 1){
goto free_all;
}
r = RSA_new();
ret = RSA_generate_key_ex(r, Parameters.bits, bne, nullptr);
if(ret != 1){
goto free_all;
}
bp_public = BIO_new_file(PubKey.path().c_str(), "w+");
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
if(ret != 1) {
goto free_all;
}
bp_private = BIO_new_file(PrivateKey.path().c_str(), "w+");
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
if(ret != 1) {
goto free_all;
}
// 2. set version of x509 req
x509_req = X509_REQ_new();
ret = X509_REQ_set_version(x509_req, nVersion);
if (ret != 1){
goto free_all;
}
// 3. set subject of x509 req
x509_name = X509_REQ_get_subject_name(x509_req);
ret = X509_NAME_add_entry_by_txt(x509_name,"C", MBSTRING_ASC, (const unsigned char*)szCountry, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"ST", MBSTRING_ASC, (const unsigned char*)szProvince, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"L", MBSTRING_ASC, (const unsigned char*)szCity, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"O", MBSTRING_ASC, (const unsigned char*)szOrganization, -1, -1, 0);
if (ret != 1){
goto free_all;
}
ret = X509_NAME_add_entry_by_txt(x509_name,"CN", MBSTRING_ASC, (const unsigned char*)szCommon, -1, -1, 0);
if (ret != 1){
goto free_all;
}
// 4. set public key of x509 req
pKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pKey, r);
r = nullptr; // will be free rsa when EVP_PKEY_free(pKey)
ret = X509_REQ_set_pubkey(x509_req, pKey);
if (ret != 1){
goto free_all;
}
// 5. set sign key of x509 req
ret = X509_REQ_sign(x509_req, pKey, EVP_sha1()); // return x509_req->signature->length
if (ret <= 0){
goto free_all;
}
bp_csr = BIO_new_file(CsrPath.path().c_str(),"w");
ret = PEM_write_bio_X509_REQ(bp_csr, x509_req);
// 6. free
free_all:
X509_REQ_free(x509_req);
BIO_free_all(bp_csr);
BIO_free_all(bp_public);
BIO_free_all(bp_private);
EVP_PKEY_free(pKey);
BN_free(bne);
if(ret==1) {
Results.CSR = FileToString(CsrPath.path());
Results.PrivateKey = FileToString(PrivateKey.path());
Results.PublicKey = FileToString(PubKey.path());
}
return ret;
}
bool VerifyECKey(const std::string &key) {
try {
Poco::TemporaryFile F;
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
of << key;
of.close();
auto Key = Poco::SharedPtr<Poco::Crypto::ECKey>(
new Poco::Crypto::ECKey("", F.path(),""));
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool VerifyRSAKey([[
maybe_unused]] const std::string &key) {
try {
Poco::TemporaryFile F;
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
of << key;
of.close();
auto Key = Poco::SharedPtr<Poco::Crypto::RSAKey>(
new Poco::Crypto::RSAKey("", F.path(),""));
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool VerifyPrivateKey(const std::string &key) {
return VerifyECKey(key) || VerifyRSAKey(key);
}
bool ValidX509Certificate([[
maybe_unused]] const std::string &Cert) {
try {
Poco::TemporaryFile F;
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
of << Cert;
of.close();
auto Key = Poco::SharedPtr<Poco::Crypto::X509Certificate>(
new Poco::Crypto::X509Certificate(F.path()));
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool ValidX509Certificate([[
maybe_unused]] const std::vector<std::string> &Certs) {
auto F = [](const std::string &C) -> bool { return ValidX509Certificate(C); };
return std::all_of(Certs.begin(),Certs.end(), F);
}
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase) {
// Define character sets for each category
const std::string lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
const std::string uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::string digitChars = "0123456789";
const std::string specialChars = "!@#$%^&*()_+[]{}|;:,.<>?";
// Check if parameters are valid
if (minLength < 1 || minLength > maxLength || minLowercase + minUppercase + numDigits + minSpecial > maxLength) {
return "Invalid parameters";
}
// Initialize random seed
std::random_device rd;
std::mt19937 g(rd());
// Initialize the password string
std::string password;
// Generate the required number of each character type
for (int i = 0; i < minLowercase; ++i) {
password += lowercaseChars[g() % lowercaseChars.length()];
}
for (int i = 0; i < minUppercase; ++i) {
password += uppercaseChars[g() % uppercaseChars.length()];
}
for (int i = 0; i < numDigits; ++i) {
password += digitChars[g() % digitChars.length()];
}
for (int i = 0; i < minSpecial; ++i) {
password += specialChars[g() % specialChars.length()];
}
// Calculate how many more characters are needed
int remainingLength = maxLength - (int)password.length();
// Generate random characters to fill the remaining length
for (int i = 0; i < remainingLength; ++i) {
int category = g() % 4; // Randomly select a category
if (category == 0) {
password += lowercaseChars[g() % lowercaseChars.length()];
} else if (category == 1) {
password += uppercaseChars[g() % uppercaseChars.length()];
} else if (category == 2) {
password += digitChars[g() % digitChars.length()];
} else {
password += specialChars[g() % specialChars.length()];
}
}
// Shuffle the password to randomize the character order
std::shuffle(password.begin(), password.end(),g);
return password;
}
// Function to query NAPTR records for a domain and return them in a vector
std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain) {
std::vector<NAPTRRecord> naptrRecords;
unsigned char buf[4096];
ns_msg handle;
ns_initparse(buf, NS_PACKETSZ, &handle);
// Query NAPTR records for the given domain
int response = res_query(domain.c_str(), ns_c_in, ns_t_naptr, buf, sizeof(buf));
if (response < 0) {
return naptrRecords;
}
if(ns_initparse(buf, response, &handle) < 0) {
return naptrRecords;
}
// Iterate through the DNS response and extract NAPTR records
int count = ns_msg_count(handle, ns_s_an);
for (int i = 0; i < count; ++i) {
ns_rr rr;
if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
char rdata[256];
ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
NAPTRRecord record;
std::istringstream os(rdata);
os >> record.name >> record.ttl >> record.rclass >> record.rtype >> record.order >> record.preference >> record.flags
>> record.service >> record.regexp >> record.replacement;
naptrRecords.push_back(record);
}
}
return naptrRecords;
}
std::vector<SrvRecord> getSRVRecords(const std::string& domain) {
std::vector<SrvRecord> srvRecords;
// Buffer to hold the DNS response
unsigned char buf[4096];
ns_msg handle;
ns_initparse(buf, NS_PACKETSZ, &handle);
// Query NAPTR records for the given domain
int response = res_query(domain.c_str(), ns_c_in, ns_t_srv, buf, sizeof(buf));
if (response < 0) {
std::cerr << "DNS query failed for " << domain << ": " << hstrerror(h_errno) << std::endl;
return srvRecords;
}
if(ns_initparse(buf, response, &handle) < 0) {
return srvRecords;
}
// Iterate through the DNS response and extract NAPTR records
int count = ns_msg_count(handle, ns_s_an);
for (int i = 0; i < count; ++i) {
ns_rr rr;
if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
char rdata[256];
ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
SrvRecord record;
std::istringstream os(rdata);
os >> record.name >> record.ttl >> record.rclass >> record.rtype >> record.pref >> record.weight >>
record.port >> record.srvname ;
srvRecords.push_back(record);
}
}
return srvRecords;
}
} // namespace OpenWifi::Utils

View File

@@ -13,8 +13,6 @@
#include <string>
#include <thread>
#include <dirent.h>
#include "Poco/Base64Decoder.h"
#include "Poco/Base64Encoder.h"
#include "Poco/File.h"
@@ -70,10 +68,8 @@ 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);
[[nodiscard]] bool ValidNumber(const std::string &number, bool isSigned);
template <typename... Args> std::string ComputeHash(Args &&...args) {
Poco::SHA2Engine E;
@@ -126,20 +122,6 @@ namespace OpenWifi::Utils {
[[nodiscard]] std::uint64_t ConvertDate(const std::string &d);
[[nodiscard]] inline uint8_t CalculateMacAddressHash(std::uint64_t value) {
uint8_t hash = 0, i=6;
while(i) {
hash ^= (value & 0xFF) + 1;
value >>= 8;
--i;
}
return hash;
}
[[nodiscard]] inline uint8_t CalculateMacAddressHash(const std::string & value) {
return CalculateMacAddressHash(MACToInt(value));
}
template <typename T> std::string int_to_hex(T i) {
std::stringstream stream;
stream << std::setfill('0') << std::setw(12) << std::hex << i;
@@ -164,171 +146,4 @@ 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;
}
static inline std::uint64_t GetValue(FILE *file) {
unsigned long v=0;
char factor[32];
if(fscanf(file, " %lu %31s", &v, factor)==2) {
switch (factor[0]) {
case 'k':
return v * 1000;
case 'M':
return v * 1000000;
case 'G':
return v * 1000000000;
}
}
return v;
}
inline bool getMemory(
std::uint64_t &currRealMem, std::uint64_t &peakRealMem,
std::uint64_t &currVirtMem, std::uint64_t &peakVirtMem) {
// stores each word in status file
char buffer[1024] = "";
currRealMem = peakRealMem = currVirtMem = peakVirtMem = 0;
// linux file contains this-process info
FILE * file = std::fopen("/proc/self/status", "r");
if (file == nullptr) {
return false;
}
// read the entire file, recording mems in kB
while (fscanf(file, " %1023s", buffer) == 1) {
if (strcmp(buffer, "VmRSS:") == 0) {
currRealMem= GetValue(file);
} else if (strcmp(buffer, "VmHWM:") == 0) {
peakRealMem= GetValue(file);
} else if (strcmp(buffer, "VmSize:") == 0) {
currVirtMem= GetValue(file);
} else if (strcmp(buffer, "VmPeak:") == 0) {
peakVirtMem= GetValue(file);
}
}
fclose(file);
return true;
}
inline int get_open_fds() {
DIR *dp = opendir("/proc/self/fd");
struct dirent *de;
int count = -3; // '.', '..', dp
if (dp == nullptr)
return -1;
while ((de = readdir(dp)) != nullptr)
count++;
(void)closedir(dp);
return count;
}
inline std::uint32_t IPtoInt(const std::string &A) {
Poco::Net::IPAddress IP;
std::uint32_t Result=0;
if(Poco::Net::IPAddress::tryParse(A,IP)) {
for(const auto i:IP.toBytes()) {
Result <<= 8;
Result += i;
}
}
return Result;
}
inline bool ValidIP(const std::string &IPstr) {
Poco::Net::IPAddress IP;
return Poco::Net::IPAddress::tryParse(IPstr,IP);
}
struct CSRCreationParameters {
std::string Country, Province, City,
Organization, CommonName;
int bits=2048;
};
struct CSRCreationResults {
std::string CSR, PublicKey, PrivateKey;
};
bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results);
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase);
bool VerifyECKey(const std::string &key);
bool VerifyRSAKey(const std::string &key);
bool VerifyPrivateKey(const std::string &key);
bool ValidX509Certificate(const std::string &Cert);
bool ValidX509Certificate(const std::vector<std::string> &Certs);
struct NAPTRRecord {
std::string name;
std::string ttl;
std::string rclass;
std::string rtype;
uint32_t order=0;
uint32_t preference=0;
std::string flags;
std::string service;
std::string regexp;
std::string replacement;
};
// Function to query NAPTR records for a domain and return them in a vector
std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
struct SrvRecord {
std::string name;
std::string ttl;
std::string rclass;
std::string rtype;
uint32_t pref = 0;
uint32_t weight = 0;
uint32_t port = 0;
std::string srvname;
};
std::vector<SrvRecord> getSRVRecords(const std::string& domain);
struct HostNameServerResult{
std::string Hostname;
uint32_t Port;
};
} // namespace OpenWifi::Utils

View File

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

View File

@@ -1,67 +0,0 @@
//
// 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;
};
}

View File

@@ -1,237 +0,0 @@
//
// 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));
}
}
};
}

View File

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

View File

@@ -21,18 +21,9 @@
#include "Poco/Net/SocketAcceptor.h"
#include <algorithm>
/*
2023-09-25 14:57:48.963 RADSEC: radsec.openro.am@3.33.129.120:2084: [Error][thr:7] SSL connection unexpectedly closed
2023-09-25 14:57:48.964 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:7] Disconnecting.
2023-09-25 14:57:50.965 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:40] Attempting to connect
2023-09-25 14:57:51.675 RTTY-SVR: [Error][thr:6] Frame readable shutdown.
2023-09-25 14:57:51.675 RTTY-SVR: [Debug][thr:6] Closing connection onClientSocketReadable:646
2023-09-25 14:57:51.717 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:40] Connected. CN=radsec.openro.am
2023-09-25 14:57:51.717 RADSEC: radsec.openro.am@3.33.129.120:2084: [Error][thr:7] SSL connection unexpectedly closed
2023-09-25 14:57:51.717 RADSEC: radsec.openro.am@3.33.129.120:2084: [Information][thr:7] Disconnecting.
*/
#define DBGLINE \
{ std::cout << __LINE__ << std::endl; }
namespace OpenWifi {
@@ -231,6 +222,7 @@ namespace OpenWifi {
}
NewSocket.close();
} catch (const Poco::Exception &E) {
std::cout << "Exception onDeviceAccept: " << E.what() << std::endl;
Logger().log(E);
}
}
@@ -254,7 +246,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(true);
Socket.setBlocking(false);
Socket.setReceiveBufferSize(RTTY_RECEIVE_BUFFER);
Socket.setSendBufferSize(RTTY_RECEIVE_BUFFER);
Poco::Timespan TS2(300, 100);
@@ -273,6 +265,7 @@ namespace OpenWifi {
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_)) {
@@ -303,8 +296,16 @@ namespace OpenWifi {
*this, &RTTYS_server::onClientSocketError));
}
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;
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) {
return Socket.impl()->sendBytes(buffer,len);
}
@@ -380,7 +381,7 @@ namespace OpenWifi {
OutBuf[5] = 'K';
OutBuf[6] = 0;
if (SendBytes(ConnectionEp,Socket,OutBuf, 7) != 7) {
if (SendBytes(Socket,OutBuf, 7) != 7) {
poco_error(
Logger(),
fmt::format("{}: Description:{} Could not send data to complete registration",
@@ -418,24 +419,15 @@ 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 {
int fd = pNf->socket().impl()->sockfd();
auto hint = Sockets_.find(fd);
if(hint==end(Sockets_)) {
poco_error(Logger(),fmt::format("{}: unknown socket",fd));
@@ -445,17 +437,19 @@ namespace OpenWifi {
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;
// int line=0;
try {
Poco::Timespan TS(5,0);
received_bytes = hint->second->socket.receiveBytes(buffer);
// std::cout << "Available: " << buffer.available() << " ";
received_bytes = hint->second->socket.receiveBytes(*hint->second->buffer);
if(received_bytes==0) {
poco_warning(Logger(), "Device Closing connection - 0 bytes received.");
EndConnection( pNf->socket(), __func__, __LINE__ );
return;
}
// for(std::size_t i=0;i< std::min(buffer.used(),(std::size_t) 16) ;++i) {
// std::cout << (int) buffer[i] << " ";
// }
// std::cout << std::endl;
} catch (const Poco::TimeoutException &E) {
poco_warning(Logger(), "Receive timeout");
EndConnection( pNf->socket(), __func__, __LINE__ );
@@ -471,10 +465,12 @@ namespace OpenWifi {
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()));
poco_debug(Logger(),fmt::format("Not enough data in the pipe for header",buffer.used()));
// std::cout << "Not enough in header: " << buffer.used() << std::endl;
// for(std::size_t i=0;i< std::min(buffer.used(),(std::size_t) 16) ;++i) {
// std::cout << (int) buffer[i] << " ";
// }
// std::cout << std::endl;
return;
}
@@ -485,15 +481,24 @@ namespace OpenWifi {
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()));
poco_debug(Logger(),fmt::format("Not enough data in the pipe for command data",buffer.used()));
// std::cout << "Not enough in header: " << buffer.used() << " msg length: " << msg_len << std::endl;
// for(std::size_t i=0;i< std::min(buffer.used(),(std::size_t) 16) ;++i) {
// std::cout << (int) buffer[i] << " ";
// }
// std::cout << std::endl;
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);
// if((line & 0x0000003f)==0) {
// do_msgTypeHeartbeat(pNf->socket(),buffer,msg_len);
// }
switch (LastCommand) {
case RTTYS_EndPoint::msgTypeRegister: {
good = do_msgTypeRegister(pNf->socket(), buffer, msg_len);
@@ -505,7 +510,7 @@ namespace OpenWifi {
good = do_msgTypeLogout(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeTermData: {
good = do_msgTypeTermData(pNf->socket(), buffer, msg_len, agg_buffer, agg_buf_pos);
good = do_msgTypeTermData(pNf->socket(), buffer, msg_len);
} break;
case RTTYS_EndPoint::msgTypeWinsize: {
good = do_msgTypeWinsize(pNf->socket(), buffer, msg_len);
@@ -537,9 +542,7 @@ 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__);
@@ -585,7 +588,7 @@ namespace OpenWifi {
}
int flags;
unsigned char FrameBuffer[64000];
unsigned char FrameBuffer[1024];
auto ReceivedBytes = Connection->WSSocket_->receiveFrame(FrameBuffer, sizeof(FrameBuffer), flags);
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
@@ -821,8 +824,9 @@ 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));
}
@@ -866,7 +870,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,Conn->DeviceSocket_, Conn->small_buf_,
auto Sent = SendBytes(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) {
@@ -884,7 +888,7 @@ namespace OpenWifi {
Msg.get()[3] = Conn->sid_;
memcpy((Msg.get() + RTTY_HDR_SIZE + 1), &buf[1], len - 1);
try {
auto Sent = SendBytes(Conn,Conn->DeviceSocket_,Msg.get(),
auto Sent = SendBytes(Conn->DeviceSocket_,Msg.get(),
RTTY_HDR_SIZE + 1 + len - 1);
return (Sent == (int)(RTTY_HDR_SIZE + 1 + len - 1));
} catch (const Poco::Exception &E) {
@@ -909,7 +913,7 @@ namespace OpenWifi {
outBuf[RTTY_HDR_SIZE + 2 + 1] = rows >> 8;
outBuf[RTTY_HDR_SIZE + 3 + 1] = rows & 0x00ff;
try {
auto Sent = SendBytes(Conn,Conn->DeviceSocket_, outBuf, RTTY_HDR_SIZE + 4 + 1);
auto Sent = SendBytes(Conn->DeviceSocket_, outBuf, RTTY_HDR_SIZE + 4 + 1);
return (Sent == (int)(RTTY_HDR_SIZE + 4 + 1));
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -927,7 +931,7 @@ namespace OpenWifi {
outBuf[2] = 0;
try {
poco_debug(Logger(), fmt::format("TID:{} Starting login on device.",Conn->TID_));
auto Sent = SendBytes(Conn,Socket,outBuf,RTTY_HDR_SIZE);
auto Sent = SendBytes(Socket,outBuf,RTTY_HDR_SIZE);
Conn->completed_ = true;
return Sent == RTTY_HDR_SIZE;
} catch (const Poco::Exception &E) {
@@ -946,7 +950,7 @@ namespace OpenWifi {
outBuf[3] = Conn->sid_;
poco_debug(Logger(), fmt::format("{}: Logout", Conn->TID_));
try {
auto Sent = SendBytes(Conn,Socket, outBuf, RTTY_HDR_SIZE + 1);
auto Sent = SendBytes(Socket, outBuf, RTTY_HDR_SIZE + 1);
return Sent == (int)(RTTY_HDR_SIZE + 1);
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -1030,18 +1034,17 @@ namespace OpenWifi {
return false;
}
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) {
bool RTTYS_server::do_msgTypeTermData(const Poco::Net::Socket &Socket, Poco::FIFOBuffer &buffer, std::size_t msg_len) {
auto EndPoint = Connected_.find(Socket.impl()->sockfd());
if (EndPoint!=end(Connected_) && EndPoint->second->WSSocket_!= nullptr && EndPoint->second->WSSocket_->impl() != nullptr) {
try {
buffer.drain(1);
msg_len--;
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;
auto good = SendToClient(*EndPoint->second->WSSocket_, (unsigned char*) buffer.begin(), (int) msg_len );
buffer.drain(msg_len);
return good;
} catch (const Poco::Exception &E) {
std::cout << "Failed to send WS stuff" << std::endl;
Logger().log(E);
} catch (const std::exception &E) {
LogStdException(E, "Cannot send data to UI Client");
@@ -1068,11 +1071,8 @@ namespace OpenWifi {
MsgBuf[0] = RTTYS_EndPoint::msgTypeHeartbeat;
MsgBuf[1] = 0;
MsgBuf[2] = 0;
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;
}
auto Sent = SendBytes(Socket,MsgBuf, RTTY_HDR_SIZE);
return Sent == RTTY_HDR_SIZE;
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (const std::exception &E) {

Some files were not shown because too many files have changed in this diff Show More