Compare commits

..

6 Commits

145 changed files with 4172 additions and 43158 deletions

View File

@@ -21,7 +21,7 @@ defaults:
jobs: jobs:
docker: docker:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
env: env:
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
DOCKER_REGISTRY_USERNAME: ucentral DOCKER_REGISTRY_USERNAME: ucentral

View File

@@ -11,7 +11,7 @@ defaults:
jobs: jobs:
helm-package: helm-package:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
env: env:
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
HELM_REPO_USERNAME: ucentral HELM_REPO_USERNAME: ucentral

4
.gitignore vendored
View File

@@ -21,12 +21,10 @@ _deps
/docker-compose/.env /docker-compose/.env
/docker-compose/.env_* /docker-compose/.env_*
/cmake-build/ /cmake-build/
/uploads/
test_scripts/curl/token.json test_scripts/curl/token.json
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
test_scripts/curl/result.json test_scripts/curl/result.json
*.swp *.swp
helm/charts/* helm/charts/*
!helm/charts/.gitkeep !helm/charts/.gitkeep
/portal-test/
/src/ow_version.h

2
.idea/.gitignore generated vendored
View File

@@ -6,5 +6,3 @@
/dataSources.local.xml /dataSources.local.xml
# Editor-based HTTP Client requests # Editor-based HTTP Client requests
/httpRequests/ /httpRequests/
# GitHub Copilot persisted chat sessions
/copilot/chatSessions

3
.idea/misc.xml generated
View File

@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.9 (wlan-cloud-ucentralgw)" />
</component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" /> <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CidrRootsConfiguration"> <component name="CidrRootsConfiguration">
<excludeRoots> <excludeRoots>

2
.idea/ucentral.iml generated
View File

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

1
.idea/vcs.xml generated
View File

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

View File

@@ -1,5 +1,5 @@
# Building from source # Building from source
In order to build OWGW, you will need to install its dependencies, which includes the following: In order to build the OWGW, you will need to install its dependencies, which includes the following:
- cmake - cmake
- boost - boost
- POCO 1.10.1 or later - POCO 1.10.1 or later
@@ -12,43 +12,43 @@ In order to build OWGW, you will need to install its dependencies, which include
The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/Telecominfraproject/wlan-cloud-lib-poco). Building from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/AriliaWireless/poco). Building
Poco may take several minutes depending on the platform you are building on. Poco may take several minutes depending on the platform you are building on.
## Ubuntu ## Ubuntu
These instructions have proven to work on Ubuntu 20.4. These instructions have proven to work on Ubuntu 20.4.
```bash ```bash
sudo apt install git cmake g++ libssl-dev libmariadb-dev \ sudo apt install git cmake g++ libssl-dev libmariadb-dev
libpq-dev libaprutil1-dev apache2-dev libboost-all-dev \ sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
librdkafka-dev // default-libmysqlclient-dev \ sudo apt install librdkafka-dev // default-libmysqlclient-dev
nlohmann-json-dev sudo apt install nlohmann-json-dev
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco cd ~
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
cd poco cd poco
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
cd ../..
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka cd ~
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
cd cppkafka cd cppkafka
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
cd ../..
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson cd ~
git clone https://github.com/AriliaWireless/valijson --branch tip-v1
cd valijson cd valijson
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
cd ../..
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
cd fmtlib cd fmtlib
@@ -57,59 +57,56 @@ cd cmake-build
cmake .. cmake ..
make make
make install make install
cd ../..
cd ~
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
cd wlan-cloud-ucentralgw cd wlan-cloud-ucentralgw
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
make -j 8 make -j 8
cd ../..
``` ```
## Fedora ## Fedora
The following instructions have proven to work on Fedora 33 The following instructions have proven to work on Fedora 33
```bash ```bash
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel \ sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
yaml-cpp-devel lua-devel sudo yum install yaml-cpp-devel lua-devel
sudo dnf install postgresql.x86_64 librdkafka-devel sudo dnf install postgresql.x86_64 librdkafka-devel
sudo dnf install postgresql-devel json-devel sudo dnf install postgresql-devel json-devel
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
cd poco cd poco
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
cd ../..
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
cd cppkafka cd cppkafka
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
cd ../..
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson cd ~
git clone https://github.com/AriliaWireless/valijson --branch tip-v1
cd valijson cd valijson
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
cd ../..
cd ~
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
cd wlan-cloud-ucentralgw cd wlan-cloud-ucentralgw
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
make make
cd ../..
``` ```
## macOS Build ## macOS Build
@@ -128,7 +125,7 @@ brew install openssl \
nlohmann-json \ nlohmann-json \
fmt fmt
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
pushd poco pushd poco
mkdir cmake-build mkdir cmake-build
push cmake-build push cmake-build
@@ -138,7 +135,7 @@ sudo cmake --build . --target install
popd popd
popd popd
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
pushd cppkafka pushd cppkafka
mkdir cmake-build mkdir cmake-build
pushd cmake-build pushd cmake-build
@@ -148,10 +145,10 @@ sudo cmake --build . --target install
popd popd
popd popd
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson git clone https://github.com/AriliaWireless/valijson --branch tip-v1
pushd valijson cd valijson
mkdir cmake-build mkdir cmake-build
pushd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
@@ -174,23 +171,20 @@ support. You can build with only SQLite support by not installing the packages f
adding -DSMALL_BUILD=1 on the cmake build line. adding -DSMALL_BUILD=1 on the cmake build line.
```bash ```bash
sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev \ sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev libboost-all-dev libyaml-cpp-dev
libboost-all-dev libyaml-cpp-dev git clone https://github.com/stephb9959/poco
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
cd poco cd poco
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake .. cmake ..
cmake --build . --config Release cmake --build . --config Release
sudo cmake --build . --target install sudo cmake --build . --target install
cd ../..
cd ~
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
cd wlan-cloud-ucentralgw cd wlan-cloud-ucentralgw
mkdir cmake-build mkdir cmake-build
cd cmake-build cd cmake-build
cmake -DSMALL_BUILD=1 .. cmake -DSMALL_BUILD=1 ..
make make
cd ../..
``` ```

View File

@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 4.1.0) project(owgw VERSION 2.9.0)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
if(UNIX AND APPLE) if(UNIX AND APPLE)
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
@@ -50,7 +49,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}") string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif() 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(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
@@ -145,15 +144,9 @@ add_executable( owgw
src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h
src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
src/RESTAPI/RESTAPI_telemetryWebSocket.cpp src/RESTAPI/RESTAPI_telemetryWebSocket.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_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_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_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/storage/storage_tables.cpp
src/RESTAPI/RESTAPI_routers.cpp src/RESTAPI/RESTAPI_routers.cpp
src/Daemon.cpp src/Daemon.h src/Daemon.cpp src/Daemon.h
@@ -177,7 +170,7 @@ add_executable( owgw
src/SDKcalls.cpp src/SDKcalls.cpp
src/SDKcalls.h src/SDKcalls.h
src/StateUtils.cpp src/StateUtils.h src/StateUtils.cpp src/StateUtils.h
src/AP_WS_Reactor_Pool.h src/AP_WS_ReactorPool.h
src/AP_WS_Connection.h src/AP_WS_Connection.h
src/AP_WS_Connection.cpp src/AP_WS_Connection.cpp
src/TelemetryClient.h src/TelemetryClient.cpp src/TelemetryClient.h src/TelemetryClient.cpp
@@ -201,20 +194,8 @@ add_executable( owgw
src/AP_WS_Process_deviceupdate.cpp src/AP_WS_Process_deviceupdate.cpp
src/AP_WS_Process_telemetry.cpp src/AP_WS_Process_telemetry.cpp
src/AP_WS_Process_venuebroadcast.cpp src/AP_WS_Process_venuebroadcast.cpp
src/RADIUS_Destination.h src/RADSEC_server.h
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h src/framework/RESTAPI_SystemConfiguration.h src/ScriptManager.cpp src/ScriptManager.h src/RESTAPI/RESTAPI_scripts_handler.cpp src/RESTAPI/RESTAPI_scripts_handler.h src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h src/storage/storage_scripts.cpp src/storage/storage_scripts.h src/SignatureMgr.h src/AP_WS_Process_event.cpp src/AP_WS_Process_wifiscan.cpp src/AP_WS_Process_alarm.cpp src/GWKafkaEvents.cpp src/GWKafkaEvents.h src/RegulatoryInfo.cpp src/RegulatoryInfo.h src/RESTAPI/RESTAPI_regulatory.cpp src/RESTAPI/RESTAPI_regulatory.h)
src/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/AP_WS_LookForUpgrade.cpp)
if(NOT SMALL_BUILD) if(NOT SMALL_BUILD)
@@ -226,17 +207,14 @@ INSTALL(TARGETS owgw
target_link_libraries(owgw PUBLIC target_link_libraries(owgw PUBLIC
${Poco_LIBRARIES} ${Poco_LIBRARIES}
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES})
)
if(NOT SMALL_BUILD) if(NOT SMALL_BUILD)
target_link_libraries(owgw PUBLIC target_link_libraries(owgw PUBLIC
${MySQL_LIBRARIES} ${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
${ZLIB_LIBRARIES} CppKafka::cppkafka
CppKafka::cppkafka fmt::fmt
fmt::fmt )
resolv
)
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
target_link_libraries(owgw PUBLIC PocoJSON) target_link_libraries(owgw PUBLIC PocoJSON)
endif() endif()

View File

@@ -1,9 +1,7 @@
ARG DEBIAN_VERSION=11.5-slim ARG DEBIAN_VERSION=11.5-slim
ARG POCO_VERSION=poco-tip-v2 ARG POCO_VERSION=poco-tip-v2
ARG CPPKAFKA_VERSION=tip-v1 ARG CPPKAFKA_VERSION=tip-v1
ARG VALIJASON_VERSION=tip-v1.0.2 ARG VALIJASON_VERSION=tip-v1
ARG APP_NAME=owgw
ARG APP_HOME_DIR=/openwifi
FROM debian:$DEBIAN_VERSION AS build-base FROM debian:$DEBIAN_VERSION AS build-base
@@ -17,8 +15,8 @@ FROM build-base AS poco-build
ARG POCO_VERSION ARG POCO_VERSION
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-poco/git/refs/tags/${POCO_VERSION} version.json ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch ${POCO_VERSION} /poco RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
WORKDIR /poco WORKDIR /poco
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -31,8 +29,8 @@ FROM build-base AS cppkafka-build
ARG CPPKAFKA_VERSION ARG CPPKAFKA_VERSION
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
WORKDIR /cppkafka WORKDIR /cppkafka
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -45,8 +43,8 @@ FROM build-base AS valijson-build
ARG VALIJASON_VERSION ARG VALIJASON_VERSION
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-valijson/git/refs/tags/${VALIJASON_VERSION} version.json ADD https://api.github.com/repos/AriliaWireless/valijson/git/refs/tags/${VALIJASON_VERSION} version.json
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch ${VALIJASON_VERSION} /valijson RUN git clone https://github.com/AriliaWireless/valijson --branch ${VALIJASON_VERSION} /valijson
WORKDIR /valijson WORKDIR /valijson
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -55,14 +53,12 @@ RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
RUN cmake --build . --target install RUN cmake --build . --target install
FROM build-base AS app-build FROM build-base AS owgw-build
ARG APP_NAME ADD CMakeLists.txt build /owgw/
ADD cmake /owgw/cmake
ADD CMakeLists.txt build /${APP_NAME}/ ADD src /owgw/src
ADD cmake /${APP_NAME}/cmake ADD .git /owgw/.git
ADD src /${APP_NAME}/src
ADD .git /${APP_NAME}/.git
COPY --from=poco-build /usr/local/include /usr/local/include COPY --from=poco-build /usr/local/include /usr/local/include
COPY --from=poco-build /usr/local/lib /usr/local/lib 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=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=valijson-build /usr/local/include /usr/local/include COPY --from=valijson-build /usr/local/include /usr/local/include
WORKDIR /${APP_NAME} WORKDIR /owgw
RUN mkdir cmake-build RUN mkdir cmake-build
WORKDIR /${APP_NAME}/cmake-build WORKDIR /owgw/cmake-build
RUN cmake .. RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
FROM debian:$DEBIAN_VERSION FROM debian:$DEBIAN_VERSION
ARG APP_NAME ENV OWGW_USER=owgw \
ARG APP_HOME_DIR OWGW_ROOT=/owgw-data \
OWGW_CONFIG=/owgw-data
ENV APP_NAME=$APP_NAME \ RUN useradd "$OWGW_USER"
APP_USER=$APP_NAME \
APP_ROOT=/$APP_NAME-data \
APP_CONFIG=/$APP_NAME-data \
APP_HOME_DIR=$APP_HOME_DIR
# This is for legacy RUN mkdir /openwifi
ENV OWGW_USER=$APP_USER \ RUN mkdir -p "$OWGW_ROOT" "$OWGW_CONFIG" && \
OWGW_ROOT=$APP_ROOT \ chown "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
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 apt-get update && apt-get install --no-install-recommends -y \ RUN apt-get update && apt-get install --no-install-recommends -y \
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \ 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 readiness_check /readiness_check
COPY test_scripts/curl/cli /cli COPY test_scripts/curl/cli /cli
COPY $APP_NAME.properties.tmpl / COPY owgw.properties.tmpl /
COPY docker-entrypoint.sh / COPY docker-entrypoint.sh /
COPY wait-for-postgres.sh / COPY wait-for-postgres.sh /
COPY rtty_ui /dist/rtty_ui COPY rtty_ui /dist/rtty_ui
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ 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 -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=cppkafka-build /cppkafka/cmake-build/src/lib /usr/local/lib/
COPY --from=poco-build /poco/cmake-build/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 EXPOSE 15002 16002 16003 17002 16102
ENTRYPOINT ["/docker-entrypoint.sh"] 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 */ - 7 : LOG_DEBUG 7 /* debug-level messages */
#### Crash Log event #### 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 ```json
{ "jsonrpc" : "2.0" , { "jsonrpc" : "2.0" ,
"method" : "crashlog" , "method" : "crashlog" ,
"params" : { "params" : {
"serial" : <serial number> , "serial" : <serial number> ,
"uuid" : <the UUID of the configuration that generated the crash log>, "uuid" : <the UUID of the configuration that generated the crash log>,
"loglines" : [ an array of strings representing the logs from the log file ] "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 #### Config change pending event
Device sends this message to tell the controller that the device 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 has received a configuration but is still running an older configuration. The controller will not
@@ -306,54 +289,8 @@ The device should answer:
}, },
"id" : <same number> "id" : <same number>
} }
```
#### Controller wants the device to apply a given fixed configuration
Controller sends this command when it requires the device to apply fixed configuration, eg. country code. The device
should respond with message indicating failure or success.
```json
{ "jsonrpc" : "2.0",
"method" : "fixedconfig",
"params" : {
"serial" : <serial number>,
"when" : Optional - <UTC time when to apply this config, 0 means immediate, this is a suggestion>
"country" : "<country-code>"
},
}
```
If AP supports compressed configuration feature by inidcating `compress_cmd=true` in its capabilities, controller
will send a compressed configuration message where configuration payload (i.e. contents of `params`) is compressed
and encoded in base64 format:
```json
{ "jsonrpc" : "2.0",
"method" : "configure",
"params" : {
"compress_64" : "<b64 encoded zlib compressed payload>",
"compress_sz" : "<size of uncompressed data in bytes>"
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0",
"result" : {
"serial": <serial number>,
"status": {
"error": 0 or an error number,
"text": <description of the error or success, eg. "Applied fixed config, rebooting">
},
"uuid": <UUID>
}
}
``` ```
##### The Answer ##### The Answer
The device can answer and tell the controller it has rejected certain parts of the config and potentially replaced them with The device can answer and tell the controller it has rejected certain parts of the config and potentially replaced them with
appropriate values. This could be used to allow a device to replace frequencies for the regions it is located in. The device appropriate values. This could be used to allow a device to replace frequencies for the regions it is located in. The device
@@ -401,39 +338,6 @@ The device should answer:
- 1 : the device is busy but will reboot soon. `text` may indicate why. - 1 : the device is busy but will reboot soon. `text` may indicate why.
- 2 : the device will not reboot. `text` contains information as to why. - 2 : the device will not reboot. `text` contains information as to why.
#### Controller wants to power-cycle PoE port(s)
Controller sends this command to power-cycle 1 or more PoE ports
```json
{ "jsonrpc" : "2.0" ,
"method" : "powercycle" ,
"params" : {
"serial" : <serial number> ,
"ports" : [ { "name" : "Ethernet1", "cycle" : 5000}, { "name" : "Ethernet8", "cycle" : 10000 } ],
"when" : Optional - <UTC time when to reboot, 0 mean immediately, this is a suggestion>
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : 0 or an error number,
"text" : [ "Error 1" , "Error 2" ],
"when" : <time when this will be performed as UTC seconds>,
},
"id" : <same id from request>
}
```
###### Error codes
- 0 : is rebooting at `when` seconds.
- 1 : the device is busy but will reboot soon. `text` may indicate why.
- 2 : the device will not reboot. `text` contains information as to why.
#### Controller wants the device to upgrade its firmware #### Controller wants the device to upgrade its firmware
Controller sends this command when it believes the device should upgrade its firmware. Controller sends this command when it believes the device should upgrade its firmware.
```json ```json
@@ -854,172 +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 perform re-enrollment
Controller sends this command to trigger re-enrollment, i.e. update of operational certificate. Extreme care must be taken.
```json
{ "jsonrpc" : "2.0" ,
"method" : "reenroll" ,
"params" : {
"serial" : <serial number>,
"when" : Optional - <UTC time when to apply this config, 0 mean immediate, this is a suggestion>
},
"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` ### `rtty server`
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here. More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.

2
build
View File

@@ -1 +1 @@
3 105

View File

@@ -6,35 +6,35 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
fi fi
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\${APP_ROOT}/certs/root.pem"} \ WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\${APP_ROOT}/certs/issuer.pem"} \ WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\${APP_ROOT}/certs/websocket-cert.pem"} \ WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\${APP_ROOT}/certs/websocket-key.pem"} \ WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\$OWGW_ROOT/certs/websocket-key.pem"} \
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\${APP_ROOT}/certs/clientcas.pem"} \ WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\$OWGW_ROOT/certs/clientcas.pem"} \
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\${APP_ROOT}/certs/cas"} \ WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\$OWGW_ROOT/certs/cas"} \
WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \ WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \ 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_PORT=${RESTAPI_HOST_PORT:-"16002"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \ RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \ RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \ 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_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \ INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.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"} \ 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_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \ FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \ FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \ FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \ 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"} \ 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"} \ 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_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \ SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
@@ -51,7 +51,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
RTTY_TOKEN=${RTTY_TOKEN:-""} \ RTTY_TOKEN=${RTTY_TOKEN:-""} \
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \ RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \ 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_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \ RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \ 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:-""} \ KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \
STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \ STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \ STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"${APP_USER}"} \ STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"${APP_USER}"} \ STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"${APP_NAME}"} \ STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \ STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \ STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"${APP_USER}"} \ STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owgw"} \
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"${APP_USER}"} \ STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"${APP_NAME}"} \ STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \ STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \ CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \ envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
envsubst < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
fi fi
# Check if rtty_ui directory exists # 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 if [ -z "$RTTY_ASSETS" ]; then
export RTTY_ASSETS="${APP_ROOT}/rtty_ui" export RTTY_ASSETS="$OWGW_ROOT/rtty_ui"
fi fi
if [[ ! -d "$(dirname $RTTY_ASSETS)" ]]; then if [[ ! -d "$(dirname $RTTY_ASSETS)" ]]; then
mkdir -p "$(dirname $RTTY_ASSETS)" mkdir -p $(dirname $RTTY_ASSETS)
fi fi
if [[ ! -d "$RTTY_ASSETS" ]]; then if [[ ! -d "$RTTY_ASSETS" ]]; then
cp -r /dist/rtty_ui $RTTY_ASSETS cp -r /dist/rtty_ui $RTTY_ASSETS
fi 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 if [ "$RUN_CHOWN" = 'true' ]; then
chown -R "$APP_USER": "${APP_ROOT}" "$APP_CONFIG" chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
fi fi
exec gosu "$APP_USER" "$@" exec gosu "$OWGW_USER" "$@"
fi fi
exec "$@" exec "$@"

View File

@@ -9,7 +9,7 @@ fullnameOverride: ""
images: images:
owgw: owgw:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
tag: master tag: v2.9.0
pullPolicy: Always pullPolicy: Always
# regcred: # regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io # 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

@@ -1,85 +0,0 @@
{
"ethernet": [
{
"select-ports": [
"Ethernet0",
"Ethernet1",
"Ethernet2",
"Ethernet3",
"Ethernet4",
"Ethernet5",
"Ethernet6",
"Ethernet7"
],
"speed": 2500,
"duplex": "full",
"enabled": true,
"poe": {
"admin-mode": true,
"power-limit": 60000
}
},
{
"select-ports": [
"Ethernet8",
"Ethernet9"
],
"speed": 10000,
"duplex": "full",
"media": "sfp-forced-1000sfp"
}
],
"interfaces": [
{
"name": "VLAN1",
"vlan": {
"id": 1
},
"ipv4": {
"addressing": "dynamic"
},
"ethernet": [
{
"select-ports": [
"Ethernet0",
"Ethernet1",
"Ethernet2",
"Ethernet3",
"Ethernet4",
"Ethernet5",
"Ethernet6",
"Ethernet7",
"Ethernet8",
"Ethernet9"
],
"vlan-tag": "un-tagged"
}
]
}
],
"metrics": {
"dhcp-snooping": {
"filters": [
"ack",
"discover",
"offer",
"request",
"solicit",
"reply",
"renew"
]
},
"health": {
"interval": 60
},
"statistics": {
"interval": 120,
"types": []
}
},
"unit": {
"leds-active": true,
"usage-threshold": 95
},
"uuid": 1678263900
}

View File

@@ -2,7 +2,7 @@ openapi: 3.0.1
info: info:
title: uCentral gateway API title: uCentral gateway API
description: A process to manage configuration for devices. description: A process to manage configuration for devices.
version: 2.11.0 version: 2.5.0
license: license:
name: BSD3 name: BSD3
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
@@ -12,7 +12,7 @@ info:
url: https://www.ucentral.info/support url: https://www.ucentral.info/support
servers: servers:
- url: 'https://localhost:16002/api/v1' - url: 'https://localhost:16001/api/v1'
security: security:
- bearerAuth: [] - bearerAuth: []
@@ -42,10 +42,12 @@ components:
schemas: schemas:
DeviceType: DeviceType:
type: string type: string
default: ap default: AP
enum: enum:
- ap - AP
- switch - SWITCH
- IOT
- MESH
DeviceRestrictionsKeyInfo: DeviceRestrictionsKeyInfo:
type: object type: object
@@ -150,14 +152,6 @@ components:
format: uuid format: uuid
restrictionDetails: restrictionDetails:
$ref: '#/components/schemas/DeviceRestrictions' $ref: '#/components/schemas/DeviceRestrictions'
simulated:
type: boolean
lastRecordedContact:
type: integer
format: int64
blackListed:
type: boolean
readOnly: true
DeviceWithStatus: DeviceWithStatus:
type: object type: object
@@ -266,25 +260,6 @@ components:
format: uuid format: uuid
restrictionDetails: restrictionDetails:
$ref: '#/components/schemas/DeviceRestrictions' $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
blackListed:
type: boolean
readOnly: true
DeviceList: DeviceList:
type: object type: object
@@ -354,9 +329,6 @@ components:
associations_5G: associations_5G:
type: integer type: integer
format: int64 format: int64
associations_6G:
type: integer
format: int64
verifiedCertificate: verifiedCertificate:
type: string type: string
enum: enum:
@@ -364,7 +336,6 @@ components:
- VALID_CERTIFICATE, - VALID_CERTIFICATE,
- MISMATCH_SERIAL, - MISMATCH_SERIAL,
- VERIFIED - VERIFIED
- SIMULATED
DeviceCapabilities: DeviceCapabilities:
type: object type: object
@@ -449,7 +420,7 @@ components:
type: string type: string
CommandSubmitSuccess: CommandSubmitSuccess:
description: The command was submitted successfully. description: The command was submitted succesfully.
properties: properties:
serialNumber: serialNumber:
type: string type: string
@@ -487,10 +458,6 @@ components:
logType: logType:
type: integer type: integer
format: int64 format: int64
example:
- 0 normal logs
- 1 crash logs
- 2 reboot logs
UUID: UUID:
type: integer type: integer
format: int64 format: int64
@@ -549,12 +516,6 @@ components:
lastModified: lastModified:
type: integer type: integer
format: int64 format: int64
platform:
type: string
enum:
- ap
- switch
default: ap
DefaultConfigurationList: DefaultConfigurationList:
properties: properties:
@@ -563,35 +524,6 @@ components:
items: items:
$ref : '#/components/schemas/DefaultConfiguration' $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: UpgradeRequest:
type: object type: object
properties: properties:
@@ -913,114 +845,6 @@ components:
kafkaClients: kafkaClients:
type: integer 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 ## These are endpoints that all services in the uCentral stack must provide
@@ -1089,6 +913,12 @@ components:
- $ref: '#/components/schemas/StringList' - $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList' - $ref: '#/components/schemas/TagValuePairList'
SystemCommandResults:
type: object
oneOf:
- $ref: '#/components/schemas/StringList'
- $ref: '#/components/schemas/TagValuePairList'
NoteInfo: NoteInfo:
type: object type: object
properties: properties:
@@ -1128,33 +958,6 @@ components:
type: integer type: integer
format: int64 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: SystemCommandSetLogLevel:
type: object type: object
properties: properties:
@@ -1457,30 +1260,6 @@ components:
$ref: '#/components/schemas/RadiusProxyServerConfig' $ref: '#/components/schemas/RadiusProxyServerConfig'
coaConfig: coaConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig' $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: RadiusProxyPoolList:
type: object type: object
@@ -1490,125 +1269,6 @@ components:
items: items:
$ref: '#/components/schemas/RadiusProxyPool' $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)
ReenrollRequest:
type: object
properties:
serialNumber:
type: string
when:
type: integer
format: int64
PowerCycleRequest:
type: object
properties:
serial:
type: string
when:
type: integer
format: int64
ports:
type: array
items:
type: object
properties:
name:
type: string
example:
- Ethernet0
cycle:
type: integer
default: 10000
minimum: 1
maximum: 60000
description: off time in milliseconds
paths: paths:
/devices: /devices:
get: get:
@@ -1700,22 +1360,6 @@ paths:
type: integer type: integer
default: 70 default: 70
required: false required: false
- in: query
description: return only devices matching a certain platform of AP or SWITCH
name: platform
schema:
type: string
default: ALL
enum:
- all
- ap
- switch
required: false
- in: query
description: only devices which are not provisioned
name: includeProvisioned
schema:
type: boolean
responses: responses:
200: 200:
description: List devices description: List devices
@@ -1733,58 +1377,6 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $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: /commands:
get: get:
tags: tags:
@@ -2041,123 +1633,6 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $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}: /device/{serialNumber}:
get: get:
tags: tags:
@@ -2300,7 +1775,7 @@ paths:
format: int64 format: int64
- in: query - in: query
name: logType 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: schema:
type: integer type: integer
format: int64 format: int64
@@ -2638,6 +2113,32 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $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: /device/{serialNumber}/configure:
post: post:
tags: tags:
@@ -2769,7 +2270,7 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $ref: '#/components/responses/NotFound'
/device/{serialNumber}/script: /device/{serialNumber}/:
post: post:
tags: tags:
- Commands - Commands
@@ -2983,142 +2484,6 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $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'
/device/{serialNumber}/reenroll:
post:
tags:
- Commands
summary: Reenroll operational certificate for the device.
operationId: reenrollCertificate
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Reenroll operational certificate for the device
content:
application/json:
schema:
$ref: '#/components/schemas/ReenrollRequest'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/powercycle:
post:
tags:
- Commands
summary: Perform PoE power cycle for some PoE ports.
operationId: performPowerCycle
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/PowerCycleRequest'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/ouis: /ouis:
get: get:
tags: tags:
@@ -3358,6 +2723,9 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $ref: '#/components/responses/NotFound'
/blacklist: /blacklist:
get: get:
tags: tags:
@@ -3550,81 +2918,6 @@ paths:
403: 403:
$ref: '#/components/responses/Unauthorized' $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: /deviceDashboard:
get: get:
tags: tags:
@@ -3721,12 +3014,16 @@ paths:
type: string type: string
enum: enum:
- info - info
- extraConfiguration
- resources
required: true required: true
responses: responses:
200: 200:
$ref: '#/components/schemas/SystemCommandResults' description: Successful command execution
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/SystemInfoResults'
403: 403:
$ref: '#/components/responses/Unauthorized' $ref: '#/components/responses/Unauthorized'
404: 404:

View File

@@ -85,7 +85,6 @@ iptocountry.ipdata.apikey = ${IPTOCOUNTRY_IPDATA_APIKEY}
autoprovisioning.process = ${AUTOPROVISIONING_PROCESS} autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
openwifi.session.timeout = ${DEVICE_SESSION_TIMEOUT}
# #
# rtty # rtty
# #
@@ -104,12 +103,6 @@ radius.proxy.accounting.port = ${RADIUS_PROXY_ACCOUNTING_PORT}
radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT} radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
radius.proxy.coa.port = ${RADIUS_PROXY_COA_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 # Generic information for all micro services
############################# #############################
@@ -145,7 +138,7 @@ storage.type.sqlite.db = devices.db
storage.type.sqlite.idletime = 120 storage.type.sqlite.idletime = 120
storage.type.sqlite.maxsessions = 128 storage.type.sqlite.maxsessions = 128
storage.type.postgresql.maxsessions = 250 storage.type.postgresql.maxsessions = 64
storage.type.postgresql.idletime = 60 storage.type.postgresql.idletime = 60
storage.type.postgresql.host = ${STORAGE_TYPE_POSTGRESQL_HOST} storage.type.postgresql.host = ${STORAGE_TYPE_POSTGRESQL_HOST}
storage.type.postgresql.username = ${STORAGE_TYPE_POSTGRESQL_USERNAME} storage.type.postgresql.username = ${STORAGE_TYPE_POSTGRESQL_USERNAME}

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_ConfigAutoUpgradeAgent::Start() {
poco_notice(Logger(), "Starting...");
QueueManager_.start(*this);
return 0;
}
void AP_WS_ConfigAutoUpgradeAgent::Stop() {
poco_notice(Logger(), "Stopping...");
Running_ = false;
Queue_.wakeUpAll();
QueueManager_.join();
poco_notice(Logger(), "Stopped...");
}
void AP_WS_ConfigAutoUpgradeAgent::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_ConfigAutoUpgradeAgent : public SubSystemServer, Poco::Runnable {
public:
int Start() final;
void Stop() final;
void run() final;
static auto instance() {
static auto instance = new AP_WS_ConfigAutoUpgradeAgent;
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_ConfigAutoUpgradeAgent() noexcept
: SubSystemServer("AutoConfigUpgrade", "AUTO-CFG-MGR", "auto.config.updater") {
}
};
inline auto AP_WS_ConfigAutoUpgradeAgent() { return AP_WS_ConfigAutoUpgradeAgent::instance(); }
} // namespace OpenWifi

View File

@@ -2,49 +2,55 @@
// Created by stephane bourque on 2022-02-03. // Created by stephane bourque on 2022-02-03.
// //
#include "AP_WS_Connection.h"
#include <Poco/Base64Decoder.h> #include "Poco/Base64Decoder.h"
#include <Poco/Net/Context.h> #include "Poco/Net/Context.h"
#include <Poco/Net/HTTPServerRequestImpl.h> #include "Poco/Net/HTTPServerRequestImpl.h"
#include <Poco/Net/HTTPServerResponseImpl.h> #include "Poco/Net/HTTPServerResponseImpl.h"
#include <Poco/Net/NetException.h> #include "Poco/Net/NetException.h"
#include <Poco/Net/SSLException.h> #include "Poco/Net/SSLException.h"
#include <Poco/Net/SecureStreamSocketImpl.h> #include "Poco/Net/SecureStreamSocketImpl.h"
#include <Poco/Net/WebSocketImpl.h> #include "Poco/Net/WebSocketImpl.h"
#include "Poco/zlib.h"
#include <framework/KafkaManager.h> #include "AP_WS_Server.h"
#include <framework/MicroServiceFuncs.h> #include "CentralConfig.h"
#include <framework/utils.h> #include "CommandManager.h"
#include <framework/ow_constants.h> #include "ConfigurationCache.h"
#include "StorageService.h"
#include "TelemetryStream.h"
#include <fmt/format.h> #include "GWKafkaEvents.h"
#include "UI_GW_WebSocketNotifications.h"
#include "framework/KafkaManager.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
#include <AP_WS_Connection.h> #include "fmt/format.h"
#include <AP_WS_Server.h>
#include <CentralConfig.h> #include "framework/ow_constants.h"
#include <CommandManager.h>
#include <StorageService.h> #include "RADIUS_proxy_server.h"
#include <RADIUSSessionTracker.h>
#include <RADIUS_proxy_server.h>
#include <GWKafkaEvents.h>
#include <UI_GW_WebSocketNotifications.h>
namespace OpenWifi { namespace OpenWifi {
#define DBL \
{ \
std::cout << __LINE__ << " ID: " << ConnectionId_ << " Ser: " << SerialNumber_ \
<< std::endl; \
}
void AP_WS_Connection::LogException(const Poco::Exception &E) { void AP_WS_Connection::LogException(const Poco::Exception &E) {
poco_information(Logger_, fmt::format("EXCEPTION({}): {}", CId_, E.displayText())); poco_information(Logger_, fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
} }
AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request, AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response, Poco::Net::HTTPServerResponse &response,
uint64_t session_id, Poco::Logger &L, uint64_t connection_id, Poco::Logger &L,
std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R) Poco::Net::SocketReactor &R)
: Logger_(L) { : Logger_(L), Reactor_(R) {
State_.sessionId = connection_id;
Reactor_ = R.first;
DbSession_ = R.second;
State_.sessionId = session_id;
WS_ = std::make_unique<Poco::Net::WebSocket>(request, response); WS_ = std::make_unique<Poco::Net::WebSocket>(request, response);
auto TS = Poco::Timespan(360, 0); auto TS = Poco::Timespan(360, 0);
@@ -54,86 +60,28 @@ namespace OpenWifi {
WS_->setNoDelay(false); WS_->setNoDelay(false);
WS_->setKeepAlive(true); WS_->setKeepAlive(true);
WS_->setBlocking(false); WS_->setBlocking(false);
uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
AP_WS_Server()->IncrementConnectionCount(); Reactor_.addEventHandler(*WS_,
} Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
*this, &AP_WS_Connection::OnSocketReadable));
void AP_WS_Connection::Start() { Reactor_.addEventHandler(*WS_,
Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
*this, &AP_WS_Connection::OnSocketShutdown));
Reactor_.addEventHandler(*WS_,
Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
*this, &AP_WS_Connection::OnSocketError));
Registered_ = true; Registered_ = true;
LastContact_ = Utils::Now(); Valid_ = true;
Reactor_->addEventHandler(*WS_,
Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
*this, &AP_WS_Connection::OnSocketReadable));
Reactor_->addEventHandler(*WS_,
Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
*this, &AP_WS_Connection::OnSocketShutdown));
Reactor_->addEventHandler(*WS_,
Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
*this, &AP_WS_Connection::OnSocketError));
}
AP_WS_Connection::~AP_WS_Connection() {
std::lock_guard G(ConnectionMutex_);
AP_WS_Server()->DecrementConnectionCount();
EndConnection();
poco_debug(Logger_, fmt::format("TERMINATION({}): Session={}, Connection removed.", SerialNumber_,
State_.sessionId));
}
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
try {
Poco::JSON::Object Disconnect;
Poco::JSON::Object Details;
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
Details.set(uCentralProtocol::UUID,uuid);
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
} catch (...) {
}
}
void AP_WS_Connection::EndConnection() {
bool expectedValue=false;
if (Dead_.compare_exchange_strong(expectedValue,true,std::memory_order_release,std::memory_order_relaxed)) {
if(!SerialNumber_.empty() && State_.LastContact!=0) {
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
}
if (Registered_) {
Registered_ = false;
Reactor_->removeEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
*this, &AP_WS_Connection::OnSocketReadable));
Reactor_->removeEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
*this, &AP_WS_Connection::OnSocketShutdown));
Reactor_->removeEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
*this, &AP_WS_Connection::OnSocketError));
Registered_=false;
}
WS_->close();
if(!SerialNumber_.empty()) {
DeviceDisconnectionCleanup(SerialNumber_, uuid_);
}
AP_WS_Server()->AddCleanupSession(State_.sessionId, SerialNumberInt_);
}
} }
bool AP_WS_Connection::ValidatedDevice() { bool AP_WS_Connection::ValidatedDevice() {
if(Dead_)
return false;
if (DeviceValidated_) if (DeviceValidated_)
return true; return true;
if (!Valid_)
return false;
std::lock_guard Lock(ConnectionMutex_);
try { try {
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl()); auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
auto SS = auto SS =
@@ -148,6 +96,7 @@ namespace OpenWifi {
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Connection is " poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Connection is "
"NOT secure. Device is not allowed.", "NOT secure. Device is not allowed.",
CId_, State_.sessionId)); CId_, State_.sessionId));
EndConnection();
return false; return false;
} }
@@ -160,6 +109,7 @@ namespace OpenWifi {
Logger_, Logger_,
fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_, fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_,
State_.sessionId)); State_.sessionId));
EndConnection();
return false; return false;
} }
@@ -170,21 +120,13 @@ namespace OpenWifi {
fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not " fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not "
"valid. Device is not allowed.", "valid. Device is not allowed.",
CId_, State_.sessionId)); CId_, State_.sessionId));
EndConnection();
return false; return false;
} }
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName())); CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
if(!Utils::ValidSerialNumber(CN_)) {
poco_trace(Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Invalid serial number: CN={}", CId_,
State_.sessionId, CN_));
return false;
}
SerialNumber_ = CN_;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE; State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
poco_trace(Logger_, poco_information(Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_, fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_,
State_.sessionId, CN_)); State_.sessionId, CN_));
@@ -192,28 +134,26 @@ namespace OpenWifi {
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is " poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is "
"not allowed. Disconnecting.", "not allowed. Disconnecting.",
CId_, State_.sessionId, CN_)); CId_, State_.sessionId, CN_));
EndConnection();
return false; return false;
} }
if(AP_WS_Server::IsSim(SerialNumber_)) {
State_.VerifiedCertificate = GWObjects::SIMULATED;
Simulated_ = true;
}
std::string reason, author; std::string reason, author;
std::uint64_t created; std::uint64_t created;
if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumberInt_, reason, author, 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( poco_warning(
Logger_, Logger_,
fmt::format( fmt::format(
"TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.", "TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
CId_, State_.sessionId, CN_)); CId_, State_.sessionId, CN_));
EndConnection();
return false; return false;
} }
State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime(); State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
State_.certificateIssuerName = PeerCert.issuerName(); SerialNumber_ = CN_;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
poco_trace(Logger_, poco_trace(Logger_,
fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,
@@ -277,14 +217,138 @@ namespace OpenWifi {
return false; return false;
} }
void AP_WS_Connection::DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) { static void NotifyKafkaDisconnect(const std::string &SerialNumber) {
if (KafkaManager()->Enabled()) { try {
NotifyKafkaDisconnect(SerialNumber, uuid); Poco::JSON::Object Disconnect;
Poco::JSON::Object Details;
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(Disconnect, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
} catch (...) {
} }
RADIUSSessionTracker()->DeviceDisconnect(SerialNumber); }
GWWebSocketNotifications::SingleDevice_t N;
N.content.serialNumber = SerialNumber; AP_WS_Connection::~AP_WS_Connection() {
GWWebSocketNotifications::DeviceDisconnected(N); Valid_ = false;
EndConnection();
}
void AP_WS_Connection::EndConnection() {
Valid_ = false;
if (!Dead_.test_and_set()) {
if (Registered_) {
Registered_ = false;
Reactor_.removeEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
*this, &AP_WS_Connection::OnSocketReadable));
Reactor_.removeEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
*this, &AP_WS_Connection::OnSocketShutdown));
Reactor_.removeEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
*this, &AP_WS_Connection::OnSocketError));
}
WS_->close();
if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
std::string s(SerialNumber_);
std::thread t([s]() { NotifyKafkaDisconnect(s); });
t.detach();
}
auto SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
if (SessionDeleted) {
GWWebSocketNotifications::SingleDevice_t N;
N.content.serialNumber = SerialNumber_;
GWWebSocketNotifications::DeviceDisconnected(N);
}
}
}
bool AP_WS_Connection::LookForUpgrade(const uint64_t UUID, uint64_t &UpgradedUUID) {
// A UUID of zero means ignore updates for that connection.
if (UUID == 0)
return false;
uint64_t GoodConfig = ConfigurationCache().CurrentConfig(SerialNumberInt_);
if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) {
UpgradedUUID = UUID;
return false;
}
GWObjects::Device D;
if (StorageService()->GetDevice(SerialNumber_, D)) {
if(D.pendingUUID!=0 && UUID==D.pendingUUID) {
// so we sent an upgrade to a device, and now it is completing now...
UpgradedUUID = D.pendingUUID;
StorageService()->CompleteDeviceConfigurationChange(SerialNumber_);
return true;
}
// This is the case where the cache is empty after a restart. So GoodConfig will 0. If
// the device already has the right UUID, we just return.
if (D.UUID == UUID) {
UpgradedUUID = UUID;
ConfigurationCache().Add(SerialNumberInt_, UUID);
return false;
}
Config::Config Cfg(D.Configuration);
if (UUID > D.UUID) {
// so we have a problem, the device has a newer config than we have. So we need to
// make sure our config is newer.
D.UUID = UUID + 2;
UpgradedUUID = D.UUID;
}
Cfg.SetUUID(D.UUID);
D.Configuration = Cfg.get();
State_.PendingUUID = UpgradedUUID = D.UUID;
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.UUID = MicroServiceCreateUUID();
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
Cmd.Status = uCentralProtocol::PENDING;
Cmd.Command = uCentralProtocol::CONFIGURE;
Poco::JSON::Parser P;
auto ParsedConfig = P.parse(D.Configuration).extract<Poco::JSON::Object::Ptr>();
Poco::JSON::Object Params;
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
Params.set(uCentralProtocol::UUID, D.UUID);
Params.set(uCentralProtocol::WHEN, 0);
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
std::ostringstream O;
Poco::JSON::Stringifier::stringify(Params, O);
Cmd.Details = O.str();
poco_information(Logger_,
fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
CId_, UUID, D.UUID));
bool Sent;
StorageService()->AddCommand(SerialNumber_, Cmd,
Storage::CommandExecutionType::COMMAND_EXECUTED);
CommandManager()->PostCommand(
CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false);
GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
Notification.content.serialNumber = D.SerialNumber;
Notification.content.oldUUID = UUID;
Notification.content.newUUID = UpgradedUUID;
GWWebSocketNotifications::DeviceConfigurationChange(Notification);
return true;
}
return false;
} }
void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) { void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
@@ -365,8 +429,8 @@ namespace OpenWifi {
std::string reason, author; std::string reason, author;
std::uint64_t created; std::uint64_t created;
if (StorageService()->IsBlackListed(SerialNumberInt_, reason, author, 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( Poco::Exception E(
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.", fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
Serial), Serial),
@@ -431,10 +495,6 @@ namespace OpenWifi {
Process_wifiscan(ParamsObj); Process_wifiscan(ParamsObj);
} break; } 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 // this will never be called but some compilers will complain if we do not have a case for
// every single values of an enum // every single values of an enum
case uCentralProtocol::Events::ET_UNKNOWN: { case uCentralProtocol::Events::ET_UNKNOWN: {
@@ -496,17 +556,17 @@ namespace OpenWifi {
} }
bool AP_WS_Connection::SetWebSocketTelemetryReporting( bool AP_WS_Connection::SetWebSocketTelemetryReporting(
std::uint64_t RPCID, std::uint64_t Interval, std::uint64_t LifeTime, uint64_t RPCID, uint64_t Interval, uint64_t LifeTime,
const std::vector<std::string> &TelemetryTypes) { const std::vector<std::string> &TelemetryTypes) {
std::unique_lock Lock(TelemetryMutex_); std::unique_lock Lock(TelemetryMutex_);
TelemetryWebSocketRefCount_++; TelemetryWebSocketRefCount_++;
TelemetryInterval_ = TelemetryInterval_ TelemetryInterval_ = TelemetryInterval_
? (Interval < (std::uint64_t)TelemetryInterval_ ? Interval : (std::uint64_t )TelemetryInterval_) ? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
: Interval; : Interval;
auto TelemetryWebSocketTimer = LifeTime + Utils::Now(); auto TelemetryWebSocketTimer = LifeTime + Utils::Now();
TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > (std::uint64_t)TelemetryWebSocketTimer_ TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > TelemetryWebSocketTimer_
? (std::uint64_t)TelemetryWebSocketTimer ? TelemetryWebSocketTimer
: (std::uint64_t)TelemetryWebSocketTimer_; : TelemetryWebSocketTimer_;
UpdateCounts(); UpdateCounts();
if (!TelemetryReporting_) { if (!TelemetryReporting_) {
TelemetryReporting_ = true; TelemetryReporting_ = true;
@@ -522,11 +582,11 @@ namespace OpenWifi {
std::unique_lock Lock(TelemetryMutex_); std::unique_lock Lock(TelemetryMutex_);
TelemetryKafkaRefCount_++; TelemetryKafkaRefCount_++;
TelemetryInterval_ = TelemetryInterval_ TelemetryInterval_ = TelemetryInterval_
? (Interval < (std::uint64_t)TelemetryInterval_ ? (std::uint64_t)Interval : (std::uint64_t)TelemetryInterval_) ? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
: Interval; : Interval;
auto TelemetryKafkaTimer = LifeTime + Utils::Now(); auto TelemetryKafkaTimer = LifeTime + Utils::Now();
TelemetryKafkaTimer_ = TelemetryKafkaTimer_ =
TelemetryKafkaTimer > (std::uint64_t)TelemetryKafkaTimer_ ? (std::uint64_t)TelemetryKafkaTimer : (std::uint64_t)TelemetryKafkaTimer_; TelemetryKafkaTimer > TelemetryKafkaTimer_ ? TelemetryKafkaTimer : TelemetryKafkaTimer_;
UpdateCounts(); UpdateCounts();
if (!TelemetryReporting_) { if (!TelemetryReporting_) {
TelemetryReporting_ = true; TelemetryReporting_ = true;
@@ -562,50 +622,49 @@ namespace OpenWifi {
void AP_WS_Connection::OnSocketShutdown( void AP_WS_Connection::OnSocketShutdown(
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) { [[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_)); poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
// std::lock_guard G(ConnectionMutex_);
return EndConnection(); return EndConnection();
} }
void AP_WS_Connection::OnSocketError( void AP_WS_Connection::OnSocketError(
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) { [[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_)); poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
// std::lock_guard G(ConnectionMutex_);
return EndConnection(); return EndConnection();
} }
void AP_WS_Connection::OnSocketReadable( void AP_WS_Connection::OnSocketReadable(
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) { [[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
if (Dead_) // we are dead, so we do not process anything. if (!Valid_)
return; return;
std::lock_guard G(ConnectionMutex_); if (!AP_WS_Server()->Running())
return EndConnection();
State_.LastContact = LastContact_ = Utils::Now(); if (!ValidatedDevice())
if (AP_WS_Server()->Running() && (DeviceValidated_ || ValidatedDevice())) { return;
try {
return ProcessIncomingFrame(); try {
} catch (const Poco::Exception &E) { return ProcessIncomingFrame();
Logger_.log(E); } catch (const Poco::Exception &E) {
} catch (const std::exception &E) { Logger_.log(E);
std::string W = E.what(); return EndConnection();
poco_information( } catch (const std::exception &E) {
Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}", std::string W = E.what();
W, CId_)); poco_information(
} catch (...) { Logger_,
poco_information( fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_));
Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_)); return EndConnection();
} } catch (...) {
poco_information(Logger_,
fmt::format("Unknown exception for {}. Connection terminated.", CId_));
return EndConnection();
} }
EndConnection();
} }
void AP_WS_Connection::ProcessIncomingFrame() { void AP_WS_Connection::ProcessIncomingFrame() {
Poco::Buffer<char> IncomingFrame(0); Poco::Buffer<char> IncomingFrame(0);
bool KillConnection=false;
try { try {
int Op, flags; int Op, flags;
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags); auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
@@ -625,81 +684,84 @@ namespace OpenWifi {
State_.LastContact = Utils::Now(); State_.LastContact = Utils::Now();
switch (Op) { switch (Op) {
case Poco::Net::WebSocket::FRAME_OP_PING: { case Poco::Net::WebSocket::FRAME_OP_PING: {
poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_)); poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_));
WS_->sendFrame("", 0, WS_->sendFrame("", 0,
(int)Poco::Net::WebSocket::FRAME_OP_PONG | (int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN); (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
if (KafkaManager()->Enabled()) { if (KafkaManager()->Enabled()) {
Poco::JSON::Object PingObject; Poco::JSON::Object PingObject;
Poco::JSON::Object PingDetails; Poco::JSON::Object PingDetails;
PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware); PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware);
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_); PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_); PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_); PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now()); PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
PingDetails.set(uCentralProtocol::UUID, uuid_); PingDetails.set("locale", State_.locale);
PingDetails.set("locale", State_.locale); PingObject.set(uCentralProtocol::PING, PingDetails);
PingObject.set(uCentralProtocol::PING, PingDetails); Poco::JSON::Stringifier Stringify;
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_)); std::ostringstream OS;
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject); Stringify.condense(PingObject, OS);
} KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
} break; }
return;
} break;
case Poco::Net::WebSocket::FRAME_OP_PONG: { case Poco::Net::WebSocket::FRAME_OP_PONG: {
poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_)); poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
} break; return;
} break;
case Poco::Net::WebSocket::FRAME_OP_TEXT: { case Poco::Net::WebSocket::FRAME_OP_TEXT: {
poco_trace(Logger_, poco_trace(Logger_,
fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}",
CId_, IncomingSize, flags, IncomingFrame.begin())); CId_, IncomingSize, flags, IncomingFrame.begin()));
Poco::JSON::Parser parser; Poco::JSON::Parser parser;
auto ParsedMessage = parser.parse(IncomingFrame.begin()); auto ParsedMessage = parser.parse(IncomingFrame.begin());
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>(); auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
if (IncomingJSON->has(uCentralProtocol::JSONRPC)) { if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
if (IncomingJSON->has(uCentralProtocol::METHOD) && if (IncomingJSON->has(uCentralProtocol::METHOD) &&
IncomingJSON->has(uCentralProtocol::PARAMS)) { IncomingJSON->has(uCentralProtocol::PARAMS)) {
ProcessJSONRPCEvent(IncomingJSON); ProcessJSONRPCEvent(IncomingJSON);
} else if (IncomingJSON->has(uCentralProtocol::RESULT) && } else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
IncomingJSON->has(uCentralProtocol::ID)) { IncomingJSON->has(uCentralProtocol::ID)) {
poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_,
IncomingFrame.begin())); IncomingFrame.begin()));
ProcessJSONRPCResult(IncomingJSON); ProcessJSONRPCResult(IncomingJSON);
} else {
poco_warning(
Logger_,
fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
CId_, IncomingFrame.begin()));
}
} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
ProcessIncomingRadiusData(IncomingJSON);
} else { } else {
std::ostringstream iS;
IncomingJSON->stringify(iS);
poco_warning( poco_warning(
Logger_, Logger_,
fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc': {}", fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
CId_, iS.str())); CId_, IncomingFrame.begin()));
Errors_++;
} }
} break; } else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
ProcessIncomingRadiusData(IncomingJSON);
case Poco::Net::WebSocket::FRAME_OP_CLOSE: { } else {
poco_information(Logger_, std::ostringstream iS;
fmt::format("CLOSE({}): Device is closing its connection.", CId_)); IncomingJSON->stringify(iS);
KillConnection=true; std::cout << iS.str() << std::endl;
} break; poco_warning(
Logger_,
default: { fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc'",
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", CId_));
CId_, std::to_string(Op)));
Errors_++; Errors_++;
return;
} }
return;
} break;
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
poco_information(Logger_,
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
return EndConnection();
} break;
default: {
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}",
CId_, std::to_string(Op)));
} break;
} }
} catch (const Poco::Net::ConnectionResetException &E) { } catch (const Poco::Net::ConnectionResetException &E) {
poco_warning(Logger_, poco_warning(Logger_,
@@ -707,21 +769,21 @@ namespace OpenWifi {
CId_, E.displayText(), CId_, E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const Poco::JSON::JSONException &E) { } catch (const Poco::JSON::JSONException &E) {
poco_warning(Logger_, poco_warning(Logger_,
fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_, fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(), E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const Poco::Net::WebSocketException &E) { } catch (const Poco::Net::WebSocketException &E) {
poco_warning(Logger_, poco_warning(Logger_,
fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_, fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(), E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) { } catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
poco_warning( poco_warning(
Logger_, Logger_,
@@ -730,54 +792,54 @@ namespace OpenWifi {
CId_, E.displayText(), CId_, E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const Poco::Net::SSLException &E) { } catch (const Poco::Net::SSLException &E) {
poco_warning(Logger_, poco_warning(Logger_,
fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_, fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(), E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const Poco::Net::NetException &E) { } catch (const Poco::Net::NetException &E) {
poco_warning(Logger_, poco_warning(Logger_,
fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_, fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(), E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const Poco::IOException &E) { } catch (const Poco::IOException &E) {
poco_warning(Logger_, poco_warning(Logger_,
fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_, fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(), E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
poco_warning(Logger_, poco_warning(Logger_,
fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_, fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(), E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (const std::exception &E) { } catch (const std::exception &E) {
poco_warning(Logger_, poco_warning(Logger_,
fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_, fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_,
E.what(), E.what(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(), IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
State_.sessionId)); State_.sessionId));
KillConnection=true; return EndConnection();
} catch (...) { } catch (...) {
poco_error(Logger_, fmt::format("UnknownException({}): Device must be disconnected. " poco_error(Logger_, fmt::format("UnknownException({}): Device must be disconnected. "
"Unknown exception. Session:{}", "Unknown exception. Session:{}",
CId_, State_.sessionId)); CId_, State_.sessionId));
KillConnection=true; return EndConnection();
} }
if (!KillConnection && Errors_ < 10) if (Errors_ < 10)
return; return;
poco_warning(Logger_, fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}", CId_, KillConnection, Errors_ )); poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_));
EndConnection(); return EndConnection();
} }
bool AP_WS_Connection::Send(const std::string &Payload) { bool AP_WS_Connection::Send(const std::string &Payload) {
@@ -889,36 +951,4 @@ namespace OpenWifi {
} }
} }
} }
void AP_WS_Connection::SetLastStats(const std::string &LastStats) {
RawLastStats_ = LastStats;
try {
Poco::JSON::Parser P;
auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
State_.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) {
State_.memoryUsed =
(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
}
if (Unit->isArray("load")) {
Poco::JSON::Array::Ptr Load = Unit->getArray("load");
if (Load->size() > 1) {
State_.load = Load->get(1);
}
}
if (Unit->isArray("temperature")) {
Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
if (Temperature->size() > 1) {
State_.temperature = Temperature->get(0);
}
}
} catch (const Poco::Exception &E) {
poco_error(Logger_, "Failed to parse last stats: " + E.displayText());
}
}
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -4,20 +4,17 @@
#pragma once #pragma once
#include <mutex> #include <shared_mutex>
#include <string> #include <string>
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include <Poco/JSON/Parser.h>
#include "Poco/Logger.h" #include "Poco/Logger.h"
#include "Poco/Net/SocketNotification.h" #include "Poco/Net/SocketNotification.h"
#include "Poco/Net/SocketReactor.h" #include "Poco/Net/SocketReactor.h"
#include "Poco/Net/StreamSocket.h" #include "Poco/Net/StreamSocket.h"
#include "Poco/Net/WebSocket.h" #include "Poco/Net/WebSocket.h"
#include <Poco/Data/Session.h>
#include "RESTObjects/RESTAPI_GWobjects.h" #include "RESTObjects/RESTAPI_GWobjects.h"
#include <AP_WS_Reactor_Pool.h>
namespace OpenWifi { namespace OpenWifi {
@@ -27,7 +24,7 @@ namespace OpenWifi {
public: public:
explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request, explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response, uint64_t connection_id, Poco::Net::HTTPServerResponse &response, uint64_t connection_id,
Poco::Logger &L, std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R); Poco::Logger &L, Poco::Net::SocketReactor &R);
~AP_WS_Connection(); ~AP_WS_Connection();
void EndConnection(); void EndConnection();
@@ -37,7 +34,6 @@ namespace OpenWifi {
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc); void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
[[nodiscard]] bool Send(const std::string &Payload); [[nodiscard]] bool Send(const std::string &Payload);
[[nodiscard]] inline bool MustBeSecureRTTY() const { return RTTYMustBeSecure_; }
bool SendRadiusAuthenticationData(const unsigned char *buffer, std::size_t size); bool SendRadiusAuthenticationData(const unsigned char *buffer, std::size_t size);
bool SendRadiusAccountingData(const unsigned char *buffer, std::size_t size); bool SendRadiusAccountingData(const unsigned char *buffer, std::size_t size);
@@ -46,7 +42,10 @@ namespace OpenWifi {
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf); void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf); void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf); void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
bool LookForUpgrade(Poco::Data::Session &Session, uint64_t UUID, uint64_t &UpgradedUUID); bool LookForUpgrade(uint64_t UUID, uint64_t &UpgradedUUID);
static bool ExtractBase64CompressedData(const std::string &CompressedData,
std::string &UnCompressedData,
uint64_t compress_sz);
void LogException(const Poco::Exception &E); void LogException(const Poco::Exception &E);
inline Poco::Logger &Logger() { return Logger_; } inline Poco::Logger &Logger() { return Logger_; }
bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval, bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval,
@@ -58,34 +57,52 @@ namespace OpenWifi {
bool StopWebSocketTelemetry(uint64_t RPCID); bool StopWebSocketTelemetry(uint64_t RPCID);
bool StopKafkaTelemetry(uint64_t RPCID); bool StopKafkaTelemetry(uint64_t RPCID);
inline void GetLastStats(std::string &LastStats) { inline void GetLastStats(std::string &LastStats) const {
if(!Dead_) { std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_); LastStats = RawLastStats_;
LastStats = RawLastStats_; }
}
inline void SetLastStats(const std::string &LastStats) {
std::unique_lock G(ConnectionMutex_);
RawLastStats_ = LastStats;
}
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
std::unique_lock G(ConnectionMutex_);
RawLastHealthcheck_ = H;
} }
inline void GetLastHealthCheck(GWObjects::HealthCheck &H) { inline void GetLastHealthCheck(GWObjects::HealthCheck &H) {
if(!Dead_) { std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_); H = RawLastHealthcheck_;
H = RawLastHealthcheck_;
}
} }
inline void GetState(GWObjects::ConnectionState &State) { inline void GetState(GWObjects::ConnectionState &State) const {
if(!Dead_) { std::shared_lock G(ConnectionMutex_);
std::lock_guard G(ConnectionMutex_); State = State_;
State = State_;
}
} }
inline GWObjects::DeviceRestrictions GetRestrictions() { inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
std::lock_guard G(ConnectionMutex_); std::shared_lock G(ConnectionMutex_);
return Restrictions_; R = Restrictions_;
} }
[[nodiscard]] inline bool HasGPS() const { return hasGPS_; } void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
[[nodiscard]] bool ValidatedDevice(); void Process_state(Poco::JSON::Object::Ptr ParamsObj);
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
bool ValidatedDevice();
inline bool GetTelemetryParameters(bool &Reporting, uint64_t &Interval, inline bool GetTelemetryParameters(bool &Reporting, uint64_t &Interval,
uint64_t &WebSocketTimer, uint64_t &KafkaTimer, uint64_t &WebSocketTimer, uint64_t &KafkaTimer,
@@ -105,14 +122,18 @@ namespace OpenWifi {
friend class AP_WS_Server; friend class AP_WS_Server;
void Start(); inline GWObjects::DeviceRestrictions Restrictions() const {
std::shared_lock G(ConnectionMutex_);
return Restrictions_;
}
inline bool MustBeSecureRtty() const { return RttyMustBeSecure_; }
private: private:
mutable std::recursive_mutex ConnectionMutex_; mutable std::shared_mutex ConnectionMutex_;
std::mutex TelemetryMutex_; std::shared_mutex TelemetryMutex_;
Poco::Logger &Logger_; Poco::Logger &Logger_;
std::shared_ptr<Poco::Net::SocketReactor> Reactor_; Poco::Net::SocketReactor &Reactor_;
std::shared_ptr<LockedDbSession> DbSession_;
std::unique_ptr<Poco::Net::WebSocket> WS_; std::unique_ptr<Poco::Net::WebSocket> WS_;
std::string SerialNumber_; std::string SerialNumber_;
uint64_t SerialNumberInt_ = 0; uint64_t SerialNumberInt_ = 0;
@@ -123,56 +144,30 @@ namespace OpenWifi {
uint64_t Errors_ = 0; uint64_t Errors_ = 0;
Poco::Net::IPAddress PeerAddress_; Poco::Net::IPAddress PeerAddress_;
volatile bool TelemetryReporting_ = false; volatile bool TelemetryReporting_ = false;
std::atomic_uint64_t TelemetryWebSocketRefCount_ = 0; volatile uint64_t TelemetryWebSocketRefCount_ = 0;
std::atomic_uint64_t TelemetryKafkaRefCount_ = 0; volatile uint64_t TelemetryKafkaRefCount_ = 0;
std::atomic_uint64_t TelemetryWebSocketTimer_ = 0; volatile uint64_t TelemetryWebSocketTimer_ = 0;
std::atomic_uint64_t TelemetryKafkaTimer_ = 0; volatile uint64_t TelemetryKafkaTimer_ = 0;
std::atomic_uint64_t TelemetryInterval_ = 0; volatile uint64_t TelemetryInterval_ = 0;
std::atomic_uint64_t TelemetryWebSocketPackets_ = 0; volatile uint64_t TelemetryWebSocketPackets_ = 0;
std::atomic_uint64_t TelemetryKafkaPackets_ = 0; volatile uint64_t TelemetryKafkaPackets_ = 0;
GWObjects::ConnectionState State_; GWObjects::ConnectionState State_;
Utils::CompressedString RawLastStats_; std::string RawLastStats_;
GWObjects::HealthCheck RawLastHealthcheck_; GWObjects::HealthCheck RawLastHealthcheck_;
std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ = std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ =
std::chrono::high_resolution_clock::now(); std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0}; std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
std::atomic<bool> Dead_ = false; std::atomic_flag Dead_ = false;
std::atomic_bool DeviceValidated_ = false; std::atomic_bool DeviceValidated_ = false;
std::atomic_bool Valid_ = false;
OpenWifi::GWObjects::DeviceRestrictions Restrictions_; OpenWifi::GWObjects::DeviceRestrictions Restrictions_;
bool RTTYMustBeSecure_ = false; bool RttyMustBeSecure_ = false;
bool hasGPS_=false;
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
std::uint64_t uuid_=0;
bool Simulated_=false;
std::atomic_uint64_t LastContact_=0;
static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0; static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
bool StartTelemetry(uint64_t RPCID, const std::vector<std::string> &TelemetryTypes); bool StartTelemetry(uint64_t RPCID, const std::vector<std::string> &TelemetryTypes);
bool StopTelemetry(uint64_t RPCID); bool StopTelemetry(uint64_t RPCID);
void UpdateCounts(); void UpdateCounts();
static void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid);
void SetLastStats(const std::string &LastStats);
void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
void Process_state(Poco::JSON::Object::Ptr ParamsObj);
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
RawLastHealthcheck_ = H;
}
}; };
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -1,111 +0,0 @@
#include <AP_WS_Connection.h>
#include "ConfigurationCache.h"
#include "UI_GW_WebSocketNotifications.h"
#include "CommandManager.h"
namespace OpenWifi {
bool AP_WS_Connection::LookForUpgrade(Poco::Data::Session &Session, const uint64_t UUID, uint64_t &UpgradedUUID) {
// A UUID of zero means ignore updates for that connection.
if (UUID == 0)
return false;
uint64_t GoodConfig = GetCurrentConfigurationID(SerialNumberInt_);
if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) {
UpgradedUUID = UUID;
State_.PendingUUID = 0;
return false;
}
GWObjects::Device D;
if (!StorageService()->GetDevice(Session,SerialNumber_, D)) {
return false;
}
if(State_.PendingUUID!=0 && UUID==State_.PendingUUID) {
// so we sent an upgrade to a device, and now it is completing now...
UpgradedUUID = UUID;
StorageService()->CompleteDeviceConfigurationChange(Session, SerialNumber_);
State_.PendingUUID = 0;
return true;
}
// dont upgrade a switch if it does not have a real config. Config will always be more than 20 characters
if (D.DeviceType==Platforms::SWITCH && D.Configuration.size()<20) {
return false;
}
Config::Config Cfg(D.Configuration);
// if this is a broken device (UUID==0) just fix it
auto StoredConfigurationUUID = Cfg.UUID();
if(D.UUID==0) {
D.UUID = StoredConfigurationUUID;
}
if (D.UUID == UUID) {
D.UUID = UpgradedUUID = UUID;
State_.PendingUUID = D.pendingUUID = 0;
D.pendingConfiguration.clear();
D.pendingConfigurationCmd.clear();
StorageService()->UpdateDevice(Session, D);
SetCurrentConfigurationID(SerialNumberInt_, UUID);
// std::cout << __LINE__ << ": " << SerialNumber_ << " GoodConfig: " << GoodConfig << " UUID:" << UUID << " Pending:" << State_.PendingUUID << std::endl;
return false;
}
if (UUID > D.UUID) {
// so we have a problem, the device has a newer config than we have. So we need to
// make sure our config is newer.
D.UUID = UUID + 2;
UpgradedUUID = D.UUID;
// std::cout << __LINE__ << ": " << SerialNumber_ << " GoodConfig: " << GoodConfig << " UUID:" << UUID << " Pending:" << State_.PendingUUID << std::endl;
}
Cfg.SetUUID(D.UUID);
D.Configuration = Cfg.get();
D.pendingUUID = State_.PendingUUID = UpgradedUUID = D.UUID;
StorageService()->UpdateDevice(Session, D);
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.UUID = MicroServiceCreateUUID();
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
Cmd.Status = uCentralProtocol::PENDING;
Cmd.Command = uCentralProtocol::CONFIGURE;
Poco::JSON::Parser P;
auto ParsedConfig = P.parse(D.Configuration).extract<Poco::JSON::Object::Ptr>();
Poco::JSON::Object Params;
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
Params.set(uCentralProtocol::UUID, D.UUID);
Params.set(uCentralProtocol::WHEN, 0);
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
std::ostringstream O;
Poco::JSON::Stringifier::stringify(Params, O);
Cmd.Details = O.str();
poco_information(Logger_,
fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
CId_, UUID, D.UUID));
bool Sent;
StorageService()->AddCommand(SerialNumber_, Cmd,
Storage::CommandExecutionType::COMMAND_EXECUTED);
CommandManager()->PostCommand(
CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false);
GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
Notification.content.serialNumber = D.SerialNumber;
Notification.content.oldUUID = UUID;
Notification.content.newUUID = UpgradedUUID;
GWWebSocketNotifications::DeviceConfigurationChange(Notification);
// std::cout << __LINE__ << ": " << SerialNumber_ << " GoodConfig: " << GoodConfig << " UUID:" << UUID <<
// " Pending:" << State_.PendingUUID << " Upgraded:" << UpgradedUUID << std::endl;
return true;
}
}

View File

@@ -21,7 +21,11 @@ namespace OpenWifi {
if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) { if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
if (KafkaManager()->Enabled()) { 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/KafkaManager.h"
#include "framework/utils.h" #include "framework/utils.h"
#include "firmware_revision_cache.h"
#include "UI_GW_WebSocketNotifications.h" #include "UI_GW_WebSocketNotifications.h"
#include <GWKafkaEvents.h> #include <GWKafkaEvents.h>
@@ -32,7 +30,9 @@ namespace OpenWifi {
Event.set("type", "device.firmware_change"); Event.set("type", "device.firmware_change");
Event.set("timestamp", Utils::Now()); Event.set("timestamp", Utils::Now());
Event.set("payload", EventDetails); 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("type", "device.not_provisioned");
Event.set("timestamp", Utils::Now()); Event.set("timestamp", Utils::Now());
Event.set("payload", EventDetails); 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,18 +63,14 @@ namespace OpenWifi {
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString(); auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
auto Capabilities = ParamsObj->getObject(uCentralProtocol::CAPABILITIES); auto Capabilities = ParamsObj->getObject(uCentralProtocol::CAPABILITIES);
std::string DevicePassword;
if(ParamsObj->has("password")) {
DevicePassword = ParamsObj->get("password").toString();
}
SerialNumber_ = Serial; SerialNumber_ = Serial;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_); SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
CommandManager()->ClearQueue(SerialNumberInt_); CommandManager()->ClearQueue(SerialNumberInt_);
AP_WS_Server()->StartSession(State_.sessionId, SerialNumberInt_); AP_WS_Server()->SetSessionDetails(State_.sessionId, SerialNumberInt_);
std::lock_guard Lock(ConnectionMutex_);
Config::Capabilities Caps(Capabilities); Config::Capabilities Caps(Capabilities);
Compatible_ = Caps.Compatible(); Compatible_ = Caps.Compatible();
@@ -83,12 +81,6 @@ namespace OpenWifi {
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString()); State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
CId_ = SerialNumber_ + "@" + CId_; CId_ = SerialNumber_ + "@" + CId_;
auto Platform = Poco::toLower(Caps.Platform());
if(ParamsObj->has("reason")) {
State_.connectReason = ParamsObj->get("reason").toString();
}
auto IP = PeerAddress_.toString(); auto IP = PeerAddress_.toString();
if (IP.substr(0, 7) == "::ffff:") { if (IP.substr(0, 7) == "::ffff:") {
IP = IP.substr(7); IP = IP.substr(7);
@@ -101,65 +93,29 @@ namespace OpenWifi {
Restrictions_.from_json(RestrictionObject); Restrictions_.from_json(RestrictionObject);
} }
if (Capabilities->has("developer") && !Capabilities->isNull("developer")) { if (Capabilities->has("developer")) {
Restrictions_.developer = Capabilities->getValue<bool>("developer"); Restrictions_.developer = Capabilities->getValue<bool>("developer");
} }
if(Capabilities->has("secure-rtty")) { if(Capabilities->has("secure-rtty")) {
RTTYMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty"); RttyMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty");
} }
State_.locale = FindCountryFromIP()->Get(IP); State_.locale = FindCountryFromIP()->Get(IP);
GWObjects::Device DeviceInfo; GWObjects::Device DeviceInfo;
std::lock_guard DbSessionLock(DbSession_->Mutex()); auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
auto DeviceExists = StorageService()->GetDevice(DbSession_->Session(), SerialNumber_, DeviceInfo);
if (Daemon()->AutoProvisioning() && !DeviceExists) { if (Daemon()->AutoProvisioning() && !DeviceExists) {
// check the firmware version. if this is too old, we cannot let that device connect yet, we must StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_);
// force a firmware upgrade
GWObjects::DefaultFirmware MinimumFirmware;
if(FirmwareRevisionCache()->DeviceMustUpgrade(Compatible_, Firmware, MinimumFirmware)) {
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( DbSession_->Session(),
SerialNumber_, Caps, Firmware, PeerAddress_,
State_.VerifiedCertificate == GWObjects::SIMULATED);
}
} else if (!Daemon()->AutoProvisioning() && !DeviceExists) { } else if (!Daemon()->AutoProvisioning() && !DeviceExists) {
SendKafkaDeviceNotProvisioned(SerialNumber_, Firmware, Compatible_, CId_); SendKafkaDeviceNotProvisioned(SerialNumber_, Firmware, Compatible_, CId_);
poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_)); poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_));
return EndConnection(); return EndConnection();
} else if (DeviceExists) { } else if (DeviceExists) {
StorageService()->UpdateDeviceCapabilities(DbSession_->Session(), SerialNumber_, Caps); StorageService()->UpdateDeviceCapabilities(SerialNumber_, Caps);
int Updated{0}; int Updated{0};
if (!Firmware.empty()) { if (!Firmware.empty()) {
if (Firmware != DeviceInfo.Firmware) { if (Firmware != DeviceInfo.Firmware) {
DeviceFirmwareChangeKafkaEvent KEvent(SerialNumberInt_, Utils::Now(), DeviceFirmwareChangeKafkaEvent KEvent(SerialNumber_, Utils::Now(),
DeviceInfo.Firmware, Firmware); DeviceInfo.Firmware, Firmware);
DeviceInfo.Firmware = Firmware; DeviceInfo.Firmware = Firmware;
DeviceInfo.LastFWUpdate = Utils::Now(); DeviceInfo.LastFWUpdate = Utils::Now();
@@ -175,44 +131,13 @@ 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) { if (DeviceInfo.locale != State_.locale) {
DeviceInfo.locale = State_.locale; DeviceInfo.locale = State_.locale;
++Updated; ++Updated;
} }
if (Compatible_ != DeviceInfo.Compatible) { if (Compatible_ != DeviceInfo.DeviceType) {
DeviceInfo.Compatible = Compatible_; DeviceInfo.DeviceType = Compatible_;
++Updated;
}
if (Platform != DeviceInfo.DeviceType) {
DeviceInfo.DeviceType = Platform;
++Updated; ++Updated;
} }
@@ -226,21 +151,13 @@ namespace OpenWifi {
++Updated; ++Updated;
} }
if(DeviceInfo.certificateExpiryDate!=State_.certificateExpiryDate) {
DeviceInfo.certificateExpiryDate = State_.certificateExpiryDate;
++Updated;
}
if (Updated) { if (Updated) {
StorageService()->UpdateDevice(DbSession_->Session(), DeviceInfo); StorageService()->UpdateDevice(DeviceInfo);
} }
}
if(!Simulated_) {
uint64_t UpgradedUUID = 0; uint64_t UpgradedUUID = 0;
if (LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID)) { LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID; State_.UUID = UpgradedUUID;
}
} }
State_.Compatible = Compatible_; State_.Compatible = Compatible_;
@@ -276,12 +193,6 @@ namespace OpenWifi {
return EndConnection(); return EndConnection();
} }
} }
} else {
poco_information(Logger_,
fmt::format("CONNECT({}): Simulator device. "
"Session={} ConnectionCompletion Time={}",
CId_, State_.sessionId,
State_.connectionCompletionTime));
} }
GWWebSocketNotifications::SingleDevice_t Notification; GWWebSocketNotifications::SingleDevice_t Notification;
@@ -289,11 +200,14 @@ namespace OpenWifi {
GWWebSocketNotifications::DeviceConnected(Notification); GWWebSocketNotifications::DeviceConnected(Notification);
if (KafkaManager()->Enabled()) { if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_); ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
ParamsObj->set("locale", State_.locale); ParamsObj->set("locale", State_.locale);
ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now()); ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
ParamsObj->set(uCentralProtocol::UUID, uuid_); std::ostringstream OS;
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, *ParamsObj); Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
} }
} else { } else {
poco_warning( poco_warning(

View File

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

View File

@@ -21,10 +21,10 @@ namespace OpenWifi {
if (ParamsObj->has("currentPassword")) { if (ParamsObj->has("currentPassword")) {
auto Password = ParamsObj->get("currentPassword").toString(); auto Password = ParamsObj->get("currentPassword").toString();
StorageService()->SetDevicePassword(*DbSession_,Serial, Password); StorageService()->SetDevicePassword(Serial, Password);
poco_trace( poco_trace(
Logger_, 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("type", EventType);
FullEvent.set("timestamp", EventTimeStamp); FullEvent.set("timestamp", EventTimeStamp);
FullEvent.set("payload", EventPayload); FullEvent.set("payload", EventPayload);
if(strncmp(EventType.c_str(),"rrm.",4) == 0 ) {
KafkaManager()->PostMessage(KafkaTopics::RRM, SerialNumber_, std::ostringstream OS;
FullEvent); FullEvent.stringify(OS);
} else { KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_, OS.str());
FullEvent);
}
} }
} }
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {

View File

@@ -3,7 +3,6 @@
// //
#include "AP_WS_Connection.h" #include "AP_WS_Connection.h"
#include "AP_WS_Server.h"
#include "StorageService.h" #include "StorageService.h"
#include "fmt/format.h" #include "fmt/format.h"
@@ -20,13 +19,10 @@ namespace OpenWifi {
Errors_++; Errors_++;
return; return;
} }
if (ParamsObj->has(uCentralProtocol::UUID) && if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
ParamsObj->has(uCentralProtocol::SANITY) &&
ParamsObj->has(uCentralProtocol::DATA)) { ParamsObj->has(uCentralProtocol::DATA)) {
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID); uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY); auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
State_.sanity = Sanity;
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString(); auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
if (CheckData.empty()) if (CheckData.empty())
CheckData = uCentralProtocol::EMPTY_JSON_DOC; CheckData = uCentralProtocol::EMPTY_JSON_DOC;
@@ -42,6 +38,10 @@ namespace OpenWifi {
CId_, UUID, request_uuid)); CId_, UUID, request_uuid));
} }
uint64_t UpgradedUUID;
LookForUpgrade(UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
GWObjects::HealthCheck Check; GWObjects::HealthCheck Check;
Check.SerialNumber = SerialNumber_; Check.SerialNumber = SerialNumber_;
@@ -50,15 +50,19 @@ namespace OpenWifi {
Check.Data = CheckData; Check.Data = CheckData;
Check.Sanity = Sanity; Check.Sanity = Sanity;
StorageService()->AddHealthCheckData(*DbSession_, Check); StorageService()->AddHealthCheckData(Check);
if (!request_uuid.empty()) { if (!request_uuid.empty()) {
StorageService()->SetCommandResult(request_uuid, CheckData); StorageService()->SetCommandResult(request_uuid, CheckData);
} }
SetLastHealthCheck(Check); SetLastHealthCheck(Check);
if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableHealthChecks()) { 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 { } else {
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_)); poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));

View File

@@ -7,7 +7,6 @@
#include "fmt/format.h" #include "fmt/format.h"
#include "framework/ow_constants.h" #include "framework/ow_constants.h"
#include <GWKafkaEvents.h>
namespace OpenWifi { namespace OpenWifi {
void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) { void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
@@ -36,8 +35,7 @@ namespace OpenWifi {
.Recorded = (uint64_t)time(nullptr), .Recorded = (uint64_t)time(nullptr),
.LogType = 0, .LogType = 0,
.UUID = State_.UUID}; .UUID = State_.UUID};
StorageService()->AddLog(*DbSession_, DeviceLog); StorageService()->AddLog(DeviceLog);
DeviceLogKafkaEvent E(DeviceLog);
} else { } else {
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_)); poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
return; 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(*DbSession_, DeviceLog);
DeviceLogKafkaEvent E(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("REBOOT-LOG({}): Missing parameters.", CId_));
}
}
} // namespace OpenWifi

View File

@@ -35,7 +35,7 @@ namespace OpenWifi {
.LogType = 1, .LogType = 1,
.UUID = 0}; .UUID = 0};
StorageService()->AddLog(*DbSession_, DeviceLog); StorageService()->AddLog(DeviceLog);
if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") { if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
GWObjects::CommandDetails Cmd; GWObjects::CommandDetails Cmd;

View File

@@ -3,7 +3,6 @@
// //
#include "AP_WS_Connection.h" #include "AP_WS_Connection.h"
#include "AP_WS_Server.h"
#include "StateUtils.h" #include "StateUtils.h"
#include "StorageService.h" #include "StorageService.h"
@@ -40,28 +39,27 @@ namespace OpenWifi {
UUID, request_uuid)); UUID, request_uuid));
} }
std::lock_guard Guard(DbSession_->Mutex()); uint64_t UpgradedUUID;
if(!Simulated_) { LookForUpgrade(UUID, UpgradedUUID);
uint64_t UpgradedUUID; State_.UUID = UpgradedUUID;
LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID);
State_.UUID = UpgradedUUID;
}
SetLastStats(StateStr); SetLastStats(StateStr);
GWObjects::Statistics Stats{ GWObjects::Statistics Stats{
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr}; .SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
Stats.Recorded = Utils::Now(); Stats.Recorded = Utils::Now();
StorageService()->AddStatisticsData(DbSession_->Session(),Stats); StorageService()->AddStatisticsData(Stats);
if (!request_uuid.empty()) { if (!request_uuid.empty()) {
StorageService()->SetCommandResult(request_uuid, StateStr); StorageService()->SetCommandResult(request_uuid, StateStr);
} }
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G, StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
State_.Associations_5G, State_.Associations_6G, State_.uptime); State_.Associations_5G, State_.Associations_6G);
if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableState()) { 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; GWWebSocketNotifications::SingleDevice_t N;

View File

@@ -27,28 +27,29 @@ namespace OpenWifi {
std::ostringstream SS; std::ostringstream SS;
Payload->stringify(SS); Payload->stringify(SS);
auto now = Utils::Now(); auto now = Utils::Now();
auto KafkaPayload = SS.str();
if (ParamsObj->has("adhoc")) { if (ParamsObj->has("adhoc")) {
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_, KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
KafkaPayload); SS.str());
return; return;
} }
if (TelemetryWebSocketRefCount_) { if (TelemetryWebSocketRefCount_) {
if (now < TelemetryWebSocketTimer_) { if (now < TelemetryWebSocketTimer_) {
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" <<
// std::endl;
TelemetryWebSocketPackets_++; TelemetryWebSocketPackets_++;
State_.websocketPackets = TelemetryWebSocketPackets_; State_.websocketPackets = TelemetryWebSocketPackets_;
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, KafkaPayload); TelemetryStream()->NotifyEndPoint(SerialNumberInt_, SS.str());
} else { } else {
StopWebSocketTelemetry(CommandManager()->Next_RPC_ID()); StopWebSocketTelemetry(CommandManager()->Next_RPC_ID());
} }
} }
if (TelemetryKafkaRefCount_) { if (TelemetryKafkaRefCount_) {
if (KafkaManager()->Enabled() && now < TelemetryKafkaTimer_) { if (KafkaManager()->Enabled() && now < TelemetryKafkaTimer_) {
// std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl;
TelemetryKafkaPackets_++; TelemetryKafkaPackets_++;
State_.kafkaPackets = TelemetryKafkaPackets_; State_.kafkaPackets = TelemetryKafkaPackets_;
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_, KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
KafkaPayload); SS.str());
} else { } else {
StopKafkaTelemetry(CommandManager()->Next_RPC_ID()); StopKafkaTelemetry(CommandManager()->Next_RPC_ID());
} }

View File

@@ -21,7 +21,11 @@ namespace OpenWifi {
if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) { if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
if (KafkaManager()->Enabled()) { 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());
} }
} }
} }

62
src/AP_WS_ReactorPool.h Normal file
View File

@@ -0,0 +1,62 @@
//
// Created by stephane bourque on 2022-02-03.
//
#pragma once
#include <shared_mutex>
#include <string>
#include "Poco/Environment.h"
#include "Poco/Net/SocketAcceptor.h"
#include "framework/utils.h"
namespace OpenWifi {
class AP_WS_ReactorThreadPool {
public:
explicit AP_WS_ReactorThreadPool() {
NumberOfThreads_ = Poco::Environment::processorCount() * 2;
if (NumberOfThreads_ == 0)
NumberOfThreads_ = 4;
}
~AP_WS_ReactorThreadPool() { Stop(); }
void Start() {
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
auto NewReactor = std::make_unique<Poco::Net::SocketReactor>();
auto NewThread = std::make_unique<Poco::Thread>();
NewThread->start(*NewReactor);
std::string ThreadName{"ap:react:" + std::to_string(i)};
Utils::SetThreadName(*NewThread, ThreadName.c_str());
Reactors_.emplace_back(std::move(NewReactor));
Threads_.emplace_back(std::move(NewThread));
}
}
void Stop() {
for (auto &i : Reactors_)
i->stop();
for (auto &i : Threads_) {
i->join();
}
Reactors_.clear();
Threads_.clear();
}
Poco::Net::SocketReactor &NextReactor() {
std::shared_lock Lock(Mutex_);
NextReactor_++;
NextReactor_ %= NumberOfThreads_;
return *Reactors_[NextReactor_];
}
private:
std::shared_mutex Mutex_;
uint64_t NumberOfThreads_;
uint64_t NextReactor_ = 0;
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
};
} // namespace OpenWifi

View File

@@ -1,77 +0,0 @@
//
// Created by stephane bourque on 2022-02-03.
//
#pragma once
#include <mutex>
#include <string>
#include <framework/utils.h>
#include <Poco/Environment.h>
#include <Poco/Net/SocketAcceptor.h>
#include <Poco/Data/SessionPool.h>
#include <StorageService.h>
namespace OpenWifi {
class AP_WS_ReactorThreadPool {
public:
explicit AP_WS_ReactorThreadPool(Poco::Logger &Logger) : Logger_(Logger) {
NumberOfThreads_ = Poco::Environment::processorCount() * 4;
if (NumberOfThreads_ == 0)
NumberOfThreads_ = 8;
NumberOfThreads_ = std::min(NumberOfThreads_, (std::uint64_t) 128);
}
~AP_WS_ReactorThreadPool() { Stop(); }
void Start() {
Reactors_.reserve(NumberOfThreads_);
DbSessions_.reserve(NumberOfThreads_);
Threads_.reserve(NumberOfThreads_);
Logger_.information(fmt::format("WebSocket Processor: starting {} threads.", NumberOfThreads_));
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
auto NewReactor = std::make_shared<Poco::Net::SocketReactor>();
auto NewThread = std::make_unique<Poco::Thread>();
NewThread->start(*NewReactor);
std::string ThreadName{"ap:react:" + std::to_string(i)};
Utils::SetThreadName(*NewThread, ThreadName.c_str());
Reactors_.emplace_back(std::move(NewReactor));
Threads_.emplace_back(std::move(NewThread));
DbSessions_.emplace_back(std::make_shared<LockedDbSession>());
}
Logger_.information(fmt::format("WebSocket Processor: {} threads started.", NumberOfThreads_));
}
void Stop() {
for (auto &i : Reactors_)
i->stop();
for (auto &i : Threads_) {
i->join();
}
Reactors_.clear();
Threads_.clear();
DbSessions_.clear();
}
auto NextReactor() {
std::lock_guard Lock(Mutex_);
NextReactor_++;
NextReactor_ %= NumberOfThreads_;
return std::make_pair(Reactors_[NextReactor_], DbSessions_[NextReactor_]);
}
private:
std::mutex Mutex_;
uint64_t NumberOfThreads_;
uint64_t NextReactor_ = 0;
std::vector<std::shared_ptr<Poco::Net::SocketReactor>> Reactors_;
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
std::vector<std::shared_ptr<LockedDbSession>> DbSessions_;
Poco::Logger &Logger_;
};
} // namespace OpenWifi

View File

@@ -6,83 +6,44 @@
// Arilia Wireless Inc. // Arilia Wireless Inc.
// //
#include <Poco/Net/Context.h> #include "Poco/Net/Context.h"
#include <Poco/Net/HTTPHeaderStream.h> #include "Poco/Net/HTTPHeaderStream.h"
#include <Poco/Net/HTTPServerRequest.h> #include "Poco/Net/HTTPServerRequest.h"
#include <AP_WS_Connection.h> #include "AP_WS_Connection.h"
#include <AP_WS_Server.h> #include "AP_WS_Server.h"
#include <ConfigurationCache.h> #include "ConfigurationCache.h"
#include <TelemetryStream.h> #include "TelemetryStream.h"
#include <fmt/format.h> #include "UI_GW_WebSocketNotifications.h"
#include "fmt/format.h"
#include <framework/MicroServiceFuncs.h> #include "framework/MicroServiceFuncs.h"
#include <framework/utils.h> #include "framework/utils.h"
#include <framework/KafkaManager.h>
#include <UI_GW_WebSocketNotifications.h>
namespace OpenWifi { namespace OpenWifi {
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler { void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
public: Poco::Net::HTTPServerResponse &response) {
explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t session_id) : Logger_(L), try {
session_id_(session_id) { AP_WS_Server()->AddConnection(
}; id_, std::make_shared<AP_WS_Connection>(request, response, id_, Logger_,
AP_WS_Server()->NextReactor()));
void handleRequest( Poco::Net::HTTPServerRequest &request, } catch (...) {
Poco::Net::HTTPServerResponse &response) override { poco_warning(Logger_, "Exception during WS creation");
try {
auto NewConnection = std::make_shared<AP_WS_Connection>(request, response, session_id_, Logger_,
AP_WS_Server()->NextReactor());
AP_WS_Server()->AddConnection(NewConnection);
NewConnection->Start();
} catch (...) {
poco_warning(Logger_, "Exception during WS creation");
}
};
private:
Poco::Logger &Logger_;
std::uint64_t session_id_;
};
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L) : Logger_(L) {}
inline Poco::Net::HTTPRequestHandler *
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
if (request.find("Upgrade") != request.end() &&
Poco::icompare(request["Upgrade"], "websocket") == 0) {
Utils::SetThreadName("ws:conn-init");
session_id_++;
return new AP_WS_RequestHandler(Logger_, session_id_);
} else {
return nullptr;
}
} }
private:
Poco::Logger &Logger_;
inline static std::atomic_uint64_t session_id_ = 0;
}; };
bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId, bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
const Poco::Crypto::X509Certificate &Certificate) { const Poco::Crypto::X509Certificate &Certificate) {
if (IsCertOk()) { if (IsCertOk()) {
// validate certificate agains trusted chain if (!Certificate.issuedBy(*IssuerCert_)) {
for (const auto &cert : ClientCasCerts_) { poco_warning(
if (Certificate.issuedBy(cert)) {
return true;
}
}
poco_warning(
Logger(), Logger(),
fmt::format( fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'",
"CERTIFICATE({}): issuer mismatch. Certificate not issued by any trusted CA", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
ConnectionId) return false;
); }
return true;
} }
return false; return false;
} }
@@ -93,9 +54,7 @@ namespace OpenWifi {
MicroServiceConfigGetBool("openwifi.certificates.allowmismatch", true); MicroServiceConfigGetBool("openwifi.certificates.allowmismatch", true);
MismatchDepth_ = MicroServiceConfigGetInt("openwifi.certificates.mismatchdepth", 2); MismatchDepth_ = MicroServiceConfigGetInt("openwifi.certificates.mismatchdepth", 2);
SessionTimeOut_ = MicroServiceConfigGetInt("openwifi.session.timeout", 10*60); Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>(Logger());
Reactor_pool_->Start(); Reactor_pool_->Start();
for (const auto &Svr : ConfigServersList_) { for (const auto &Svr : ConfigServersList_) {
@@ -137,13 +96,6 @@ namespace OpenWifi {
Context->addChainCertificate(Issuing); Context->addChainCertificate(Issuing);
Context->addCertificateAuthority(Issuing); Context->addCertificateAuthority(Issuing);
// add certificates from clientcas to trust chain
ClientCasCerts_ = Poco::Net::X509Certificate::readPEM(Svr.ClientCas());
for (const auto &cert : ClientCasCerts_) {
Context->addChainCertificate(cert);
Context->addCertificateAuthority(cert);
}
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword()); Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
Context->usePrivateKey(Key); Context->usePrivateKey(Key);
@@ -152,6 +104,7 @@ namespace OpenWifi {
Context->flushSessionCache(); Context->flushSessionCache();
Context->enableSessionCache(true); Context->enableSessionCache(true);
Context->enableExtendedCertificateVerification(false); Context->enableExtendedCertificateVerification(false);
// Context->disableStatelessSessionResumption();
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 | Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 |
Poco::Net::Context::PROTO_TLSV1_1); Poco::Net::Context::PROTO_TLSV1_1);
@@ -180,9 +133,6 @@ namespace OpenWifi {
WebServerHttpParams); WebServerHttpParams);
WebServers_.push_back(std::move(NewWebServer)); WebServers_.push_back(std::move(NewWebServer));
} }
KafkaDisableState_ = MicroServiceConfigGetBool("openwifi.kafka.disablestate", false);
KafkaDisableHealthChecks_ = MicroServiceConfigGetBool("openwifi.kafka.disablehealthchecks", false);
} }
for (auto &server : WebServers_) { for (auto &server : WebServers_) {
@@ -204,420 +154,204 @@ namespace OpenWifi {
UseDefaultConfig_ = true; UseDefaultConfig_ = true;
} }
SimulatorId_ = Poco::toLower(MicroServiceConfigGetString("simulatorid", "")); SimulatorId_ = MicroServiceConfigGetString("simulatorid", "");
SimulatorEnabled_ = !SimulatorId_.empty(); SimulatorEnabled_ = !SimulatorId_.empty();
Utils::SetThreadName(ReactorThread_, "dev:react:head"); Utils::SetThreadName(ReactorThread_, "dev:react:head");
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(
*this, &AP_WS_Server::onGarbageCollecting);
Timer_.setStartInterval(10 * 1000);
Timer_.setPeriodicInterval(5 * 1000); // every minute
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
Running_ = true; Running_ = true;
GarbageCollector_.setName("ws:garbage");
GarbageCollector_.start(*this);
std::thread CleanupThread([this](){ CleanupSessions(); });
CleanupThread.detach();
return 0; return 0;
} }
bool AP_WS_Server::Disconnect(uint64_t SerialNumber) { void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
std::shared_ptr<AP_WS_Connection> Connection; std::lock_guard Lock(WSServerMutex_);
{ if (!Garbage_.empty()) {
auto hashIndex = MACHash::Hash(SerialNumber); Garbage_.clear();
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
if (DeviceHint == SerialNumbers_[hashIndex].end() || DeviceHint->second == nullptr) {
return false;
}
Connection = DeviceHint->second;
SerialNumbers_[hashIndex].erase(DeviceHint);
} }
{ static uint64_t last_log = Utils::Now();
auto H = SessionHash::Hash(Connection->State_.sessionId);
std::lock_guard SessionLock(SessionMutex_[H]);
Sessions_[H].erase(Connection->State_.sessionId);
}
return true; NumberOfConnectedDevices_ = 0;
} NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
uint64_t total_connected_time = 0;
void AP_WS_Server::CleanupSessions() { auto now = Utils::Now();
for (const auto &connection : SerialNumbers_) {
while(Running_) { if (connection.second.second == nullptr) {
std::this_thread::sleep_for(std::chrono::seconds(10)); continue;
}
while(Running_ && !CleanupSessions_.empty()) { if (connection.second.second->State_.Connected) {
std::pair<uint64_t, uint64_t> Session; NumberOfConnectedDevices_++;
{ total_connected_time += (now - connection.second.second->State_.started);
std::lock_guard G(CleanupMutex_); } else {
Session = CleanupSessions_.front(); NumberOfConnectingDevices_++;
CleanupSessions_.pop_front();
}
poco_trace(this->Logger(),fmt::format("Cleaning up session: {} for device: {}", Session.first, Utils::IntToSerialNumber(Session.second)));
EndSession(Session.first, Session.second);
} }
} }
}
void AP_WS_Server::run() { AverageDeviceConnectionTime_ =
uint64_t last_log = Utils::Now(), (NumberOfConnectedDevices_ != 0) ? total_connected_time / NumberOfConnectedDevices_ : 0;
last_zombie_run = 0, if ((now - last_log) > 120) {
last_garbage_run = 0; last_log = now;
poco_information(
Poco::Logger &LocalLogger = Poco::Logger::create( Logger(),
"WS-Session-Janitor", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel()); fmt::format(
"Active AP connections: {} Connecting: {} Average connection time: {} seconds",
while(Running_) { NumberOfConnectedDevices_, NumberOfConnectingDevices_,
AverageDeviceConnectionTime_));
if(!Poco::Thread::trySleep(30000)) {
break;
}
LocalLogger.information(fmt::format("Garbage collecting starting run." ));
uint64_t total_connected_time = 0, now = Utils::Now();
if(now-last_zombie_run > 60) {
try {
poco_information(LocalLogger,
fmt::format("Garbage collecting zombies... (step 1)"));
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
int waits = 0;
for (int hashIndex = 0; hashIndex < MACHash::HashMax(); hashIndex++) {
last_zombie_run = now;
waits = 0;
while (true) {
if (SerialNumbersMutex_[hashIndex].try_lock()) {
waits = 0;
auto hint = SerialNumbers_[hashIndex].begin();
while (hint != end(SerialNumbers_[hashIndex])) {
if (hint->second == nullptr) {
poco_information(
LocalLogger,
fmt::format("Dead device found in hash index {}", hashIndex));
hint = SerialNumbers_[hashIndex].erase(hint);
} else {
auto Device = hint->second;
auto RightNow = Utils::Now();
if (Device->Dead_) {
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
++hint;
// hint = SerialNumbers_[hashIndex].erase(hint);
} else if (RightNow > Device->LastContact_ &&
(RightNow - Device->LastContact_) > SessionTimeOut_) {
poco_information(
LocalLogger,
fmt::format(
"{}: Session seems idle. Controller disconnecting device.",
Device->SerialNumber_));
// hint = SerialNumbers_[hashIndex].erase(hint);
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
++hint;
} else {
if (Device->State_.Connected) {
total_connected_time +=
(RightNow - Device->State_.started);
}
++hint;
}
}
}
SerialNumbersMutex_[hashIndex].unlock();
break;
} else if (waits < 5) {
waits++;
Poco::Thread::trySleep(10);
} else {
break;
}
}
}
poco_information(LocalLogger, fmt::format("Garbage collecting zombies... (step 2)"));
LeftOverSessions_ = 0;
for (int i = 0; i < SessionHash::HashMax(); i++) {
waits = 0;
while (true) {
if (SessionMutex_[i].try_lock()) {
waits = 0;
auto hint = Sessions_[i].begin();
auto RightNow = Utils::Now();
while (hint != end(Sessions_[i])) {
if (hint->second == nullptr) {
hint = Sessions_[i].erase(hint);
} else if (hint->second->Dead_) {
// hint = Sessions_[i].erase(hint);
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
++hint;
} else if (RightNow > hint->second->LastContact_ &&
(RightNow - hint->second->LastContact_) >
SessionTimeOut_) {
poco_information(
LocalLogger,
fmt::format("{}: Session seems idle. Controller disconnecting device.",
hint->second->SerialNumber_));
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
++hint;
// hint = Sessions_[i].erase(hint);
} else {
++LeftOverSessions_;
++hint;
}
}
SessionMutex_[i].unlock();
break;
} else if (waits < 5) {
Poco::Thread::trySleep(10);
waits++;
} else {
break;
}
}
}
AverageDeviceConnectionTime_ = NumberOfConnectedDevices_ > 0
? total_connected_time / NumberOfConnectedDevices_
: 0;
poco_information(LocalLogger, fmt::format("Garbage collecting zombies done..."));
} catch (const Poco::Exception &E) {
poco_error(LocalLogger, fmt::format("Poco::Exception: Garbage collecting zombies failed: {}", E.displayText()));
} catch (const std::exception &E) {
poco_error(LocalLogger, fmt::format("std::exception: Garbage collecting zombies failed: {}", E.what()));
} catch (...) {
poco_error(LocalLogger, fmt::format("exception:Garbage collecting zombies failed: {}", "unknown"));
}
}
if(NumberOfConnectedDevices_) {
if (last_garbage_run > 0) {
AverageDeviceConnectionTime_ += (now - last_garbage_run);
}
}
try {
if ((now - last_log) > 60) {
last_log = now;
poco_information(
LocalLogger,
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds. Left Over Sessions: {}",
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
AverageDeviceConnectionTime_, LeftOverSessions_));
}
GWWebSocketNotifications::NumberOfConnection_t Notification;
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
GetTotalDataStatistics(Notification.content.tx, Notification.content.rx);
GWWebSocketNotifications::NumberOfConnections(Notification);
Poco::JSON::Object KafkaNotification;
Notification.to_json(KafkaNotification);
Poco::JSON::Object FullEvent;
FullEvent.set("type", "load-update");
FullEvent.set("timestamp", now);
FullEvent.set("payload", KafkaNotification);
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
LocalLogger.information(fmt::format("Garbage collection finished run."));
last_garbage_run = now;
} catch (const Poco::Exception &E) {
LocalLogger.error(fmt::format("Poco::Exception: Garbage collecting failed: {}", E.displayText()));
} catch (const std::exception &E) {
LocalLogger.error(fmt::format("std::exception: Garbage collecting failed: {}", E.what()));
} catch (...) {
LocalLogger.error(fmt::format("exception:Garbage collecting failed: {}", "unknown"));
}
} }
LocalLogger.information(fmt::format("Garbage collector done for the day." ));
GWWebSocketNotifications::NumberOfConnection_t Notification;
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
GetTotalDataStatistics(Notification.content.tx,Notification.content.rx);
GWWebSocketNotifications::NumberOfConnections(Notification);
} }
void AP_WS_Server::Stop() { void AP_WS_Server::Stop() {
poco_information(Logger(), "Stopping..."); poco_information(Logger(), "Stopping...");
Running_ = false; Running_ = false;
GarbageCollector_.wakeUp(); Timer_.stop();
GarbageCollector_.join();
for (auto &server : WebServers_) { for (auto &server : WebServers_) {
server->stopAll(); server->stopAll();
} }
Reactor_pool_->Stop(); Reactor_pool_->Stop();
Reactor_.stop(); Reactor_.stop();
ReactorThread_.join(); ReactorThread_.join();
poco_information(Logger(), "Stopped..."); poco_information(Logger(), "Stopped...");
} }
bool AP_WS_Server::GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
SerialNumbers.clear();
for(int i=0;i<SessionHash::HashMax();i++) {
std::lock_guard Lock(SessionMutex_[i]);
for (const auto &connection : Sessions_[i]) {
if (connection.second->RawLastHealthcheck_.Sanity >= lowLimit &&
connection.second->RawLastHealthcheck_.Sanity <= highLimit) {
SerialNumbers.push_back(connection.second->SerialNumber_);
}
}
}
return true;
}
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const { bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
if (DeviceHint == SerialNumbers_[hashIndex].end() || DeviceHint->second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
Connection->GetLastStats(Statistics); DevicePtr->GetLastStats(Statistics);
return true; return true;
} }
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const { bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
if (DeviceHint == SerialNumbers_[hashIndex].end() ||
DeviceHint->second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
Connection->GetState(State); DevicePtr->GetState(State);
return true; return true;
} }
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber, bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber,
GWObjects::HealthCheck &CheckData) const { GWObjects::HealthCheck &CheckData) const {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
if (Device == SerialNumbers_[hashIndex].end() || Device->second == nullptr) {
return false; return false;
} }
Connection = Device->second; DevicePtr = Device->second.second;
}
Connection->GetLastHealthCheck(CheckData);
return true;
}
void AP_WS_Server::StartSession(uint64_t session_id, uint64_t SerialNumber) {
auto sessionHash = SessionHash::Hash(session_id);
std::shared_ptr<AP_WS_Connection> Connection;
{
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
auto SessionHint = Sessions_[sessionHash].find(session_id);
if (SessionHint == end(Sessions_[sessionHash])) {
return;
}
Connection = SessionHint->second;
Sessions_[sessionHash].erase(SessionHint);
}
auto deviceHash = MACHash::Hash(SerialNumber);
std::lock_guard DeviceLock(SerialNumbersMutex_[deviceHash]);
SerialNumbers_[deviceHash][SerialNumber] = Connection;
}
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {
{
poco_trace(Logger(), fmt::format("Ending session 1: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
auto sessionHash = SessionHash::Hash(session_id);
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
Sessions_[sessionHash].erase(session_id);
poco_trace(Logger(), fmt::format("Ended session 1: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
}
{
auto hashIndex = MACHash::Hash(SerialNumber);
poco_trace(Logger(), fmt::format("Ending session 2.0: {} for device: {} hi:{}", session_id, Utils::IntToSerialNumber(SerialNumber), hashIndex));
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
poco_trace(Logger(), fmt::format("Ending session 2.1: {} for device: {} hi:{}", session_id, Utils::IntToSerialNumber(SerialNumber), hashIndex));
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
poco_trace(Logger(), fmt::format("Ending session 2.2: {} for device: {} hi:{}", session_id, Utils::IntToSerialNumber(SerialNumber), hashIndex));
if (DeviceHint == SerialNumbers_[hashIndex].end()
|| DeviceHint->second == nullptr
|| DeviceHint->second->State_.sessionId != session_id) {
poco_trace(Logger(), fmt::format("Did not end session 2: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
return false;
}
SerialNumbers_[hashIndex].erase(DeviceHint);
poco_trace(Logger(), fmt::format("Ended session 2: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
} }
DevicePtr->GetLastHealthCheck(CheckData);
return true; return true;
} }
void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
std::lock_guard Lock(WSServerMutex_);
auto Conn = Sessions_.find(connection_id);
if (Conn == end(Sessions_))
return;
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
if ((CurrentSerialNumber == SerialNumbers_.end()) ||
(CurrentSerialNumber->second.first < connection_id)) {
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second);
return;
}
}
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t serial_number) {
std::lock_guard G(WSServerMutex_);
auto Session = Sessions_.find(session_id);
if (Session == end(Sessions_))
return false;
Garbage_.push_back(Session->second);
auto Device = SerialNumbers_.find(serial_number);
if (Device == end(SerialNumbers_)) {
Sessions_.erase(Session);
return false;
}
if (Device->second.first == session_id) {
Sessions_.erase(Session);
SerialNumbers_.erase(Device);
return true;
}
Sessions_.erase(Session);
return false;
}
bool AP_WS_Server::Connected(uint64_t SerialNumber, bool AP_WS_Server::Connected(uint64_t SerialNumber,
GWObjects::DeviceRestrictions &Restrictions) const { GWObjects::DeviceRestrictions &Restrictions) const {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
DevicePtr->GetRestrictions(Restrictions);
if(Connection->Dead_) { return DevicePtr->State_.Connected;
return false;
}
Restrictions = Connection->GetRestrictions();
return Connection->State_.Connected;
} }
bool AP_WS_Server::Connected(uint64_t SerialNumber) const { bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
return DevicePtr->State_.Connected;
if(Connection->Dead_) {
return false;
}
return Connection->State_.Connected;
} }
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const { bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const {
auto hashIndex = MACHash::Hash(SerialNumber); std::shared_ptr<AP_WS_Connection> DevicePtr;
std::shared_ptr<AP_WS_Connection> Connection;
{ {
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); std::lock_guard Lock(WSServerMutex_);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); auto Device = SerialNumbers_.find(SerialNumber);
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) { if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
if(Connection->Dead_) {
return false;
}
try { try {
return Connection->Send(Payload); return DevicePtr->Send(Payload);
} catch (...) { } catch (...) {
poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'", poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'",
Utils::IntToSerialNumber(SerialNumber))); Utils::IntToSerialNumber(SerialNumber)));
@@ -626,64 +360,61 @@ namespace OpenWifi {
} }
void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) { void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
auto Device = SerialNumbers_[hashIndex].find(SerialNumber); auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_[hashIndex]) || Device->second == nullptr) { if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return; return;
} }
Connection = Device->second; DevicePtr = Device->second.second;
} }
Connection->StopWebSocketTelemetry(RPCID); DevicePtr->StopWebSocketTelemetry(RPCID);
} }
void void
AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime, uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes) { const std::vector<std::string> &TelemetryTypes) {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return; return;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
Connection->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes); DevicePtr->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
} }
void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime, uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes) { const std::vector<std::string> &TelemetryTypes) {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return; return;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
Connection->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes); DevicePtr->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
} }
void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) { void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return; return;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
Connection->StopKafkaTelemetry(RPCID); DevicePtr->StopKafkaTelemetry(RPCID);
} }
void AP_WS_Server::GetTelemetryParameters( void AP_WS_Server::GetTelemetryParameters(
@@ -691,19 +422,16 @@ namespace OpenWifi {
uint64_t &TelemetryWebSocketTimer, uint64_t &TelemetryKafkaTimer, uint64_t &TelemetryWebSocketTimer, uint64_t &TelemetryKafkaTimer,
uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount, uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount,
uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) { uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
std::shared_ptr<AP_WS_Connection> Connection;
{ {
auto hashIndex = MACHash::Hash(SerialNumber); std::lock_guard Lock(WSServerMutex_);
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); auto Device = SerialNumbers_.find(SerialNumber);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber); if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return; return;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
DevicePtr->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
Connection->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
TelemetryWebSocketTimer, TelemetryKafkaTimer, TelemetryWebSocketTimer, TelemetryKafkaTimer,
TelemetryWebSocketCount, TelemetryKafkaCount, TelemetryWebSocketCount, TelemetryKafkaCount,
TelemetryWebSocketPackets, TelemetryKafkaPackets); TelemetryWebSocketPackets, TelemetryKafkaPackets);
@@ -711,25 +439,18 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusAccountingData(const std::string &SerialNumber, bool AP_WS_Server::SendRadiusAccountingData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) { const unsigned char *buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
std::shared_ptr<AP_WS_Connection> Connection;
{ {
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber); std::lock_guard Lock(WSServerMutex_);
auto hashIndex = MACHash::Hash(IntSerialNumber); auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
}
if(Connection->Dead_) {
return false;
} }
try { try {
return Connection->SendRadiusAccountingData(buffer, size); return DevicePtr->SendRadiusAccountingData(buffer, size);
} catch (...) { } catch (...) {
poco_debug( poco_debug(
Logger(), Logger(),
@@ -741,24 +462,18 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber, bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) { const unsigned char *buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber); std::lock_guard Lock(WSServerMutex_);
auto hashIndex = MACHash::Hash(IntSerialNumber); auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]); if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
}
if(Connection->Dead_) {
return false;
} }
try { try {
return Connection->SendRadiusAuthenticationData(buffer, size); return DevicePtr->SendRadiusAuthenticationData(buffer, size);
} catch (...) { } catch (...) {
poco_debug( poco_debug(
Logger(), Logger(),
@@ -770,23 +485,18 @@ namespace OpenWifi {
bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber, bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size) { const unsigned char *buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> Connection; std::shared_ptr<AP_WS_Connection> DevicePtr;
{ {
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber); std::lock_guard Lock(WSServerMutex_);
auto hashIndex = MACHash::Hash(IntSerialNumber); auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
return false; return false;
} }
Connection = DeviceHint->second; DevicePtr = Device->second.second;
} }
if(Connection->Dead_) {
return false;
}
try { try {
return Connection->SendRadiusCoAData(buffer, size); return DevicePtr->SendRadiusCoAData(buffer, size);
} catch (...) { } catch (...) {
poco_debug(Logger(), poco_debug(Logger(),
fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", fmt::format(": SendRadiusCoAData: Could not send data to device '{}'",
@@ -795,4 +505,4 @@ namespace OpenWifi {
return false; return false;
} }
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -24,51 +24,46 @@
#include "Poco/Timer.h" #include "Poco/Timer.h"
#include "AP_WS_Connection.h" #include "AP_WS_Connection.h"
#include "AP_WS_Reactor_Pool.h" #include "AP_WS_ReactorPool.h"
#include "framework/SubSystemServer.h" #include "framework/SubSystemServer.h"
#include "framework/utils.h" #include "framework/utils.h"
namespace OpenWifi { namespace OpenWifi {
constexpr uint MACHashMax = 256; class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
constexpr uint MACHashMask = MACHashMax-1;
class MACHash {
public: public:
[[nodiscard]] static inline uint16_t Hash(std::uint64_t value) { explicit AP_WS_RequestHandler(Poco::Logger &L, uint64_t id) : Logger_(L), id_(id){};
uint8_t hash = 0, i=6;
while(i) { void handleRequest(Poco::Net::HTTPServerRequest &request,
hash ^= (value & MACHashMask) + 1; Poco::Net::HTTPServerResponse &response) override;
value >>= 8;
--i; private:
Poco::Logger &Logger_;
uint64_t id_ = 0;
};
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L) : Logger_(L) {}
inline Poco::Net::HTTPRequestHandler *
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
if (request.find("Upgrade") != request.end() &&
Poco::icompare(request["Upgrade"], "websocket") == 0) {
Utils::SetThreadName("ws:conn-init");
return new AP_WS_RequestHandler(Logger_, id_++);
} else {
return nullptr;
} }
return hash;
} }
[[nodiscard]] static inline uint16_t Hash(const std::string & value) { private:
return Hash(Utils::MACToInt(value)); Poco::Logger &Logger_;
} inline static uint64_t id_ = 1;
[[nodiscard]] static inline uint16_t HashMax() {
return MACHashMax;
}
}; };
constexpr uint SessionHashMax = 256; class AP_WS_Server : public SubSystemServer {
constexpr uint SessionHashMask = SessionHashMax-1;
class SessionHash {
public:
[[nodiscard]] static inline uint16_t Hash(std::uint64_t value) {
return (value & SessionHashMask);
}
[[nodiscard]] static inline uint16_t HashMax() {
return SessionHashMax;
}
};
class AP_WS_Server : public SubSystemServer, public Poco::Runnable {
public: public:
static auto instance() { static auto instance() {
static auto instance_ = new AP_WS_Server; static auto instance_ = new AP_WS_Server;
@@ -80,52 +75,59 @@ namespace OpenWifi {
bool IsCertOk() { return IssuerCert_ != nullptr; } bool IsCertOk() { return IssuerCert_ != nullptr; }
bool ValidateCertificate(const std::string &ConnectionId, bool ValidateCertificate(const std::string &ConnectionId,
const Poco::Crypto::X509Certificate &Certificate); const Poco::Crypto::X509Certificate &Certificate);
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
inline bool IsSimSerialNumber(const std::string &SerialNumber) const { inline bool IsSimSerialNumber(const std::string &SerialNumber) const {
return IsSim(SerialNumber) && return IsSim(Poco::toLower(SerialNumber)) &&
SerialNumber == SimulatorId_; Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
} }
inline static bool IsSim(const std::string &SerialNumber) { inline static bool IsSim(const std::string &SerialNumber) {
return SerialNumber.substr(0, 6) == "53494d"; return SerialNumber.substr(0, 6) == "53494d";
} }
void run() override; // Garbage collector thread. inline bool IsSimEnabled() const { return SimulatorEnabled_; }
[[nodiscard]] inline bool IsSimEnabled() const { return SimulatorEnabled_; }
[[nodiscard]] inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; } inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; }
[[nodiscard]] inline uint64_t MismatchDepth() const { return MismatchDepth_; }
[[nodiscard]] inline bool UseProvisioning() const { return LookAtProvisioning_; } inline uint64_t MismatchDepth() const { return MismatchDepth_; }
[[nodiscard]] inline bool UseDefaults() const { return UseDefaultConfig_; }
[[nodiscard]] inline bool Running() const { return Running_; } inline bool UseProvisioning() const { return LookAtProvisioning_; }
[[nodiscard]] inline std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> NextReactor() { inline bool UseDefaults() const { return UseDefaultConfig_; }
[[nodiscard]] inline Poco::Net::SocketReactor &NextReactor() {
return Reactor_pool_->NextReactor(); return Reactor_pool_->NextReactor();
} }
[[nodiscard]] inline bool Running() const { return Running_; }
inline void AddConnection(std::shared_ptr<AP_WS_Connection> Connection) { inline void AddConnection(uint64_t session_id,
std::uint64_t sessionHash = SessionHash::Hash(Connection->State_.sessionId); std::shared_ptr<AP_WS_Connection> Connection) {
std::lock_guard SessionLock(SessionMutex_[sessionHash]); std::lock_guard Lock(WSServerMutex_);
if(Sessions_[sessionHash].find(Connection->State_.sessionId)==end(Sessions_[sessionHash])) { Sessions_[session_id] = std::move(Connection);
Sessions_[sessionHash][Connection->State_.sessionId] = std::move(Connection);
}
} }
[[nodiscard]] inline bool DeviceRequiresSecureRTTY(uint64_t serialNumber) const { inline std::shared_ptr<AP_WS_Connection> FindConnection(uint64_t session_id) const {
std::shared_ptr<AP_WS_Connection> Connection; std::lock_guard Lock(WSServerMutex_);
{
auto hashIndex = MACHash::Hash(serialNumber); auto Connection = Sessions_.find(session_id);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]); if (Connection != end(Sessions_))
auto DeviceHint = SerialNumbers_[hashIndex].find(serialNumber); return Connection->second;
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) return nullptr;
return false; }
Connection = DeviceHint->second;
} inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const {
return Connection->RTTYMustBeSecure_; 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_;
} }
inline bool GetStatistics(const std::string &SerialNumber, std::string &Statistics) const { inline bool GetStatistics(const std::string &SerialNumber, std::string &Statistics) const {
return GetStatistics(Utils::SerialNumberToInt(SerialNumber), Statistics); return GetStatistics(Utils::SerialNumberToInt(SerialNumber), Statistics);
} }
[[nodiscard]] bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const; bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const;
inline bool GetState(const std::string &SerialNumber, inline bool GetState(const std::string &SerialNumber,
GWObjects::ConnectionState &State) const { GWObjects::ConnectionState &State) const {
@@ -141,8 +143,13 @@ namespace OpenWifi {
bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const; bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const;
bool Connected(uint64_t SerialNumber) const; bool Connected(uint64_t SerialNumber) const;
bool Disconnect(uint64_t SerialNumber);
inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const {
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
}
bool SendFrame(uint64_t SerialNumber, const std::string &Payload) const; bool SendFrame(uint64_t SerialNumber, const std::string &Payload) const;
bool SendRadiusAuthenticationData(const std::string &SerialNumber, bool SendRadiusAuthenticationData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size); const unsigned char *buffer, std::size_t size);
bool SendRadiusAccountingData(const std::string &SerialNumber, const unsigned char *buffer, bool SendRadiusAccountingData(const std::string &SerialNumber, const unsigned char *buffer,
@@ -150,8 +157,9 @@ namespace OpenWifi {
bool SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer, bool SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer,
std::size_t size); std::size_t size);
void StartSession(uint64_t session_id, uint64_t SerialNumber); void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
bool EndSession(uint64_t session_id, uint64_t SerialNumber); bool EndSession(uint64_t connection_id, uint64_t serial_number);
void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
uint64_t Interval, uint64_t Lifetime, uint64_t Interval, uint64_t Lifetime,
const std::vector<std::string> &TelemetryTypes); const std::vector<std::string> &TelemetryTypes);
@@ -168,9 +176,7 @@ namespace OpenWifi {
uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryWebSocketPackets,
uint64_t &TelemetryKafkaPackets); uint64_t &TelemetryKafkaPackets);
bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers); void onGarbageCollecting(Poco::Timer &timer);
// bool ExtendedAttributes(const std::string &serialNumber, bool & hasGPS, std::uint64_t &Sanity,
// std::double_t &MemoryUsed, std::double_t &Load, std::double_t &Temperature);
inline void AverageDeviceStatistics(uint64_t &Connections, uint64_t &AverageConnectionTime, inline void AverageDeviceStatistics(uint64_t &Connections, uint64_t &AverageConnectionTime,
uint64_t &NumberOfConnectingDevices) const { uint64_t &NumberOfConnectingDevices) const {
@@ -179,81 +185,63 @@ namespace OpenWifi {
NumberOfConnectingDevices = NumberOfConnectingDevices_; NumberOfConnectingDevices = NumberOfConnectingDevices_;
} }
inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const {
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
}
inline void AddRX(std::uint64_t bytes) { inline void AddRX(std::uint64_t bytes) {
std::lock_guard G(StatsMutex_);
RX_ += bytes; RX_ += bytes;
} }
inline void AddTX(std::uint64_t bytes) { inline void AddTX(std::uint64_t bytes) {
std::lock_guard G(StatsMutex_);
TX_ += bytes; TX_ += bytes;
} }
inline void GetTotalDataStatistics(std::uint64_t &TX, std::uint64_t &RX) const { inline void GetTotalDataStatistics(std::uint64_t &TX, std::uint64_t &RX) const {
std::lock_guard G(StatsMutex_);
TX = TX_; TX = TX_;
RX = RX_; RX = RX_;
} }
bool KafkaDisableState() const { return KafkaDisableState_; } inline bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
bool KafkaDisableHealthChecks() const { return KafkaDisableHealthChecks_; } std::lock_guard G(WSServerMutex_);
inline void IncrementConnectionCount() { for(const auto &connection:Sessions_) {
++NumberOfConnectedDevices_; if( connection.second->RawLastHealthcheck_.Sanity>=lowLimit &&
connection.second->RawLastHealthcheck_.Sanity<=highLimit) {
SerialNumbers.push_back(connection.second->SerialNumber_);
}
}
return true;
} }
inline void DecrementConnectionCount() {
--NumberOfConnectedDevices_;
}
inline void AddCleanupSession(uint64_t session_id, uint64_t SerialNumber) {
std::lock_guard G(CleanupMutex_);
CleanupSessions_.emplace_back(session_id, SerialNumber);
}
void CleanupSessions();
private: private:
std::array<std::mutex,SessionHashMax> SessionMutex_; mutable std::recursive_mutex WSServerMutex_;
std::array<std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>>,SessionHashMax> Sessions_;
using SerialNumberMap = std::map<uint64_t /* serial number */,
std::shared_ptr<AP_WS_Connection>>;
std::array<SerialNumberMap,MACHashMax> SerialNumbers_;
mutable std::array<std::mutex,MACHashMax> SerialNumbersMutex_;
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_; std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
std::vector<Poco::Crypto::X509Certificate> ClientCasCerts_;
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_; std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
Poco::Net::SocketReactor Reactor_; Poco::Net::SocketReactor Reactor_;
Poco::Thread ReactorThread_; Poco::Thread ReactorThread_;
std::string SimulatorId_; std::string SimulatorId_;
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 2, 64};
bool LookAtProvisioning_ = false; bool LookAtProvisioning_ = false;
bool UseDefaultConfig_ = true; bool UseDefaultConfig_ = true;
bool SimulatorEnabled_ = false; bool SimulatorEnabled_ = false;
bool AllowSerialNumberMismatch_ = true;
Poco::Thread CleanupThread_;
std::mutex CleanupMutex_;
std::deque<std::pair<uint64_t, uint64_t>> CleanupSessions_;
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_; std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
std::atomic_bool Running_ = false; std::atomic_bool Running_ = false;
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Sessions_;
std::map<uint64_t, std::pair<uint64_t, std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
std::atomic_bool AllowSerialNumberMismatch_ = true;
std::atomic_uint64_t MismatchDepth_ = 2;
std::uint64_t MismatchDepth_ = 2; std::atomic_uint64_t NumberOfConnectedDevices_ = 0;
std::atomic_uint64_t AverageDeviceConnectionTime_ = 0;
std::atomic_uint64_t NumberOfConnectingDevices_ = 0;
std::atomic_uint64_t NumberOfConnectedDevices_ = 0; mutable std::mutex StatsMutex_;
std::atomic_uint64_t AverageDeviceConnectionTime_ = 0;
std::uint64_t NumberOfConnectingDevices_ = 0;
std::uint64_t SessionTimeOut_ = 10*60;
std::uint64_t LeftOverSessions_ = 0;
std::atomic_uint64_t TX_=0,RX_=0; std::atomic_uint64_t TX_=0,RX_=0;
std::atomic_bool KafkaDisableState_=false, std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;
KafkaDisableHealthChecks_=false;
Poco::Thread GarbageCollector_; std::unique_ptr<Poco::TimerCallback<AP_WS_Server>> GarbageCollectorCallback_;
Poco::Timer Timer_;
Poco::Thread GarbageCollector_;
AP_WS_Server() noexcept AP_WS_Server() noexcept
: SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {} : SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {}

View File

@@ -10,7 +10,6 @@
#include <string> #include <string>
#include "framework/MicroServiceFuncs.h" #include "framework/MicroServiceFuncs.h"
#include "framework/ow_constants.h"
#include "CentralConfig.h" #include "CentralConfig.h"
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
@@ -35,7 +34,7 @@ namespace OpenWifi {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
if (!PlatformsLoaded_) if (!PlatformsLoaded_)
LoadPlatforms(); LoadPlatforms();
auto P = Poco::toLower(Caps.Platform()); auto P = Poco::toUpper(Caps.Platform());
auto Hint = Platforms_.find(Caps.Compatible()); auto Hint = Platforms_.find(Caps.Compatible());
if (Hint == Platforms_.end()) { if (Hint == Platforms_.end()) {
Platforms_.insert(std::make_pair(Caps.Compatible(), P)); Platforms_.insert(std::make_pair(Caps.Compatible(), P));
@@ -69,7 +68,7 @@ namespace OpenWifi {
auto Hint = Platforms_.find(DeviceType); auto Hint = Platforms_.find(DeviceType);
if (Hint == Platforms_.end()) if (Hint == Platforms_.end())
return Platforms::AP; return "AP";
return Hint->second; return Hint->second;
} }
@@ -111,7 +110,7 @@ namespace OpenWifi {
i >> cache; i >> cache;
for (const auto &[Type, Platform] : cache.items()) { for (const auto &[Type, Platform] : cache.items()) {
Platforms_[Type] = Poco::toLower(Platform.get<std::string>()); Platforms_[Type] = Platform;
} }
} catch (...) { } catch (...) {
} }

View File

@@ -204,17 +204,6 @@ namespace OpenWifi::Config {
return false; return false;
} }
std::uint64_t Config::UUID() {
try {
Poco::JSON::Parser Parser;
auto object = Parser.parse(Config_).extract<Poco::JSON::Object::Ptr>();
if (object->has("uuid"))
return object->get("uuid");
} catch (...) {
}
return 0;
}
bool Config::Valid() { bool Config::Valid() {
try { try {
Poco::JSON::Parser Parser; Poco::JSON::Parser Parser;
@@ -265,11 +254,7 @@ namespace OpenWifi::Config {
Model_ = Caps->get("model").toString(); Model_ = Caps->get("model").toString();
if (Caps->has("platform")) if (Caps->has("platform"))
Platform_ = Poco::toLower(Caps->get("platform").toString()); Platform_ = Caps->get("platform").toString();
if(Compatible_.empty()) {
Compatible_ = Model_;
}
std::ostringstream OS; std::ostringstream OS;
Caps->stringify(OS); Caps->stringify(OS);

View File

@@ -23,7 +23,6 @@ namespace OpenWifi::Config {
[[nodiscard]] std::string get() { return Config_; }; [[nodiscard]] std::string get() { return Config_; };
[[nodiscard]] std::string Default(); [[nodiscard]] std::string Default();
[[nodiscard]] Poco::JSON::Object::Ptr to_json(); [[nodiscard]] Poco::JSON::Object::Ptr to_json();
[[nodiscard]] std::uint64_t UUID();
private: private:
void Init(); void Init();

View File

@@ -45,9 +45,11 @@ namespace OpenWifi {
std::lock_guard Lock(LocalMutex_); std::lock_guard Lock(LocalMutex_);
auto RPC = OutStandingRequests_.find(ID); auto RPC = OutStandingRequests_.find(ID);
if (RPC == OutStandingRequests_.end()) { if (RPC == OutStandingRequests_.end()) {
// std::cout << __LINE__ << std::endl;
poco_debug(Logger(), fmt::format("({}): RPC {} cannot be found.", poco_debug(Logger(), fmt::format("({}): RPC {} cannot be found.",
SerialNumberStr, ID)); SerialNumberStr, ID));
} else if (RPC->second.SerialNumber != Resp->SerialNumber_) { } else if (RPC->second.SerialNumber != Resp->SerialNumber_) {
// std::cout << __LINE__ << std::endl;
poco_debug( poco_debug(
Logger(), Logger(),
fmt::format("({}): RPC {} serial number mismatch {}!={}.", fmt::format("({}): RPC {} serial number mismatch {}!={}.",
@@ -58,6 +60,7 @@ namespace OpenWifi {
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::duration<double, std::milli> rpc_execution_time =
std::chrono::high_resolution_clock::now() - std::chrono::high_resolution_clock::now() -
RPC->second.submitted; RPC->second.submitted;
// std::cout << __LINE__ << std::endl;
poco_debug(Logger(), poco_debug(Logger(),
fmt::format("({}): Received RPC answer {}. Command={}", fmt::format("({}): Received RPC answer {}. Command={}",
SerialNumberStr, ID, SerialNumberStr, ID,
@@ -137,6 +140,7 @@ namespace OpenWifi {
} }
} }
} else { } else {
// std::cout << __LINE__ << std::endl;
} }
Command.State = 0; Command.State = 0;
@@ -159,6 +163,7 @@ namespace OpenWifi {
if (Command.rpc_entry) { if (Command.rpc_entry) {
TmpRpcEntry = Command.rpc_entry; TmpRpcEntry = Command.rpc_entry;
} }
// std::cout << __LINE__ << " State=" << Command.State << std::endl;
if (Command.State == 2) { if (Command.State == 2) {
// look at the payload to see if we should continue or not... // look at the payload to see if we should continue or not...
if (Payload->has("result")) { if (Payload->has("result")) {
@@ -168,10 +173,12 @@ namespace OpenWifi {
std::uint64_t Error = Status->get("error"); std::uint64_t Error = Status->get("error");
if (Error == 0) { if (Error == 0) {
// std::cout << __LINE__ << std::endl;
StorageService()->CommandCompleted(Command.UUID, Payload, StorageService()->CommandCompleted(Command.UUID, Payload,
rpc_execution_time, true); rpc_execution_time, true);
Command.State = 1; Command.State = 1;
} else { } else {
// std::cout << __LINE__ << std::endl;
StorageService()->CommandCompleted(Command.UUID, Payload, StorageService()->CommandCompleted(Command.UUID, Payload,
rpc_execution_time, true); rpc_execution_time, true);
std::string ErrorTxt = Status->get("result"); std::string ErrorTxt = Status->get("result");
@@ -179,11 +186,14 @@ namespace OpenWifi {
Command.State = 0; Command.State = 0;
} }
} else { } else {
// std::cout << __LINE__ << std::endl;
} }
} else { } else {
// std::cout << __LINE__ << std::endl;
Command.State = 0; Command.State = 0;
} }
} else if (Command.State == 1) { } else if (Command.State == 1) {
// std::cout << "Completing script 2 phase commit." << std::endl;
StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true); StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true);
if (Command.Deferred) { if (Command.Deferred) {
Reply = false; Reply = false;
@@ -192,6 +202,7 @@ namespace OpenWifi {
} }
if (Command.State == 0) { if (Command.State == 0) {
// std::cout << __LINE__ << " State=" << Command.State << std::endl;
OutStandingRequests_.erase(Command.Id); OutStandingRequests_.erase(Command.Id);
} }
if (Reply && TmpRpcEntry != nullptr) if (Reply && TmpRpcEntry != nullptr)
@@ -251,6 +262,8 @@ namespace OpenWifi {
for (auto request = OutStandingRequests_.begin(); request != OutStandingRequests_.end();) { for (auto request = OutStandingRequests_.begin(); request != OutStandingRequests_.end();) {
std::chrono::duration<double, std::milli> delta = now - request->second.submitted; std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
if (delta > 10min) { if (delta > 10min) {
// std::cout << __LINE__ << " -->> " << request->second.Id <<
// std::endl;
MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.", request->second.UUID, MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.", request->second.UUID,
APCommands::to_string(request->second.Command), APCommands::to_string(request->second.Command),
Utils::IntToSerialNumber(request->second.SerialNumber))); Utils::IntToSerialNumber(request->second.SerialNumber)));
@@ -262,6 +275,8 @@ namespace OpenWifi {
StorageService()->SetCommandTimedOut(request->second.UUID); StorageService()->SetCommandTimedOut(request->second.UUID);
request = OutStandingRequests_.erase(request); request = OutStandingRequests_.erase(request);
} else { } else {
// std::cout << __LINE__ << " -->> " << request->second.Id <<
// std::endl;
++request; ++request;
} }
} }
@@ -287,116 +302,97 @@ namespace OpenWifi {
StorageService()->RemovedExpiredCommands(); StorageService()->RemovedExpiredCommands();
StorageService()->RemoveTimedOutCommands(); StorageService()->RemoveTimedOutCommands();
std::uint64_t offset = 0; std::vector<GWObjects::CommandDetails> Commands;
bool Done = false; if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
while (!Done) { poco_trace(MyLogger,
std::vector<GWObjects::CommandDetails> Commands; fmt::format("Scheduler about to process {} commands.", Commands.size()));
if (StorageService()->GetReadyToExecuteCommands(offset, 200, Commands)) { for (auto &Cmd : Commands) {
if(Commands.empty()) { if (!Running_) {
Done=true; poco_warning(MyLogger, "Scheduler quitting because service is stopping.");
continue; break;
} }
poco_trace(MyLogger, fmt::format("Scheduler about to process {} commands.", poco_trace(MyLogger,
Commands.size())); fmt::format("{}: Serial={} Command={} Starting processing.",
for (auto &Cmd : Commands) { Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
if (!Running_) { try {
poco_warning(MyLogger,
"Scheduler quitting because service is stopping."); // Skip an already running command
break; 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 auto now = Utils::Now();
if (IsCommandRunning(Cmd.UUID)) { // 2 hour timeout for commands
continue; 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(); auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
// 2 hour timeout for commands if (!AP_WS_Server()->Connected(SerialNumberInt)) {
if ((now - Cmd.Submitted) > commandTimeOut_) { poco_trace(
poco_information(
MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandTimedOut(Cmd.UUID);
continue;
}
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
if (!AP_WS_Server()->Connected(SerialNumberInt)) {
poco_trace(
MyLogger,
fmt::format("{}: Serial={} Command={} Device is not connected.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandLastTry(Cmd.UUID);
continue;
}
std::string ExecutingUUID;
APCommands::Commands ExecutingCommand = APCommands::Commands::unknown;
if (CommandRunningForDevice(SerialNumberInt, ExecutingUUID,
ExecutingCommand)) {
poco_trace(
MyLogger,
fmt::format("{}: Serial={} Command={} Device is already busy "
"with command {} (Command={}).",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command,
ExecutingUUID,
APCommands::to_string(ExecutingCommand)));
continue;
}
Poco::JSON::Parser P;
bool Sent;
poco_information(
MyLogger, MyLogger,
fmt::format("{}: Serial={} Command={} Preparing execution.", fmt::format("{}: Serial={} Command={} Device is not connected.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command)); Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>(); StorageService()->SetCommandLastTry(Cmd.UUID);
auto Result = PostCommandDisk( continue;
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);
} }
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); MyLogger.log(E);
} } catch (...) {
catch (...) {
poco_warning(MyLogger, "Exception during command processing."); poco_warning(MyLogger, "Exception during command processing.");
} }
poco_trace(MyLogger, "Scheduler done."); poco_trace(MyLogger, "Scheduler done.");
@@ -452,16 +448,4 @@ namespace OpenWifi {
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID)); poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID));
return nullptr; 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 } // namespace OpenWifi

View File

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

View File

@@ -11,12 +11,12 @@
namespace OpenWifi { namespace OpenWifi {
class ConfigurationCache { class ConfigurationCache {
public: public:
static auto instance() { static ConfigurationCache &instance() {
static auto instance = new ConfigurationCache; static ConfigurationCache instance;
return instance; return instance;
} }
inline uint64_t GetCurrentConfig(std::uint64_t SerialNumber) { inline uint64_t CurrentConfig(uint64_t SerialNumber) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
const auto Hint = Cache_.find(SerialNumber); const auto Hint = Cache_.find(SerialNumber);
if (Hint == end(Cache_)) if (Hint == end(Cache_))
@@ -24,25 +24,25 @@ namespace OpenWifi {
return Hint->second; return Hint->second;
} }
inline void SetCurrentConfig(std::uint64_t SerialNumber, uint64_t Id) { inline void Add(uint64_t SerialNumber, uint64_t Id) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
Cache_[SerialNumber] = Id; Cache_[SerialNumber] = Id;
} }
private: private:
std::mutex Mutex_; std::recursive_mutex Mutex_;
std::map<uint64_t, uint64_t> Cache_; std::map<uint64_t, uint64_t> Cache_;
}; };
inline auto GetCurrentConfigurationID(std::uint64_t SerialNumber) { inline uint64_t GetCurrentConfigurationID(uint64_t SerialNumber) {
return ConfigurationCache::instance()->GetCurrentConfig(SerialNumber); return ConfigurationCache::instance().CurrentConfig(SerialNumber);
} }
inline void SetCurrentConfigurationID(const std::string &SerialNumber, std::uint64_t ID) { inline void SetCurrentConfigurationID(const std::string &SerialNumber, uint64_t ID) {
return ConfigurationCache::instance()->SetCurrentConfig(Utils::SerialNumberToInt(SerialNumber), ID); return ConfigurationCache::instance().Add(Utils::SerialNumberToInt(SerialNumber), ID);
} }
inline void SetCurrentConfigurationID(uint64_t SerialNumber, std::uint64_t ID) { inline void SetCurrentConfigurationID(uint64_t SerialNumber, uint64_t ID) {
return ConfigurationCache::instance()->SetCurrentConfig(SerialNumber, ID); return ConfigurationCache::instance().Add(SerialNumber, ID);
} }
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -11,17 +11,12 @@
#include "Poco/Util/Application.h" #include "Poco/Util/Application.h"
#include "Poco/Util/Option.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 "AP_WS_Server.h"
#include "CommandManager.h" #include "CommandManager.h"
#include "Daemon.h" #include "Daemon.h"
#include "FileUploader.h" #include "FileUploader.h"
#include "FindCountry.h" #include "FindCountry.h"
#include "OUIServer.h" #include "OUIServer.h"
#include "RADIUSSessionTracker.h"
#include "RADIUS_proxy_server.h" #include "RADIUS_proxy_server.h"
#include "RegulatoryInfo.h" #include "RegulatoryInfo.h"
#include "ScriptManager.h" #include "ScriptManager.h"
@@ -30,47 +25,64 @@
#include "StorageArchiver.h" #include "StorageArchiver.h"
#include "StorageService.h" #include "StorageService.h"
#include "TelemetryStream.h" #include "TelemetryStream.h"
#include "GenericScheduler.h"
#include "UI_GW_WebSocketNotifications.h" #include "UI_GW_WebSocketNotifications.h"
#include "VenueBroadcaster.h" #include "VenueBroadcaster.h"
#include "AP_WS_ConfigAutoUpgrader.h" #include "framework/ConfigurationValidator.h"
#include "framework/UI_WebSocketClientServer.h"
#include "rttys/RTTYS_server.h" #include "rttys/RTTYS_server.h"
#include "firmware_revision_cache.h"
namespace OpenWifi { namespace OpenWifi {
class Daemon *Daemon::instance() { class Daemon *Daemon::instance() {
static Daemon instance( static Daemon instance(
vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, vDAEMON_CONFIG_ENV_VAR, vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, vDAEMON_CONFIG_ENV_VAR,
vDAEMON_APP_NAME, vDAEMON_BUS_TIMER, vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
SubSystemVec{GenericScheduler(), StorageService(), SerialNumberCache(), ConfigurationValidator(), SubSystemVec{StorageService(), SerialNumberCache(), ConfigurationValidator(),
UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(), UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(),
CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(), CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(),
RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(), RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(),
SignatureManager(), AP_WS_Server(), SignatureManager(), AP_WS_Server(),
RegulatoryInfo(), RegulatoryInfo()
RADIUSSessionTracker(),
AP_WS_ConfigAutoUpgradeAgent(),
FirmwareRevisionCache()
}); });
return &instance; return &instance;
} }
static std::string ALBHealthCallback() { static const std::vector<std::pair<std::string, std::string>> DefaultDeviceTypes{
uint64_t Connections, AverageConnectionTime, NumberOfConnectingDevices; {"cig_wf160d", "AP"},
AP_WS_Server()->AverageDeviceStatistics(Connections, AverageConnectionTime, {"cig_wf188", "AP"},
NumberOfConnectingDevices); {"cig_wf188n", "AP"},
std::ostringstream os; {"cig_wf194c", "AP"},
os << "Connections: " << Connections << std::endl << {"cig_wf194c4", "AP"},
"ConnectingDevices: " << NumberOfConnectingDevices << std::endl << {"edgecore_eap101", "AP"},
"ConnectionTime: " << AverageConnectionTime << std::endl; {"edgecore_eap102", "AP"},
return os.str(); {"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) { void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning", false); AutoProvisioning_ = config().getBool("openwifi.autoprovisioning", false);
DeviceTypes_ = DefaultDeviceTypeList; DeviceTypes_ = DefaultDeviceTypes;
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger()); WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
MicroServiceALBCallback(ALBHealthCallback);
} }
[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string &Id) const { [[nodiscard]] std::string Daemon::IdentifyDevice(const std::string &Id) const {
@@ -78,7 +90,7 @@ namespace OpenWifi {
if (Id == DeviceType) if (Id == DeviceType)
return Type; return Type;
} }
return Platforms::AP; return "AP";
} }
void DaemonPostInitialization(Poco::Util::Application &self) { void DaemonPostInitialization(Poco::Util::Application &self) {

View File

@@ -21,6 +21,7 @@ namespace OpenWifi {
void DeviceDashboard::Generate(GWObjects::Dashboard &D, Poco::Logger &Logger) { void DeviceDashboard::Generate(GWObjects::Dashboard &D, Poco::Logger &Logger) {
if (GeneratingDashboard_.load()) { if (GeneratingDashboard_.load()) {
// std::cout << "Trying to generate dashboard but already being generated" << std::endl;
while (GeneratingDashboard_.load()) { while (GeneratingDashboard_.load()) {
Poco::Thread::trySleep(100); Poco::Thread::trySleep(100);
} }
@@ -30,6 +31,7 @@ namespace OpenWifi {
GeneratingDashboard_ = true; GeneratingDashboard_ = true;
ValidDashboard_ = false; ValidDashboard_ = false;
try { try {
// std::cout << "Generating dashboard." << std::endl;
poco_information(Logger, "DASHBOARD: Generating a new dashboard."); poco_information(Logger, "DASHBOARD: Generating a new dashboard.");
GWObjects::Dashboard NewData; GWObjects::Dashboard NewData;
StorageService()->AnalyzeCommands(NewData.commands); StorageService()->AnalyzeCommands(NewData.commands);

View File

@@ -8,12 +8,12 @@
#pragma once #pragma once
#include <Poco/Net/HTTPRequestHandler.h> #include "Poco/Net/HTTPRequestHandler.h"
#include <Poco/Net/HTTPRequestHandlerFactory.h> #include "Poco/Net/HTTPRequestHandlerFactory.h"
#include <Poco/Net/HTTPServer.h> #include "Poco/Net/HTTPServer.h"
#include <Poco/Net/HTTPServerRequest.h> #include "Poco/Net/HTTPServerRequest.h"
#include <framework/SubSystemServer.h> #include "framework/SubSystemServer.h"
namespace OpenWifi { namespace OpenWifi {

View File

@@ -12,7 +12,9 @@ namespace OpenWifi {
Event.set("type", type_); Event.set("type", type_);
Event.set("timestamp", timestamp_); Event.set("timestamp", timestamp_);
Event.set("payload", payload_); 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 #pragma once
#include <string>
#include <Poco/JSON/Object.h> #include <Poco/JSON/Object.h>
#include <RESTObjects/RESTAPI_GWobjects.h>
#include <framework/KafkaManager.h> #include <framework/KafkaManager.h>
#include <string>
namespace OpenWifi { namespace OpenWifi {
class GWKafkaEvents { class GWKafkaEvents {
public: public:
GWKafkaEvents(std::uint64_t serialNumber, const std::string &type, GWKafkaEvents(const std::string &serialNumber, const std::string &type,
std::uint64_t timestamp) std::uint64_t timestamp)
: serialNumber_(serialNumber), type_(type), timestamp_(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_;};
protected: inline void SetPayload(Poco::JSON::Object::Ptr payload) { payload_ = std::move(payload); }
std::uint64_t serialNumber_; void Send();
private:
std::string serialNumber_;
std::string type_; std::string type_;
std::uint64_t timestamp_ = 0; std::uint64_t timestamp_ = 0;
Poco::JSON::Object::Ptr payload_; Poco::JSON::Object::Ptr payload_;
@@ -31,15 +28,17 @@ namespace OpenWifi {
class DeviceFirmwareChangeKafkaEvent : public GWKafkaEvents { class DeviceFirmwareChangeKafkaEvent : public GWKafkaEvents {
public: 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 &oldFirmware,
const std::string &newFirmware) const std::string &newFirmware)
: GWKafkaEvents(serialNumber, "unit.firmware_change", timestamp), : GWKafkaEvents(serialNumber, "unit.firmware_change", timestamp),
oldFirmware_(oldFirmware), newFirmware_(newFirmware) {} oldFirmware_(oldFirmware), newFirmware_(newFirmware) {}
~DeviceFirmwareChangeKafkaEvent() { ~DeviceFirmwareChangeKafkaEvent() {
payload_->set("oldFirmware", oldFirmware_); Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
payload_->set("newFirmware", newFirmware_); payload->set("oldFirmware", oldFirmware_);
payload->set("newFirmware", newFirmware_);
SetPayload(payload);
Send(); Send();
} }
@@ -49,33 +48,25 @@ namespace OpenWifi {
class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents { class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
public: public:
DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber, DeviceConfigurationChangeKafkaEvent(const std::string &serialNumber,
std::uint64_t timestamp, std::uint64_t timestamp, const std::string config)
const Poco::JSON::Object::Ptr config)
: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) { : GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
} }
~DeviceConfigurationChangeKafkaEvent() { ~DeviceConfigurationChangeKafkaEvent() {
if(config_!= nullptr) { Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
std::ostringstream os; payload->set("configuration", config_);
config_->stringify(os); SetPayload(payload);
if(os.str().size()> KafkaManager()->KafkaManagerMaximumPayloadSize()) {
payload_->set("configuration", "{}");
payload_->set("configurationTooBig", true);
} else {
payload_->set("configuration", *config_);
}
}
Send(); Send();
} }
private: private:
Poco::JSON::Object::Ptr config_; std::string config_;
}; };
class DeviceBlacklistedKafkaEvent : public GWKafkaEvents { class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {
public: public:
explicit DeviceBlacklistedKafkaEvent(std::uint64_t serialNumber, explicit DeviceBlacklistedKafkaEvent(const std::string &serialNumber,
std::uint64_t timestamp, const std::string &reason, std::uint64_t timestamp, const std::string &reason,
const std::string &author, std::uint64_t created, const std::string &author, std::uint64_t created,
std::string &IP) std::string &IP)
@@ -83,10 +74,12 @@ namespace OpenWifi {
author_(author), created_(created), IP_(IP) {} author_(author), created_(created), IP_(IP) {}
~DeviceBlacklistedKafkaEvent() { ~DeviceBlacklistedKafkaEvent() {
payload_->set("reason", reason_); Poco::JSON::Object::Ptr payload = new Poco::JSON::Object;
payload_->set("author", author_); payload->set("reason", reason_);
payload_->set("created", created_); payload->set("author", author_);
payload_->set("ipaddress", IP_); payload->set("created", created_);
payload->set("ipaddress", IP_);
SetPayload(payload);
Send(); Send();
} }
@@ -96,21 +89,4 @@ namespace OpenWifi {
std::string IP_; 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 } // 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; bool Recovered = false;
Poco::File OuiFile(CurrentOUIFileName_); Poco::File OuiFile(CurrentOUIFileName_);
if (OuiFile.exists()) { if (OuiFile.exists()) {
std::lock_guard Lock(LocalMutex_); std::unique_lock Lock(LocalMutex_);
Recovered = ProcessFile(CurrentOUIFileName_, OUIs_); Recovered = ProcessFile(CurrentOUIFileName_, OUIs_);
if (Recovered) { if (Recovered) {
poco_notice(Logger(), poco_notice(Logger(),
@@ -150,7 +150,7 @@ namespace OpenWifi {
OUIMap TmpOUIs; OUIMap TmpOUIs;
if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) { if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
std::lock_guard G(LocalMutex_); std::unique_lock G(LocalMutex_);
OUIs_ = std::move(TmpOUIs); OUIs_ = std::move(TmpOUIs);
LastUpdate_ = Utils::Now(); LastUpdate_ = Utils::Now();
Poco::File F1(CurrentOUIFileName_); Poco::File F1(CurrentOUIFileName_);
@@ -163,7 +163,7 @@ namespace OpenWifi {
} else if (OUIs_.empty()) { } else if (OUIs_.empty()) {
if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) { if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
LastUpdate_ = Utils::Now(); LastUpdate_ = Utils::Now();
std::lock_guard G(LocalMutex_); std::unique_lock G(LocalMutex_);
OUIs_ = std::move(TmpOUIs); OUIs_ = std::move(TmpOUIs);
} }
} }
@@ -173,7 +173,7 @@ namespace OpenWifi {
} }
std::string OUIServer::GetManufacturer(const std::string &MAC) { 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)); auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
if (Manufacturer != OUIs_.end()) if (Manufacturer != OUIs_.end())

View File

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

View File

@@ -1753,6 +1753,7 @@ namespace OpenWifi {
nlohmann::json new_ie; nlohmann::json new_ie;
nlohmann::json content; nlohmann::json content;
// std::cout << BufferToHex(&data[0],data.size()) << std::endl;
uint offset = 0; uint offset = 0;
auto sub_ie = data[offset++]; auto sub_ie = data[offset++];
switch (sub_ie) { switch (sub_ie) {
@@ -1787,6 +1788,7 @@ namespace OpenWifi {
try { try {
nlohmann::json D = nlohmann::json::parse(ofs.str()); nlohmann::json D = nlohmann::json::parse(ofs.str());
// std::cout << "Start of parsing wifi" << std::endl;
if (D.contains("status")) { if (D.contains("status")) {
auto Status = D["status"]; auto Status = D["status"];
if (Status.contains("scan") && Status["scan"].is_array()) { if (Status.contains("scan") && Status["scan"].is_array()) {
@@ -1801,6 +1803,8 @@ namespace OpenWifi {
if (ie.contains("type") && ie.contains("data")) { if (ie.contains("type") && ie.contains("data")) {
uint64_t ie_type = ie["type"]; uint64_t ie_type = ie["type"];
std::string ie_data = ie["data"]; std::string ie_data = ie["data"];
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data
// << std::endl;
auto data = Base64Decode2Vec(ie_data); auto data = Base64Decode2Vec(ie_data);
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) { if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data)); new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
@@ -1854,12 +1858,18 @@ namespace OpenWifi {
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) { } else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data)); new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
} else { } else {
// std::cout
// << "Skipping IE: no parsing available: " << ie_type
// << std::endl;
new_ies.push_back(ie); new_ies.push_back(ie);
} }
} else { } else {
// std::cout << "Skipping IE: no data and type" <<
// std::endl;
new_ies.push_back(ie); new_ies.push_back(ie);
} }
} catch (...) { } catch (...) {
// std::cout << "Skipping IE: exception" << std::endl;
Logger.information(fmt::format("Error parsing IEs")); Logger.information(fmt::format("Error parsing IEs"));
new_ies.push_back(ie); new_ies.push_back(ie);
} }
@@ -1867,6 +1877,7 @@ namespace OpenWifi {
scan_entry["ies"] = new_ies; scan_entry["ies"] = new_ies;
ParsedScan.push_back(scan_entry); ParsedScan.push_back(scan_entry);
} else { } else {
// std::cout << "Skipping scan" << std::endl;
ParsedScan.push_back(scan_entry); ParsedScan.push_back(scan_entry);
} }
} }
@@ -1875,6 +1886,7 @@ namespace OpenWifi {
} }
} }
Result << to_string(D); Result << to_string(D);
// std::cout << "End of parsing wifi" << std::endl;
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
Logger.log(E); Logger.log(E);

View File

@@ -1,443 +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();
}
}
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) {
std::lock_guard Guard(Mutex_);
auto hint = AccountingSessions_.find(SerialNumber);
if(hint==end(AccountingSessions_)) {
return;
}
poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber));
// we need to go through all sessions and send an accounting stop
for(const auto &session:hint->second) {
poco_debug(Logger(), fmt::format("Stopping accounting for {}:{}", SerialNumber, session.first ));
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,747 +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);
if(Type_!=GWObjects::RadiusEndpointType::generic) {
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()));
}
return;
} else {
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
}
Disconnect();
}
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();
auto 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);
}
auto 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() {
poco_information(Logger_, fmt::format("Connecting {}", Pool_.name));
if (TryAgain_ && !Connected_) {
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);
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));
/*
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 AcctSockAddrV6(
Poco::Net::AddressFamily::IPv6,
MicroServiceConfigGetInt("radius.proxy.accounting.port",
DEFAULT_RADIUS_AUTHENTICATION_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(
*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));
*/
Connected_ = true;
}
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) {
poco_information(Logger_, fmt::format("Disconnecting {} generic server. Releasing all UDP resources.", Pool_.name));
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) {
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_, fmt::format("Disconnecting {}", Pool_.name));
}
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_helpers.h"
#include "RADIUS_proxy_server.h" #include "RADIUS_proxy_server.h"
#include "RADIUSSessionTracker.h"
#include "framework/MicroServiceFuncs.h" #include "framework/MicroServiceFuncs.h"
namespace OpenWifi { 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_AUTHENTICATION_PORT = 1812;
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813; const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799; const int DEFAULT_RADIUS_CoA_PORT = 3799;
*/
int RADIUS_proxy_server::Start() { int RADIUS_proxy_server::Start() {
@@ -27,7 +24,7 @@ namespace OpenWifi {
Enabled_ = MicroServiceConfigGetBool("radius.proxy.enable", false); Enabled_ = MicroServiceConfigGetBool("radius.proxy.enable", false);
if (!Enabled_ && !Config.exists()) { if (!Enabled_ && !Config.exists()) {
StopRADIUSDestinations(); StopRADSECServers();
return 0; return 0;
} }
@@ -35,101 +32,227 @@ namespace OpenWifi {
Enabled_ = true; 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(); ParseConfig();
StartRADIUSDestinations(); StartRADSECServers();
RadiusReactorThread_.start(RadiusReactor_); RadiusReactorThread_.start(*RadiusReactor_);
Utils::SetThreadName(RadiusReactorThread_, "rad:reactor"); Utils::SetThreadName(RadiusReactorThread_, "rad:reactor");
Running_ = true; Running_ = true;
return 0; return 0;
} }
void RADIUS_proxy_server::Stop() { void RADIUS_proxy_server::Stop() {
if (Enabled_ && Running_) { if (Enabled_ && Running_) {
poco_information(Logger(), "Stopping..."); 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_->removeEventHandler(
RadiusReactor_.stop(); *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(); RadiusReactorThread_.join();
Running_ = false; Running_ = false;
poco_information(Logger(), "Stopped..."); poco_information(Logger(), "Stopped...");
} }
} }
/* inline static bool isRadsec(const GWObjects::RadiusProxyPool &Cfg) { void RADIUS_proxy_server::StartRADSECServers() {
return Cfg.radsecPoolType=="orion" || Cfg.radsecPoolType=="globalreach" || Cfg.radsecPoolType=="radsec";
}
*/
void RADIUS_proxy_server::StartRADIUSDestinations() {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
for (const auto &pool : PoolList_.pools) { for (const auto &pool : PoolList_.pools) {
if(pool.enabled) { for (const auto &entry : pool.authConfig.servers) {
RADIUS_Destinations_[Utils::IPtoInt(pool.poolProxyIp)] = if (entry.radsec) {
std::make_unique<RADIUS_Destination>(RadiusReactor_, pool); RADSECservers_[Poco::Net::SocketAddress(entry.ip, 0)] =
} else { std::make_unique<RADSEC_server>(*RadiusReactor_, entry);
poco_information(Logger(),fmt::format("Pool {} is not enabled.", pool.name)); }
} }
} }
} }
void RADIUS_proxy_server::StopRADIUSDestinations() { void RADIUS_proxy_server::StopRADSECServers() {
std::lock_guard G(Mutex_); 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) { void RADIUS_proxy_server::OnAccountingSocketReadable(
try{ const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
// are we sending this to a pool? auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
auto DstParts = Utils::Split(Destination, ':'); if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
std::uint32_t DtsIp = Utils::IPtoInt(DstParts[0]); poco_warning(Logger(), "Accounting: bad packet received.");
return;
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));
} }
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) { void RADIUS_proxy_server::OnAuthenticationSocketReadable(
static std::uint64_t pkt=0; 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); poco_debug(
ofs.write(buffer,size); Logger(),
ofs.close(); 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) { const char *buffer, std::size_t size) {
if (!Continue()) if (!Continue())
@@ -138,9 +261,46 @@ namespace OpenWifi {
try { try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size); RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto Destination = P.ExtractProxyStateDestination(); auto Destination = P.ExtractProxyStateDestination();
std::string Secret; auto CallingStationID = P.ExtractCallingStationID();
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, Secret); auto CalledStationID = P.ExtractCalledStationID();
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, Secret); 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) { } catch (const Poco::Exception &E) {
Logger().log(E); Logger().log(E);
} catch (...) { } catch (...) {
@@ -162,31 +322,46 @@ namespace OpenWifi {
try { try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size); 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::lock_guard G(Mutex_);
bool UseRADSEC = false;
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint(); auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
auto DestinationServer = RADIUS_Destinations_.find(DstIp); if (UseRADSEC) {
if (DestinationServer != end(RADIUS_Destinations_)) { Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
if(Logger().trace()) { auto DestinationServer = RADSECservers_.find(RSP);
auto CallingStationID = P.ExtractCallingStationID(); if (DestinationServer != end(RADSECservers_)) {
auto CalledStationID = P.ExtractCalledStationID(); DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
auto SessionID = P.ExtractAccountingSessionID(); size);
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));
} }
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) { } else {
DestinationServer->second->SendData(serialNumber, if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
(const unsigned char *)buffer, size); AuthenticationSocketV4_ == nullptr) ||
} (Dst.family() == Poco::Net::SocketAddress::IPv6 &&
else { AuthenticationSocketV6_ == nullptr)) {
DestinationServer->second->SendRadiusDataAuthData( poco_debug(
serialNumber, (const unsigned char *)buffer, size); 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) { } catch (const Poco::Exception &E) {
Logger().log(E); Logger().log(E);
@@ -204,35 +379,54 @@ namespace OpenWifi {
try { try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size); RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto CallingStationID = P.ExtractCallingStationID(); auto Destination = P.ExtractProxyStateDestination();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
if (Destination.empty()) {
Destination = "0.0.0.0:0";
}
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint(); bool UseRADSEC = false;
auto DestinationServer = RADIUS_Destinations_.find(DstIp); auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
if (DestinationServer != end(RADIUS_Destinations_)) { if (UseRADSEC) {
poco_trace(Logger(),fmt::format("{}: Sending CoA {} bytes to {}", serialNumber, P.Size(), DestinationServer->second->Pool().coaConfig.servers[0].ip)); Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) { auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
size); 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) { } catch (const Poco::Exception &E) {
Logger().log(E); Logger().log(E);
} catch (...) { } catch (...) {
poco_warning(Logger(), 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, void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
std::vector<Destination> &V4, std::vector<Destination> &V4,
std::vector<Destination> &V6, bool setAsDefault, std::vector<Destination> &V6, bool setAsDefault) {
const std::string &poolProxyIp) {
uint64_t TotalV4 = 0, TotalV6 = 0; uint64_t TotalV4 = 0, TotalV6 = 0;
for (const auto &server : Config.servers) { for (const auto &server : Config.servers) {
@@ -255,9 +449,7 @@ namespace OpenWifi {
.methodParameters = Config.methodParameters, .methodParameters = Config.methodParameters,
.useAsDefault = setAsDefault, .useAsDefault = setAsDefault,
.useRADSEC = server.radsec, .useRADSEC = server.radsec,
.realms = server.radsecRealms, .realms = server.radsecRealms};
.secret = server.secret,
.poolProxyIp = poolProxyIp};
if (setAsDefault && D.useRADSEC) if (setAsDefault && D.useRADSEC)
DefaultIsRADSEC_ = true; DefaultIsRADSEC_ = true;
@@ -306,11 +498,11 @@ namespace OpenWifi {
for (const auto &pool : RPC.pools) { for (const auto &pool : RPC.pools) {
RadiusPool NewPool; RadiusPool NewPool;
ParseServerList(pool.authConfig, NewPool.AuthV4, NewPool.AuthV6, ParseServerList(pool.authConfig, NewPool.AuthV4, NewPool.AuthV6,
pool.useByDefault, pool.poolProxyIp); pool.useByDefault);
ParseServerList(pool.acctConfig, NewPool.AcctV4, NewPool.AcctV6, ParseServerList(pool.acctConfig, NewPool.AcctV4, NewPool.AcctV6,
pool.useByDefault, pool.poolProxyIp); pool.useByDefault);
ParseServerList(pool.coaConfig, NewPool.CoaV4, NewPool.CoaV6, ParseServerList(pool.coaConfig, NewPool.CoaV4, NewPool.CoaV6,
pool.useByDefault, pool.poolProxyIp); pool.useByDefault);
Pools_.push_back(NewPool); Pools_.push_back(NewPool);
} }
} else { } else {
@@ -329,7 +521,6 @@ namespace OpenWifi {
} }
} }
/*
static bool RealmMatch(const std::string &user_realm, const std::string &realm) { static bool RealmMatch(const std::string &user_realm, const std::string &realm) {
if (realm.find_first_of('*') == std::string::npos) if (realm.find_first_of('*') == std::string::npos)
return user_realm == realm; return user_realm == realm;
@@ -339,9 +530,7 @@ namespace OpenWifi {
Poco::Net::SocketAddress Poco::Net::SocketAddress
RADIUS_proxy_server::DefaultRoute(radius_type rtype, RADIUS_proxy_server::DefaultRoute(radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress, const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
std::string &Secret) {
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4; bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
// find the realm... // find the realm...
@@ -356,6 +545,7 @@ namespace OpenWifi {
if (!server.realms.empty()) { if (!server.realms.empty()) {
for (const auto &realm : server.realms) { for (const auto &realm : server.realms) {
if (RealmMatch(UserRealm, realm)) { if (RealmMatch(UserRealm, realm)) {
std::cout << "Realm match..." << std::endl;
UseRADSEC = true; UseRADSEC = true;
return server.Addr; return server.Addr;
} }
@@ -375,18 +565,18 @@ namespace OpenWifi {
case radius_type::auth: { case radius_type::auth: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AuthV4 return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AuthV4
: Pools_[DefaultPoolIndex_].AuthV6, : Pools_[DefaultPoolIndex_].AuthV6,
RequestedAddress, Secret); RequestedAddress);
}
case radius_type::coa: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].CoaV4
: Pools_[DefaultPoolIndex_].CoaV6,
RequestedAddress, Secret);
} }
case radius_type::acct: case radius_type::acct:
default: { default: {
return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AcctV4 return ChooseAddress(IsV4 ? Pools_[DefaultPoolIndex_].AcctV4
: Pools_[DefaultPoolIndex_].AcctV6, : 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 Poco::Net::SocketAddress
RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype,
const Poco::Net::SocketAddress &RequestedAddress, const Poco::Net::SocketAddress &RequestedAddress,
const RADIUS::RadiusPacket &P, bool &UseRADSEC, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
std::string &Secret) { std::lock_guard G(Mutex_);
if (Pools_.empty()) { if (Pools_.empty()) {
UseRADSEC = false; UseRADSEC = false;
@@ -404,47 +594,39 @@ namespace OpenWifi {
bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4; bool IsV4 = RequestedAddress.family() == Poco::Net::SocketAddress::IPv4;
bool useDefault; bool useDefault;
useDefault = IsV4 ? RequestedAddress.host() == useDefault = IsV4 ? RequestedAddress.host() ==
Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4) Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4)
: RequestedAddress.host() == : RequestedAddress.host() ==
Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6); Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6);
if (useDefault) { 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 { auto isAddressInPool = [&](const std::vector<Destination> &D, bool &UseRADSEC) -> bool {
for (const auto &entry : D) { for (const auto &entry : D)
if (!entry.poolProxyIp.empty() &&
entry.poolProxyIp == RequestedAddress.host().toString()) {
UseRADSEC = entry.useRADSEC;
return true;
}
if (entry.Addr.host() == RequestedAddress.host()) { if (entry.Addr.host() == RequestedAddress.host()) {
UseRADSEC = entry.useRADSEC; UseRADSEC = entry.useRADSEC;
return true; return true;
} }
}
return false; return false;
}; };
for (auto &pool : Pools_) { for (auto &i : Pools_) {
// try and match the pool's address to the destination
switch (rtype) { switch (rtype) {
case radius_type::coa: { case radius_type::coa: {
if (isAddressInPool((IsV4 ? pool.CoaV4 : pool.CoaV6), UseRADSEC)) { if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.CoaV4 : pool.CoaV6, RequestedAddress, Secret); return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
} }
} break; } break;
case radius_type::auth: { case radius_type::auth: {
if (isAddressInPool((IsV4 ? pool.AuthV4 : pool.AuthV6), UseRADSEC)) { if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.AuthV4 : pool.AuthV6, RequestedAddress, Secret); return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
} }
} break; } break;
case radius_type::acct: { case radius_type::acct: {
if (isAddressInPool((IsV4 ? pool.AcctV4 : pool.AcctV6), UseRADSEC)) { if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? pool.AcctV4 : pool.AcctV6, RequestedAddress, Secret); return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
} }
} break; } break;
} }
@@ -456,13 +638,10 @@ namespace OpenWifi {
Poco::Net::SocketAddress Poco::Net::SocketAddress
RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool, RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool,
const Poco::Net::SocketAddress &OriginalAddress, const Poco::Net::SocketAddress &OriginalAddress) {
std::string &Secret) {
if (Pool.size() == 1) { if (Pool.size() == 1) {
Secret = Pool[0].secret; return Pool[0].Addr;
auto A = Pool[0].Addr;
return A;
} }
if (Pool[0].strategy == "weighted") { if (Pool[0].strategy == "weighted") {
@@ -478,7 +657,6 @@ namespace OpenWifi {
index = pos; index = pos;
cur_state = i.state; cur_state = i.state;
found = true; found = true;
Secret = i.secret ;
} }
pos++; pos++;
} }
@@ -486,9 +664,9 @@ namespace OpenWifi {
if (!found) { if (!found) {
return OriginalAddress; return OriginalAddress;
} }
Pool[index].state += Pool[index].step; Pool[index].state += Pool[index].step;
return Pool[index].Addr; return Pool[index].Addr;
} else if (Pool[0].strategy == "round_robin") { } else if (Pool[0].strategy == "round_robin") {
bool found = false; bool found = false;
uint64_t cur_state = std::numeric_limits<uint64_t>::max(); uint64_t cur_state = std::numeric_limits<uint64_t>::max();
@@ -501,30 +679,27 @@ namespace OpenWifi {
if (i.state < cur_state) { if (i.state < cur_state) {
index = pos; index = pos;
cur_state = i.state; cur_state = i.state;
Secret = i.secret;
found = true; found = true;
} }
pos++; pos++;
} }
if (!found) { if (!found) {
// return OriginalAddress; return OriginalAddress;
} }
Pool[index].state += 1; Pool[index].state += 1;
return Pool[index].Addr; return Pool[index].Addr;
} else if (Pool[0].strategy == "random") { } else if (Pool[0].strategy == "random") {
if (Pool.size() > 1) { if (Pool.size() > 1) {
auto index = std::rand() % Pool.size(); return Pool[std::rand() % Pool.size()].Addr;
Secret = Pool[index].secret;
return Pool[index].Addr;
} else { } else {
return OriginalAddress; return OriginalAddress;
} }
} }
return OriginalAddress; return OriginalAddress;
} }
*/
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) { void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);

View File

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

@@ -25,23 +25,9 @@ namespace OpenWifi::RESTAPI_RPC {
if (StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Status)) { if (StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Status)) {
Poco::JSON::Object RetObj; Poco::JSON::Object RetObj;
Cmd.to_json(RetObj); Cmd.to_json(RetObj);
if (Handler == nullptr) { if (Handler != nullptr)
// nothing to process/return return Handler->ReturnObject(RetObj);
return; return;
}
Poco::Net::HTTPResponse::HTTPStatus cmd_status = Poco::Net::HTTPResponse::HTTP_OK;
if (Cmd.ErrorCode > 0) {
// command returned error
cmd_status = Poco::Net::HTTPResponse::HTTP_BAD_REQUEST;
if (Cmd.Command == uCentralProtocol::CONFIGURE) {
// special handling for configure command
if (!Handler->GetBoolParameter("strict", false)) {
// in non-strict mode return success for failed configure command
cmd_status = Poco::Net::HTTPResponse::HTTP_OK;
}
}
}
return Handler->ReturnObject(RetObj, cmd_status);
} }
if (Handler != nullptr) if (Handler != nullptr)
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
@@ -54,8 +40,8 @@ namespace OpenWifi::RESTAPI_RPC {
std::chrono::milliseconds WaitTimeInMs, Poco::JSON::Object *ObjectToReturn, std::chrono::milliseconds WaitTimeInMs, Poco::JSON::Object *ObjectToReturn,
RESTAPIHandler *Handler, Poco::Logger &Logger, bool Deferred) { RESTAPIHandler *Handler, Poco::Logger &Logger, bool Deferred) {
Logger.information(fmt::format("{},{}: New {} command. User={} Serial={} Details={}. ", Cmd.UUID, Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID,
RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber, Cmd.Details)); RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
Cmd.Submitted = Utils::Now(); Cmd.Submitted = Utils::Now();
Cmd.Executed = 0; Cmd.Executed = 0;
@@ -181,29 +167,12 @@ namespace OpenWifi::RESTAPI_RPC {
Cmd.AttachType = ""; Cmd.AttachType = "";
} }
// If the command fails on the device we should show it as failed and not return 200 OK
// exception is configure command which only reported failed in strict validation mode
if (Cmd.ErrorCode &&
(Cmd.Command != uCentralProtocol::CONFIGURE ||
(Cmd.Command == uCentralProtocol::CONFIGURE && Handler->GetBoolParameter("strict", false))
))
{
Logger.information(fmt::format(
"Command failed with error on device: {} Reason: {}.",
Cmd.ErrorCode, Cmd.ErrorText));
return SetCommandStatus(Cmd, Request, Response, Handler,
Storage::CommandExecutionType::COMMAND_FAILED, Logger);
}
if (Cmd.ErrorCode == 0 && Cmd.Command == uCentralProtocol::CONFIGURE) { if (Cmd.ErrorCode == 0 && Cmd.Command == uCentralProtocol::CONFIGURE) {
// we need to post a kafka event for this. // we need to post a kafka event for this.
if (Params.has(uCentralProtocol::CONFIG) && Params.isObject(uCentralProtocol::CONFIG)) { if (Params.has(uCentralProtocol::CONFIG)) {
auto Config = Params.get(uCentralProtocol::CONFIG)
.extract<Poco::JSON::Object::Ptr>();
DeviceConfigurationChangeKafkaEvent KEvent( DeviceConfigurationChangeKafkaEvent KEvent(
Utils::SerialNumberToInt(Cmd.SerialNumber), Utils::Now(), Cmd.SerialNumber, Utils::Now(),
Config); Params.get(uCentralProtocol::CONFIG).toString());
} }
} }

View File

@@ -63,7 +63,7 @@ namespace OpenWifi {
poco_debug(Logger(), fmt::format("BLACKLIST-POST: {}", D.serialNumber)); poco_debug(Logger(), fmt::format("BLACKLIST-POST: {}", D.serialNumber));
Poco::toLowerInPlace(D.serialNumber); Poco::toLowerInPlace(D.serialNumber);
if (StorageService()->IsBlackListed(Utils::MACToInt(D.serialNumber))) { if (StorageService()->IsBlackListed(D.serialNumber)) {
return BadRequest(RESTAPI::Errors::SerialNumberExists); return BadRequest(RESTAPI::Errors::SerialNumberExists);
} }

View File

@@ -56,27 +56,17 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument); return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
} }
if (DefConfig.models.empty()) { if (DefConfig.Models.empty()) {
return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty); return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty);
} }
DefConfig.platform = DefConfig.platform.empty() ? Platforms::AP : DefConfig.platform; std::vector<std::string> Error;
if(DefConfig.platform != Platforms::AP && DefConfig.platform != Platforms::SWITCH) { if (!ValidateUCentralConfiguration(DefConfig.Configuration, Error,
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if(DefConfig.configuration.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
std::string Error;
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DefConfig.platform),
DefConfig.configuration, Error,
GetBoolParameter("strict", false))) { GetBoolParameter("strict", false))) {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
DefConfig.created = DefConfig.lastModified = Utils::Now(); DefConfig.Created = DefConfig.LastModified = Utils::Now();
if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) { if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) {
return OK(); return OK();
} }
@@ -98,31 +88,19 @@ namespace OpenWifi {
return NotFound(); return NotFound();
} }
if(Existing.platform.empty()) { if (!NewConfig.Configuration.empty()) {
Existing.platform = Platforms::AP; std::vector<std::string> Error;
} if (!ValidateUCentralConfiguration(NewConfig.Configuration, Error,
if(ParsedBody_->has("platform")) {
if(NewConfig.platform.empty() || (NewConfig.platform != Platforms::AP && NewConfig.platform != Platforms::SWITCH)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
Existing.platform = NewConfig.platform;
}
if (!NewConfig.configuration.empty()) {
std::string Error;
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Existing.platform),
NewConfig.configuration, Error,
GetBoolParameter("strict", false))) { GetBoolParameter("strict", false))) {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
Existing.configuration = NewConfig.configuration; Existing.Configuration = NewConfig.Configuration;
} }
Existing.lastModified = Utils::Now(); Existing.LastModified = Utils::Now();
AssignIfPresent(Obj, "description", Existing.description); AssignIfPresent(Obj, "description", Existing.Description);
if (Obj->has("modelIds")) if (Obj->has("modelIds"))
Existing.models = NewConfig.models; Existing.Models = NewConfig.Models;
if (StorageService()->UpdateDefaultConfiguration(Name, Existing)) { if (StorageService()->UpdateDefaultConfiguration(Name, Existing)) {
GWObjects::DefaultConfiguration ModifiedConfig; GWObjects::DefaultConfiguration ModifiedConfig;

View File

@@ -7,6 +7,7 @@
// //
#include "Poco/Array.h" #include "Poco/Array.h"
#include "Poco/JSON/Stringifier.h"
#include "RESTAPI_default_configurations.h" #include "RESTAPI_default_configurations.h"
#include "StorageService.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

@@ -87,7 +87,7 @@ namespace OpenWifi {
poco_debug( poco_debug(
Logger_, Logger_,
fmt::format( fmt::format(
"Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}", "Command rtty TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
TransactionId_, UUID, RPC, Poco::Thread::current()->id())); TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
return Rtty(UUID, RPC, 60000ms, Restrictions); return Rtty(UUID, RPC, 60000ms, Restrictions);
}; };
@@ -163,16 +163,8 @@ namespace OpenWifi {
{APCommands::Commands::telemetry, false, true, &RESTAPI_device_commandHandler::Telemetry, {APCommands::Commands::telemetry, false, true, &RESTAPI_device_commandHandler::Telemetry,
30000ms}, 30000ms},
{APCommands::Commands::ping, false, true, &RESTAPI_device_commandHandler::Ping, 60000ms}, {APCommands::Commands::ping, false, true, &RESTAPI_device_commandHandler::Ping, 60000ms},
{APCommands::Commands::rrm, false, true, &RESTAPI_device_commandHandler::RRM, 60000ms}, {APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script,
{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms}, 300000ms}};
{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 60000ms},
{APCommands::Commands::powercycle, false, true, &RESTAPI_device_commandHandler::PowerCycle, 60000ms},
{APCommands::Commands::fixedconfig, false, true, &RESTAPI_device_commandHandler::FixedConfig, 120000ms},
{APCommands::Commands::cablediagnostics, false, true, &RESTAPI_device_commandHandler::CableDiagnostics, 120000ms},
{APCommands::Commands::reenroll, false, true, &RESTAPI_device_commandHandler::ReEnroll, 120000ms},
};
void RESTAPI_device_commandHandler::DoPost() { void RESTAPI_device_commandHandler::DoPost() {
if (!ValidateParameters()) { if (!ValidateParameters()) {
@@ -317,7 +309,7 @@ namespace OpenWifi {
if (AP_WS_Server()->GetState(SerialNumber_, State)) { if (AP_WS_Server()->GetState(SerialNumber_, State)) {
Poco::JSON::Object RetObject; Poco::JSON::Object RetObject;
State.to_json(SerialNumber_, RetObject); State.to_json(RetObject);
return ReturnObject(RetObject); return ReturnObject(RetObject);
} else { } else {
Poco::JSON::Object RetObject; Poco::JSON::Object RetObject;
@@ -414,7 +406,6 @@ namespace OpenWifi {
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) { [[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("PING({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC, poco_debug(Logger_, fmt::format("PING({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
TransactionId_, Requester(), SerialNumber_)); TransactionId_, Requester(), SerialNumber_));
const auto &Obj = ParsedBody_; const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER)) { if (Obj->has(RESTAPI::Protocol::SERIALNUMBER)) {
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString(); auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
@@ -468,14 +459,6 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::MissingSerialNumber); 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, void RESTAPI_device_commandHandler::CallCanceled(const char *Cmd, const std::string &UUID,
uint64_t RPC, uint64_t RPC,
const OpenWifi::RESTAPI::Errors::msg &Err) { const OpenWifi::RESTAPI::Errors::msg &Err) {
@@ -491,10 +474,6 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("SCRIPT({},{}): TID={} user={} serial={}", CMD_UUID, poco_debug(Logger_, fmt::format("SCRIPT({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_)); CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_; const auto &Obj = ParsedBody_;
GWObjects::ScriptRequest SCR; GWObjects::ScriptRequest SCR;
if (!SCR.from_json(Obj)) { if (!SCR.from_json(Obj)) {
@@ -658,18 +637,13 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::SerialNumberMismatch); return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
} }
GWObjects::Device DeviceInfo;
if (!StorageService()->GetDevice(SerialNumber_, DeviceInfo)) {
return NotFound();
}
auto Configuration = auto Configuration =
GetS(RESTAPI::Protocol::CONFIGURATION, Obj, uCentralProtocol::EMPTY_JSON_DOC); GetS(RESTAPI::Protocol::CONFIGURATION, Obj, uCentralProtocol::EMPTY_JSON_DOC);
std::string Error; std::vector<std::string> Error;
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceInfo.DeviceType), if (!ValidateUCentralConfiguration(Configuration, Error,
Configuration, Error,
GetBoolParameter("strict", false))) { GetBoolParameter("strict", false))) {
CallCanceled("CONFIGURE", CMD_UUID, CMD_RPC, RESTAPI::Errors::ConfigBlockInvalid); CallCanceled("CONFIGURE", CMD_UUID, CMD_RPC, RESTAPI::Errors::ConfigBlockInvalid);
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
auto When = GetWhen(Obj); auto When = GetWhen(Obj);
@@ -695,31 +669,9 @@ namespace OpenWifi {
Params.stringify(ParamStream); Params.stringify(ParamStream);
Cmd.Details = ParamStream.str(); Cmd.Details = ParamStream.str();
// retrieve capabilities and encode/compress parameters, if required
Poco::JSON::Object ConfigParams = Params;
GWObjects::Capabilities Caps;
if (StorageService()->GetDeviceCapabilities(SerialNumber_, Caps)) {
Poco::JSON::Object CapsJson;
Caps.to_json(CapsJson);
auto DeviceCaps = CapsJson.getObject(uCentralProtocol::CAPABILITIES);
if (DeviceCaps->has("compress_cmd") && DeviceCaps->get("compress_cmd")) {
// compressed command capability present and it is set, compress parameters
Poco::JSON::Object CompressedParams;
std::string CompressedBase64Data;
std::uint64_t UncompressedDataLen = ParamStream.str().length();
if (Utils::CompressAndEncodeBase64(ParamStream.str(), CompressedBase64Data)) {
// set compressed, base 64 encoded data and length of uncompressed data
CompressedParams.set(uCentralProtocol::COMPRESS_64, CompressedBase64Data);
CompressedParams.set(uCentralProtocol::COMPRESS_SZ, UncompressedDataLen);
ConfigParams = CompressedParams;
}
}
}
// AP_WS_Server()->SetPendingUUID(SerialNumber_, NewUUID); // AP_WS_Server()->SetPendingUUID(SerialNumber_, NewUUID);
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::configure, true, RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::configure, true,
Cmd, ConfigParams, *Request, *Response, timeout, Cmd, Params, *Request, *Response, timeout,
nullptr, this, Logger_); nullptr, this, Logger_);
if(!Cmd.Executed) { if(!Cmd.Executed) {
@@ -947,10 +899,6 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("TRACE({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC, poco_debug(Logger_, fmt::format("TRACE({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
TransactionId_, Requester(), SerialNumber_)); TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_; const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) &&
@@ -1008,12 +956,6 @@ namespace OpenWifi {
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) { [[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("WIFISCAN({},{}): TID={} user={} serial={}", CMD_UUID, poco_debug(Logger_, fmt::format("WIFISCAN({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_)); CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_; const auto &Obj = ParsedBody_;
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString(); auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
@@ -1069,10 +1011,6 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("EVENT-QUEUE({},{}): TID={} user={} serial={}", CMD_UUID, poco_debug(Logger_, fmt::format("EVENT-QUEUE({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_)); CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_; const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->isArray(RESTAPI::Protocol::TYPES)) { if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->isArray(RESTAPI::Protocol::TYPES)) {
@@ -1117,10 +1055,6 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("FORCE-REQUEST({},{}): TID={} user={} serial={}", CMD_UUID, poco_debug(Logger_, fmt::format("FORCE-REQUEST({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_)); CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_; const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(uCentralProtocol::MESSAGE)) { if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(uCentralProtocol::MESSAGE)) {
@@ -1161,16 +1095,15 @@ namespace OpenWifi {
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
} }
#define DBGLINE \
{ std::cout << __LINE__ << std::endl; }
void RESTAPI_device_commandHandler::Rtty( void RESTAPI_device_commandHandler::Rtty(
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout, const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) { [[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("RTTY({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC, poco_debug(Logger_, fmt::format("RTTY({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
TransactionId_, Requester(), SerialNumber_)); TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
if (!Restrictions.developer && Restrictions.rtty) { if (!Restrictions.developer && Restrictions.rtty) {
return BadRequest(RESTAPI::Errors::DeviceIsRestricted); return BadRequest(RESTAPI::Errors::DeviceIsRestricted);
} }
@@ -1179,11 +1112,6 @@ namespace OpenWifi {
GWObjects::Device Device; GWObjects::Device Device;
if (StorageService()->GetDevice(SerialNumber_, Device)) { if (StorageService()->GetDevice(SerialNumber_, Device)) {
if(Device.simulated) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
static std::uint64_t rtty_sid = 0; static std::uint64_t rtty_sid = 0;
rtty_sid += std::rand(); rtty_sid += std::rand();
GWObjects::RttySessionDetails Rtty{ GWObjects::RttySessionDetails Rtty{
@@ -1201,7 +1129,7 @@ namespace OpenWifi {
if (RTTYS_server()->UseInternal()) { if (RTTYS_server()->UseInternal()) {
std::uint64_t SN = Utils::SerialNumberToInt(SerialNumber_); std::uint64_t SN = Utils::SerialNumberToInt(SerialNumber_);
bool mTLS = AP_WS_Server()->DeviceRequiresSecureRTTY(SN); bool mTLS = AP_WS_Server()->DeviceRequiresSecureRtty(SN);
auto Hash = Utils::ComputeHash(UserInfo_.webtoken.refresh_token_, Utils::Now()); auto Hash = Utils::ComputeHash(UserInfo_.webtoken.refresh_token_, Utils::Now());
Rtty.Token = Hash.substr(0, RTTY_DEVICE_TOKEN_LENGTH); Rtty.Token = Hash.substr(0, RTTY_DEVICE_TOKEN_LENGTH);
if (!RTTYS_server()->CreateEndPoint(Rtty.ConnectionId, Rtty.Token, Requester(), if (!RTTYS_server()->CreateEndPoint(Rtty.ConnectionId, Rtty.Token, Requester(),
@@ -1257,10 +1185,6 @@ namespace OpenWifi {
poco_debug(Logger_, fmt::format("TELEMETRY({},{}): TID={} user={} serial={}", CMD_UUID, poco_debug(Logger_, fmt::format("TELEMETRY({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_)); CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_; const auto &Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(RESTAPI::Protocol::INTERVAL) && if (Obj->has(RESTAPI::Protocol::SERIALNUMBER) && Obj->has(RESTAPI::Protocol::INTERVAL) &&
@@ -1374,323 +1298,4 @@ namespace OpenWifi {
} }
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); 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)) {
Cmd.Status= "completed";
StorageService()->AddCommand(SerialNumber_, Cmd,
Storage::CommandExecutionType::COMMAND_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_);
}
void RESTAPI_device_commandHandler::PowerCycle(
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("POWERCYCLE({},{}): 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::PowerCycleRequest PR;
if(!PR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::POWERCYCLE;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = PR.when;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::powercycle, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
// `fixedconfig` command is used set country propery on AP
// This handler uses `fixedconfig` command definitions
void RESTAPI_device_commandHandler::FixedConfig(
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("FIXEDCONFIG({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
TransactionId_, Requester(), SerialNumber_));
// do not allow `fixedconfig` command for simulated devices
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("FIXEDCONFIG", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
// setup and validate fixedconfig object
GWObjects::FixedConfig fixed_config;
if(!fixed_config.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
// setup command message
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::FIXEDCONFIG;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = 0;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
// send fixedconfig command to device and return status
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::fixedconfig, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
void RESTAPI_device_commandHandler::CableDiagnostics(
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("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
poco_debug(Logger_, fmt::format("CABLEDIAGNOSTICS({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
GWObjects::CableDiagnostics PR;
if(!PR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::CABLEDIAGNOSTICS;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = PR.when;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::cablediagnostics, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
void RESTAPI_device_commandHandler::ReEnroll(
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("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
poco_debug(Logger_, fmt::format("REENROLL({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
GWObjects::ReEnroll PR;
if(!PR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::REENROLL;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = PR.when;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::reenroll, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -34,8 +34,6 @@ namespace OpenWifi {
void GetChecks(); void GetChecks();
void DeleteChecks(); void DeleteChecks();
bool IsDeviceSimulated(std::string &Serial);
void Configure(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout, void Configure(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R); const GWObjects::DeviceRestrictions &R);
void Upgrade(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout, void Upgrade(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
@@ -62,20 +60,6 @@ namespace OpenWifi {
const GWObjects::DeviceRestrictions &R); const GWObjects::DeviceRestrictions &R);
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout, void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R); 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);
void PowerCycle(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void FixedConfig(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void CableDiagnostics(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void ReEnroll(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
static auto PathName() { static auto PathName() {
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"}; return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};

View File

@@ -17,8 +17,6 @@
#include "RESTAPI_device_helper.h" #include "RESTAPI_device_helper.h"
#include "AP_WS_Server.h"
namespace OpenWifi { namespace OpenWifi {
void RESTAPI_device_handler::DoGet() { void RESTAPI_device_handler::DoGet() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
@@ -43,10 +41,6 @@ namespace OpenWifi {
void RESTAPI_device_handler::DoDelete() { void RESTAPI_device_handler::DoDelete() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!RESTAPI_utils::IsRootOrAdmin(UserInfo_.userinfo)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if (!Utils::NormalizeMac(SerialNumber)) { if (!Utils::NormalizeMac(SerialNumber)) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber); return BadRequest(RESTAPI::Errors::MissingSerialNumber);
} }
@@ -82,9 +76,6 @@ namespace OpenWifi {
return OK(); return OK();
} else if (StorageService()->DeleteDevice(SerialNumber)) { } else if (StorageService()->DeleteDevice(SerialNumber)) {
if(AP_WS_Server()->Connected(Utils::SerialNumberToInt(SerialNumber))) {
AP_WS_Server()->Disconnect(Utils::SerialNumberToInt(SerialNumber));
}
return OK(); return OK();
} }
@@ -106,10 +97,9 @@ namespace OpenWifi {
} }
auto Config = Obj->get("configuration").toString(); auto Config = Obj->get("configuration").toString();
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
std::string Error; std::vector<std::string> Error;
auto DeviceType = Poco::toLower(GetParameter("deviceType", Platforms::AP));
auto Res = auto Res =
ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceType),Config, Error, GetBoolParameter("strict", false)); ValidateUCentralConfiguration(Config, Error, GetBoolParameter("strict", false));
Answer.set("valid", Res); Answer.set("valid", Res);
if (!Error.empty()) if (!Error.empty())
Answer.set("error", Error); Answer.set("error", Error);
@@ -129,13 +119,12 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::SerialNumberMismatch); return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
} }
std::string Error; std::vector<std::string> Error;
if (Device.Configuration.empty() || if (Device.Configuration.empty() ||
(!Device.Configuration.empty() && (!Device.Configuration.empty() &&
!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Device.DeviceType), !ValidateUCentralConfiguration(Device.Configuration, Error,
Device.Configuration, Error,
GetBoolParameter("strict", false)))) { GetBoolParameter("strict", false)))) {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
for (auto &i : Device.Notes) { for (auto &i : Device.Notes) {
@@ -176,11 +165,10 @@ namespace OpenWifi {
} }
if (!NewDevice.Configuration.empty()) { if (!NewDevice.Configuration.empty()) {
std::string Error; std::vector<std::string> Error;
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Existing.DeviceType), if (!ValidateUCentralConfiguration(NewDevice.Configuration, Error,
NewDevice.Configuration, Error,
GetBoolParameter("strict", false))) { GetBoolParameter("strict", false))) {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
Config::Config NewConfig(NewDevice.Configuration); Config::Config NewConfig(NewDevice.Configuration);
uint64_t NewConfigUUID = Utils::Now(); uint64_t NewConfigUUID = Utils::Now();

View File

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

View File

@@ -82,24 +82,15 @@ namespace OpenWifi {
} }
} }
auto platform = Poco::toLower(GetParameter("platform", ""));
auto serialOnly = GetBoolParameter(RESTAPI::Protocol::SERIALONLY, false); auto serialOnly = GetBoolParameter(RESTAPI::Protocol::SERIALONLY, false);
auto deviceWithStatus = GetBoolParameter(RESTAPI::Protocol::DEVICEWITHSTATUS, false); auto deviceWithStatus = GetBoolParameter(RESTAPI::Protocol::DEVICEWITHSTATUS, false);
auto completeInfo = GetBoolParameter("completeInfo", false); auto completeInfo = GetBoolParameter("completeInfo", false);
auto includeProvisioned = GetBoolParameter("includeProvisioned", true);
if(!platform.empty() && (platform!=Platforms::AP && platform!=Platforms::SWITCH && platform!="all")) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if(platform=="all")
platform="";
Poco::JSON::Object RetObj; Poco::JSON::Object RetObj;
if (!QB_.Select.empty()) { if (!QB_.Select.empty()) {
Poco::JSON::Array Objects; Poco::JSON::Array Objects;
for (auto &i : SelectedRecords()) { for (auto &i : SelectedRecords()) {
auto &SerialNumber = i; auto SerialNumber = i;
if (!Utils::ValidSerialNumber(i)) if (!Utils::ValidSerialNumber(i))
continue; continue;
GWObjects::Device D; GWObjects::Device D;
@@ -125,14 +116,14 @@ namespace OpenWifi {
else else
RetObj.set(RESTAPI::Protocol::DEVICES, Objects); RetObj.set(RESTAPI::Protocol::DEVICES, Objects);
} else if (QB_.CountOnly) { } else if (QB_.CountOnly == true) {
uint64_t Count = 0; uint64_t Count = 0;
if (StorageService()->GetDeviceCount(Count, platform)) { if (StorageService()->GetDeviceCount(Count)) {
return ReturnCountOnly(Count); return ReturnCountOnly(Count);
} }
} else if (serialOnly) { } else if (serialOnly) {
std::vector<std::string> SerialNumbers; std::vector<std::string> SerialNumbers;
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers, OrderBy, platform, includeProvisioned); StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers, OrderBy);
Poco::JSON::Array Objects; Poco::JSON::Array Objects;
for (const auto &i : SerialNumbers) { for (const auto &i : SerialNumbers) {
Objects.add(i); Objects.add(i);
@@ -150,7 +141,7 @@ namespace OpenWifi {
RetObj.set("serialNumbers", Objects); RetObj.set("serialNumbers", Objects);
} else { } else {
std::vector<GWObjects::Device> Devices; std::vector<GWObjects::Device> Devices;
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices, OrderBy, platform, includeProvisioned); StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices, OrderBy);
Poco::JSON::Array Objects; Poco::JSON::Array Objects;
for (const auto &i : Devices) { for (const auto &i : Devices) {
Poco::JSON::Object Obj; Poco::JSON::Object Obj;
@@ -167,63 +158,4 @@ namespace OpenWifi {
} }
ReturnObject(RetObj); 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)) {
auto F = []() ->void {
StorageService()->DeleteSimulatedDevice("");
};
std::thread T(F);
T.detach();
return OK();
}
if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
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 } // namespace OpenWifi

View File

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

View File

@@ -22,15 +22,9 @@ namespace OpenWifi {
std::string FileType; std::string FileType;
std::string FileContent; std::string FileContent;
int WaitingForFile = 0; if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType) || FileContent.empty()) {
if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType, WaitingForFile) && !WaitingForFile) {
return NotFound(); return NotFound();
} }
else if (WaitingForFile) {
// waiting for file to be uploaded, return Accepted
return Accepted();
}
if (FileType == "pcap") { if (FileType == "pcap") {
SendFileContent(FileContent, "application/vnd.tcpdump.pcap", UUID + ".pcap"); SendFileContent(FileContent, "application/vnd.tcpdump.pcap", UUID + ".pcap");
} }

View File

@@ -8,7 +8,7 @@
#pragma once #pragma once
#include <framework/RESTAPI_Handler.h> #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_file : public RESTAPIHandler { class RESTAPI_file : public RESTAPIHandler {

View File

@@ -8,11 +8,6 @@
namespace OpenWifi { 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() { void RESTAPI_radiusProxyConfig_handler::DoGet() {
Logger_.information(fmt::format("GET-RADIUS-PROXY-CONFIG: TID={} user={} thr_id={}", Logger_.information(fmt::format("GET-RADIUS-PROXY-CONFIG: TID={} user={} thr_id={}",
TransactionId_, Requester(), TransactionId_, Requester(),
@@ -49,22 +44,10 @@ namespace OpenWifi {
} }
// Logically validate the config. // Logically validate the config.
for (auto &pool : C.pools) { for (const auto &pool : C.pools) {
if (pool.name.empty()) { if (pool.name.empty()) {
return BadRequest(RESTAPI::Errors::PoolNameInvalid); 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}) { for (const auto &config : {pool.acctConfig, pool.authConfig, pool.coaConfig}) {
if (config.servers.empty()) if (config.servers.empty())
continue; 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_script_handler.h"
#include "RESTAPI/RESTAPI_scripts_handler.h" #include "RESTAPI/RESTAPI_scripts_handler.h"
#include "RESTAPI/RESTAPI_telemetryWebSocket.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_SystemCommand.h"
#include "framework/RESTAPI_SystemConfiguration.h" #include "framework/RESTAPI_SystemConfiguration.h"
@@ -42,9 +39,8 @@ namespace OpenWifi {
RESTAPI_system_configuration, RESTAPI_deviceDashboardHandler, RESTAPI_webSocketServer, RESTAPI_system_configuration, RESTAPI_deviceDashboardHandler, RESTAPI_webSocketServer,
RESTAPI_blacklist, RESTAPI_blacklist_list, RESTAPI_iptocountry_handler, RESTAPI_blacklist, RESTAPI_blacklist_list, RESTAPI_iptocountry_handler,
RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler, RESTAPI_script_handler, RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler, RESTAPI_script_handler,
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket, RESTAPI_radiussessions_handler, RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket,
RESTAPI_regulatory, RESTAPI_default_firmwares, RESTAPI_regulatory>(Path, Bindings, L, S,
RESTAPI_default_firmware>(Path, Bindings, L, S,
TransactionId); TransactionId);
} }
@@ -57,8 +53,7 @@ namespace OpenWifi {
RESTAPI_default_configurations, RESTAPI_default_configuration, RESTAPI_command, RESTAPI_default_configurations, RESTAPI_default_configuration, RESTAPI_command,
RESTAPI_commands, RESTAPI_ouis, RESTAPI_file, RESTAPI_blacklist, RESTAPI_commands, RESTAPI_ouis, RESTAPI_file, RESTAPI_blacklist,
RESTAPI_iptocountry_handler, RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler, RESTAPI_iptocountry_handler, RESTAPI_radiusProxyConfig_handler, RESTAPI_scripts_handler,
RESTAPI_script_handler, RESTAPI_blacklist_list, RESTAPI_radiussessions_handler, RESTAPI_script_handler, RESTAPI_blacklist_list,
RESTAPI_regulatory, RESTAPI_default_firmwares, RESTAPI_regulatory>(Path, Bindings, L, S, TransactionId);
RESTAPI_default_firmware>(Path, Bindings, L, S, TransactionId);
} }
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -7,7 +7,6 @@
#include "RESTAPI_ProvObjects.h" #include "RESTAPI_ProvObjects.h"
#include "framework/utils.h" #include "framework/utils.h"
#include <vector> #include <vector>
#include "framework/ow_constants.h"
namespace OpenWifi { namespace OpenWifi {

View File

@@ -12,9 +12,7 @@
#include "Daemon.h" #include "Daemon.h"
#ifdef TIP_GATEWAY_SERVICE #ifdef TIP_GATEWAY_SERVICE
#include "AP_WS_Server.h" #include "AP_WS_Server.h"
#include "StorageService.h"
#include "CapabilitiesCache.h" #include "CapabilitiesCache.h"
#include "RADIUSSessionTracker.h"
#endif #endif
#include "RESTAPI_GWobjects.h" #include "RESTAPI_GWobjects.h"
@@ -30,8 +28,7 @@ namespace OpenWifi::GWObjects {
void Device::to_json(Poco::JSON::Object &Obj) const { void Device::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "serialNumber", SerialNumber); field_to_json(Obj, "serialNumber", SerialNumber);
#ifdef TIP_GATEWAY_SERVICE #ifdef TIP_GATEWAY_SERVICE
field_to_json(Obj, "deviceType", StorageService()->GetPlatform(SerialNumber)); field_to_json(Obj, "deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible));
field_to_json(Obj, "blackListed", StorageService()->IsBlackListed(Utils::MACToInt(SerialNumber)));
#endif #endif
field_to_json(Obj, "macAddress", MACAddress); field_to_json(Obj, "macAddress", MACAddress);
field_to_json(Obj, "manufacturer", Manufacturer); field_to_json(Obj, "manufacturer", Manufacturer);
@@ -58,10 +55,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd); field_to_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd);
field_to_json(Obj, "restrictionDetails", restrictionDetails); field_to_json(Obj, "restrictionDetails", restrictionDetails);
field_to_json(Obj, "pendingUUID", pendingUUID); 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 { void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
@@ -69,14 +62,9 @@ namespace OpenWifi::GWObjects {
#ifdef TIP_GATEWAY_SERVICE #ifdef TIP_GATEWAY_SERVICE
ConnectionState ConState; ConnectionState ConState;
#ifdef USE_MEDUSA_CLIENT
auto Res = GS()->GetState(SerialNumber); if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
if (Res.has_value()) { ConState.to_json(Obj);
Res.value().to_json(SerialNumber,Obj);
#else
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
ConState.to_json(SerialNumber,Obj);
#endif
} else { } else {
field_to_json(Obj, "ipAddress", ""); field_to_json(Obj, "ipAddress", "");
field_to_json(Obj, "txBytes", (uint64_t)0); field_to_json(Obj, "txBytes", (uint64_t)0);
@@ -88,13 +76,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "associations_2G", (uint64_t)0); field_to_json(Obj, "associations_2G", (uint64_t)0);
field_to_json(Obj, "associations_5G", (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, "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 #endif
} }
@@ -128,10 +109,6 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd); field_from_json(Obj, "pendingConfigurationCmd", pendingConfigurationCmd);
field_from_json(Obj, "restrictionDetails", restrictionDetails); field_from_json(Obj, "restrictionDetails", restrictionDetails);
field_from_json(Obj, "pendingUUID", pendingUUID); 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; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
} }
@@ -172,43 +149,15 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "recorded", Recorded); field_to_json(Obj, "recorded", Recorded);
} }
bool HealthCheck::from_json(const Poco::JSON::Object::Ptr &Obj) { void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
try { EmbedDocument("configuration", Obj, Configuration);
field_from_json(Obj, "UUID", UUID); field_to_json(Obj, "name", Name);
field_from_json(Obj, "sanity", Sanity); field_to_json(Obj, "modelIds", Models);
field_from_json(Obj, "recorded", Recorded);
return true;
} catch(...) {
}
return false;
}
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, "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, "created", Created);
field_to_json(Obj, "lastModified", LastModified); 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 { void CommandDetails::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("details", Obj, Details); EmbedDocument("details", Obj, Details);
EmbedDocument("results", Obj, Results); EmbedDocument("results", Obj, Results);
@@ -231,25 +180,12 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "deferred", deferred); field_to_json(Obj, "deferred", deferred);
} }
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("configuration", Obj, configuration);
field_to_json(Obj, "name", name);
field_to_json(Obj, "modelIds", models);
field_to_json(Obj, "description", description);
field_to_json(Obj, "created", created);
field_to_json(Obj, "lastModified", lastModified);
field_to_json(Obj, "platform", platform);
}
bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj, "configuration", configuration); field_from_json(Obj, "name", Name);
field_from_json(Obj, "name", name); field_from_json(Obj, "configuration", Configuration);
field_from_json(Obj, "modelIds", models); field_from_json(Obj, "modelIds", Models);
field_from_json(Obj, "description", description); field_from_json(Obj, "description", Description);
field_from_json(Obj, "created", created);
field_from_json(Obj, "lastModified", lastModified);
field_from_json(Obj, "platform", platform);
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
} }
@@ -275,7 +211,7 @@ namespace OpenWifi::GWObjects {
return false; 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, "ipAddress", Address);
field_to_json(Obj, "txBytes", TX); field_to_json(Obj, "txBytes", TX);
field_to_json(Obj, "rxBytes", RX); field_to_json(Obj, "rxBytes", RX);
@@ -297,21 +233,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime); field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_to_json(Obj, "totalConnectionTime", Utils::Now() - started); field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate); field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_to_json(Obj, "certificateIssuerName", certificateIssuerName);
field_to_json(Obj, "connectReason", connectReason);
field_to_json(Obj, "uptime", uptime);
field_to_json(Obj, "compatible", Compatible);
#ifdef TIP_GATEWAY_SERVICE
hasRADIUSSessions = RADIUSSessionTracker()->HasSessions(SerialNumber);
#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) { switch (VerifiedCertificate) {
case NO_CERTIFICATE: case NO_CERTIFICATE:
@@ -326,55 +247,12 @@ namespace OpenWifi::GWObjects {
case VERIFIED: case VERIFIED:
field_to_json(Obj, "verifiedCertificate", "VERIFIED"); field_to_json(Obj, "verifiedCertificate", "VERIFIED");
break; break;
case SIMULATED:
field_to_json(Obj, "verifiedCertificate", "SIMULATED");
break;
default: default:
field_to_json(Obj, "verifiedCertificate", "NO_CERTIFICATE"); field_to_json(Obj, "verifiedCertificate", "NO_CERTIFICATE");
break; break;
} }
} }
bool ConnectionState::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "compatible", Compatible);
field_from_json(Obj, "ipAddress", Address);
field_from_json(Obj, "txBytes", TX);
field_from_json(Obj, "rxBytes", RX);
field_from_json(Obj, "messageCount", MessageCount);
field_from_json(Obj, "UUID", UUID);
field_from_json(Obj, "connected", Connected);
field_from_json(Obj, "firmware", Firmware);
field_from_json(Obj, "lastContact", LastContact);
field_from_json(Obj, "associations_2G", Associations_2G);
field_from_json(Obj, "associations_5G", Associations_5G);
field_from_json(Obj, "associations_6G", Associations_6G);
field_from_json(Obj, "webSocketClients", webSocketClients);
field_from_json(Obj, "websocketPackets", websocketPackets);
field_from_json(Obj, "kafkaClients", kafkaClients);
field_from_json(Obj, "kafkaPackets", kafkaPackets);
field_from_json(Obj, "locale", locale);
field_from_json(Obj, "started", started);
field_from_json(Obj, "sessionId", sessionId);
field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_from_json(Obj, "certificateIssuerName", certificateIssuerName);
field_from_json(Obj, "connectReason", connectReason);
field_from_json(Obj, "uptime", uptime);
field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
field_from_json(Obj, "hasGPS", hasGPS);
field_from_json(Obj, "sanity", sanity);
field_from_json(Obj, "memoryUsed", memoryUsed);
field_from_json(Obj, "sanity", sanity);
field_from_json(Obj, "load", load);
field_from_json(Obj, "temperature", temperature);
return true;
} catch(const Poco::Exception &E) {
}
return false;
}
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const { void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "averageConnectionTime", averageConnectionTime); field_to_json(Obj, "averageConnectionTime", averageConnectionTime);
field_to_json(Obj, "connectedDevices", connectedDevices); field_to_json(Obj, "connectedDevices", connectedDevices);
@@ -495,10 +373,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "acctConfig", acctConfig); field_to_json(Obj, "acctConfig", acctConfig);
field_to_json(Obj, "coaConfig", coaConfig); field_to_json(Obj, "coaConfig", coaConfig);
field_to_json(Obj, "useByDefault", useByDefault); 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) { bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -509,10 +383,6 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj, "acctConfig", acctConfig); field_from_json(Obj, "acctConfig", acctConfig);
field_from_json(Obj, "coaConfig", coaConfig); field_from_json(Obj, "coaConfig", coaConfig);
field_from_json(Obj, "useByDefault", useByDefault); 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; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
} }
@@ -710,125 +580,4 @@ namespace OpenWifi::GWObjects {
(T.commands != commands) || (T.developer != developer) || (T.ssh != ssh) || (T.commands != commands) || (T.developer != developer) || (T.ssh != ssh) ||
(T.key_info != key_info) || (T.country != country)); (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, "serial", serialNumber);
field_from_json(Obj, "encodedCertificate", encodedCertificate);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool PowerCyclePort::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "name", name);
field_from_json(Obj, "cycle", cycle);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool PowerCycleRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serial", serialNumber);
field_from_json(Obj, "when", when);
field_from_json(Obj, "ports", ports);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool FixedConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serial", serialNumber);
field_from_json(Obj, "country", country);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool CableDiagnostics::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serial", serialNumber);
field_from_json(Obj, "when", when);
field_from_json(Obj, "ports", ports);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool ReEnroll::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serial", serialNumber);
field_from_json(Obj, "when", when);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
} // namespace OpenWifi::GWObjects } // namespace OpenWifi::GWObjects

View File

@@ -11,13 +11,9 @@
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include "RESTAPI_SecurityObjects.h" #include "RESTAPI_SecurityObjects.h"
#ifdef TIP_GATEWAY_SERVICE
#include <RADIUS_helpers.h>
#endif
namespace OpenWifi::GWObjects { namespace OpenWifi::GWObjects {
enum CertificateValidation { NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED, SIMULATED }; enum CertificateValidation { NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED };
struct ConnectionState { struct ConnectionState {
uint64_t MessageCount = 0; uint64_t MessageCount = 0;
@@ -42,19 +38,8 @@ namespace OpenWifi::GWObjects {
uint64_t sessionId = 0; uint64_t sessionId = 0;
double connectionCompletionTime = 0.0; double connectionCompletionTime = 0.0;
std::uint64_t certificateExpiryDate = 0; std::uint64_t certificateExpiryDate = 0;
std::string certificateIssuerName;
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;
std::uint64_t uptime=0;
std::uint64_t totalConnectionTime=0;
void to_json(const std::string &SerialNumber, Poco::JSON::Object &Obj) ; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
struct DeviceRestrictionsKeyInfo { struct DeviceRestrictionsKeyInfo {
@@ -112,11 +97,6 @@ namespace OpenWifi::GWObjects {
std::string pendingConfigurationCmd; std::string pendingConfigurationCmd;
DeviceRestrictions restrictionDetails; DeviceRestrictions restrictionDetails;
std::uint64_t pendingUUID = 0; std::uint64_t pendingUUID = 0;
bool simulated=false;
std::uint64_t lastRecordedContact=0;
std::uint64_t certificateExpiryDate = 0;
std::string connectReason;
bool blackListed=false;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const; void to_json_with_status(Poco::JSON::Object &Obj) const;
@@ -142,15 +122,13 @@ namespace OpenWifi::GWObjects {
}; };
struct HealthCheck { struct HealthCheck {
std::string SerialNumber; std::string SerialNumber;
uint64_t UUID = 0; uint64_t UUID = 0;
std::string Data; std::string Data;
uint64_t Recorded = 0; uint64_t Recorded = 0;
uint64_t Sanity = 0; uint64_t Sanity = 0;
void to_json(Poco::JSON::Object &Obj) const;
void to_json(Poco::JSON::Object &Obj) const; };
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Capabilities { struct Capabilities {
std::string Capabilities; std::string Capabilities;
@@ -181,33 +159,12 @@ namespace OpenWifi::GWObjects {
}; };
struct DefaultConfiguration { struct DefaultConfiguration {
std::string name; std::string Name;
std::string configuration; std::string Configuration;
Types::StringVec models; Types::StringVec Models;
std::string description;
uint64_t created;
uint64_t lastModified;
std::string platform;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DefaultFirmware {
std::string deviceType;
std::string Description; std::string Description;
std::string uri;
std::string revision;
uint64_t imageCreationDate;
uint64_t Created; uint64_t Created;
uint64_t LastModified; 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; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
@@ -370,10 +327,6 @@ namespace OpenWifi::GWObjects {
RadiusProxyServerConfig acctConfig; RadiusProxyServerConfig acctConfig;
RadiusProxyServerConfig coaConfig; RadiusProxyServerConfig coaConfig;
bool useByDefault = false; 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; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -417,141 +370,5 @@ namespace OpenWifi::GWObjects {
using RegulatoryInfoCountryMap = std::map<std::string,RegulatoryCountryInfo>; 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);
};
struct PowerCyclePort {
std::string name;
std::uint64_t cycle=10000;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct PowerCycleRequest {
std::string serialNumber;
std::uint64_t when;
std::vector<PowerCyclePort> ports;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct FixedConfig {
std::string serialNumber;
std::string country;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct CableDiagnostics {
std::string serialNumber;
std::uint64_t when;
std::vector<std::string> ports;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ReEnroll {
std::string serialNumber;
std::uint64_t when;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
} // namespace OpenWifi::GWObjects } // namespace OpenWifi::GWObjects

View File

@@ -78,22 +78,21 @@ namespace OpenWifi::OWLSObjects {
return false; return false;
} }
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const { void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id); field_to_json(Obj, "id", id);
field_to_json(Obj, "simulationId", simulationId); field_to_json(Obj, "simulationId", simulationId);
field_to_json(Obj, "state", state); field_to_json(Obj, "state", state);
field_to_json(Obj, "tx", tx); field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx); field_to_json(Obj, "rx", rx);
field_to_json(Obj, "msgsTx", msgsTx); field_to_json(Obj, "msgsTx", msgsTx);
field_to_json(Obj, "msgsRx", msgsRx); field_to_json(Obj, "msgsRx", msgsRx);
field_to_json(Obj, "liveDevices", liveDevices); field_to_json(Obj, "liveDevices", liveDevices);
field_to_json(Obj, "timeToFullDevices", timeToFullDevices); field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
field_to_json(Obj, "startTime", startTime); field_to_json(Obj, "startTime", startTime);
field_to_json(Obj, "endTime", endTime); field_to_json(Obj, "endTime", endTime);
field_to_json(Obj, "errorDevices", errorDevices); field_to_json(Obj, "errorDevices", errorDevices);
field_to_json(Obj, "owner", owner); field_to_json(Obj, "owner", owner);
field_to_json(Obj, "expectedDevices", expectedDevices); }
}
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {} 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); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
struct SimulationStatus { struct SimulationStatus {
std::string id; std::string id;
std::string simulationId; std::string simulationId;
std::string state; std::string state;
uint64_t tx; uint64_t tx;
uint64_t rx; uint64_t rx;
uint64_t msgsTx; uint64_t msgsTx;
uint64_t msgsRx; uint64_t msgsRx;
uint64_t liveDevices; uint64_t liveDevices;
uint64_t timeToFullDevices; uint64_t timeToFullDevices;
uint64_t startTime; uint64_t startTime;
uint64_t endTime; uint64_t endTime;
uint64_t errorDevices; uint64_t errorDevices;
std::string owner; std::string owner;
uint64_t expectedDevices;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct Dashboard { struct Dashboard {
int O; int O;

View File

@@ -587,9 +587,6 @@ namespace OpenWifi::ProvObjects {
field_to_json(Obj, "locale", locale); field_to_json(Obj, "locale", locale);
field_to_json(Obj, "realMacAddress", realMacAddress); field_to_json(Obj, "realMacAddress", realMacAddress);
field_to_json(Obj, "doNotAllowOverrides", doNotAllowOverrides); field_to_json(Obj, "doNotAllowOverrides", doNotAllowOverrides);
field_to_json(Obj, "imported", imported);
field_to_json(Obj, "connected", connected);
field_to_json(Obj, "platform", platform);
} }
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -612,9 +609,6 @@ namespace OpenWifi::ProvObjects {
field_from_json(Obj, "locale", locale); field_from_json(Obj, "locale", locale);
field_from_json(Obj, "realMacAddress", realMacAddress); field_from_json(Obj, "realMacAddress", realMacAddress);
field_from_json(Obj, "doNotAllowOverrides", doNotAllowOverrides); field_from_json(Obj, "doNotAllowOverrides", doNotAllowOverrides);
field_from_json(Obj, "imported", imported);
field_from_json(Obj, "connected", connected);
field_from_json(Obj, "platform", platform);
return true; return true;
} catch (...) { } catch (...) {
} }
@@ -1200,243 +1194,4 @@ namespace OpenWifi::ProvObjects {
return false; 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 } // namespace OpenWifi::ProvObjects

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -24,7 +24,7 @@ namespace OpenWifi::StateUtils {
} }
bool ComputeAssociations(const Poco::JSON::Object::Ptr RawObject, uint64_t &Radios_2G, bool ComputeAssociations(const Poco::JSON::Object::Ptr RawObject, uint64_t &Radios_2G,
uint64_t &Radios_5G, uint64_t &Radios_6G, uint64_t &UpTime ) { uint64_t &Radios_5G, uint64_t &Radios_6G) {
Radios_2G = 0; Radios_2G = 0;
Radios_5G = 0; Radios_5G = 0;
Radios_6G = 0; Radios_6G = 0;
@@ -90,15 +90,9 @@ namespace OpenWifi::StateUtils {
} }
} }
} }
// std::cout << Radios_2G << " " << Radios_5G << " " << Radios_6G << std::endl;
return true; return true;
} }
if(RawObject->has("unit") && !RawObject->isNull("unit") && RawObject->isObject("unit")) {
auto unit = RawObject->getObject("unit");
if(unit->has("uptime")) {
UpTime = unit->get("uptime");
}
}
return false; return false;
} }
} // namespace OpenWifi::StateUtils } // namespace OpenWifi::StateUtils

View File

@@ -8,5 +8,5 @@
namespace OpenWifi::StateUtils { namespace OpenWifi::StateUtils {
bool ComputeAssociations(const Poco::JSON::Object::Ptr RawObject, uint64_t &Radios_2G, bool ComputeAssociations(const Poco::JSON::Object::Ptr RawObject, uint64_t &Radios_2G,
uint64_t &Radios_5G, uint64_t &Radio_6G, uint64_t &UpTime); uint64_t &Radios_5G, uint64_t &Radio_6G);
} }

View File

@@ -22,8 +22,6 @@ namespace OpenWifi {
ScriptDB_->Create(); ScriptDB_->Create();
ScriptDB_->Initialize(); ScriptDB_->Initialize();
FixDeviceTypeBug();
return 0; return 0;
} }

View File

@@ -16,22 +16,6 @@
namespace OpenWifi { namespace OpenWifi {
class LockedDbSession {
public:
explicit LockedDbSession();
~LockedDbSession() = default;
inline std::mutex &Mutex() { return *Mutex_; };
inline Poco::Data::Session &Session() {
if(!Session_->isConnected()) {
Session_->reconnect();
}
return *Session_;
};
private:
std::shared_ptr<Poco::Data::Session> Session_;
std::shared_ptr<std::mutex> Mutex_;
};
class Storage : public StorageClass { class Storage : public StorageClass {
public: public:
@@ -106,8 +90,7 @@ namespace OpenWifi {
// typedef std::map<std::string,std::string> DeviceCapabilitiesCache; // typedef std::map<std::string,std::string> DeviceCapabilitiesCache;
bool AddLog(LockedDbSession &Session, const GWObjects::DeviceLog &Log); bool AddLog(const GWObjects::DeviceLog &Log);
bool AddStatisticsData(Poco::Data::Session &Session, const GWObjects::Statistics &Stats);
bool AddStatisticsData(const GWObjects::Statistics &Stats); bool AddStatisticsData(const GWObjects::Statistics &Stats);
bool GetStatisticsData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate, bool GetStatisticsData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
uint64_t Offset, uint64_t HowMany, uint64_t Offset, uint64_t HowMany,
@@ -119,7 +102,6 @@ namespace OpenWifi {
std::vector<GWObjects::Statistics> &Stats); std::vector<GWObjects::Statistics> &Stats);
bool AddHealthCheckData(const GWObjects::HealthCheck &Check); bool AddHealthCheckData(const GWObjects::HealthCheck &Check);
bool AddHealthCheckData(LockedDbSession &Session, const GWObjects::HealthCheck &Check);
bool GetHealthCheckData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate, bool GetHealthCheckData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
uint64_t Offset, uint64_t HowMany, uint64_t Offset, uint64_t HowMany,
std::vector<GWObjects::HealthCheck> &Checks); std::vector<GWObjects::HealthCheck> &Checks);
@@ -133,43 +115,27 @@ namespace OpenWifi {
uint64_t &NewUUID); uint64_t &NewUUID);
bool RollbackDeviceConfigurationChange(std::string & SerialNumber); bool RollbackDeviceConfigurationChange(std::string & SerialNumber);
bool CompleteDeviceConfigurationChange(Poco::Data::Session &Session, std::string & SerialNumber);
bool CompleteDeviceConfigurationChange(std::string & SerialNumber); bool CompleteDeviceConfigurationChange(std::string & SerialNumber);
bool CreateDevice(LockedDbSession &Session, GWObjects::Device &);
bool CreateDevice(GWObjects::Device &);
bool CreateDefaultDevice(Poco::Data::Session &Session,std::string &SerialNumber,
const Config::Capabilities &Caps,
std::string &Firmware, const Poco::Net::IPAddress &IPAddress,
bool simulated);
bool CreateDevice(Poco::Data::Session &Sess, GWObjects::Device &DeviceDetails);
bool GetDevice(LockedDbSession &Session, const std::string &SerialNumber, GWObjects::Device &); bool CreateDevice(GWObjects::Device &);
bool GetDevice(Poco::Data::Session &Session, const std::string &SerialNumber, GWObjects::Device &DeviceDetails); bool CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
bool GetDevice(const std::string &SerialNumber, GWObjects::Device &); 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, bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices,
const std::string &orderBy = "", const std::string &orderBy = "");
const std::string &platform = "",
bool includeProvisioned = true);
// bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select, // bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select,
// std::vector<GWObjects::Device> &Devices, const std::string & orderBy=""); // std::vector<GWObjects::Device> &Devices, const std::string & orderBy="");
bool DeleteDevice(std::string &SerialNumber); bool DeleteDevice(std::string &SerialNumber);
bool DeleteDevices(std::string &SerialPattern, bool SimulatedOnly);
bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly);
std::string GetPlatform(const std::string &SerialNumber);
bool UpdateDevice(GWObjects::Device &); bool UpdateDevice(GWObjects::Device &);
bool UpdateDevice(LockedDbSession &Session, GWObjects::Device &);
bool UpdateDevice(Poco::Data::Session &Sess, GWObjects::Device &NewDeviceDetails);
bool DeviceExists(std::string &SerialNumber); bool DeviceExists(std::string &SerialNumber);
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware); bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
bool GetDeviceCount(uint64_t &Count, const std::string &platform = ""); bool GetDeviceCount(uint64_t &Count);
bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany, bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany,
std::vector<std::string> &SerialNumbers, std::vector<std::string> &SerialNumbers,
const std::string &orderBy = "", const std::string &orderBy = "");
const std::string &platform = "",
bool includeProvisioned = true);
bool GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy); bool GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy);
bool SetDevicePassword(LockedDbSession &Session, std::string &SerialNumber, std::string &Password); bool SetDevicePassword(std::string &SerialNumber, std::string &Password);
bool UpdateSerialNumberCache(); bool UpdateSerialNumberCache();
static void GetDeviceDbFieldList(Types::StringVec &Fields); static void GetDeviceDbFieldList(Types::StringVec &Fields);
@@ -178,11 +144,9 @@ namespace OpenWifi {
bool UpdateDeviceCapabilities(std::string &SerialNumber, bool UpdateDeviceCapabilities(std::string &SerialNumber,
const Config::Capabilities &Capabilities); const Config::Capabilities &Capabilities);
bool UpdateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber,
const Config::Capabilities &Capabilities);
bool GetDeviceCapabilities(std::string &SerialNumber, GWObjects::Capabilities &); bool GetDeviceCapabilities(std::string &SerialNumber, GWObjects::Capabilities &);
bool DeleteDeviceCapabilities(std::string &SerialNumber); bool DeleteDeviceCapabilities(std::string &SerialNumber);
bool CreateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber, bool CreateDeviceCapabilities(std::string &SerialNumber,
const Config::Capabilities &Capabilities); const Config::Capabilities &Capabilities);
bool InitCapabilitiesCache(); bool InitCapabilitiesCache();
@@ -203,24 +167,10 @@ namespace OpenWifi {
bool GetDefaultConfigurations(uint64_t From, uint64_t HowMany, bool GetDefaultConfigurations(uint64_t From, uint64_t HowMany,
std::vector<GWObjects::DefaultConfiguration> &Devices); std::vector<GWObjects::DefaultConfiguration> &Devices);
bool FindDefaultConfigurationForModel(const std::string &Model, bool FindDefaultConfigurationForModel(const std::string &Model,
const std::string &Platform,
GWObjects::DefaultConfiguration &DefConfig); GWObjects::DefaultConfiguration &DefConfig);
uint64_t GetDefaultConfigurationsCount(); uint64_t GetDefaultConfigurationsCount();
bool DefaultConfigurationAlreadyExists(std::string &Name); 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, bool AddCommand(std::string &SerialNumber, GWObjects::CommandDetails &Command,
CommandExecutionType Type); CommandExecutionType Type);
bool GetCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate, bool GetCommands(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
@@ -243,7 +193,7 @@ namespace OpenWifi {
const std::string &Type); const std::string &Type);
bool CancelWaitFile(std::string &UUID, std::string &ErrorText); bool CancelWaitFile(std::string &UUID, std::string &ErrorText);
bool GetAttachedFileContent(std::string &UUID, const std::string &SerialNumber, bool GetAttachedFileContent(std::string &UUID, const std::string &SerialNumber,
std::string &FileContent, std::string &Type, int& WaitingForFile); std::string &FileContent, std::string &Type);
bool RemoveAttachedFile(std::string &UUID); bool RemoveAttachedFile(std::string &UUID);
bool SetCommandResult(std::string &UUID, std::string &Result); bool SetCommandResult(std::string &UUID, std::string &Result);
bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany, bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany,
@@ -255,33 +205,27 @@ namespace OpenWifi {
void RemovedExpiredCommands(); void RemovedExpiredCommands();
void RemoveTimedOutCommands(); void RemoveTimedOutCommands();
bool RemoveOldCommands(std::string &SerialNumber, std::string &Command); bool RemoveOldCommands(std::string &SerilNumber, std::string &Command);
bool AddBlackListDevices(std::vector<GWObjects::BlackListedDevice> &Devices); bool AddBlackListDevices(std::vector<GWObjects::BlackListedDevice> &Devices);
bool AddBlackListDevice(GWObjects::BlackListedDevice &Device); bool AddBlackListDevice(GWObjects::BlackListedDevice &Device);
bool GetBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device); bool GetBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
bool DeleteBlackListDevice(std::string &SerialNumber); bool DeleteBlackListDevice(std::string &SerialNumber);
bool IsBlackListed(std::uint64_t SerialNumber, std::string &reason, bool IsBlackListed(const std::string &SerialNumber, std::string &reason,
std::string &author, std::uint64_t &created); std::string &author, std::uint64_t &created);
bool IsBlackListed(std::uint64_t SerialNumber); bool IsBlackListed(const std::string &SerialNumber);
bool InitializeBlackListCache(); bool InitializeBlackListCache();
bool GetBlackListDevices(uint64_t Offset, uint64_t HowMany, bool GetBlackListDevices(uint64_t Offset, uint64_t HowMany,
std::vector<GWObjects::BlackListedDevice> &Devices); std::vector<GWObjects::BlackListedDevice> &Devices);
bool UpdateBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device); bool UpdateBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
uint64_t GetBlackListDeviceCount(); uint64_t GetBlackListDeviceCount();
bool DeleteSimulatedDevice(const std::string &SerialNumber);
bool RemoveHealthChecksRecordsOlderThan(uint64_t Date); bool RemoveHealthChecksRecordsOlderThan(uint64_t Date);
bool RemoveDeviceLogsRecordsOlderThan(uint64_t Date); bool RemoveDeviceLogsRecordsOlderThan(uint64_t Date);
bool RemoveStatisticsRecordsOlderThan(uint64_t Date); bool RemoveStatisticsRecordsOlderThan(uint64_t Date);
bool RemoveCommandListRecordsOlderThan(uint64_t Date); bool RemoveCommandListRecordsOlderThan(uint64_t Date);
bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date); bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date);
bool SetDeviceLastRecordedContact(LockedDbSession &Session, std::string & SerialNumber, std::uint64_t lastRecordedContact);
bool SetDeviceLastRecordedContact(std::string & SerialNumber, std::uint64_t lastRecordedContact);
bool SetDeviceLastRecordedContact(Poco::Data::Session & Session, std::string & SerialNumber, std::uint64_t lastRecordedContact);
int Create_Tables(); int Create_Tables();
int Create_Statistics(); int Create_Statistics();
int Create_Devices(); int Create_Devices();
@@ -292,29 +236,17 @@ namespace OpenWifi {
int Create_CommandList(); int Create_CommandList();
int Create_BlackList(); int Create_BlackList();
int Create_FileUploads(); int Create_FileUploads();
int Create_DefaultFirmwares();
bool AnalyzeCommands(Types::CountedMap &R); bool AnalyzeCommands(Types::CountedMap &R);
bool AnalyzeDevices(GWObjects::Dashboard &D); bool AnalyzeDevices(GWObjects::Dashboard &D);
void FixDeviceTypeBug();
int Start() override; int Start() override;
void Stop() override; void Stop() override;
inline Poco::Data::Session StartSession() {
return Pool_->get();
}
private: private:
std::unique_ptr<OpenWifi::ScriptDB> ScriptDB_; std::unique_ptr<OpenWifi::ScriptDB> ScriptDB_;
}; };
inline auto StorageService() { return Storage::instance(); } inline auto StorageService() { return Storage::instance(); }
inline LockedDbSession::LockedDbSession() {
Session_ = std::make_shared<Poco::Data::Session>(Poco::Data::Session(StorageService()->StartSession()));
Mutex_ = std::make_shared<std::mutex>();
}
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -111,6 +111,7 @@ namespace OpenWifi {
} }
} break; } break;
case TelemetryNotification::NotificationType::unregister: { case TelemetryNotification::NotificationType::unregister: {
std::lock_guard G(Mutex_);
auto client = Clients_.find(Notification->Data_); auto client = Clients_.find(Notification->Data_);
if (client != Clients_.end()) { if (client != Clients_.end()) {

View File

@@ -23,7 +23,7 @@
#include "framework/SubSystemServer.h" #include "framework/SubSystemServer.h"
#include "AP_WS_Reactor_Pool.h" #include "AP_WS_ReactorPool.h"
#include "TelemetryClient.h" #include "TelemetryClient.h"
namespace OpenWifi { namespace OpenWifi {

View File

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

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