Compare commits

..

12 Commits

Author SHA1 Message Date
TIP Automation User
4405c01b73 Chg: update image tag in helm values to v2.5.3 2022-09-15 11:37:18 +00:00
Dmitry Dunaev
c1db70d8c4 Merge pull request #196 from Telecominfraproject/feature/wifi-10842--docker-compose--iptocountry-2-5
[WIFI-10842] Add: docker-compose support for iptocountry
2022-09-15 14:29:54 +03:00
Dmitry Dunaev
ef6e4809f5 [WIFI-10842] Add: docker-compose support for iptocountry
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-09-15 14:29:04 +03:00
TIP Automation User
4b190a571f Chg: update image tag in helm values to v2.5.2 2022-07-26 10:29:43 +00:00
Dmitry Dunaev
c6b84434ea [WIFI-1998] Add: gracefull ingress deprecation
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-07-21 17:40:21 +03:00
Dmitry Dunaev
acad0cd99f Merge pull request #96 from Telecominfraproject/fix/wifi-9174--dep-charts-2.5
[WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
2022-06-03 15:52:43 +03:00
Dmitry Dunaev
7f675733df [WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-06-03 15:51:56 +03:00
Johann Hoffmann
4f1d05467f Update image tag in helm values to v2.5.1
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-04-29 19:06:38 +02:00
Johann Hoffmann
27bffaa734 Update image tag in helm values to v2.5.1-RC1
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-04-29 18:10:44 +02:00
stephb9959
b005b57137 Fixing https://telecominfraproject.atlassian.net/browse/WIFI-7812 2022-04-28 14:28:19 -07:00
TIP Automation User
2bae52e67e Chg: update image tag in helm values to v2.5.0 2022-03-30 13:48:16 +00:00
TIP Automation User
7766fe08cd Chg: update image tag in helm values to v2.5.0-RC1 2022-02-11 16:02:37 +00:00
243 changed files with 13814 additions and 67692 deletions

View File

@@ -4,4 +4,4 @@ TabWidth: 4
IndentWidth: 4
UseTab: Always
ColumnLimit: 100
Language: Cpp
Language: Cpp

View File

@@ -13,7 +13,6 @@ on:
pull_request:
branches:
- master
- 'release/*'
defaults:
run:
@@ -27,7 +26,7 @@ jobs:
DOCKER_REGISTRY_USERNAME: ucentral
steps:
- name: Checkout actions repo
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github
@@ -40,16 +39,6 @@ jobs:
registry_user: ucentral
registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
- name: Notify on failure via Slack
if: failure() && github.ref == 'refs/heads/master'
uses: rtCamp/action-slack-notify@v2
env:
SLACK_USERNAME: GitHub Actions failure notifier
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_COLOR: "${{ job.status }}"
SLACK_ICON: https://raw.githubusercontent.com/quintessence/slack-icons/master/images/github-logo-slack-icon.png
SLACK_TITLE: Docker build failed for OWGW service
trigger-testing:
if: startsWith(github.ref, 'refs/pull/')
runs-on: ubuntu-latest
@@ -58,10 +47,10 @@ jobs:
- name: Get base branch name and set as output
id: get_base_branch
run: |
echo "branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/master/main/g')" >> $GITHUB_OUTPUT
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/master/main/g')
- name: Checkout actions repo
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github
@@ -76,26 +65,4 @@ jobs:
workflow: ow_docker-compose.yml
token: ${{ secrets.WLAN_TESTING_PAT }}
ref: master
inputs: '{"deployment_version": "${{ env.BASE_BRANCH }}", "owgw_version": "${{ github.sha }}", "owsec_version": "${{ env.BASE_BRANCH }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "${{ env.BASE_BRANCH }}", "owanalytics_version": "${{ env.BASE_BRANCH }}", "owsub_version": "${{ env.BASE_BRANCH }}", "microservice": "owgw"}'
trigger-deploy-to-dev:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
needs:
- docker
steps:
- name: Checkout actions repo
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github
- name: Trigger deployment of the latest version to dev instance and wait for result
uses: ./github/composite-actions/trigger-workflow-and-wait
with:
owner: Telecominfraproject
repo: wlan-testing
workflow: ucentralgw-dev-deployment.yaml
token: ${{ secrets.WLAN_TESTING_PAT }}
ref: master
inputs: '{"force_latest": "true"}'
inputs: '{"owgw_version": "${{ github.sha }}", "owgwui_version": "${{ env.BASE_BRANCH }}", "owsec_version": "${{ env.BASE_BRANCH }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "main", "owprovui_version": "main"}'

View File

@@ -17,10 +17,4 @@ jobs:
- name: Cleanup Docker image with PR branch tag
run: |
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then
echo "PR branch is $PR_BRANCH_TAG, deleting Docker image"
curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"
else
echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image"
fi
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout actions repo
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github

View File

@@ -1,40 +0,0 @@
name: Update OpenAPI docs on GitHub Pages
on:
push:
paths:
- 'openapi/**'
branches:
- master
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
docsgen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Generate static HTML page with docs from OpenAPI definition
run: |
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralgw/master/openapi/owgw.yaml -g html2 --skip-validate-spec -o /local/
- name: Update OpenAPI docs
run: |
mkdir tmp-docs
mv index.html tmp-docs/index.html
mkdir -p ~/.ssh
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
git config --global credential.helper store
git config --global user.email "tip-automation@telecominfraproject.com"
git config --global user.name "TIP Automation User"
git pull
git checkout gh-pages || git checkout -b gh-pages
mv tmp-docs docs
git add docs
git commit -m'Update OpenAPI docs for GitHub pages'
git push --set-upstream origin gh-pages

View File

@@ -1,46 +0,0 @@
name: Release chart package
on:
push:
tags:
- 'v*'
defaults:
run:
shell: bash
jobs:
helm-package:
runs-on: ubuntu-20.04
env:
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
HELM_REPO_USERNAME: ucentral
steps:
- name: Checkout uCentral assembly chart repo
uses: actions/checkout@v3
with:
path: wlan-cloud-ucentralgw
- name: Build package
working-directory: wlan-cloud-ucentralgw/helm
run: |
helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm dependency update
mkdir dist
helm package . -d dist
- name: Generate GitHub release body
working-directory: wlan-cloud-ucentralgw/helm
run: |
pip3 install yq -q
echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owgw:$GITHUB_REF_NAME" > release.txt
echo "Helm charted may be attached to this release" >> release.txt
echo "Deployment artifacts may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/$GITHUB_REF_NAME" >> release.txt
- name: Create GitHub release
uses: softprops/action-gh-release@v1
with:
body_path: wlan-cloud-ucentralgw/helm/release.txt
files: wlan-cloud-ucentralgw/helm/dist/*

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 2.8.0)
project(owgw VERSION 2.5.0)
set(CMAKE_CXX_STANDARD 17)
@@ -30,30 +30,26 @@ else()
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
endif()
if(ASAN)
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
add_compile_options(-fsanitize=undefined)
add_link_options(-fsanitize=undefined)
endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULT
OUTPUT_VARIABLE GIT_HASH)
if(NOT GIT_RESULT EQUAL "0")
message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
endif()
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
add_definitions(-DTIP_GATEWAY_SERVICE="1")
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost REQUIRED system)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(fmt REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(nlohmann_json_schema_validator REQUIRED)
@@ -70,8 +66,6 @@ include_directories(/usr/local/include /usr/local/opt/openssl/include src inclu
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
add_compile_options(-Wall -Wextra)
add_executable( owgw
build
src/ow_version.h.in
@@ -80,55 +74,14 @@ add_executable( owgw
src/framework/MicroService.h
src/framework/OpenWifiTypes.h
src/framework/orm.h
src/framework/RESTAPI_errors.h
src/framework/RESTAPI_protocol.h
src/framework/StorageClass.h
src/framework/MicroServiceErrorHandler.h
src/framework/UI_WebSocketClientServer.cpp
src/framework/UI_WebSocketClientServer.h
src/framework/UI_WebSocketClientNotifications.cpp
src/framework/UI_WebSocketClientNotifications.h
src/framework/utils.h
src/framework/utils.cpp
src/framework/AppServiceRegistry.h
src/framework/SubSystemServer.cpp
src/framework/SubSystemServer.h
src/framework/RESTAPI_utils.h
src/framework/AuthClient.cpp
src/framework/AuthClient.h
src/framework/MicroServiceNames.h
src/framework/MicroServiceFuncs.h
src/framework/OpenAPIRequests.cpp
src/framework/OpenAPIRequests.h
src/framework/MicroServiceFuncs.cpp
src/framework/ALBserver.cpp
src/framework/ALBserver.h
src/framework/KafkaManager.cpp
src/framework/KafkaManager.h
src/framework/RESTAPI_RateLimiter.h
src/framework/WebSocketLogger.h
src/framework/RESTAPI_GenericServerAccounting.h
src/framework/CIDR.h
src/framework/RESTAPI_Handler.cpp
src/framework/RESTAPI_Handler.h
src/framework/RESTAPI_ExtServer.h
src/framework/RESTAPI_ExtServer.cpp
src/framework/RESTAPI_IntServer.cpp
src/framework/RESTAPI_IntServer.h
src/framework/RESTAPI_SystemCommand.h
src/framework/RESTAPI_WebSocketServer.h
src/framework/RESTAPI_SystemConfiguration.h
src/framework/EventBusManager.cpp
src/framework/EventBusManager.h
src/framework/RESTAPI_PartHandler.h
src/framework/MicroService.cpp
src/framework/MicroServiceExtra.h
src/framework/uCentral_Protocol.h
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
src/RESTAPI/RESTAPI_devices_handler.cpp src/RESTAPI/RESTAPI_devices_handler.h
src/RESTAPI/RESTAPI_device_handler.cpp src/RESTAPI/RESTAPI_device_handler.h
src/RESTAPI/RESTAPI_device_commandHandler.cpp src/RESTAPI/RESTAPI_device_commandHandler.h
@@ -144,14 +97,16 @@ add_executable( owgw
src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h
src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
src/RESTAPI/RESTAPI_telemetryWebSocket.cpp src/RESTAPI/RESTAPI_telemetryWebSocket.h
src/RESTAPI/RESTAPI_webSocketServer.cpp src/RESTAPI/RESTAPI_webSocketServer.h
src/storage/storage_blacklist.cpp src/storage/storage_tables.cpp src/storage/storage_logs.cpp
src/storage/storage_command.cpp src/storage/storage_healthcheck.cpp src/storage/storage_statistics.cpp
src/storage/storage_device.cpp src/storage/storage_capabilities.cpp src/storage/storage_defconfig.cpp
src/storage/storage_tables.cpp
src/RESTAPI/RESTAPI_routers.cpp
src/Daemon.cpp src/Daemon.h
src/AP_WS_Server.cpp src/AP_WS_Server.h
src/WS_Server.cpp src/WS_Server.h
src/StorageService.cpp src/StorageService.h
src/DeviceRegistry.cpp src/DeviceRegistry.h
src/CommandManager.cpp src/CommandManager.h
src/CentralConfig.cpp src/CentralConfig.h
src/FileUploader.cpp src/FileUploader.h
@@ -162,44 +117,7 @@ add_executable( owgw
src/TelemetryStream.cpp src/TelemetryStream.h
src/framework/ConfigurationValidator.cpp src/framework/ConfigurationValidator.h
src/ConfigurationCache.h
src/CapabilitiesCache.h src/FindCountry.h
src/rttys/RTTYS_server.cpp
src/rttys/RTTYS_server.h
src/rttys/RTTYS_device.cpp
src/rttys/RTTYS_device.h
src/rttys/RTTYS_ClientConnection.cpp
src/rttys/RTTYS_ClientConnection.h
src/rttys/RTTYS_WebServer.cpp
src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h
src/SDKcalls.cpp
src/SDKcalls.h
src/StateUtils.cpp src/StateUtils.h
src/AP_WS_ReactorPool.h
src/AP_WS_Connection.h
src/AP_WS_Connection.cpp
src/TelemetryClient.h src/TelemetryClient.cpp
src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h
src/framework/ow_constants.h
src/GwWebSocketClient.cpp src/GwWebSocketClient.h
src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h
src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h
src/ParseWifiScan.h
src/RADIUS_helpers.h
src/VenueBroadcaster.h
src/sdks/sdk_prov.h
src/AP_WS_Process_connect.cpp
src/AP_WS_Process_state.cpp
src/AP_WS_Process_healthcheck.cpp
src/AP_WS_Process_log.cpp
src/AP_WS_Process_crashlog.cpp
src/AP_WS_Process_ping.cpp
src/AP_WS_Process_cfgpending.cpp
src/AP_WS_Process_recovery.cpp
src/AP_WS_Process_deviceupdate.cpp
src/AP_WS_Process_telemetry.cpp
src/AP_WS_Process_venuebroadcast.cpp
src/RADSEC_server.h
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h src/framework/RESTAPI_SystemConfiguration.h src/AP_restrictions.h)
src/CapabilitiesCache.h src/FindCountry.h src/rttys/RTTYS_server.cpp src/rttys/RTTYS_server.h src/rttys/RTTYS_device.cpp src/rttys/RTTYS_device.h src/rttys/RTTYS_ClientConnection.cpp src/rttys/RTTYS_ClientConnection.h src/rttys/RTTYS_WebServer.cpp src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h src/SDKcalls.cpp src/SDKcalls.h src/StateUtils.cpp src/StateUtils.h src/WS_ReactorPool.h src/WS_Connection.h src/WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h)
if(NOT SMALL_BUILD)
@@ -210,17 +128,14 @@ INSTALL(TARGETS owgw
)
target_link_libraries(owgw PUBLIC
${Poco_LIBRARIES}
${ZLIB_LIBRARIES})
${Poco_LIBRARIES} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES})
if(NOT SMALL_BUILD)
target_link_libraries(owgw PUBLIC
${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
CppKafka::cppkafka
nlohmann_json_schema_validator
fmt::fmt
)
if(UNIX AND NOT APPLE)
target_link_libraries(owgw PUBLIC PocoJSON)
endif()
endif()
endif()

View File

@@ -1,22 +1,15 @@
ARG DEBIAN_VERSION=11.5-slim
ARG POCO_VERSION=poco-tip-v1
ARG CPPKAFKA_VERSION=tip-v1
ARG JSON_VALIDATOR_VERSION=2.1.0
FROM alpine:3.15 AS build-base
FROM debian:$DEBIAN_VERSION AS build-base
RUN apt-get update && apt-get install --no-install-recommends -y \
RUN apk add --update --no-cache \
make cmake g++ git \
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
librdkafka-dev libboost-all-dev libssl-dev \
zlib1g-dev nlohmann-json3-dev ca-certificates libfmt-dev
unixodbc-dev postgresql-dev mariadb-dev \
librdkafka-dev boost-dev openssl-dev \
zlib-dev nlohmann-json
FROM build-base AS poco-build
ARG POCO_VERSION
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/poco /poco
WORKDIR /poco
RUN mkdir cmake-build
@@ -27,10 +20,8 @@ RUN cmake --build . --target install
FROM build-base AS cppkafka-build
ARG CPPKAFKA_VERSION
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
WORKDIR /cppkafka
RUN mkdir cmake-build
@@ -41,10 +32,8 @@ RUN cmake --build . --target install
FROM build-base AS json-schema-validator-build
ARG JSON_VALIDATOR_VERSION
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
WORKDIR /json-schema-validator
RUN mkdir cmake-build
@@ -73,21 +62,21 @@ WORKDIR /owgw/cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
FROM debian:$DEBIAN_VERSION
FROM alpine:3.15
ENV OWGW_USER=owgw \
OWGW_ROOT=/owgw-data \
OWGW_CONFIG=/owgw-data
RUN useradd "$OWGW_USER"
RUN addgroup -S "$OWGW_USER" && \
adduser -S -G "$OWGW_USER" "$OWGW_USER"
RUN mkdir /openwifi
RUN mkdir -p "$OWGW_ROOT" "$OWGW_CONFIG" && \
chown "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
RUN apt-get update && apt-get install --no-install-recommends -y \
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
libmariadb-dev-compat libpq5 unixodbc postgresql-client libfmt7 sqlite3
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
mariadb-connector-c libpq unixodbc postgresql-client
COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
@@ -95,15 +84,12 @@ COPY test_scripts/curl/cli /cli
COPY owgw.properties.tmpl /
COPY docker-entrypoint.sh /
COPY wait-for-postgres.sh /
COPY rtty_ui /dist/rtty_ui
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
COPY --from=owgw-build /owgw/cmake-build/owgw /openwifi/owgw
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib /usr/local/lib/
COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib/
RUN ldconfig
COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib
EXPOSE 15002 16002 16003 17002 16102

View File

@@ -1,194 +0,0 @@
# Micro-service backbone responsibilities
## Bus management
Each microservice must get onto kafka and consume/produce messages on the kafka bus. The topic to subscribe to is `service_events`.
## System messages
System messages are what maintains the collection of micro-services working on the system. Each message has the format
```json
{
"event": <event-type>,
"id": 1234567890,
"type": "owrrm",
"publicEndPoint": "https://myhostname.com:16020",
"privateEndPoint": "https://localhost:17020",
"key" : "289479847948794870749",
"version" : "1.0"
}
```
### Responsibilities
Each micro service is responsible to generate its own messages and keep track of messages coming from other
micro services. This is necessary so that any micro service may reach our any other micro service. This provides
discovery for any micro service. All current micro services provided in OpenWiFi perform these functions. If you leverage
the C++ framework, this functionality if performed automatically.
### `event-type`
Each micro service is responsible to generate and consume these events
#### `join` event
When a service start and joins the bus, it should generate an event-type of `join`.
### `leave` event
When a service shuts down, it should generate a `leave` event-type.
### `keep-alive` event
Every 30 seconds, a service should generate a `keep-alive` message.
### `id`
You should generate a random number from some unique factor for the system. This ID is used to identify different services. You should reuse that ID
when you restart.
## The `type`
The `type` in the system message is oen of the following:
```c++
static const std::string uSERVICE_SECURITY{"owsec"};
static const std::string uSERVICE_GATEWAY{"owgw"};
static const std::string uSERVICE_FIRMWARE{ "owfms"};
static const std::string uSERVICE_TOPOLOGY{ "owtopo"};
static const std::string uSERVICE_PROVISIONING{ "owprov"};
static const std::string uSERVICE_OWLS{ "owls"};
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
static const std::string uSERVICE_INSTALLER{ "owinst"};
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
static const std::string uSERVICE_OWRRM{ "owrrm"};
```
The `type` is what you should use to find the `privateEndPoint` you are looking to communicate with.
### Example
Assume you want to communicate with the gateway to configure a device.
```text
1. Look into my list of current Micro-services for the type=owgw.
2. Use the privateEndPoint associated with that entry
```
## REST API calls on the private interface
For inter-service REST calls, you should never use the `Authorization: Bearer token` method. Instead, the following headers should be included in all API calls
```json
{
"X-API-KEY" : "289479847948794870749",
"X-INTERNAL-NAME" : "https://myhostname.com:16020"
}
```
### `X-API-KEY`
This is the `key` you included in your `system-messages`.
### `X-INTERNAL-NAME`
This is the `publicEndPoint` you included in your `system-messages`.
This method can _only_ be used to any another `privateEndPoint` in the system. You can use the exact same EndPoints provided in the OpenAPI files for any of the services.
## OpenAPI Integration
To appear in the UI consoles, a microservice should be able to handle a get to the `/api/v1/system` endpoint on its `publicEndPoint` interface.
Here is a brief description of what the microservice should answer:
```yaml
/system:
get:
tags:
- System Commands
summary: Retrieve different values from the running service.
operationId: getSystemCommand
parameters:
- in: query
description: Get a value
name: command
schema:
type: string
enum:
- info
required: true
responses:
200:
description: Successful command execution
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/SystemInfoResults'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
```
The relevant data structures are:
```yaml
SystemInfoResults:
type: object
properties:
version:
type: string
uptime:
type: integer
format: integer64
start:
type: integer
format: integer64
os:
type: string
processors:
type: integer
hostname:
type: string
certificates:
type: array
items:
type: object
properties:
filename:
type: string
expires:
type: integer
format: int64
```
and
```yaml
responses:
NotFound:
description: The specified resource was not found.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: string
Unauthorized:
description: The requested does not have sufficient rights to perform the operation.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
enum:
- 0 # Success
- 1 # PASSWORD_CHANGE_REQUIRED,
- 2 # INVALID_CREDENTIALS,
- 3 # PASSWORD_ALREADY_USED,
- 4 # USERNAME_PENDING_VERIFICATION,
- 5 # PASSWORD_INVALID,
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
- 9 # EXPIRED_TOKEN
- 10 # RATE_LIMIT_EXCEEDED
- 11 # BAD_MFA_TRANSACTION
- 12 # MFA_FAILURE
- 13 # SECURITY_SERVICE_UNREACHABLE
ErrorDetails:
type: string
ErrorDescription:
type: string
```

View File

@@ -5,11 +5,6 @@ This document will describe how the API is built and how to use it.
This uses OpenAPI definition 3.0 and can be found [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/openapi/ucentral/owgw.yaml).
All endpoints begin with `/api/v1`.
## OpenAPI docs
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralgw).
Also you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralgw/master/openapi/owgw.yaml)) to get interactive docs page.
## The flow
In order to use any of the API calls, you must obtain a token (I know - shocking). You do so by calling the end-point
`/oauth2`. Once you obtain that `access-token`, you will need to pass it in the headers under `Authorization: Bearer <place your token here>`.

View File

@@ -30,7 +30,7 @@ In this RPC, here are some common interpretations:
#### Connection event
Device Sends connection notification to the controller after establishing a connection. The controller
my decide to send the AP a newer configuration. The controller will record the device capabilities provided.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "connect" ,
"params" : {
@@ -47,7 +47,7 @@ my decide to send the AP a newer configuration. The controller will record the d
#### State event
The device sends device state information periodically. If the controller detects that it has a newer configuration, it
may decide to send this new configuration to the AP.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "state" ,
"params" : {
@@ -62,7 +62,7 @@ may decide to send this new configuration to the AP.
#### Healthcheck event
Device sends a `healthcheck` periodically. This message contains information about how vital subsystems are operating and
if they need attention.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "healthcheck" ,
"params" : {
@@ -77,7 +77,7 @@ if they need attention.
#### Log event
Device sends a log message whenever necessary. The controller will log this message to the log system for the device.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "log" ,
"params" : {
@@ -102,7 +102,7 @@ The `severity` matches the `syslog` levels. Here are the details:
#### Crash Log event
Device may send a crash log event after rebooting after a crash. The event cannot be sent until a connection event has been sent.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "crashlog" ,
"params" : {
@@ -117,7 +117,7 @@ Device may send a crash log event after rebooting after a crash. The event canno
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
reply to this message.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "cfgpending" ,
"params" : {
@@ -131,7 +131,7 @@ reply to this message.
#### DeviceUpdate event
Device sends this message to tell the controller it is changing something is its configuration because
of some requirement or some changes.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "deviceupdate" ,
"params" : {
@@ -145,7 +145,7 @@ of some requirement or some changes.
#### Send a keepalive to the controller event
Device sends a keepalive whenever necessary. The device will send this message to tell the controller
which version it is running. The Controller may decide to send the device a newer configuration.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "ping" ,
"params" : {
@@ -157,7 +157,7 @@ which version it is running. The Controller may decide to send the device a newe
#### Recovery Event
Device may decide it has to do into recovery mode. This event should be used.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "recovery" ,
"params" : {
@@ -170,34 +170,6 @@ Device may decide it has to do into recovery mode. This event should be used.
}
```
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>
}
},
"id" : <same number>
}
```
#### Device requests a venue broadcast message
Device send this message when it wants to reach out to all other APs in the same venue. The GW will find the
venue where this device belongs and resend the same message to all other devices in the venue.
```json
{ "jsonrpc" : "2.0" ,
"method" : "venue_broadcast" ,
"params" : {
"serial" : <serial number> ,
"timestamp" : <the UTC timestamp when the message was sent>,
"data" : <an opaque string from the AP. This could be Zipped and so on and most likely base64 encoded>
}
}
```
Upon receiving a `venue_broadcast` message, the GW will simply resent the message to all the APs in the venue.
### Controller commands
Most controller commands include a `when` member. This is a UTC clock time asking the AP
@@ -208,7 +180,7 @@ always a numeric parameter.
#### Controller wants the device to apply a given configuration
Controller sends this command when it believes the device should load a new configuration. The device
should send message with `pending change` events until this version has been applied and running.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "configure" ,
"params" : {
@@ -222,7 +194,7 @@ should send message with `pending change` events until this version has been app
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -261,7 +233,7 @@ The rejected section is an array containing the following:
#### Controller wants the device to reboot
Controller sends this command when it believes the device should reboot.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "reboot" ,
"params" : {
@@ -273,7 +245,7 @@ Controller sends this command when it believes the device should reboot.
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -292,21 +264,20 @@ The device should answer:
#### Controller wants the device to upgrade its firmware
Controller sends this command when it believes the device should upgrade its firmware.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "upgrade" ,
"params" : {
"serial" : <serial number> ,
"when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
"uri" : <URI to download the firmware>,
"FWsignature" : <string representation of the signature for the FW> (optional)
"uri" : <URI to download the firmware>
},
"id" : <some number>
}
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -319,17 +290,10 @@ The device should answer:
"id" : <same number>
}
```
Here are the error values
```text
0: No error
1: Bad firmware
2: Missing signature
```
#### Controller wants the device to perform a factory reset
Controller sends this command when it believes the device should upgrade its firmware.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "factory" ,
"params" : {
@@ -342,7 +306,7 @@ Controller sends this command when it believes the device should upgrade its fir
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -356,50 +320,9 @@ The device should answer:
}
```
#### Controller issuing RRM commands to the AP
Controller sends this command to perform several RRM commands.
```json
{ "jsonrpc" : "2.0" ,
"method" : "rrm" ,
"params" : {
"serial" : <serial number> ,
"actions": [
{
"type": "roam",
"bss": [ "00:11:22:33:44:55", ... ],
"params" : { action specific data }
}, {
"type": "tx-power",
"bss": [ "00:11:22:33:44:55", ... ],
params: { action specific data }
}, {
"type": "beacon-request",
"bss": [ "00:11:22:33:44:55", ... ],
"params": { action specific data }
}
]
},
"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>,
}
},
"id" : <same number>
}
```
#### Controller wants the device to flash its LEDs
Controller sends this command when it wants the device to flash its LEDs.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "leds" ,
"params" : {
@@ -413,13 +336,14 @@ Controller sends this command when it wants the device to flash its LEDs.
```
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>,
"when" : <time when this will be performed as UTC seconds>,
}
},
"id" : <same number>
@@ -431,9 +355,47 @@ The device should answer:
- 1 : device cannot flash LEDs because it does not have any.
- 2 : device rejects the request. `text` should include information as to why.
#### Controller sends a device specific command
Controller sends this command specific to this device. The command is proprietary and must be agreed upon by the device
and the controller.
```
{ "jsonrpc" : "2.0" ,
"method" : "perform" ,
"params" : {
"serial" : <serial number> ,
"when" : Optional - <UTC time when to perform this command, 0 mean immediate, this is a suggestion>,
"command" : <this is device specific and is TEXT only>,
"payload" : <JSON Document: containing additional information about the command>
},
"id" : <some number>
}
```
The device should answer:
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : 0 or an error number,
"text" : <description of the error or success>,
"when" : <in UTC time in seconds>,
"resultCode" : <0 or an appropriate error code>,
"resultText" : <any text resulting from the command. This is propietary to each command>
}
},
"id" : <same number>
}
```
##### The device answer
The device should answer with teh above message. The `error` value should be interpreted the following way:
- 0 : the command was performed as requested and the reults of the command is available in the `resultCode` and `resultText` parameters.
- 1 : the command will be performed in the future and `when` shows that time. The `resultCode` and `resultText` dod not contain anything relevant.
- 2 : the command cannot be performed as indicated. `resultCode` and `resultText` may contain some indication as to why.
#### Controller wants the device to perform a trace
Controller sends this command when it needs the device to perform a trace (i.e. tcpdump).
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "trace" ,
"params" : {
@@ -450,7 +412,7 @@ Controller sends this command when it needs the device to perform a trace (i.e.
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -476,7 +438,7 @@ uploaded or the timeout occurs, the upload will be rejected.
#### Controller wants the device to perform a WiFi Scan
Controller sends this command when it needs the device to perform a WiFi Scan.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "wifiscan" ,
"params" : {
@@ -484,16 +446,14 @@ Controller sends this command when it needs the device to perform a WiFi Scan.
"bands" : [ "2","5","5l","5u",6" ], <optional this is a list of bands to scan: on or more bands >
"channels" : [ 1,2,3...] , <optional list of discreet channels to scan >
"verbose" : <optional boolean: true or false> (by default false),
"bandwidth" : <optional int: 20,40,80 in MHz>,
"active" : 0 or 1 (to select passive or active scan),
"ies": <optional: array of unsigned int 8 bits: i.e. [1,4,34,58,91]>
"active" : 0 or 1 (to select passive or active scan)
},
"id" : <some number>
}
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -516,7 +476,7 @@ Controller sends this command when it needs the device to provide a message back
supported messages are "state" and "healthcheck". More messages maybe added later. The messages will
be returned the usual way. The RPC response to this message just says that the request has been accepted and the
message will be returned "soon".
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "request" ,
"params" : {
@@ -530,7 +490,7 @@ message will be returned "soon".
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -546,7 +506,7 @@ The device should answer:
#### Controller requesting eventqueue buffers
Controller sends this command when it needs the device to provide the content of ist ring buffers.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "event" ,
"params" : {
@@ -560,7 +520,7 @@ Controller sends this command when it needs the device to provide the content of
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -576,7 +536,7 @@ The device should answer:
#### Controller requesting telemetry stream information
Controller sends this command when it needs the device to telemetry streaming.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "telemetry" ,
"params" : {
@@ -589,7 +549,7 @@ Controller sends this command when it needs the device to telemetry streaming.
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -603,7 +563,7 @@ The device should answer:
```
When the interval is greater than 0, the gateway will start to receive messages
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "telemetry" ,
"params" : {
@@ -618,7 +578,7 @@ The device will stop sending data after 30 minutes or if it receives a `telemetr
#### Controller requesting an `rtty` session
Controller sends this command an administrator requests to start an `rtty` session with the AP.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "remote_access" ,
"params" : {
@@ -636,7 +596,7 @@ Controller sends this command an administrator requests to start an `rtty` sessi
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -652,7 +612,7 @@ The device should answer:
#### Controller wants to ping the device
Controller sends this command when it tries to establish latency to the device.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "ping" ,
"params" : {
@@ -663,7 +623,7 @@ Controller sends this command when it tries to establish latency to the device.
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -674,43 +634,8 @@ The device should answer:
}
```
#### Controller wants the device to perform a script
Controller sends this command to run a predefined script. Extreme care must be taken.
```json
{ "jsonrpc" : "2.0" ,
"method" : "script" ,
"params" : {
"serial" : <serial number>,
"type" : <one of "shell", "ucode", "bundle">,
"script" : <text blob containing the script, This must be vase64 encoded>,
"timeout" : <max timeout in seconds, default is 30, unused if URI is supplied>,
"uri": "<upload script results using this URI>",
"signature" : "<signature for script>: must be supplied to restricted devices",
"when" : <time when this will be performed as UTC seconds>
},
"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>,
one of either
"result_64" : <gzipped base64 result of running the command>,
"result_sz" : <size of unzipped content>
or
"result" : <a single text blob of the result>
}
},
"id" : <same number>
}
```
### `rtty server`
#### `rtty server`
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.
### Message compression
@@ -721,48 +646,21 @@ Should other messages get larger, the client may decide to compress the. Only me
#### Identifying a compressed message
A compressed message has a single member to the `params` field. It's only parameter must be called `compress_64`. Any other elements under
params will be dropped. Additional compression schemes may be developed later. The device should also include
a hint to the actual size of the uncompressed data. This would allow listeners to create sufficiently sized
buffers right away instead of guessing. If the device includes `compressed_sz` as the second field in the
params objects. This should be an unsigned int representing the total size of the uncompressed data.
params will be dropped. Additional compression schemes may be developed later.
#### How to compress
The original `params` element should be run through `zlib:compress` and then encoded using base64, and passed as a string. Here is an example
of the completed message. The following should how the `state` event could be compressed:
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "state" ,
"params" : {
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk",
"compress_sz" : 212322
"compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk"
}
}
```
### 'Radius Proxying'
The gateway can receive RADIUS messages from the device and forward them. It can also receive messages
on its behalf and send them to the device.
```json
{
"radius" : <type, can be auth, acct, coa> ,
"data" : <base 64 encoded raw RADIUS payload>
}
```
The GW will include a TLV to mark the sender MAC. The RADIUS server must use the same TLV to
identify the destination for its messages.
#### Incoming RADIUS messages configuration
The GW must be configured with the following:
```asm
radius.proxy.enable = true
radius.proxy.accounting.port = 1813
radius.proxy.authentication.port = 1812
radius.proxy.coa.port = 3799
```

134
README.md
View File

@@ -11,16 +11,16 @@ In order to build the uCentralGW, you will need to install its dependencies, whi
- boost
- POCO 1.10.1 or later
- a C++17 compiler
- libyaml
- openssl
- libpq-dev (PortgreSQL development libraries)
- mysql-client (MySQL client)
- librdkafka
- cppkafka
-
The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/AriliaWireless/poco). Building
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/stephb9959/poco). Building
Poco may take several minutes depending on the platform you are building on.
### Ubuntu
@@ -29,10 +29,9 @@ These instructions have proven to work on Ubuntu 20.4.
sudo apt install git cmake g++ libssl-dev libmariadb-dev
sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
sudo apt install librdkafka-dev // default-libmysqlclient-dev
sudo apt install nlohmann-json-dev
cd ~
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
git clone https://github.com/stephb9959/poco
cd poco
mkdir cmake-build
cd cmake-build
@@ -41,7 +40,7 @@ cmake --build . --config Release
sudo cmake --build . --target install
cd ~
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
git clone https://github.com/stephb9959/cppkafka
cd cppkafka
mkdir cmake-build
cd cmake-build
@@ -50,21 +49,22 @@ cmake --build . --config Release
sudo cmake --build . --target install
cd ~
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
cd json-schema-validator
git clone https://github.com/nlohmann/json.git
cd json
mkdir cmake-build
cd cmake-build
cmake ..
make -j
sudo make install
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
cd fmtlib
cd ~
git clone https://github.com/pboettch/json-schema-validator.git
cd json-schema-validator
mkdir cmake-build
cd cmake-build
cmake ..
make
make install
make -j
sudo make install
cd ~
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
@@ -80,12 +80,12 @@ make -j 8
### Fedora
The following instructions have proven to work on Fedora 33
```
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
sudo yum install cmake g++ openssl-devel unixODBC-devel mysql-devel mysql apr-util-devel boost boost-devel
sudo yum install yaml-cpp-devel lua-devel
sudo dnf install postgresql.x86_64 librdkafka-devel
sudo dnf install postgresql-devel json-devel
sudo dnf install postgresql-devel
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
git clone https://github.com/stephb9959/poco
cd poco
mkdir cmake-build
cd cmake-build
@@ -93,7 +93,7 @@ cmake ..
cmake --build . --config Release
sudo cmake --build . --target install
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
git clone https://github.com/stephb9959/cppkafka
cd cppkafka
mkdir cmake-build
cd cmake-build
@@ -101,15 +101,6 @@ cmake ..
cmake --build . --config Release
sudo cmake --build . --target install
cd ~
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
cd json-schema-validator
mkdir cmake-build
cd cmake-build
cmake ..
make -j
sudo make install
cd ~
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
cd wlan-cloud-ucentralgw
@@ -119,61 +110,45 @@ cmake ..
make
```
### macOS Build
The following instructions have proven to work on macOS Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
### OSX Build
The following instructions have proven to work on OSX Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
```
brew install openssl \
cmake \
libpq \
mysql-client \
apr \
apr-util \
boost \
yaml-cpp \
postgresql \
librdkafka \
nlohmann-json \
fmt
brew install openssl
brew install cmake
brew install libpq
brew install mysql-client
brew install apr
brew install apr-util
brew install boost
brew install yaml-cpp
brew install postgresql
brew install unixodbc
brew install librdkafka
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
pushd poco
mkdir cmake-build
push cmake-build
cmake -DOPENSSL_ROOT_DIR=</path/to/openssl> -DENABLE_NETSSL=1 -DENABLE_JWT=1 -DENABLE_CRYPTO=1 ..
cmake --build . --config Release
git clone https://github.com/stephb9959/poco
cd poco
mkdir cmake-build
cd cmake-build
cmake ..
cmake --build . --config Release -j
sudo cmake --build . --target install
popd
popd
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
pushd cppkafka
git clone https://github.com/stephb9959/cppkafka
cd cppkafka
mkdir cmake-build
pushd cmake-build
cd cmake-build
cmake ..
cmake --build . --config Release
sudo cmake --build . --target install
popd
popd
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
pushd json-schema-validator
mkdir cmake-build
pushd cmake-build
cmake ..
make -j
sudo make install
popd
popd
cd ~
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
pushd wlan-cloud-ucentralgw
cd wlan-cloud-ucentralgw
mkdir cmake-build
pushd cmake-build
cd cmake-build
cmake ..
make -j
popd
popd
```
### Raspberry
@@ -273,7 +248,7 @@ little changes if you keep the suggested directory structure. For the sample con
environment variables.
```
export OWGW_ROOT=`pwd`
export OWGW_CONFIG=`pwd`
export UCENTRALGW_CONFIG=`pwd`
```
If you current working directory is the root of the project, this will set the variables properly. Otherwise, you can set the variables
to point to wherever is necessary.
@@ -585,31 +560,6 @@ Toe read more about Kafka, follow the [document](https://github.com/Telecominfra
#### Securing `kafka`
This is beyond the scope of this document. As it stands today, the communication between the gateway and `kafka` is expected to be behind a firewall.
#### `iptocountry` feature
In the UI, you will notice the presence of small flags showing where the device connections are from. This feature is
available through the `iptocountry` settings in the configuration. This feature is then also available through the `OpenAPI` for the CLI
and other applications.
##### Config file entries
In the configuration file, you must include the following lines:
```asm
iptocountry.default = US
iptocountry.provider = ipinfo
#iptocountry.provider = ipdata
#iptocountry.provider = ipdata
iptocountry.ipinfo.token =
#ip2location.ipinfo.token =
#iptocountry.ipdata.apikey =
#iptocountry.ip2location.apikey =
```
So you select your provider with the `iptocountry.provider` be specifying ipinfo, or ipdata, or ip2location.
And then you provide the corresponding api key or token.
Only select one. If you select 2, undefined behaviour. All the line you do not need, just put a `#` before to comment it
out.
You will find the supported providers at: `ip2location.com`, `ipinfo.io`, or `ipdata.co`. You MUST supply a valid default
country code in `iptocountry.default`.
## Contributors
We love ya! We need more of ya! If you want to contribute, make sure you review
the [coding style](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CODING_STYLE.md) document.

View File

@@ -1,36 +0,0 @@
scripts:
- name: List Antennas
description: A script to list all antennas on a device
type: shell
runtype:
timeout: 30
filename: listantennas.sh
readme: listantennas.md
help: https://authors.com/scripts/index.html
- name: List AP Noise
description: A script to list all noise values on all APs
type: shell
runtype:
deferred: true
filename: listnoise.sh
readme: listnoise.md
help: https://authors.com/scripts/index.html
- name: Reset AP Statistics
description: A script to reset the statistics on a given AP
type: shell
runtype:
timeout: 30
filename: resetstats.sh
readme: resetstats.md
help: https://authors.com/scripts/index.html
- name: Gather kernel stats
description: A script to all the kernel stats for an AP
type: bundle
runtype:
deferred: true
filename: kstats.uci
readme: kstats.md
help: https://authors.com/scripts/index.html

View File

@@ -1 +0,0 @@
#!/bin/sh

View File

@@ -1,2 +0,0 @@
#!/bin/sh

View File

@@ -1,2 +0,0 @@
#!/bin/sh

View File

@@ -1 +0,0 @@
# Repo for scripts

2
build
View File

@@ -1 +1 @@
44
171

View File

@@ -0,0 +1,4 @@
#include <librdkafka/rdkafka.h>
#if RD_KAFKA_VERSION >= 0x00090400
int main() { }
#endif

BIN
cmake-build-debug/ucentralgw Executable file

Binary file not shown.

View File

@@ -0,0 +1,637 @@
<?xml version="1.0" encoding="UTF-8"?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6"/>
<Project>
<Option title="ucentralgw"/>
<Option makefile_is_custom="1"/>
<Option compiler="gcc"/>
<Option virtualFolders="CMake Files\;CMake Files\..\;CMake Files\..\..\;CMake Files\..\..\..\;CMake Files\..\..\..\..\;CMake Files\..\..\..\..\..\;CMake Files\..\..\..\..\..\..\;CMake Files\..\..\..\..\..\..\usr\;CMake Files\..\..\..\..\..\..\usr\local\;CMake Files\..\..\..\..\..\..\usr\local\lib\;CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\;CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Boost-1.75.0\;CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_headers-1.75.0\;CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_system-1.75.0\;CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\CppKafka\;CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\;CMake Files\cmake\;CMake Files\cmake-build-debug\;"/>
<Build>
<Target title="all">
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option type="4"/>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 all"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="install/local">
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option type="4"/>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 install/local"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="rebuild_cache">
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option type="4"/>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 rebuild_cache"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="edit_cache">
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option type="4"/>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 edit_cache"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="install/strip">
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option type="4"/>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 install/strip"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="install">
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option type="4"/>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 install"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="list_install_components">
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option type="4"/>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 list_install_components"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="ucentralgw">
<Option output="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/ucentralgw" prefix_auto="0" extension_auto="0"/>
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option object_output="./"/>
<Option type="1"/>
<Option compiler="gcc"/>
<Compiler>
<Add option="-DAPP_VERSION=&quot;0.7.0&quot;"/>
<Add option="-DBUILD_NUMBER=&quot;120&quot;"/>
<Add option="-DTIP_GATEWAY_SERVICE=&quot;1&quot;"/>
<Add option="-D_DEBUG"/>
<Add option="-DPOCO_ENABLE_CPP14"/>
<Add option="-DPOCO_ENABLE_CPP11"/>
<Add option="-DPOCO_OS_FAMILY_UNIX"/>
<Add option="-DPOCO_HAVE_IPv6"/>
<Add option="-DPOCO_NO_STAT64"/>
<Add option="-DXML_DTD"/>
<Add option="-DTHREADSAFE"/>
<Add option="-DNO_TCL"/>
<Add option="-DBOOST_ALL_NO_LIB"/>
<Add directory="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src"/>
<Add directory="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/include/kafka"/>
<Add directory="/usr/local/opt/mysql-client/include"/>
<Add directory="/usr/local/include"/>
<Add directory="/usr/local/opt/openssl/include"/>
<Add directory="/usr/local/opt/mysql-client/include/mysql"/>
<Add directory="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1"/>
<Add directory="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.5/include"/>
<Add directory="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include"/>
<Add directory="/System/Library/Frameworks"/>
<Add directory="/Library/Frameworks"/>
</Compiler>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 ucentralgw"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
<Target title="ucentralgw/fast">
<Option output="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/ucentralgw" prefix_auto="0" extension_auto="0"/>
<Option working_dir="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug"/>
<Option object_output="./"/>
<Option type="1"/>
<Option compiler="gcc"/>
<Compiler>
<Add option="-DAPP_VERSION=&quot;0.7.0&quot;"/>
<Add option="-DBUILD_NUMBER=&quot;120&quot;"/>
<Add option="-DTIP_GATEWAY_SERVICE=&quot;1&quot;"/>
<Add option="-D_DEBUG"/>
<Add option="-DPOCO_ENABLE_CPP14"/>
<Add option="-DPOCO_ENABLE_CPP11"/>
<Add option="-DPOCO_OS_FAMILY_UNIX"/>
<Add option="-DPOCO_HAVE_IPv6"/>
<Add option="-DPOCO_NO_STAT64"/>
<Add option="-DXML_DTD"/>
<Add option="-DTHREADSAFE"/>
<Add option="-DNO_TCL"/>
<Add option="-DBOOST_ALL_NO_LIB"/>
<Add directory="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src"/>
<Add directory="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/include/kafka"/>
<Add directory="/usr/local/opt/mysql-client/include"/>
<Add directory="/usr/local/include"/>
<Add directory="/usr/local/opt/openssl/include"/>
<Add directory="/usr/local/opt/mysql-client/include/mysql"/>
<Add directory="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1"/>
<Add directory="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.5/include"/>
<Add directory="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include"/>
<Add directory="/System/Library/Frameworks"/>
<Add directory="/Library/Frameworks"/>
</Compiler>
<MakeCommands>
<Build command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 ucentralgw/fast"/>
<CompileFile command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 &quot;$file&quot;"/>
<Clean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
<DistClean command="/usr/local/bin/gmake -j16 -f &quot;/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/Makefile&quot; VERBOSE=1 clean"/>
</MakeCommands>
</Target>
</Build>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/build">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/ALBHealthCheckServer.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/AuthClient.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/AuthClient.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/CentralConfig.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/CentralConfig.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/CommandChannel.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/CommandChannel.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/CommandManager.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/CommandManager.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/Daemon.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/Daemon.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/DeviceRegistry.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/DeviceRegistry.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/FileUploader.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/FileUploader.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/KafkaManager.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/KafkaManager.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/Kafka_topics.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/MicroService.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/MicroService.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/OUIServer.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/OUIServer.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/OpenAPIRequest.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/OpenAPIRequest.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_BlackList.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_BlackList.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_GWobjects.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_GWobjects.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_InternalServer.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_InternalServer.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_RPC.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_RPC.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_SecurityObjects.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_SecurityObjects.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_command.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_command.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_commands.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_commands.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_default_configuration.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_default_configuration.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_default_configurations.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_default_configurations.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_device_commandHandler.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_device_commandHandler.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_device_handler.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_device_handler.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_devices_handler.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_devices_handler.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_file.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_file.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_handler.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_handler.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_ouis.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_ouis.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_protocol.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_server.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_server.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_system_command.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_system_command.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_utils.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/RESTAPI_utils.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/StateProcessor.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/StateProcessor.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/StorageArchiver.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/StorageArchiver.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/StorageService.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/StorageService.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/SubSystemServer.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/SubSystemServer.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/Utils.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/Utils.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/WebSocketServer.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/WebSocketServer.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_blacklist.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_capabilities.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_command.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_defconfig.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_device.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_healthcheck.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_lifetime_stats.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_logs.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_mysql.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_pgql.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_sqlite.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_statistics.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/storage_tables.cpp">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/uCentralProtocol.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/src/uCentralTypes.h">
<Option target="ucentralgw"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/CMakeLists.txt">
<Option virtualFolder="CMake Files\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/BoostDetectToolset-1.75.0.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Boost-1.75.0/BoostConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Boost-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Boost-1.75.0/BoostConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Boost-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_headers-1.75.0/boost_headers-config-version.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_headers-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_headers-1.75.0/boost_headers-config.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_headers-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_system-1.75.0/boost_system-config-version.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_system-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_system-1.75.0/boost_system-config.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_system-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_system-1.75.0/libboost_system-variant-mt-shared.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_system-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_system-1.75.0/libboost_system-variant-mt-static.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_system-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_system-1.75.0/libboost_system-variant-shared.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_system-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/boost_system-1.75.0/libboost_system-variant-static.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\boost_system-1.75.0\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/CppKafka/CppKafkaConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\CppKafka\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/CppKafka/CppKafkaConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\CppKafka\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/CppKafka/CppKafkaTargets-noconfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\CppKafka\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/CppKafka/CppKafkaTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\CppKafka\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoCryptoConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoCryptoConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoCryptoTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoCryptoTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataMySQLConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataMySQLConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataMySQLTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataMySQLTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataPostgreSQLConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataPostgreSQLConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataPostgreSQLTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataPostgreSQLTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataSQLiteConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataSQLiteConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataSQLiteTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataSQLiteTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoDataTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoFoundationConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoFoundationConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoFoundationTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoFoundationTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJSONConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJSONConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJSONTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJSONTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJWTConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJWTConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJWTTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoJWTTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetSSLConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetSSLConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetSSLTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetSSLTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoNetTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoUtilConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoUtilConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoUtilTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoUtilTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoXMLConfig.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoXMLConfigVersion.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoXMLTargets-relwithdebinfo.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/../../../../../../usr/local/lib/cmake/Poco/PocoXMLTargets.cmake">
<Option virtualFolder="CMake Files\..\..\..\..\..\..\usr\local\lib\cmake\Poco\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake/FindMySQL.cmake">
<Option virtualFolder="CMake Files\cmake\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake/FindPostgreSQL.cmake">
<Option virtualFolder="CMake Files\cmake\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake/FindRdKafka.cmake">
<Option virtualFolder="CMake Files\cmake\"/>
</Unit>
<Unit filename="/Users/stephb/Desktop/Dropbox/clion/wlan-cloud-ucentralgw/cmake-build-debug/rdkafka_version_test.cpp">
<Option virtualFolder="CMake Files\cmake-build-debug\"/>
</Unit>
</Project>
</CodeBlocks_project_file>

26
config.yaml Normal file
View File

@@ -0,0 +1,26 @@
tip:
port: 6051
server: ssc.wlan.local
username: support@example.com
password: support
certificates:
keyfile: keyfile.pem
certfile: certfile.pem
password: mypassword
ucentral:
port: 1991
listeners: 100
logger:
size: 10
days: 31
ui:
port: 9771
username: support@example.com
password: support

View File

@@ -1,101 +1,75 @@
#!/bin/bash
#!/bin/sh
set -e
if [ "$SELFSIGNED_CERTS" = 'true' ]; then
update-ca-certificates
fi
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\$OWGW_ROOT/certs/websocket-key.pem"} \
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\$OWGW_ROOT/certs/clientcas.pem"} \
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\$OWGW_ROOT/certs/cas"} \
WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
FILEUPLOADER_HOST_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\$OWGW_ROOT/uploads"} \
FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
SERVICE_KEY=${SERVICE_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
SYSTEM_DATA=${SYSTEM_DATA:-"\$OWGW_ROOT/data"} \
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
SIMULATORID=${SIMULATORID:-""} \
IPTOCOUNTRY_PROVIDER=${IPTOCOUNTRY_PROVIDER:-"ipinfo"} \
IPTOCOUNTRY_IPINFO_TOKEN=${IPTOCOUNTRY_IPINFO_TOKEN:-""} \
IPTOCOUNTRY_IPDATA_APIKEY=${IPTOCOUNTRY_IPDATA_APIKEY:-""} \
AUTOPROVISIONING_PROCESS=${AUTOPROVISIONING_PROCESS:-"prov,default"} \
RTTY_INTERNAL=${RTTY_INTERNAL:-"true"} \
RTTY_ENABLED=${RTTY_ENABLED:-"true"} \
RTTY_SERVER=${RTTY_SERVER:-"localhost"} \
RTTY_PORT=${RTTY_PORT:-"5912"} \
RTTY_TOKEN=${RTTY_TOKEN:-""} \
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
RTTY_ASSETS=${RTTY_ASSETS:-"\$OWGW_ROOT/rtty_ui"} \
RADIUS_PROXY_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \
RADIUS_PROXY_COA_PORT=${RADIUS_PROXY_COA_PORT:-"3799"} \
KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \
KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \
KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \
KAFKA_SSL_CERTIFICATE_LOCATION=${KAFKA_SSL_CERTIFICATE_LOCATION:-""} \
KAFKA_SSL_KEY_LOCATION=${KAFKA_SSL_KEY_LOCATION:-""} \
KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \
STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owgw"} \
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
fi
# Check if rtty_ui directory exists
export RTTY_ASSETS=$(grep 'rtty.assets' $OWGW_CONFIG/owgw.properties | awk -F '=' '{print $2}' | xargs | envsubst)
if [ -z "$RTTY_ASSETS" ]; then
export RTTY_ASSETS="$OWGW_ROOT/rtty_ui"
fi
if [[ ! -d "$(dirname $RTTY_ASSETS)" ]]; then
mkdir -p $(dirname $RTTY_ASSETS)
fi
if [[ ! -d "$RTTY_ASSETS" ]]; then
cp -r /dist/rtty_ui $RTTY_ASSETS
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWGW_CONFIG"/owgw.properties ]]; then
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\$OWGW_ROOT/certs/websocket-key.pem"} \
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\$OWGW_ROOT/certs/clientcas.pem"} \
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\$OWGW_ROOT/certs/cas"} \
WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
FILEUPLOADER_HOST_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\$OWGW_ROOT/uploads"} \
FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
SERVICE_KEY=${SERVICE_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
SYSTEM_DATA=${SYSTEM_DATA:-"\$OWGW_ROOT/data"} \
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
SIMULATORID=${SIMULATORID:-""} \
IPTOCOUNTRY_PROVIDER=${IPTOCOUNTRY_PROVIDER:-"ipinfo"} \
IPTOCOUNTRY_IPINFO_TOKEN=${IPTOCOUNTRY_IPINFO_TOKEN:-""} \
IPTOCOUNTRY_IPDATA_APIKEY=${IPTOCOUNTRY_IPDATA_APIKEY:-""} \
AUTOPROVISIONING_PROCESS=${AUTOPROVISIONING_PROCESS:-"prov,default"} \
RTTY_ENABLED=${RTTY_ENABLED:-"false"} \
RTTY_SERVER=${RTTY_SERVER:-"localhost"} \
RTTY_PORT=${RTTY_PORT:-"5912"} \
RTTY_TOKEN=${RTTY_TOKEN:-"96181c567b4d0d98c50f127230068fa8"} \
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \
KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \
STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owgw"} \
STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owgw"} \
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
fi
if [ "$1" = '/openwifi/owgw' -a "$(id -u)" = '0' ]; then
if [ "$RUN_CHOWN" = 'true' ]; then
chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
fi
exec gosu "$OWGW_USER" "$@"
exec su-exec "$OWGW_USER" "$@"
fi
exec "$@"

14
docker_build.sh Executable file
View File

@@ -0,0 +1,14 @@
USERNAME=arilia
HUBNAME=tip-tip-wlan-cloud-ucentral.jfrog.io
IMAGE_NAME=ucentralgw
echo "Removing docker images before build..."
docker rmi -f $(docker images -a -q)
echo "Building $IMAGE_NAME image..."
docker build --no-cache --tag $IMAGE_NAME .
IMAGE_ID=`docker images -q $IMAGE_NAME`
docker login --username=$USERNAME $HUBNAME
docker tag $IMAGE_ID $HUBNAME/$IMAGE_NAME:latest
echo "Updating $HUBNAME with the latest $IMAGE_NAME image..."
docker push $HUBNAME/$IMAGE_NAME
docker logout $HUBNAME

5
docker_clean.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
# Removes all local images. This is dangerous but good when debugging
docker rmi -f $(docker images -a -q)

43
docker_run.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/bin/sh
HUBNAME=tip-tip-wlan-cloud-ucentral.jfrog.io
IMAGE_NAME=ucentralgw
DOCKER_NAME=$HUBNAME/$IMAGE_NAME:master
CONTAINER_NAME=ucentralgw
#stop previously running images
docker container stop $CONTAINER_NAME
docker container rm $CONTAINER_NAME --force
if [[ ! -d logs ]]
then
mkdir logs
fi
if [[ ! -d uploads ]]
then
mkdir uploads
fi
if [[ ! -d certs ]]
then
echo "certs directory does not exist. Please create and add the proper certificates."
exit 1
fi
if [[ ! -f owgw.properties ]]
then
echo "Configuration file ucentral.properties is missing in the current directory"
exit 2
fi
docker run -d -p 15002:15002 \
-p 16001:16001 \
-p 16003:16003 \
--init \
--volume="$PWD:/ucentral-data" \
-e UCENTRALGW_ROOT="/ucentral-data" \
-e UCENTRALGW_CONFIG="/ucentral-data" \
--name="ucentralgw" $DOCKER_NAME

File diff suppressed because one or more lines are too long

View File

@@ -79,8 +79,7 @@ The following table lists the configurable parameters of the chart and their def
| persistence.size | string | Defines PV size | `'10Gi'` |
| public_env_variables | hash | Defines list of environment variables to be passed to the Gateway | |
| configProperties | hash | Configuration properties that should be passed to the application in `owgw.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | |
| existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` |
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owgw` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. | |
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owgw` on where it is mounted) | |
| certsCAs | hash | Defines files with CAs that should be passed to the Gateway (see `volumes.owgw` on where it is mounted) | |

View File

@@ -1,5 +1,4 @@
{{- $root := . -}}
{{- $storageType := index .Values.configProperties "storage.type" -}}
---
apiVersion: apps/v1
kind: Deployment
@@ -49,38 +48,6 @@ spec:
- tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }}
- -timeout
- 600s
{{- if eq $storageType "postgresql" }}
- name: wait-postgres
image: "{{ .Values.images.owgw.repository }}:{{ .Values.images.owgw.tag }}"
imagePullPolicy: {{ .Values.images.owgw.pullPolicy }}
command:
- /wait-for-postgres.sh
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
- echo
- "PostgreSQL is ready"
env:
- name: KUBERNETES_DEPLOYED
value: "{{ now }}"
{{- range $key, $value := .Values.public_env_variables }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- range $key, $value := .Values.secret_env_variables }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ include "owgw.fullname" $root }}-env
key: {{ $key }}
{{- end }}
volumeMounts:
{{- range .Values.volumes.owgw }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- if .subPath }}
subPath: {{ .subPath }}
{{- end }}
{{- end }}
{{- end }}
containers:
@@ -109,11 +76,6 @@ spec:
containerPort: {{ $portValue.targetPort }}
protocol: {{ $portValue.protocol }}
{{- end }}
{{- range $port, $portValue := .Values.services.radius.ports }}
- name: {{ $port }}
containerPort: {{ $portValue.targetPort }}
protocol: {{ $portValue.protocol }}
{{- end }}
volumeMounts:
{{- range .Values.volumes.owgw }}

View File

@@ -9,7 +9,7 @@ fullnameOverride: ""
images:
owgw:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
tag: master
tag: v2.5.3
pullPolicy: Always
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
@@ -40,27 +40,6 @@ services:
servicePort: 16003
targetPort: 16003
protocol: TCP
rttys:
servicePort: 5912
targetPort: 5912
rttys-view:
servicePort: 5913
targetPort: 5913
radius:
type: ClusterIP
ports:
acc:
servicePort: 1813
targetPort: 1813
protocol: UDP
auth:
servicePort: 1812
targetPort: 1812
protocol: UDP
coa:
servicePort: 3799
targetPort: 3799
protocol: UDP
checks:
owgw:
@@ -112,7 +91,7 @@ volumes:
mountPath: /owgw-data/certs
volumeDefinition: |
secret:
secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owgw.fullname" . }}-certs{{ end }}
secretName: {{ include "owgw.fullname" . }}-certs
- name: certs-cas
mountPath: /owgw-data/certs/cas
volumeDefinition: |
@@ -138,7 +117,7 @@ resources: {}
# memory: 128Mi
securityContext:
fsGroup: 1000
fsGroup: 101
# Usage of unsafe sysctls requires multiple things:
# - allow these unsafe sysctls on kubelet level (by adding --allowed-unsafe-sysctls flag)
# - enabling addition of PodSecurityContext setting podSecurityPolicy.enabled to "true" below
@@ -230,27 +209,19 @@ configProperties:
openwifi.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
openwifi.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
openwifi.devicetypes.2: IOT:esp32
oui.download.uri: https://standards-oui.ieee.org/oui/oui.txt
oui.download.uri: https://linuxnet.ca/ieee/oui.txt
firmware.autoupdate.policy.default: auto
iptocountry.provider: ipinfo
# Callback
openwifi.callback.enable: "false"
openwifi.callback.0.local: localhost:16001
openwifi.callback.0.remote: localhost:15055
openwifi.callback.0.topics: owfws
# rtty
rtty.internal: "true"
rtty.enabled: "true"
rtty.server: localhost
rtty.port: 5912
rtty.timeout: 60
rtty.viewport: 5913
rtty.assets: $OWGW_ROOT/rtty_ui
# RADIUS proxy
radius.proxy.enable: "true"
radius.proxy.accounting.port: 1813
radius.proxy.authentication.port: 1812
radius.proxy.coa.port: 3799
# ALB
alb.enable: "true"
alb.port: 16102
@@ -261,10 +232,6 @@ configProperties:
openwifi.kafka.brokerlist: localhost:9092
openwifi.kafka.auto.commit: false
openwifi.kafka.queue.buffering.max.ms: 50
openwifi.kafka.ssl.ca.location: ""
openwifi.kafka.ssl.certificate.location: ""
openwifi.kafka.ssl.key.location: ""
openwifi.kafka.ssl.key.password: ""
# Storage
storage.type: sqlite # (sqlite|postgresql|mysql|odbc)
## SQLite
@@ -291,7 +258,6 @@ configProperties:
openwifi.system.debug: "true"
openwifi.system.uri.private: https://localhost:17002
openwifi.system.uri.public: https://localhost:16002
openwifi.system.uri.ui: https://localhost
openwifi.system.commandchannel: /tmp/app_owgw
# Logging
logging.type: console
@@ -331,22 +297,166 @@ configProperties:
storage.type.mysql.username: stephb
storage.type.mysql.password: snoopy99
# NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr
existingCertsSecret: ""
certs:
clientcas.pem: ""
issuer.pem: ""
restapi-ca.pem: ""
restapi-cert.pem: ""
restapi-key.pem: ""
root.pem: ""
websocket-cert.pem: ""
websocket-key.pem: ""
clientcas.pem: |
-----BEGIN CERTIFICATE-----
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
5IOM7ItsRmen6u3qu+JXros54e4juQ==
-----END CERTIFICATE-----
issuer.pem: |
-----BEGIN CERTIFICATE-----
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
-----END CERTIFICATE-----
# restapi-ca.pem: ""
# restapi-cert.pem: ""
# restapi-key.pem: ""
root.pem: |
-----BEGIN CERTIFICATE-----
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
5IOM7ItsRmen6u3qu+JXros54e4juQ==
-----END CERTIFICATE-----
# websocket-cert.pem: ""
# websocket-key.pem: ""
certsCAs:
issuer.pem: ""
root.pem: ""
issuer.pem: |
-----BEGIN CERTIFICATE-----
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
-----END CERTIFICATE-----
root.pem: |
-----BEGIN CERTIFICATE-----
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
5IOM7ItsRmen6u3qu+JXros54e4juQ==
-----END CERTIFICATE-----
# PostgreSQL (https://github.com/bitnami/charts/tree/master/bitnami/postgresql)
postgresql:

View File

@@ -31,13 +31,58 @@ components:
responses:
NotFound:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
description: The specified resource was not found.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: string
Unauthorized:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
description: The requested does not have sufficient rights to perform the operation.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
enum:
- 0 # Success
- 1 # PASSWORD_CHANGE_REQUIRED,
- 2 # INVALID_CREDENTIALS,
- 3 # PASSWORD_ALREADY_USED,
- 4 # USERNAME_PENDING_VERIFICATION,
- 5 # PASSWORD_INVALID,
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
- 9 # EXPIRED_TOKEN
- 10 # RATE_LIMIT_EXCEEDED
- 11 # BAD_MFA_TRANSACTION
- 12 # MFA_FAILURE
- 13 # SECURITY_SERVICE_UNREACHABLE
ErrorDetails:
type: string
ErrorDescription:
type: string
Success:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
BadRequest:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
description: The requested operation was performed.
content:
application/json:
schema:
properties:
Operation:
type: string
Details:
type: string
Code:
type: integer
schemas:
DeviceType:
@@ -94,25 +139,6 @@ components:
type: string
devicePassword:
type: string
subscriber:
type: string
format: uuid
entity:
type: string
format: uuid
modified:
type: integer
format: int64
locale:
type: string
minLength: 2
maxLength: 2
FCC:
type: boolean
default: false
certificateExpiryDate:
type: integer
format: int64
DeviceWithStatus:
type: object
@@ -183,37 +209,6 @@ components:
lastContact:
type: integer
format: int64
subscriber:
type: string
format: uuid
entity:
type: string
format: uuid
modified:
type: integer
format: int64
locale:
type: string
minLength: 2
maxLength: 2
started:
type: integer
format: int64
sessionId:
type: integer
format: int64
connectionCompletionTime:
type: number
format: double
totalConnectionTime:
type: integer
format: int64
restrictedDevice:
type: boolean
default: false
certificateDate:
type: integer
format: int64
DeviceList:
type: object
@@ -306,17 +301,6 @@ components:
type: integer
format: int64
DeviceConnectionStatistics:
type: object
description: Return some basic device statistics.
properties:
connectedDevices:
type: integer
format: int64
averageConnectionTime:
type: integer
format: int64
StatisticsDetails:
type: object
properties:
@@ -500,33 +484,6 @@ components:
type: integer
format: int64
ScriptRequest:
type: object
properties:
serialNumber:
type: string
timeout:
type: integer
format: int64
default: 30
type:
type: string
enum:
- shell
- bundle
script:
type: string
when:
type: integer
format: int64
default: 0
signature:
type: string
deferred:
type: boolean
uri:
type: string
FactoryRequest:
type: object
properties:
@@ -935,26 +892,9 @@ components:
items:
$ref: '#/components/schemas/TagValuePair'
ExtraSystemConfiguration:
type: array
items:
type: object
properties:
parameterName:
type: string
parameterType:
type: string
enum:
- string
- integer
- boolean
- path
parameterValue:
{}
#########################################################################################
##
## End of uCentral system-wide values
## End of uCentral system wide values
##
#########################################################################################
BlackDeviceInfo:
@@ -1010,12 +950,6 @@ components:
oneOf:
- $ref: '#/components/schemas/WifiBands'
- $ref: '#/components/schemas/WifiChannels'
ies:
type: array
items:
type: integer
minimum: 0
maximum: 255
required:
- serialNumber
@@ -1087,99 +1021,6 @@ components:
items:
$ref: '#/components/schemas/CapabilitiesModel'
RadiusProxyServerEntry:
type: object
properties:
name:
type: string
ip:
type: string
format: ip-addr
port:
type: integer
weight:
type: integer
secret:
type: string
certificate:
type: string
radsec:
type: boolean
default: false
radsecPort:
type: integer
minimum: 1
maximum: 65535
radsecSecret:
type: string
radsecCacerts:
type: array
items:
type: string
radsecCert:
type: string
description: this must be the base64 encoded of the entire content of the certificate file, including the -----BEGIN lines
radsecKey:
type: string
description: this must be the base64 encoded of the entire content of the key file, including the -----BEGIN lines
radsecRealms:
description: each entry must be the base64 encoded of the entire content of the ca files, including the -----BEGIN lines
type: array
items:
type: string
ignore:
type: boolean
default: false
RadiusProxyServerConfig:
type: object
properties:
strategy:
type: string
enum:
- random
- round_robin
- weighted
monitor:
type: boolean
default: false
monitorMethod:
type: string
enum:
- none
- https
- radius
methodParameters:
type: array
items:
type: string
servers:
type: array
items:
$ref: '#/components/schemas/RadiusProxyServerEntry'
RadiusProxyPool:
type: object
properties:
name:
type: string
description:
type: string
authConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig'
acctConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig'
coaConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig'
RadiusProxyPoolList:
type: object
properties:
pools:
type: array
items:
$ref: '#/components/schemas/RadiusProxyPool'
paths:
/devices:
get:
@@ -1229,27 +1070,6 @@ paths:
name: deviceWithStatus
schema:
type: boolean
- in: query
description: return extended information
name: orderBy
schema:
type: string
example: serialNumber:a,created:d
required: false
- in: query
description: return extended information
name: orderSpec
schema:
type: boolean
default: false
required: false
- in: query
description: return extended information
name: connectionStatistics
schema:
type: boolean
default: false
required: false
responses:
200:
description: List devices
@@ -1261,7 +1081,6 @@ paths:
- $ref: '#/components/schemas/DeviceListWithStatus'
- $ref: '#/components/schemas/SerialNumberList'
- $ref: '#/components/schemas/DeviceCount'
- $ref: '#/components/schemas/DeviceConnectionStatistics'
403:
$ref: '#/components/responses/Unauthorized'
404:
@@ -1921,12 +1740,6 @@ paths:
schema:
type: boolean
required: false
- in: query
description: Return the number of matching records.
name: countOnly
schema:
type: boolean
required: false
responses:
200:
@@ -1936,8 +1749,6 @@ paths:
schema:
oneOf:
- $ref: '#/components/schemas/StatisticsRecords'
- $ref: '#/components/schemas/DeviceCount'
403:
$ref: '#/components/responses/Unauthorized'
404:
@@ -2115,11 +1926,6 @@ paths:
schema:
type: string
required: true
- in: query
name: FWsignature
schema:
type: string
required: false
requestBody:
description: Command details
content:
@@ -2160,32 +1966,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/script:
post:
tags:
- Commands
summary: Debug a device.
operationId: debugDevice
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Command details
content:
application/json:
schema:
$ref: '#/components/schemas/ScriptRequest'
responses:
200:
$ref: '#/components/schemas/CommandInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/factory:
post:
tags:
@@ -2627,45 +2407,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/radiusProxyConfig:
get:
tags:
- RADIUSProxy
summary: Retrieve RADIUS Proxy configuration.
operationId: getRadiusProxyConfig
responses:
200:
$ref: '#/components/schemas/RadiusProxyPoolList'
403:
$ref: '#/components/responses/Unauthorized'
put:
tags:
- RADIUSProxy
summary: Modify RADIUS Proxy configuration.
operationId: modifyRadiusProxyConfig
requestBody:
description: Change RADIUS configuration pool config
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusProxyPoolList'
responses:
200:
$ref: '#/components/schemas/RadiusProxyPoolList'
403:
$ref: '#/components/responses/Unauthorized'
delete:
tags:
- RADIUSProxy
summary: Delete RADIUS Proxy configuration.
operationId: deleteRadiusProxyConfig
responses:
204:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
/deviceDashboard:
get:
tags:
@@ -2775,51 +2516,4 @@ paths:
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/systemConfiguration:
get:
tags:
- SystemConfiguration
summary: Retrieve system configuration items
operationId: getSystemConfiguration
responses:
200:
$ref: '#/components/schemas/ExtraSystemConfiguration'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- SystemConfiguration
summary: Set some or all system configuration
operationId: setSystemConfiguration
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ExtraSystemConfiguration'
responses:
200:
$ref: '#/components/schemas/ExtraSystemConfiguration'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- SystemConfiguration
summary: Delete all additional system configuration
operationId: deleteSystemConfiguration
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
$ref: '#/components/responses/NotFound'

View File

@@ -65,7 +65,6 @@ openwifi.system.debug = true
openwifi.system.uri.private = https://localhost:17002
openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16002
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
openwifi.security.restapi.disable = false
openwifi.system.commandchannel = /tmp/app.ucentralgw
#
@@ -75,7 +74,7 @@ openwifi.autoprovisioning = true
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
openwifi.devicetypes.2 = IOT:esp32
oui.download.uri = https://standards-oui.ieee.org/oui/oui.txt
oui.download.uri = https://linuxnet.ca/ieee/oui.txt
iptocountry.default = US
iptocountry.provider = ipinfo
@@ -97,12 +96,6 @@ rtty.timeout = 60
rtty.viewport = 5913
rtty.assets = $OWGW_ROOT/rtty_ui
### RADIUS proxy config
radius.proxy.enable = false
radius.proxy.accounting.port = 1813
radius.proxy.authentication.port = 1812
radius.proxy.coa.port = 3799
#############################
# Generic information for all micro services
#############################
@@ -122,11 +115,6 @@ openwifi.kafka.brokerlist = a1.arilia.com:9092
openwifi.kafka.auto.commit = false
openwifi.kafka.queue.buffering.max.ms = 50
openwifi.kafka.ssl.ca.location =
openwifi.kafka.ssl.certificate.location =
openwifi.kafka.ssl.key.location =
openwifi.kafka.ssl.key.password =
#
# This section select which form of persistence you need
# Only one selected at a time. If you select multiple, this service will die if a horrible
@@ -178,4 +166,4 @@ archiver.db.3.keep = 7
########################################################################
logging.type = file
logging.path = $OWGW_ROOT/logs
logging.level = information
logging.level = debug

View File

@@ -65,7 +65,6 @@ openwifi.system.debug = true
openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
openwifi.system.commandchannel = /tmp/app.ucentralgw
#
@@ -75,8 +74,9 @@ openwifi.autoprovisioning = true
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
openwifi.devicetypes.2 = IOT:esp32
oui.download.uri = https://standards-oui.ieee.org/oui/oui.txt
oui.download.uri = https://linuxnet.ca/ieee/oui.txt
simulatorid = ${SIMULATORID}
iptocountry.default = US
iptocountry.provider = ${IPTOCOUNTRY_PROVIDER}
iptocountry.ipinfo.token = ${IPTOCOUNTRY_IPINFO_TOKEN}
@@ -87,20 +87,12 @@ autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
#
# rtty
#
rtty.internal = ${RTTY_INTERNAL}
rtty.enabled = ${RTTY_ENABLED}
rtty.server = ${RTTY_SERVER}
rtty.port = ${RTTY_PORT}
rtty.token = ${RTTY_TOKEN}
rtty.timeout = ${RTTY_TIMEOUT}
rtty.viewport = ${RTTY_VIEWPORT}
rtty.assets = ${RTTY_ASSETS}
### RADIUS proxy config
radius.proxy.enable = ${RADIUS_PROXY_ENABLE}
radius.proxy.accounting.port = ${RADIUS_PROXY_ACCOUNTING_PORT}
radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
radius.proxy.coa.port = ${RADIUS_PROXY_COA_PORT}
#############################
# Generic information for all micro services
@@ -121,11 +113,6 @@ openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST}
openwifi.kafka.auto.commit = false
openwifi.kafka.queue.buffering.max.ms = 50
openwifi.kafka.ssl.ca.location = ${KAFKA_SSL_CA_LOCATION}
openwifi.kafka.ssl.certificate.location = ${KAFKA_SSL_CERTIFICATE_LOCATION}
openwifi.kafka.ssl.key.location = ${KAFKA_SSL_KEY_LOCATION}
openwifi.kafka.ssl.key.password = ${KAFKA_SSL_KEY_PASSWORD}
#
# This section select which form of persistence you need
# Only one selected at a time. If you select multiple, this service will die if a horrible
@@ -174,4 +161,4 @@ archiver.db.3.keep = 7
########################################################################
logging.type = console
logging.path = $OWGW_ROOT/logs
logging.level = information
logging.level = debug

View File

@@ -1,205 +0,0 @@
{
"interfaces": [
{
"ethernet": [
{
"select-ports": [
"WAN*"
]
}
],
"ipv4": {
"addressing": "dynamic"
},
"ipv6": {
"addressing": "dynamic"
},
"name": "wan",
"role": "upstream",
"services": [
"ssh"
],
"ssids": []
},
{
"ethernet": [
{
"select-ports": [
"LAN*"
]
}
],
"ipv4": {
"addressing": "static",
"dhcp": {
"lease-count": 100,
"lease-first": 10,
"lease-time": "6h"
},
"gateway": "192.168.1.1",
"send-hostname": true,
"subnet": "192.168.1.1/24",
"use-dns": []
},
"ipv6": {
"addressing": "dynamic"
},
"name": "lan",
"role": "downstream",
"services": [
"wifi-steering",
"ssh"
],
"ssids": [
{
"bss-mode": "ap",
"encryption": {
"ieee80211w": "required",
"proto": "wpa"
},
"hidden-ssid": false,
"isolate-clients": false,
"maximum-clients": 64,
"name": "arilia-rad",
"radius": {
"authentication": {
"host": "0.0.0.0",
"port": 1812,
"secret": "radsec"
},
"accounting": {
"host": "0.0.0.0",
"port": 1813,
"secret": "radsec"
}
},
"services": [
"radius-gw-proxy"
],
"wifi-bands": [
"2G",
"5G"
],
"pass-point": {
"venue-name": [
"eng:Example passpoint_venue",
"fra:Exemple de lieu"
],
"domain-name": [
"onboard.almondlabs.net",
"test.com"
],
"asra": false,
"internet": true,
"esr": false,
"uesa": false,
"access-network-type": 0,
"hessid":"11:22:33:44:55:66",
"venue-group": 2,
"venue-type": 8,
"connection-capability":[
"1:0:2",
"6:22:1",
"17:5060:0"
],
"roaming-consortium": [
"F4F5E8F5F4",
"BAA2D00100",
"BAA2D00000"
],
"disable-dgaf": true,
"anqp-domain": 8888,
"ipaddr-type-available": 14,
"nai-realm": [
],
"osen": false,
"anqp-3gpp-cell-net": [
],
"friendly-name": [
"eng:AlmondLabs",
"fra:AlmondLabs"
],
"venue-url": [
"http://www.example.com/info-fra",
"http://www.example.com/info-eng"
],
"auth-type": {
"type": "terms-and-conditions"
}
}
}
]
}
],
"metrics": {
"dhcp-snooping": {
"filters": [
"ack",
"discover",
"offer",
"request",
"solicit",
"reply",
"renew"
]
},
"health": {
"interval": 60
},
"statistics": {
"interval": 60,
"types": [
"ssids",
"lldp",
"clients"
]
},
"wifi-frames": {
"filters": [
"probe",
"auth",
"assoc",
"disassoc",
"deauth",
"local-deauth",
"inactive-deauth",
"key-mismatch",
"beacon-report",
"radar-detected"
]
}
},
"radios": [
{
"band": "2G",
"bandwidth": 10,
"beacon-interval": 100,
"channel": "auto",
"channel-mode": "HT",
"channel-width": 20,
"country": "CA",
"dtim-period": 2,
"maximum-clients": 64,
"tx-power": 0
},
{
"band": "5G",
"bandwidth": 20,
"beacon-interval": 100,
"channel": "auto",
"channel-mode": "HE",
"channel-width": 40,
"country": "CA",
"dtim-period": 2,
"maximum-clients": 64,
"tx-power": 0
}
],
"services": {
"ssh": {
"password-authentication": true,
"port": 22
}
},
"uuid": 1661312631
}

View File

@@ -1,72 +0,0 @@
{
"pools" : [
{
"name" : "master" ,
"description" : "master pool",
"useByDefault" : true,
"authConfig" : {
"strategy" : "weighted",
"monitor" : false,
"monitorMethod" : "none",
"methodParameters" : [],
"servers" : [ {
"name" : "svr1",
"ip" : "10.100.0.1",
"port" : 1812,
"weight" : 10,
"secret" : "my_secret!"
},
{
"name" : "svr2",
"ip" : "10.100.10.1",
"port" : 1812,
"weight" : 20,
"secret" : "my_secret!"
}
]
},
"acctConfig" : {
"strategy" : "random",
"monitor" : false,
"monitorMethod" : "none",
"methodParameters" : [],
"servers" : [ {
"name" : "svr1",
"ip" : "10.100.0.1",
"port" : 1813,
"weight" : 10,
"secret" : "my_secret!"
},
{
"name" : "svr2",
"ip" : "10.100.10.1",
"port" : 1813,
"weight" : 20,
"secret" : "my_secret!"
}
]
},
"coaConfig" : {
"strategy" : "round_robin",
"monitor" : false,
"monitorMethod" : "none",
"methodParameters" : [],
"servers" : [ {
"name" : "svr1",
"ip" : "10.100.0.1",
"port" : 3799,
"weight" : 10,
"secret" : "my_secret!"
},
{
"name" : "svr2",
"ip" : "10.100.10.1",
"port" : 3799,
"weight" : 20,
"secret" : "my_secret!"
}
]
}
}
]
}

View File

@@ -1,32 +0,0 @@
{
"pools" : [
{
"name" : "master" ,
"description" : "master pool",
"useByDefault" : true,
"authConfig" : {
"strategy" : "weighted",
"monitor" : false,
"monitorMethod" : "none",
"methodParameters" : [],
"servers" : [ {
"name" : "orion",
"ip" : "216.239.32.91",
"port" : 2083,
"weight" : 10,
"radsec" : true,
"radsecPort" : 2083,
"radsecSecret" : "radsec",
"radsecKey" : "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUR6RnpXeTZlYXg0QVoxTySG9VUURRZ0FFS3BnWVBHMktPTVd2S0w1Z3NMRXpUc09rREg1M3NHaEQyS3RsRXBDTXVnNDNIZlFnTFVpUgpTR1R2S1l0bDFmbmJaU1lnY0RJdncxdjNYRy9hVDhOY2JBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=",
"radsecCert" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNRVENDQWVpZ0F3SUJBZ0lVY3BKS3pVM0Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa0oxZEhSdmJuZHZiMlF4SFRBYkJnTlZCQU1URkVKMQpkSFJ2Ym5kdmIyUWdVbUZrYzJWaklFTkJNQjRYRFRJeU1EY3dNekExTWpVeE5Gb1hEVEkzTURVeE9UQTFNalV4Ck5Gb3dkVEVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFvVENrSjFkSFJ2Ym5kdmIyUXhOakEwQmdOVkJBTVQKTFdGeWFXeHBZUzVqWWpFd2FtTnVjemgxYlhCbk9HWnBjRFowTUM1dmNtbHZiaTVoY21WaE1USXdMbU52YlRFWgpNQmNHQ2dtU0pvbVQ4aXhrQVFFVENVZHZiMmRzWlRwVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQ3FZR0R4dGlqakZyeWkrWUxDeE0wN0RwQXgrZDdCb1E5aXJaUktRakxvT054MzBJQzFJa1Voazd5bUwKWmRYNTIyVW1JSEF5TDhOYjkxeHYyay9EWEd5amdZa3dnWVl3RGdZRFZSMFBBUUgvQkFRREFnZUFNQk1HQTFVZApKUVFNTUFvR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3T0FZRFZSMFJCREV3TDRJdFlYSnBiR2xoCkxtTmlNVEJxWTI1ek9IVnRjR2M0Wm1sd05uUXdMbTl5YVc5dUxtRnlaV0V4TWpBdVkyOXRNQmNHQTFVZElBUVEKTUE0d0RBWUtLd1lCQkFIdUtnRUJCVEFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFwTmM1dUNBSkp6KzVyakdqdwpCWGtOdHE3UU83bWU5dUg5bkNsTDZnSVE5Z0lnUHM2VkVKVW5CcEZ0RktXbFF4eWJ1YlBxYnpJNjBPSERHQ0ExCmhXUk1PS1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
"radsecCacerts" : [
"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ0akNDQVZ1Z0F3SUJBZ0lCQyOXZaREVkTUJzR0ExVUVBeE1VUW5WMGRHOXVkMjl2WkNCU1lXUnpaV01nUTBFdwpJQmNOTVRrd05qQTJNVFV4TlRNeVdoZ1BNalV4T1RBMk1EY3hOVEUxTXpKYU1FRXhDekFKQmdOVkJBWVRBbFZUCk1STXdFUVlEVlFRS0V3cENkWFIwYjI1M2IyOWtNUjB3R3dZRFZRUURFeFJDZFhSMGIyNTNiMjlrSUZKaFpITmwKWXlCRFFUQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJJUW40QVBKaXdvUVFQblR1cFgrZTk1Ugp0ZzVoQVFVbUhCN1E0UkpwSG4welF6TUJpMDdSejkxV05RamFHeERydktLVlQ1OThIM2dxYkI4TTViOHN3aytqClFqQkFNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBZ1lJS3dZQkJRVUgKQXdFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQTkrbHUwN2NlaGc1OQpxSi81dWtzN05oL3F2aXFHWCs1WDFwSVVxdENGVlJjQ0lRREZmUGhwZzZJOFE0SUdBbzNuamlHRTdDWC9nMm56CkRzSW5FcG9vRlkxV0xRPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
],
"radsecRealms" : [],
"ignore" : false
}
]
}
}
]
}

View File

@@ -1,26 +1 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="icon" href="/favicon.ico">
<title>RTTYs</title>
<link href="/css/app.0e046291.css" rel="preload" as="style">
<link href="/css/chunk-vendors.b221ddbd.css" rel="preload" as="style">
<link href="/css/chunk-vendors.b221ddbd.css" rel="stylesheet">
<link href="/css/app.0e046291.css" rel="stylesheet">
<link href="/js/app.79bf330a.js" rel="preload" as="script">
<link href="/js/chunk-vendors.7fd2577a.js" rel="preload" as="script">
</head>
<body>
<noscript>
<strong>We're sorry but Rttys doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<script src="/js/chunk-vendors.7fd2577a.js">
</script><script src="/js/app.79bf330a.js">
</script>
</body>
</html>
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>Rttys</title><link href="/css/app.0e046291.css" rel="preload" as="style"><link href="/css/chunk-vendors.b221ddbd.css" rel="preload" as="style"><link href="/js/app.79bf330a.js" rel="preload" as="script"><link href="/js/chunk-vendors.7fd2577a.js" rel="preload" as="script"><link href="/css/chunk-vendors.b221ddbd.css" rel="stylesheet"><link href="/css/app.0e046291.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but Rttys doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.7fd2577a.js"></script><script src="/js/app.79bf330a.js"></script></body></html>

24
run.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
daemon=ucentralgw
if [[ "$1" == "aws" ]]
then
cp ${daemon}.properties.aws ${daemon}.properties
. ./set_env.sh
cd cmake-build
./${daemon} --daemon
echo "Running AWS version as daemon..."
fi
if [[ "$1" == "priv" ]]
then
cp ${daemon}.properties.priv ${daemon}.properties
. ./set_env.sh
cd cmake-build
./${daemon} --daemon
echo "Running private version as daemon..."
fi

View File

@@ -1,806 +0,0 @@
//
// Created by stephane bourque on 2022-02-03.
//
#include "AP_WS_Connection.h"
#include "Poco/Net/SecureStreamSocketImpl.h"
#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/SSLException.h"
#include "Poco/Net/Context.h"
#include "Poco/Base64Decoder.h"
#include "Poco/Net/WebSocketImpl.h"
#include "Poco/zlib.h"
#include "AP_WS_Server.h"
#include "CentralConfig.h"
#include "CommandManager.h"
#include "ConfigurationCache.h"
#include "StorageService.h"
#include "TelemetryStream.h"
#include "framework/KafkaManager.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
#include "UI_GW_WebSocketNotifications.h"
#include "fmt/format.h"
#include "RADIUS_proxy_server.h"
namespace OpenWifi {
#define DBL { std::cout << __LINE__ << " ID: " << ConnectionId_ << " Ser: " << SerialNumber_ << std::endl; }
void AP_WS_Connection::LogException(const Poco::Exception &E) {
poco_information(Logger_,fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
}
AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response,
uint64_t connection_id,
Poco::Logger &L,
Poco::Net::SocketReactor &R)
: Logger_(L) ,
Reactor_(R)
{
State_.sessionId = connection_id;
WS_ = std::make_unique<Poco::Net::WebSocket>(request,response);
auto TS = Poco::Timespan(360, 0);
WS_->setMaxPayloadSize(BufSize);
WS_->setReceiveTimeout(TS);
WS_->setNoDelay(true);
WS_->setKeepAlive(true);
WS_->setBlocking(false);
Reactor_.addEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
*this, &AP_WS_Connection::OnSocketReadable));
Reactor_.addEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
*this, &AP_WS_Connection::OnSocketShutdown));
Reactor_.addEventHandler(
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
*this, &AP_WS_Connection::OnSocketError));
Registered_ = true;
Valid_ = true;
}
bool AP_WS_Connection::ValidatedDevice() {
if(DeviceValidated_)
return true;
if(!Valid_)
return false;
std::lock_guard Lock(ConnectionMutex_);
try {
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(SockImpl->streamSocketImpl());
PeerAddress_ = SS->peerAddress().host();
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
State_.started = Utils::Now();
if (!SS->secure()) {
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is NOT secure. Device is not allowed.", CId_, State_.sessionId ));
EndConnection();
return false;
}
poco_debug(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is secure.", CId_, State_.sessionId ));
if (!SS->havePeerCertificate()) {
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId ));
EndConnection();
return false;
}
Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not valid. Device is not allowed.",
CId_, State_.sessionId ));
EndConnection();
return false;
}
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
poco_debug(Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_, State_.sessionId , CN_));
if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
poco_warning(
Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is not allowed. Disconnecting.",
CId_, State_.sessionId , CN_));
EndConnection();
return false;
}
if (!CN_.empty() && StorageService()->IsBlackListed(CN_)) {
poco_warning(
Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
CId_, State_.sessionId , CN_));
EndConnection();
return false;
}
State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
SerialNumber_ = CN_;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
poco_debug(Logger_, fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, State_.sessionId , CN_, ConcurrentStartingDevices_));
DeviceValidated_ = true;
return true;
} catch (const Poco::Net::CertificateValidationException &E) {
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate Validation failed during connection. Device will have to retry.",
CId_, State_.sessionId ));
Logger_.log(E);
} catch (const Poco::Net::WebSocketException &E) {
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket error during connection. Device will have to retry.",
CId_, State_.sessionId ));
Logger_.log(E);
} catch (const Poco::Net::ConnectionAbortedException &E) {
poco_error(Logger_,fmt::format("CONNECTION({}):Session:{} Poco::ConnectionAbortedException Connection was aborted during connection. Device will have to retry.",
CId_, State_.sessionId ));
Logger_.log(E);
} catch (const Poco::Net::ConnectionResetException &E) {
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection was reset during connection. Device will have to retry.",
CId_, State_.sessionId ));
Logger_.log(E);
} catch (const Poco::Net::InvalidCertificateException &E) {
poco_error(Logger_,fmt::format(
"CONNECTION({}): Session:{} Poco::InvalidCertificateException Invalid certificate. Device will have to retry.",
CId_, State_.sessionId ));
Logger_.log(E);
} catch (const Poco::Net::SSLException &E) {
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception during connection. Device will have to retry.",
CId_, State_.sessionId ));
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::Exception caught during device connection. Device will have to retry.",
CId_, State_.sessionId ));
Logger_.log(E);
} catch (...) {
poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. Device will have to retry. Unsecure connect denied.",
CId_, State_.sessionId ));
}
EndConnection();
return false;
}
static void NotifyKafkaDisconnect(const std::string & SerialNumber) {
try {
Poco::JSON::Object Disconnect;
Poco::JSON::Object Details;
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(Disconnect, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
} catch (...) {
}
}
AP_WS_Connection::~AP_WS_Connection() {
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)) {
// This is the case where the cache is empty after a restart. So GoodConfig will 0. If the device already has the right UUID, we just return.
if (D.UUID == UUID) {
UpgradedUUID = UUID;
ConfigurationCache().Add(SerialNumberInt_, UUID);
return false;
}
if(UUID>D.UUID) {
// so we have a problem, the device has a newer config than we have. So we need to make sure our config
// is newer.
Config::Config Cfg(D.Configuration);
D.UUID = UUID+2;
UpgradedUUID = D.UUID;
Cfg.SetUUID(D.UUID);
D.Configuration = Cfg.get();
StorageService()->UpdateDevice(D);
}
UpgradedUUID = D.UUID;
State_.PendingUUID = D.UUID;
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.UUID = 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(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
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) {
poco_debug(Logger_,fmt::format("RECEIVED-RPC({}): {}.", CId_, Doc->get(uCentralProtocol::ID).toString()));
CommandManager()->PostCommandResult(SerialNumber_, Doc);
}
void AP_WS_Connection::ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc) {
auto Method = Doc->get(uCentralProtocol::METHOD).toString();
auto EventType = uCentralProtocol::Events::EventFromString(Method);
if (EventType == uCentralProtocol::Events::ET_UNKNOWN) {
poco_warning(Logger_,fmt::format("ILLEGAL-PROTOCOL({}): Unknown message type '{}'", CId_, Method));
Errors_++;
return;
}
if (!Doc->isObject(uCentralProtocol::PARAMS)) {
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): params must be an object.", CId_));
Errors_++;
return;
}
// expand params if necessary
auto ParamsObj = Doc->get(uCentralProtocol::PARAMS).extract<Poco::JSON::Object::Ptr>();
if (ParamsObj->has(uCentralProtocol::COMPRESS_64)) {
std::string UncompressedData;
try {
auto CompressedData = ParamsObj->get(uCentralProtocol::COMPRESS_64).toString();
uint64_t compress_sz = 0 ;
if(ParamsObj->has("compress_sz")) {
compress_sz = ParamsObj->get("compress_sz");
}
if (Utils::ExtractBase64CompressedData(CompressedData, UncompressedData, compress_sz)) {
poco_trace(Logger_,fmt::format("EVENT({}): Found compressed payload expanded to '{}'.",
CId_, UncompressedData));
Poco::JSON::Parser Parser;
ParamsObj = Parser.parse(UncompressedData).extract<Poco::JSON::Object::Ptr>();
} else {
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-DATA({}): Compressed cannot be uncompressed - content must be corrupt..: size={}",
CId_, CompressedData.size()));
Errors_++;
return;
}
} catch (const Poco::Exception &E) {
poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-JSON-DATA({}): Compressed cannot be parsed - JSON must be corrupt..",
CId_));
Logger_.log(E);
return;
}
}
if (!ParamsObj->has(uCentralProtocol::SERIAL)) {
poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): Serial number is missing in message.", CId_));
return;
}
auto Serial = Poco::trim(Poco::toLower(ParamsObj->get(uCentralProtocol::SERIAL).toString()));
if (!Utils::ValidSerialNumber(Serial)) {
Poco::Exception E(
fmt::format(
"ILLEGAL-DEVICE-NAME({}): device name is illegal and not allowed to connect.",
Serial),
EACCES);
E.rethrow();
}
if (StorageService()->IsBlackListed(Serial)) {
Poco::Exception E(
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
Serial),
EACCES);
E.rethrow();
}
switch (EventType) {
case uCentralProtocol::Events::ET_CONNECT: {
Process_connect(ParamsObj, Serial);
} break;
case uCentralProtocol::Events::ET_STATE: {
Process_state(ParamsObj);
} break;
case uCentralProtocol::Events::ET_HEALTHCHECK: {
Process_healthcheck(ParamsObj);
} break;
case uCentralProtocol::Events::ET_LOG: {
Process_log(ParamsObj);
} break;
case uCentralProtocol::Events::ET_CRASHLOG: {
Process_crashlog(ParamsObj);
} break;
case uCentralProtocol::Events::ET_PING: {
Process_ping(ParamsObj);
} break;
case uCentralProtocol::Events::ET_CFGPENDING: {
Process_cfgpending(ParamsObj);
} break;
case uCentralProtocol::Events::ET_RECOVERY: {
Process_recovery(ParamsObj);
} break;
case uCentralProtocol::Events::ET_DEVICEUPDATE: {
Process_deviceupdate(ParamsObj, Serial);
} break;
case uCentralProtocol::Events::ET_TELEMETRY: {
Process_telemetry(ParamsObj);
} break;
case uCentralProtocol::Events::ET_VENUEBROADCAST: {
Process_venuebroadcast(ParamsObj);
} break;
// this will never be called but some compilers will complain if we do not have a case for
// every single values of an enum
case uCentralProtocol::Events::ET_UNKNOWN: {
poco_warning(Logger_, fmt::format("ILLEGAL-EVENT({}): Event '{}' unknown. CN={}", CId_, Method, CN_));
Errors_++;
}
}
}
bool AP_WS_Connection::StartTelemetry(uint64_t RPCID) {
poco_information(Logger_, fmt::format("TELEMETRY({}): Starting.", CId_));
Poco::JSON::Object StartMessage;
StartMessage.set("jsonrpc", "2.0");
StartMessage.set("method", "telemetry");
Poco::JSON::Object Params;
Params.set("serial", SerialNumber_);
Params.set("interval", (uint64_t)TelemetryInterval_);
Poco::JSON::Array Types;
Types.add("wifi-frames");
Types.add("dhcp-snooping");
Types.add("state");
Params.set(RESTAPI::Protocol::TYPES, Types);
StartMessage.set("id", RPCID);
StartMessage.set("params", Params);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(StartMessage, OS);
return Send(OS.str());
}
bool AP_WS_Connection::StopTelemetry(uint64_t RPCID) {
poco_information(Logger_, fmt::format("TELEMETRY({}): Stopping.", CId_));
Poco::JSON::Object StopMessage;
StopMessage.set("jsonrpc", "2.0");
StopMessage.set("method", "telemetry");
Poco::JSON::Object Params;
Params.set("serial", SerialNumber_);
Params.set("interval", 0);
StopMessage.set("id", RPCID);
StopMessage.set("params", Params);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(StopMessage, OS);
TelemetryKafkaPackets_ = TelemetryWebSocketPackets_ = TelemetryInterval_ =
TelemetryKafkaTimer_ = TelemetryWebSocketTimer_ = 0;
return Send(OS.str());
}
void AP_WS_Connection::UpdateCounts() {
State_.kafkaClients = TelemetryKafkaRefCount_;
State_.webSocketClients = TelemetryWebSocketRefCount_;
}
bool AP_WS_Connection::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t Interval,
uint64_t LifeTime) {
std::unique_lock Lock(TelemetryMutex_);
TelemetryWebSocketRefCount_++;
TelemetryInterval_ = TelemetryInterval_ ? ( Interval< TelemetryInterval_ ? Interval : TelemetryInterval_) : Interval;
auto TelemetryWebSocketTimer = LifeTime + Utils::Now();
TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > TelemetryWebSocketTimer_ ? TelemetryWebSocketTimer : TelemetryWebSocketTimer_;
UpdateCounts();
if (!TelemetryReporting_) {
TelemetryReporting_ = true;
return StartTelemetry(RPCID);
}
return true;
}
bool AP_WS_Connection::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t Interval, uint64_t LifeTime) {
std::unique_lock Lock(TelemetryMutex_);
TelemetryKafkaRefCount_++;
TelemetryInterval_ = TelemetryInterval_ ? ( Interval<TelemetryInterval_ ? Interval : TelemetryInterval_) : Interval;
auto TelemetryKafkaTimer = LifeTime + Utils::Now();
TelemetryKafkaTimer_ = TelemetryKafkaTimer > TelemetryKafkaTimer_ ? TelemetryKafkaTimer : TelemetryKafkaTimer_;
UpdateCounts();
if (!TelemetryReporting_) {
TelemetryReporting_ = true;
return StartTelemetry(RPCID);
}
return true;
}
bool AP_WS_Connection::StopWebSocketTelemetry(uint64_t RPCID) {
std::unique_lock Lock(TelemetryMutex_);
if (TelemetryWebSocketRefCount_)
TelemetryWebSocketRefCount_--;
UpdateCounts();
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
TelemetryReporting_ = false;
StopTelemetry(RPCID);
}
return true;
}
bool AP_WS_Connection::StopKafkaTelemetry(uint64_t RPCID) {
std::unique_lock Lock(TelemetryMutex_);
if (TelemetryKafkaRefCount_)
TelemetryKafkaRefCount_--;
UpdateCounts();
if (TelemetryWebSocketRefCount_ == 0 && TelemetryKafkaRefCount_ == 0) {
TelemetryReporting_ = false;
StopTelemetry(RPCID);
}
return true;
}
void AP_WS_Connection::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
return EndConnection();
}
void AP_WS_Connection::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
return EndConnection();
}
void AP_WS_Connection::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
if(!Valid_)
return;
if(!AP_WS_Server()->Running())
return EndConnection();
if(!ValidatedDevice())
return;
try {
return ProcessIncomingFrame();
} catch (const Poco::Exception &E) {
Logger_.log(E);
return EndConnection();
} catch (const std::exception &E) {
std::string W = E.what();
poco_information(Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_));
return EndConnection();
} catch (...) {
poco_information(Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_));
return EndConnection();
}
}
void AP_WS_Connection::ProcessIncomingFrame() {
Poco::Buffer<char> IncomingFrame(0);
try {
int Op, flags;
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
if (IncomingSize == 0 && flags == 0 && Op == 0) {
poco_information(Logger_, fmt::format("DISCONNECT({}): device has disconnected. Session={}", CId_, State_.sessionId));
return EndConnection();
}
IncomingFrame.append(0);
State_.RX += IncomingSize;
State_.MessageCount++;
State_.LastContact = Utils::Now();
switch (Op) {
case Poco::Net::WebSocket::FRAME_OP_PING: {
poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_));
WS_->sendFrame("", 0,
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
if (KafkaManager()->Enabled()) {
Poco::JSON::Object PingObject;
Poco::JSON::Object PingDetails;
PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware);
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
PingDetails.set("locale", State_.locale );
PingObject.set(uCentralProtocol::PING, PingDetails);
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(PingObject, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
}
return;
} break;
case Poco::Net::WebSocket::FRAME_OP_PONG: {
poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
return;
} break;
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
poco_trace(Logger_, fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", CId_,
IncomingSize, flags, IncomingFrame.begin()));
Poco::JSON::Parser parser;
auto ParsedMessage = parser.parse(IncomingFrame.begin());
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
if (IncomingJSON->has(uCentralProtocol::METHOD) &&
IncomingJSON->has(uCentralProtocol::PARAMS)) {
ProcessJSONRPCEvent(IncomingJSON);
} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
IncomingJSON->has(uCentralProtocol::ID)) {
poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, IncomingFrame.begin()));
ProcessJSONRPCResult(IncomingJSON);
} else {
poco_warning(Logger_,
fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
CId_, IncomingFrame.begin()));
}
} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
ProcessIncomingRadiusData(IncomingJSON);
} else {
std::ostringstream iS;
IncomingJSON->stringify(iS);
std::cout << iS.str() << std::endl;
poco_warning(Logger_, fmt::format(
"FRAME({}): illegal transaction header, missing 'jsonrpc'", CId_));
Errors_++;
}
return;
} break;
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
poco_information(Logger_,
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
return EndConnection();
} break;
default: {
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", CId_,
std::to_string(Op)));
} break;
}
} catch (const Poco::Net::ConnectionResetException &E) {
poco_warning(Logger_, fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const Poco::JSON::JSONException &E) {
poco_warning(Logger_, fmt::format("JSONException({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const Poco::Net::WebSocketException &E) {
poco_warning(Logger_, fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
poco_warning(Logger_, fmt::format("SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const Poco::Net::SSLException &E) {
poco_warning(Logger_, fmt::format("SSLException({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const Poco::Net::NetException &E) {
poco_warning(Logger_, fmt::format("NetException({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const Poco::IOException &E) {
poco_warning(Logger_, fmt::format("IOException({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const Poco::Exception &E) {
poco_warning(Logger_, fmt::format("Exception({}): Text:{} Payload:{} Session:{}",
CId_,
E.displayText(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (const std::exception &E) {
poco_warning(Logger_, fmt::format("std::exception({}): Text:{} Payload:{} Session:{}",
CId_,
E.what(),
IncomingFrame.begin()==nullptr ? "" : IncomingFrame.begin(),
State_.sessionId));
return EndConnection();
} catch (...) {
poco_error(Logger_,fmt::format("UnknownException({}): Device must be disconnected. Unknown exception. Session:{}", CId_, State_.sessionId));
return EndConnection();
}
if (Errors_ < 10)
return;
poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_));
return EndConnection();
}
bool AP_WS_Connection::Send(const std::string &Payload) {
try {
size_t BytesSent = WS_->sendFrame(Payload.c_str(), (int)Payload.size());
State_.TX += BytesSent;
return BytesSent == Payload.size();
} catch(const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
std::string Base64Encode(const unsigned char *buffer, std::size_t size) {
return Utils::base64encode(buffer,size);
}
std::string Base64Decode(const std::string &F) {
std::istringstream ifs(F);
Poco::Base64Decoder b64in(ifs);
std::ostringstream ofs;
Poco::StreamCopier::copyStream(b64in, ofs);
return ofs.str();
}
bool AP_WS_Connection::SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size) {
Poco::JSON::Object Answer;
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSAUTH);
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
std::ostringstream Payload;
Answer.stringify(Payload);
return Send(Payload.str());
}
bool AP_WS_Connection::SendRadiusAccountingData(const unsigned char * buffer, std::size_t size) {
Poco::JSON::Object Answer;
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSACCT);
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
std::ostringstream Payload;
Answer.stringify(Payload);
return Send(Payload.str());
}
bool AP_WS_Connection::SendRadiusCoAData(const unsigned char * buffer, std::size_t size) {
Poco::JSON::Object Answer;
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSCOA);
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
std::ostringstream Payload;
Answer.stringify(Payload);
return Send(Payload.str());
}
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
if( Doc->has(uCentralProtocol::RADIUSDATA)) {
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();
if(Type==uCentralProtocol::RADIUSACCT) {
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
auto DecodedData = Base64Decode(Data);
RADIUS_proxy_server()->SendAccountingData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
} else if(Type==uCentralProtocol::RADIUSAUTH) {
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
auto DecodedData = Base64Decode(Data);
RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
} else if(Type==uCentralProtocol::RADIUSCOA) {
auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
auto DecodedData = Base64Decode(Data);
RADIUS_proxy_server()->SendCoAData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
}
}
}
}

View File

@@ -1,162 +0,0 @@
//
// Created by stephane bourque on 2022-02-03.
//
#pragma once
#include <string>
#include <shared_mutex>
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/JSON/Object.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Logger.h"
#include "Poco/Net/WebSocket.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "AP_restrictions.h"
namespace OpenWifi {
class AP_WS_Connection {
static constexpr int BufSize = 256000;
public:
explicit AP_WS_Connection( Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response,
uint64_t connection_id,
Poco::Logger &L,
Poco::Net::SocketReactor &R);
~AP_WS_Connection();
void EndConnection();
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr & Doc);
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
void ProcessIncomingFrame();
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
bool Send(const std::string &Payload);
bool SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size);
bool SendRadiusAccountingData(const unsigned char * buffer, std::size_t size);
bool SendRadiusCoAData(const unsigned char * buffer, std::size_t size);
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf);
bool LookForUpgrade(uint64_t UUID, uint64_t & UpgradedUUID);
static bool ExtractBase64CompressedData(const std::string & CompressedData, std::string & UnCompressedData, uint64_t compress_sz);
void LogException(const Poco::Exception &E);
inline Poco::Logger & Logger() { return Logger_; }
bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval, uint64_t TelemetryWebSocketTimer);
bool SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t interval, uint64_t TelemetryKafkaTimer);
bool StopWebSocketTelemetry(uint64_t RPCID);
bool StopKafkaTelemetry(uint64_t RPCID);
inline void GetLastStats(std::string &LastStats) const {
std::shared_lock G(ConnectionMutex_);
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) {
std::shared_lock G(ConnectionMutex_);
H = RawLastHealthcheck_;
}
inline void GetState(GWObjects::ConnectionState &State) const {
std::shared_lock G(ConnectionMutex_);
State = State_;
}
inline void GetRestrictions(AP_Restrictions & R) const {
std::shared_lock G(ConnectionMutex_);
R = Restrictions_;
}
void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
void Process_state(Poco::JSON::Object::Ptr ParamsObj);
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
bool ValidatedDevice();
inline bool GetTelemetryParameters(bool & Reporting, uint64_t & Interval,
uint64_t & WebSocketTimer, uint64_t & KafkaTimer,
uint64_t &WebSocketCount, uint64_t & KafkaCount,
uint64_t &WebSocketPackets,
uint64_t &KafkaPackets ) const {
Reporting = TelemetryReporting_;
WebSocketTimer = TelemetryWebSocketTimer_;
KafkaTimer = TelemetryKafkaTimer_;
WebSocketCount = TelemetryWebSocketRefCount_;
KafkaCount = TelemetryKafkaRefCount_;
Interval = TelemetryInterval_;
WebSocketPackets = TelemetryWebSocketPackets_;
KafkaPackets = TelemetryKafkaPackets_;
return true;
}
friend class AP_WS_Server;
inline AP_Restrictions Restrictions() const {
std::shared_lock G(ConnectionMutex_);
return Restrictions_;
}
private:
mutable std::shared_mutex ConnectionMutex_;
std::shared_mutex TelemetryMutex_;
Poco::Logger &Logger_;
Poco::Net::SocketReactor &Reactor_;
std::unique_ptr<Poco::Net::WebSocket> WS_;
std::string SerialNumber_;
uint64_t SerialNumberInt_=0;
std::string Compatible_;
std::atomic_bool Registered_ = false ;
std::string CId_;
std::string CN_;
uint64_t Errors_=0;
Poco::Net::IPAddress PeerAddress_;
volatile bool TelemetryReporting_ = false;
volatile uint64_t TelemetryWebSocketRefCount_ = 0;
volatile uint64_t TelemetryKafkaRefCount_ = 0;
volatile uint64_t TelemetryWebSocketTimer_ = 0;
volatile uint64_t TelemetryKafkaTimer_ = 0 ;
volatile uint64_t TelemetryInterval_ = 0;
volatile uint64_t TelemetryWebSocketPackets_=0;
volatile uint64_t TelemetryKafkaPackets_=0;
GWObjects::ConnectionState State_;
std::string RawLastStats_;
GWObjects::HealthCheck RawLastHealthcheck_;
std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
std::atomic_flag Dead_=false;
std::atomic_bool DeviceValidated_=false;
std::atomic_bool Valid_=false;
AP_Restrictions Restrictions_;
static inline std::atomic_uint64_t ConcurrentStartingDevices_=0;
bool StartTelemetry(uint64_t RPCID);
bool StopTelemetry(uint64_t RPCID);
void UpdateCounts();
};
}

View File

@@ -1,26 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "fmt/format.h"
#include "framework/ow_constants.h"
namespace OpenWifi {
void AP_WS_Connection::Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj) {
if (!State_.Connected) {
poco_warning(Logger_, fmt::format(
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
Errors_++;
return;
}
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::ACTIVE)) {
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
[[maybe_unused]] uint64_t Active = ParamsObj->get(uCentralProtocol::ACTIVE);
poco_trace(Logger_, fmt::format("CFG-PENDING({}): Active: {} Target: {}", CId_, Active, UUID));
} else {
poco_warning(Logger_, fmt::format("CFG-PENDING({}): Missing some parameters", CId_));
}
}
}

View File

@@ -1,159 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "AP_WS_Server.h"
#include "StorageService.h"
#include "FindCountry.h"
#include "Daemon.h"
#include "CentralConfig.h"
#include "CommandManager.h"
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "UI_GW_WebSocketNotifications.h"
namespace OpenWifi {
void AP_WS_Connection::Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial) {
if (ParamsObj->has(uCentralProtocol::UUID) &&
ParamsObj->has(uCentralProtocol::FIRMWARE) &&
ParamsObj->has(uCentralProtocol::CAPABILITIES)) {
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
auto Capabilities = ParamsObj->getObject(uCentralProtocol::CAPABILITIES);
SerialNumber_ = Serial;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
CommandManager()->ClearQueue(SerialNumberInt_);
AP_WS_Server()->SetSessionDetails(State_.sessionId,SerialNumberInt_);
std::lock_guard Lock(ConnectionMutex_);
Config::Capabilities Caps(Capabilities);
Compatible_ = Caps.Compatible();
State_.UUID = UUID;
State_.Firmware = Firmware;
State_.PendingUUID = 0;
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
CId_ = SerialNumber_ + "@" + CId_;
auto IP = PeerAddress_.toString();
if(IP.substr(0,7)=="::ffff:") {
IP = IP.substr(7);
}
bool RestrictedDevice = false;
if(ParamsObj->has("restricted") && ParamsObj->get("restricted").isBoolean()) {
RestrictedDevice = true;
if(Capabilities->has("restrictions")) {
auto RestrictionObject = Capabilities->getObject("restrictions");
Restrictions_.initialize(Logger_, SerialNumber_, RestrictionObject);
}
}
State_.locale = FindCountryFromIP()->Get(IP);
GWObjects::Device DeviceInfo;
auto DeviceExists = StorageService()->GetDevice(SerialNumber_,DeviceInfo);
if (Daemon()->AutoProvisioning() && !DeviceExists) {
StorageService()->CreateDefaultDevice(SerialNumber_, Caps, Firmware, PeerAddress_);
} else if (DeviceExists) {
StorageService()->UpdateDeviceCapabilities(SerialNumber_, Caps );
int Updated{0};
if(!Firmware.empty()) {
if(Firmware!=DeviceInfo.Firmware) {
DeviceInfo.Firmware = Firmware;
DeviceInfo.LastFWUpdate = Utils::Now();
++Updated;
GWWebSocketNotifications::SingleDeviceFirmwareChange_t Notification;
Notification.content.serialNumber = SerialNumber_;
Notification.content.newFirmware = Firmware;
GWWebSocketNotifications::DeviceFirmwareUpdated(Notification);
} else if(DeviceInfo.LastFWUpdate==0) {
DeviceInfo.LastFWUpdate = Utils::Now();
++Updated;
}
}
if(DeviceInfo.locale != State_.locale) {
DeviceInfo.locale = State_.locale;
++Updated;
}
if(Compatible_ != DeviceInfo.DeviceType) {
DeviceInfo.DeviceType = Compatible_;
++Updated;
}
if(RestrictedDevice != DeviceInfo.restrictedDevice) {
DeviceInfo.restrictedDevice = RestrictedDevice;
++Updated;
}
if(Updated) {
StorageService()->UpdateDevice(DeviceInfo);
}
uint64_t UpgradedUUID=0;
LookForUpgrade(UUID,UpgradedUUID);
State_.UUID = UpgradedUUID;
}
State_.Compatible = Compatible_;
State_.Connected = true;
ConnectionCompletionTime_ = std::chrono::high_resolution_clock::now() - ConnectionStart_;
State_.connectionCompletionTime = ConnectionCompletionTime_.count();
if(State_.VerifiedCertificate == GWObjects::VALID_CERTIFICATE) {
if (( Utils::SerialNumberMatch(CN_, SerialNumber_, AP_WS_Server()->MismatchDepth())) ||
AP_WS_Server()->IsSimSerialNumber(CN_)) {
State_.VerifiedCertificate = GWObjects::VERIFIED;
poco_information(Logger_, fmt::format("CONNECT({}): Fully validated and authenticated device. Session={} ConnectionCompletion Time={}",
CId_,
State_.sessionId,
State_.connectionCompletionTime ));
} else {
State_.VerifiedCertificate = GWObjects::MISMATCH_SERIAL;
if(AP_WS_Server()->AllowSerialNumberMismatch()) {
poco_information(
Logger_, fmt::format("CONNECT({}): Serial number mismatch allowed. CN={} Serial={} Session={} ConnectionCompletion Time={}",
CId_, CN_, SerialNumber_, State_.sessionId,
State_.connectionCompletionTime));
} else {
poco_information(
Logger_, fmt::format("CONNECT({}): Serial number mismatch disallowed. Device rejected. CN={} Serial={} Session={} ConnectionCompletion Time={}",
CId_, CN_, SerialNumber_, State_.sessionId,
State_.connectionCompletionTime));
return EndConnection();
}
}
}
GWWebSocketNotifications::SingleDevice_t Notification;
Notification.content.serialNumber = SerialNumber_;
GWWebSocketNotifications::DeviceConnected(Notification);
// std::cout << "Serial: " << SerialNumber_ << "Session: " << State_.sessionId << std::endl;
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
ParamsObj->set("locale", State_.locale );
ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
}
} else {
poco_warning(Logger_,fmt::format("INVALID-PROTOCOL({}): Missing one of uuid, firmware, or capabilities", CId_));
Errors_++;
}
}
}

View File

@@ -1,38 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "framework/utils.h"
#include "framework/ow_constants.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
poco_trace(Logger_, fmt::format("CRASH-LOG({}): new entry.", CId_));
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
std::string LogText;
if (LogLines.isArray()) {
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
for (const auto &i : *LogLinesArray)
LogText += i.toString() + "\r\n";
}
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
.Log = LogText,
.Data = "",
.Severity = GWObjects::DeviceLog::LOG_EMERG,
.Recorded = (uint64_t)time(nullptr),
.LogType = 1,
.UUID = 0};
StorageService()->AddLog(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
return;
}
}
}

View File

@@ -1,27 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_Connection::Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial) {
if (!State_.Connected) {
poco_warning(Logger_, fmt::format(
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
Errors_++;
return;
}
if (ParamsObj->has("currentPassword")) {
auto Password = ParamsObj->get("currentPassword").toString();
StorageService()->SetDevicePassword(Serial, Password);
poco_trace(Logger_, fmt::format("DEVICEUPDATE({}): Device is updating its login password.", Serial));
}
}
}

View File

@@ -1,74 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
if (!State_.Connected) {
poco_warning(Logger_, fmt::format(
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
Errors_++;
return;
}
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
ParamsObj->has(uCentralProtocol::DATA)) {
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
if (CheckData.empty())
CheckData = uCentralProtocol::EMPTY_JSON_DOC;
std::string request_uuid;
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
if (request_uuid.empty()) {
poco_trace(Logger_,
fmt::format("HEALTHCHECK({}): UUID={} Updating.", CId_, UUID));
} else {
poco_trace(Logger_,
fmt::format("HEALTHCHECK({}): UUID={} Updating for CMD={}.", CId_,
UUID, request_uuid));
}
uint64_t UpgradedUUID;
LookForUpgrade(UUID,UpgradedUUID);
State_.UUID = UpgradedUUID;
GWObjects::HealthCheck Check;
Check.SerialNumber = SerialNumber_;
Check.Recorded = Utils::Now();
Check.UUID = UUID;
Check.Data = CheckData;
Check.Sanity = Sanity;
StorageService()->AddHealthCheckData(Check);
if (!request_uuid.empty()) {
StorageService()->SetCommandResult(request_uuid, CheckData);
}
SetLastHealthCheck(Check);
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
ParamsObj->set("timestamp", Utils::Now());
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
}
} else {
poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));
return;
}
}
}

View File

@@ -1,44 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
if (!State_.Connected) {
poco_warning(
Logger_,
fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
Errors_++;
return;
}
if (ParamsObj->has(uCentralProtocol::LOG) && ParamsObj->has(uCentralProtocol::SEVERITY)) {
poco_trace(Logger_, fmt::format("LOG({}): new entry.", CId_));
auto Log = ParamsObj->get(uCentralProtocol::LOG).toString();
auto Severity = ParamsObj->get(uCentralProtocol::SEVERITY);
std::string DataStr = uCentralProtocol::EMPTY_JSON_DOC;
if (ParamsObj->has(uCentralProtocol::DATA)) {
auto DataObj = ParamsObj->get(uCentralProtocol::DATA);
if (DataObj.isStruct())
DataStr = DataObj.toString();
}
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
.Log = Log,
.Data = DataStr,
.Severity = Severity,
.Recorded = (uint64_t)time(nullptr),
.LogType = 0,
.UUID = State_.UUID};
StorageService()->AddLog(DeviceLog);
} else {
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
return;
}
}
}

View File

@@ -1,18 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "fmt/format.h"
#include "framework/ow_constants.h"
namespace OpenWifi {
void AP_WS_Connection::Process_ping(Poco::JSON::Object::Ptr ParamsObj) {
if (ParamsObj->has(uCentralProtocol::UUID)) {
[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
poco_trace(Logger_, fmt::format("PING({}): Current config is {}", CId_, UUID));
} else {
poco_warning(Logger_, fmt::format("PING({}): Missing parameter.", CId_));
}
}
}

View File

@@ -1,66 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "CommandManager.h"
#include "framework/ow_constants.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_Connection::Process_recovery(Poco::JSON::Object::Ptr ParamsObj) {
if (ParamsObj->has(uCentralProtocol::SERIAL) &&
ParamsObj->has(uCentralProtocol::FIRMWARE) && ParamsObj->has(uCentralProtocol::UUID) &&
ParamsObj->has(uCentralProtocol::REBOOT) &&
ParamsObj->has(uCentralProtocol::LOGLINES)) {
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
std::string LogText;
LogText = "Firmware: " + ParamsObj->get(uCentralProtocol::FIRMWARE).toString() + "\r\n";
if (LogLines.isArray()) {
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
for (const auto &i : *LogLinesArray)
LogText += i.toString() + "\r\n";
}
GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
.Log = LogText,
.Data = "",
.Severity = GWObjects::DeviceLog::LOG_EMERG,
.Recorded = (uint64_t)time(nullptr),
.LogType = 1,
.UUID = 0};
StorageService()->AddLog(DeviceLog);
if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.UUID = MicroServiceCreateUUID();
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
Cmd.Status = uCentralProtocol::PENDING;
Cmd.Command = uCentralProtocol::REBOOT;
Poco::JSON::Object Params;
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
Params.set(uCentralProtocol::WHEN, 0);
std::ostringstream O;
Poco::JSON::Stringifier::stringify(Params, O);
Cmd.Details = O.str();
bool Sent;
CommandManager()->PostCommand(CommandManager()->Next_RPC_ID(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
poco_information(Logger_, fmt::format("RECOVERY({}): Recovery mode received, need for a reboot.", CId_));
} else {
poco_information(Logger_, fmt::format(
"RECOVERY({}): Recovery mode received, no need for a reboot.", CId_));
}
} else {
poco_warning(Logger_, fmt::format("RECOVERY({}): Recovery missing one of serialnumber, firmware, uuid, loglines, reboot",
CId_));
}
}
}

View File

@@ -1,74 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "StateUtils.h"
#include "UI_GW_WebSocketNotifications.h"
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_Connection::Process_state(Poco::JSON::Object::Ptr ParamsObj) {
if (!State_.Connected) {
poco_warning(Logger_, fmt::format(
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
Errors_++;
return;
}
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::STATE)) {
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
auto StateStr = ParamsObj->get(uCentralProtocol::STATE).toString();
auto StateObj = ParamsObj->getObject(uCentralProtocol::STATE);
std::string request_uuid;
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
if (request_uuid.empty()) {
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating.", CId_, UUID));
} else {
poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating for CMD={}.",
CId_, UUID, request_uuid));
}
uint64_t UpgradedUUID;
LookForUpgrade(UUID,UpgradedUUID);
State_.UUID = UpgradedUUID;
SetLastStats(StateStr);
GWObjects::Statistics Stats{
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
Stats.Recorded = Utils::Now();
StorageService()->AddStatisticsData(Stats);
if (!request_uuid.empty()) {
StorageService()->SetCommandResult(request_uuid, StateStr);
}
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
State_.Associations_5G,
State_.Associations_6G
);
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
}
GWWebSocketNotifications::SingleDevice_t N;
N.content.serialNumber = SerialNumber_;
GWWebSocketNotifications::DeviceStatistics(N);
} else {
poco_warning(Logger_, fmt::format("STATE({}): Invalid request. Missing serial, uuid, or state", CId_));
}
}
}

View File

@@ -1,59 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "TelemetryStream.h"
#include "CommandManager.h"
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_Connection::Process_telemetry(Poco::JSON::Object::Ptr ParamsObj) {
if (!State_.Connected) {
poco_warning(Logger_, fmt::format(
"INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
Errors_++;
return;
}
poco_trace(Logger_,fmt::format("Telemetry data received for {}", SerialNumber_));
if (TelemetryReporting_) {
if (ParamsObj->has("data")) {
auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
Payload->set("timestamp", Utils::Now());
std::ostringstream SS;
Payload->stringify(SS);
auto now=Utils::Now();
if (TelemetryWebSocketRefCount_) {
if(now<TelemetryWebSocketTimer_) {
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
TelemetryWebSocketPackets_++;
State_.websocketPackets = TelemetryWebSocketPackets_;
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, SS.str());
} else {
StopWebSocketTelemetry(CommandManager()->Next_RPC_ID());
}
}
if (TelemetryKafkaRefCount_) {
if(KafkaManager()->Enabled() && now<TelemetryKafkaTimer_) {
// std::cout << SerialNumber_ << ": Updating Kafka telemetry" << std::endl;
TelemetryKafkaPackets_++;
State_.kafkaPackets = TelemetryKafkaPackets_;
KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
SS.str());
} else {
StopKafkaTelemetry(CommandManager()->Next_RPC_ID());
}
}
} else {
poco_debug(Logger_,fmt::format("TELEMETRY({}): Invalid telemetry packet.",SerialNumber_));
}
} else {
// if we are ignoring telemetry, then close it down on the device.
poco_debug(Logger_,fmt::format("TELEMETRY({}): Stopping runaway telemetry.",SerialNumber_));
StopTelemetry(CommandManager()->Next_RPC_ID());
}
}
}

View File

@@ -1,17 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "VenueBroadcaster.h"
namespace OpenWifi {
void AP_WS_Connection::Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj) {
if(ParamsObj->has("data") && ParamsObj->has("serial") && ParamsObj->has("timestamp")) {
VenueBroadcaster()->Broadcast(
ParamsObj->get("serial").toString(),
ParamsObj->get("data").toString(),
ParamsObj->get("timestamp"));
}
}
}

View File

@@ -1,477 +0,0 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
//
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "AP_WS_Server.h"
#include "AP_WS_Connection.h"
#include "ConfigurationCache.h"
#include "TelemetryStream.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
#include "UI_GW_WebSocketNotifications.h"
#include "fmt/format.h"
namespace OpenWifi {
void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response) {
try {
AP_WS_Server()->AddConnection(id_,std::make_shared<AP_WS_Connection>(request,response,id_, Logger_, AP_WS_Server()->NextReactor()));
} catch (...) {
poco_warning(Logger_,"Exception during WS creation");
}
};
bool AP_WS_Server::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
if(IsCertOk()) {
if(!Certificate.issuedBy(*IssuerCert_)) {
poco_warning(Logger(),fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
return false;
}
return true;
}
return false;
}
int AP_WS_Server::Start() {
AllowSerialNumberMismatch_ = MicroServiceConfigGetBool("openwifi.certificates.allowmismatch",true);
MismatchDepth_ = MicroServiceConfigGetInt("openwifi.certificates.mismatchdepth",2);
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
Reactor_pool_->Start();
for(const auto & Svr : ConfigServersList_ ) {
poco_notice(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(),
Svr.Port(), Svr.KeyFile(), Svr.CertFile()));
Svr.LogCert(Logger());
if (!Svr.RootCA().empty())
Svr.LogCas(Logger());
if (!IsCertOk()) {
IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
poco_information(Logger(),
fmt::format("Certificate Issuer Name:{}", IssuerCert_->issuerName()));
}
Poco::Net::Context::Params P;
P.verificationMode = Poco::Net::Context::VERIFY_ONCE;
P.verificationDepth = 9;
P.loadDefaultCAs = Svr.RootCA().empty();
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
P.caLocation = Svr.Cas();
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
/* if(!Svr.KeyFilePassword().empty()) {
auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(Svr.KeyFilePassword(),Logger()));
Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr,Context);
}
*/
Poco::Crypto::X509Certificate Cert(Svr.CertFile());
Poco::Crypto::X509Certificate Root(Svr.RootCA());
Context->useCertificate(Cert);
Context->addChainCertificate(Root);
Context->addCertificateAuthority(Root);
Poco::Crypto::X509Certificate Issuing(Svr.IssuerCertFile());
Context->addChainCertificate(Issuing);
Context->addCertificateAuthority(Issuing);
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
Context->usePrivateKey(Key);
Context->setSessionCacheSize(0);
Context->setSessionTimeout(120);
Context->flushSessionCache();
Context->enableSessionCache(true);
Context->enableExtendedCertificateVerification(false);
// Context->disableStatelessSessionResumption();
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 | Poco::Net::Context::PROTO_TLSV1_1);
auto WebServerHttpParams = new Poco::Net::HTTPServerParams;
WebServerHttpParams->setMaxThreads(50);
WebServerHttpParams->setMaxQueued(200);
WebServerHttpParams->setKeepAlive(true);
WebServerHttpParams->setName("ws:ap_dispatch");
if (Svr.Address() == "*") {
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
: Poco::Net::AddressFamily::IPv4));
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
WebServers_.push_back(std::move(NewWebServer));
} else {
Poco::Net::IPAddress Addr(Svr.Address());
Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
WebServers_.push_back(std::move(NewWebServer));
}
}
for(auto &server:WebServers_) {
server->start();
}
ReactorThread_.start(Reactor_);
auto ProvString = MicroServiceConfigGetString("autoprovisioning.process","default");
if(ProvString!="default") {
auto Tokens = Poco::StringTokenizer(ProvString, ",");
for (const auto &i : Tokens) {
if (i == "prov")
LookAtProvisioning_ = true;
else
UseDefaultConfig_ = true;
}
} else {
UseDefaultConfig_ = true;
}
SimulatorId_ = MicroServiceConfigGetString("simulatorid","");
SimulatorEnabled_ = !SimulatorId_.empty();
Utils::SetThreadName(ReactorThread_,"dev:react:head");
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(*this,&AP_WS_Server::onGarbageCollecting);
Timer_.setStartInterval(10 * 1000);
Timer_.setPeriodicInterval(5 * 1000); // every minute
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
Running_ = true;
return 0;
}
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
std::lock_guard Lock(WSServerMutex_);
if(!Garbage_.empty()) {
Garbage_.clear();
}
static uint64_t last_log = Utils::Now();
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
uint64_t total_connected_time=0;
auto now = Utils::Now();
for (const auto & connection:SerialNumbers_) {
if(connection.second.second == nullptr) {
continue;
}
if (connection.second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - connection.second.second->State_.started);
} else {
NumberOfConnectingDevices_++;
}
}
AverageDeviceConnectionTime_ = (NumberOfConnectedDevices_!=0) ? total_connected_time/NumberOfConnectedDevices_ : 0;
if((now-last_log)>120) {
last_log = now;
poco_information(Logger(),
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
NumberOfConnectedDevices_, NumberOfConnectingDevices_, AverageDeviceConnectionTime_));
}
GWWebSocketNotifications::NumberOfConnection_t Notification;
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
GWWebSocketNotifications::NumberOfConnections(Notification);
}
void AP_WS_Server::Stop() {
poco_information(Logger(),"Stopping...");
Running_ = false;
Timer_.stop();
for(auto &server:WebServers_) {
server->stopAll();
}
Reactor_pool_->Stop();
Reactor_.stop();
ReactorThread_.join();
poco_information(Logger(),"Stopped...");
}
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
DevicePtr->GetLastStats(Statistics);
return true;
}
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
DevicePtr->GetState(State);
return true;
}
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
DevicePtr->GetLastHealthCheck(CheckData);
return true;
}
void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
std::lock_guard Lock(WSServerMutex_);
auto Conn = Sessions_.find(connection_id);
if(Conn == end(Sessions_))
return;
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
if( (CurrentSerialNumber==SerialNumbers_.end()) ||
(CurrentSerialNumber->second.first<connection_id)) {
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second);
return;
}
}
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t serial_number) {
std::lock_guard G(WSServerMutex_);
auto Session = Sessions_.find(session_id);
if(Session==end(Sessions_))
return false;
Garbage_.push_back(Session->second);
auto Device = SerialNumbers_.find(serial_number);
if (Device == end(SerialNumbers_)) {
Sessions_.erase(Session);
return false;
}
if(Device->second.first==session_id) {
Sessions_.erase(Session);
SerialNumbers_.erase(Device);
return true;
}
Sessions_.erase(Session);
return false;
}
bool AP_WS_Server::Connected(uint64_t SerialNumber, AP_Restrictions & Restrictions) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
DevicePtr->GetRestrictions(Restrictions);
return DevicePtr->State_.Connected;
}
bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
return DevicePtr->State_.Connected;
}
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string & Payload) const {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return DevicePtr->Send(Payload);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber)));
}
return false;
}
void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
DevicePtr->StopWebSocketTelemetry(RPCID);
}
void AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
DevicePtr->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
}
void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
DevicePtr->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
}
void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
DevicePtr->StopKafkaTelemetry(RPCID);
}
void AP_WS_Server::GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
uint64_t & TelemetryInterval,
uint64_t & TelemetryWebSocketTimer,
uint64_t & TelemetryKafkaTimer,
uint64_t & TelemetryWebSocketCount,
uint64_t & TelemetryKafkaCount,
uint64_t & TelemetryWebSocketPackets,
uint64_t & TelemetryKafkaPackets) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
return;
}
DevicePtr = Device->second.second;
}
DevicePtr->GetTelemetryParameters(
TelemetryRunning, TelemetryInterval, TelemetryWebSocketTimer, TelemetryKafkaTimer,
TelemetryWebSocketCount, TelemetryKafkaCount, TelemetryWebSocketPackets,
TelemetryKafkaPackets);
}
bool AP_WS_Server::SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return DevicePtr->SendRadiusAccountingData(buffer,size);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
}
return false;
}
bool AP_WS_Server::SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return DevicePtr->SendRadiusAuthenticationData(buffer,size);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
}
return false;
}
bool AP_WS_Server::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
std::shared_ptr<AP_WS_Connection> DevicePtr;
{
std::lock_guard Lock(WSServerMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
return false;
}
DevicePtr = Device->second.second;
}
try {
return DevicePtr->SendRadiusCoAData(buffer,size);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
}
return false;
}
} //namespace

View File

@@ -1,210 +0,0 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
//
#pragma once
#include <mutex>
#include <thread>
#include <array>
#include <ctime>
#include "Poco/AutoPtr.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/ParallelSocketAcceptor.h"
#include "Poco/Net/SocketAcceptor.h"
#include "Poco/Timer.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "AP_WS_Connection.h"
#include "AP_WS_ReactorPool.h"
#include "framework/utils.h"
#include "framework/SubSystemServer.h"
namespace OpenWifi {
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
public:
explicit AP_WS_RequestHandler(Poco::Logger &L, uint64_t id)
: Logger_(L),
id_(id){
};
void handleRequest(Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response) override;
private:
Poco::Logger &Logger_;
uint64_t id_=0;
};
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L)
: Logger_(L) {
}
inline Poco::Net::HTTPRequestHandler *
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
if (request.find("Upgrade") != request.end() &&
Poco::icompare(request["Upgrade"], "websocket") == 0) {
Utils::SetThreadName("ws:conn-init");
return new AP_WS_RequestHandler(Logger_,id_++);
} else {
return nullptr;
}
}
private:
Poco::Logger &Logger_;
inline static uint64_t id_=1;
};
class AP_WS_Server : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new AP_WS_Server;
return instance_;
}
int Start() override;
void Stop() override;
bool IsCertOk() { return IssuerCert_!= nullptr; }
bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
inline bool IsSimSerialNumber(const std::string & SerialNumber) const {
return IsSim(Poco::toLower(SerialNumber)) && Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
}
inline static bool IsSim(const std::string & SerialNumber) {
return SerialNumber.substr(0,6) == "53494d";
}
inline bool IsSimEnabled() const {
return SimulatorEnabled_;
}
inline bool AllowSerialNumberMismatch() const {
return AllowSerialNumberMismatch_;
}
inline uint64_t MismatchDepth() const {
return MismatchDepth_;
}
inline bool UseProvisioning() const { return LookAtProvisioning_; }
inline bool UseDefaults() const { return UseDefaultConfig_; }
[[nodiscard]] inline Poco::Net::SocketReactor & NextReactor() { return Reactor_pool_->NextReactor(); }
[[nodiscard]] inline bool Running() const { return Running_; }
inline void AddConnection(uint64_t session_id, std::shared_ptr<AP_WS_Connection> Connection ) {
std::lock_guard Lock(WSServerMutex_);
Sessions_[session_id] = std::move(Connection);
}
inline std::shared_ptr<AP_WS_Connection> FindConnection(uint64_t session_id) const {
std::lock_guard Lock(WSServerMutex_);
auto Connection = Sessions_.find(session_id);
if(Connection!=end(Sessions_))
return Connection->second;
return nullptr;
}
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) const {
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
}
bool GetStatistics(uint64_t SerialNumber, std::string & Statistics) const ;
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) const {
return GetState(Utils::SerialNumberToInt(SerialNumber), State);
}
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const;
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) const {
return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
}
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const ;
bool Connected(uint64_t SerialNumber, AP_Restrictions & Restrictions) const ;
bool Connected(uint64_t SerialNumber) const ;
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) const {
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
}
bool SendFrame(uint64_t SerialNumber, const std::string & Payload) const ;
bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
bool EndSession(uint64_t connection_id, uint64_t serial_number);
void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
void StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber);
void SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
void StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber);
void GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
uint64_t & TelemetryInterval,
uint64_t & TelemetryWebSocketTimer,
uint64_t & TelemetryKafkaTimer,
uint64_t & TelemetryWebSocketCount,
uint64_t & TelemetryKafkaCount,
uint64_t & TelemetryWebSocketPackets,
uint64_t & TelemetryKafkaPackets);
void onGarbageCollecting(Poco::Timer & timer);
inline void AverageDeviceStatistics( uint64_t & Connections, uint64_t & AverageConnectionTime, uint64_t & NumberOfConnectingDevices) const {
Connections = NumberOfConnectedDevices_;
AverageConnectionTime = AverageDeviceConnectionTime_;
NumberOfConnectingDevices = NumberOfConnectingDevices_;
}
private:
mutable std::recursive_mutex WSServerMutex_;
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
Poco::Net::SocketReactor Reactor_;
Poco::Thread ReactorThread_;
std::string SimulatorId_;
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 2, 64};
bool LookAtProvisioning_ = false;
bool UseDefaultConfig_ = true;
bool SimulatorEnabled_=false;
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
std::atomic_bool Running_=false;
// std::map<uint64_t, std::pair<std::shared_ptr<AP_WS_Connection>,bool>> Sessions_;
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::atomic_uint64_t NumberOfConnectedDevices_=0;
std::atomic_uint64_t AverageDeviceConnectionTime_=0;
std::atomic_uint64_t NumberOfConnectingDevices_=0;
std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;
std::unique_ptr<Poco::TimerCallback<AP_WS_Server>> GarbageCollectorCallback_;
Poco::Timer Timer_;
Poco::Thread GarbageCollector_;
AP_WS_Server() noexcept:
SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {
}
};
inline auto AP_WS_Server() { return AP_WS_Server::instance(); }
} //namespace

View File

@@ -1,77 +0,0 @@
//
// Created by stephane bourque on 2022-11-14.
//
#pragma once
#include <string>
#include <set>
#include "Poco/JSON/Object.h"
#include "Poco/Logger.h"
#include "fmt/format.h"
/*
{
“country”: [
“US”, “CA”
],
“dfs”: true,
“ssh”: true,
“rtty”: true,
“tty”: true,
“developer”: true,
“sysupgrade”: true,
“commands”: true
}
*/
namespace OpenWifi {
class AP_Restrictions {
public:
inline bool initialize(Poco::Logger & Logger, const std::string & serialNumber, const Poco::JSON::Object::Ptr &O) {
try {
dfs_ = O->optValue("dfs",false);
ssh_ = O->optValue("ssh",false);
rtty_ = O->optValue("rtty",false);
tty_ = O->optValue("tty",false);
developer_ = O->optValue("developer",false);
sysupgrade_ = O->optValue("sysupgrade",false);
commands_ = O->optValue("commands",false);
if(O->has("country") && O->isArray("country")) {
auto Countries = O->getArray("country");
for(const auto &country:*Countries) {
countries_.insert(Poco::toLower(country.toString()));
}
}
return true;
} catch (...) {
poco_error(Logger,fmt::format("Cannot parse restrictions for device {}", serialNumber));
}
return false;
}
[[nodiscard]] inline auto dfs_not_allowed() const { return dfs_; }
[[nodiscard]] inline auto ssh_not_allowed() const { return ssh_; }
[[nodiscard]] inline auto rtty_not_allowed() const { return rtty_; }
[[nodiscard]] inline auto tty_not_allowed() const { return tty_; }
[[nodiscard]] inline auto developer_not_allowed() const { return developer_; }
[[nodiscard]] inline auto sysupgrade_not_allowed() const { return sysupgrade_; }
[[nodiscard]] inline auto commands_not_allowed() const { return commands_; }
[[nodiscard]] inline bool valid_country(const std::string &c) const {
if(countries_.empty())
return true;
return countries_.find(Poco::toLower(c))!=countries_.end();
}
private:
std::set<std::string> countries_;
bool dfs_ = false;
bool ssh_ = false;
bool rtty_ = false;
bool tty_ = false;
bool developer_ = false;
bool sysupgrade_ = false;
bool commands_ = false;
};
}

View File

@@ -4,15 +4,8 @@
#pragma once
#include <string>
#include <map>
#include <mutex>
#include <fstream>
#include "framework/MicroServiceFuncs.h"
#include "framework/MicroService.h"
#include "nlohmann/json.hpp"
#include "CentralConfig.h"
namespace OpenWifi {
const std::string PlatformCacheFileName{"/plat_cache.json"};
@@ -28,17 +21,17 @@ namespace OpenWifi {
return instance;
}
inline void Add(const Config::Capabilities &Caps) {
if(Caps.Compatible().empty() || Caps.Platform().empty())
inline void Add(const std::string & DeviceType, const std::string & Platform, const std::string & FullCapabilities) {
if(DeviceType.empty() || Platform.empty())
return;
std::lock_guard G(Mutex_);
if(!PlatformsLoaded_)
LoadPlatforms();
auto P = Poco::toUpper(Caps.Platform());
auto Hint = Platforms_.find(Caps.Compatible());
auto P = Poco::toUpper(Platform);
auto Hint = Platforms_.find(DeviceType);
if(Hint==Platforms_.end()) {
Platforms_.insert(std::make_pair(Caps.Compatible(),P));
Platforms_.insert(std::make_pair(DeviceType,P));
SavePlatforms();
} else if(Hint->second != P) {
Hint->second = P;
@@ -48,14 +41,12 @@ namespace OpenWifi {
if(!CapabilitiesLoaded_)
LoadCapabilities();
auto CapHint = Capabilities_.find(Caps.Compatible());
auto CapHint = Capabilities_.find(DeviceType);
if(CapHint==Capabilities_.end()) {
auto C = nlohmann::json::parse(Caps.AsString());
C.erase("restrictions");
Capabilities_[Caps.Compatible()] = nlohmann::json::parse(Caps.AsString());
Capabilities_[DeviceType] = nlohmann::json::parse(FullCapabilities);
SaveCapabilities();
} else {
CapHint->second = nlohmann::json::parse(Caps.AsString());
CapHint->second = nlohmann::json::parse(FullCapabilities);
SaveCapabilities();
}
}
@@ -100,8 +91,8 @@ namespace OpenWifi {
std::atomic_bool CapabilitiesLoaded_=false;
std::map<std::string,std::string> Platforms_;
CapabilitiesCache_t Capabilities_;
std::string PlatformCacheFileName_{ MicroServiceDataDirectory()+PlatformCacheFileName };
std::string CapabilitiesCacheFileName_{ MicroServiceDataDirectory()+CapabilitiesCacheFileName };
std::string PlatformCacheFileName_{ MicroService::instance().DataDir()+PlatformCacheFileName };
std::string CapabilitiesCacheFileName_{ MicroService::instance().DataDir()+CapabilitiesCacheFileName };
inline void LoadPlatforms() {
try {
@@ -153,7 +144,4 @@ namespace OpenWifi {
}
}
};
inline auto CapabilitiesCache() { return CapabilitiesCache::instance(); };
}

View File

@@ -12,141 +12,110 @@
#include "Poco/File.h"
#include "CentralConfig.h"
#include "framework/MicroService.h"
#include "Daemon.h"
namespace OpenWifi::Config {
const static std::string BasicConfig {
R"lit(
{
"interfaces": [
{
"ethernet": [
{
"select-ports": [
"WAN*"
]
}
],
"ipv4": {
"addressing": "dynamic"
},
"name": "WAN",
"role": "upstream",
"services": [
"ssh",
"lldp",
"dhcp-snooping"
],
"ssids": [
{
"bss-mode": "ap",
"encryption": {
"ieee80211w": "optional",
"key": "OpenWifi",
"proto": "psk2"
},
"name": "OpenWifi",
"services": [
"wifi-frames"
],
"wifi-bands": [
"2G","5G"
]
}
]
},
{
"ethernet": [
{
"select-ports": [
"LAN*"
]
}
],
"ipv4": {
"addressing": "static",
"dhcp": {
"lease-count": 10000,
"lease-first": 10,
"lease-time": "6h"
},
"subnet": "192.168.1.1/16"
},
"name": "LAN",
"role": "downstream",
"services": [
"ssh",
"lldp",
"dhcp-snooping"
]
}
],
"metrics": {
"dhcp-snooping": {
"filters": [
"ack",
"discover",
"offer",
"request",
"solicit",
"reply",
"renew"
]
},
"health": {
"interval": 120
},
"statistics": {
"interval": 60,
"types": [
"ssids",
"lldp",
"clients"
]
},
"wifi-frames": {
"filters": [
"probe",
"auth",
"assoc",
"disassoc",
"deauth",
"local-deauth",
"inactive-deauth",
"key-mismatch",
"beacon-report",
"radar-detected"
]
}
},
"radios": [
{
"band": "2G",
"channel": "auto",
"channel-mode": "HE",
"country": "CA"
},
{
"allow-dfs": true,
"band": "5G",
"channel": "auto",
"channel-mode": "HE",
"country": "CA"
}
],
"services": {
"lldp": {
"describe": "TIP OpenWiFi",
"location": "QA"
},
"ssh": {
"port": 22
}
},
"uuid": 2
}
)lit"};
R"lit({
"uuid": 1,
"radios": [
{
"band": "5G",
"country": "CA",
"channel-mode": "HE",
"channel-width": 80,
"channel": 32
}
],
"interfaces": [
{
"name": "WAN",
"role": "upstream",
"services": [ "lldp" ],
"ethernet": [
{
"select-ports": [
"WAN*"
]
}
],
"ipv4": {
"addressing": "dynamic"
},
"ssids": [
{
"name": "OpenWifi",
"wifi-bands": [
"5G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
}
}
]
},
{
"name": "LAN",
"role": "downstream",
"services": [ "ssh", "lldp" ],
"ethernet": [
{
"select-ports": [
"LAN*"
]
}
],
"ipv4": {
"addressing": "static",
"subnet": "192.168.1.1/24",
"dhcp": {
"lease-first": 10,
"lease-count": 100,
"lease-time": "6h"
}
},
"ssids": [
{
"name": "OpenWifi",
"wifi-bands": [
"5G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
}
}
]
}
],
"metrics": {
"statistics": {
"interval": 120,
"types": [ "ssids", "lldp", "clients" ]
},
"health": {
"interval": 120
}
},
"services": {
"lldp": {
"describe": "uCentral",
"location": "universe"
},
"ssh": {
"port": 22
}
}
})lit"};
void Config::SetBasicConfigFile() {
try {
@@ -228,7 +197,7 @@ R"lit(
return DefaultConfiguration_;
}
/* std::string Capabilities::Default() {
std::string Capabilities::Default() {
return std::string(R"lit({"model":{"id":"linksys,ea8300","name":"Linksys EA8300 (Dallas)"},
"network":{"lan":{"ifname":"eth0","protocol":"static"},"wan":{"ifname":"eth1","protocol":"dhcp"}},
"switch":{"switch0":{"enable":true,"reset":true,"ports":[{"num":0,"device":"eth0","need_tag":false,
@@ -242,23 +211,27 @@ R"lit(
"platform/soc/a800000.wifi":{"band":["5l"],"ht_capa":6639,"vht_capa":865687986,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],
"tx_ant":3,"rx_ant":3,"channels":[36,40,44,48,52,56,60,64]}}})lit");
}
*/
Capabilities::Capabilities(const Poco::JSON::Object::Ptr &Caps) {
void Capabilities::Parse() {
if(Capabilities_.empty())
Capabilities_=Default();
try {
Poco::JSON::Parser parser;
if(Caps->has("compatible"))
Compatible_ = Caps->get("compatible").toString();
auto Result = parser.parse(Capabilities_);
auto Objects = Result.extract<Poco::JSON::Object::Ptr>();
if(Caps->has("model"))
Model_ = Caps->get("model").toString();
if(Objects->has("compatible"))
Compatible_ = Objects->get("compatible").toString();
if(Caps->has("platform"))
Platform_ = Caps->get("platform").toString();
if(Objects->has("model"))
Model_ = Objects->get("model").toString();
std::ostringstream OS;
Caps->stringify(OS);
AsString_ = OS.str();
if(Objects->has("platform"))
Platform_ = Objects->get("platform").toString();
Parsed_ = true ;
}
catch ( const Poco::Exception & E )
{
@@ -266,20 +239,22 @@ R"lit(
}
}
const std::string & Capabilities::Compatible() const {
const std::string & Capabilities::Compatible() {
if(!Parsed_)
Parse();
return Compatible_;
}
const std::string & Capabilities::Model() const {
const std::string & Capabilities::Model() {
if(!Parsed_)
Parse();
return Model_;
}
const std::string & Capabilities::Platform() const {
const std::string & Capabilities::Platform() {
if(!Parsed_)
Parse();
return Platform_;
}
const std::string & Capabilities::AsString() const {
return AsString_;
}
} // namespace

View File

@@ -35,28 +35,29 @@ namespace OpenWifi::Config {
class Capabilities {
public:
explicit Capabilities(const Poco::JSON::Object::Ptr &Caps);
explicit Capabilities(std::string Caps)
: Capabilities_(std::move(Caps))
{
/* Capabilities()
}
Capabilities()
{
Capabilities_ = Default();
}
static std::string Default();
[[nodiscard]] const std::string & Get() const { return Capabilities_; };
*/
[[nodiscard]] const std::string & Compatible() const;
[[nodiscard]] const std::string & Model() const;
[[nodiscard]] const std::string & Platform() const;
[[nodiscard]] const std::string & AsString() const;
[[nodiscard]] const std::string & Compatible();
[[nodiscard]] const std::string & Model();
[[nodiscard]] const std::string & Platform();
private:
std::string Capabilities_;
bool Parsed_=false;
std::string Compatible_;
std::string Model_;
std::string Platform_;
std::string AsString_;
void Parse();
};

View File

@@ -11,275 +11,173 @@
#include "Poco/JSON/Parser.h"
#include "CommandManager.h"
#include "AP_WS_Server.h"
#include "DeviceRegistry.h"
#include "RESTObjects//RESTAPI_GWobjects.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
using namespace std::chrono_literals;
#include "framework/MicroService.h"
#include "framework/uCentral_Protocol.h"
namespace OpenWifi {
void CommandManager::run() {
Utils::SetThreadName("cmd:mgr");
Running_ = true;
while(Running_)
{
Poco::Thread::trySleep(30000);
if(!Running_)
break;
Poco::AutoPtr<Poco::Notification> NextMsg(ResponseQueue_.waitDequeueNotification());
while (NextMsg && Running_) {
auto Resp = dynamic_cast<RPCResponseNotification *>(NextMsg.get());
try {
if (Resp != nullptr) {
Poco::JSON::Object::Ptr Payload = Resp->Payload_;
std::string SerialNumberStr = Utils::IntToSerialNumber(Resp->SerialNumber_);
std::ostringstream SS;
Payload->stringify(SS);
if (!Payload->has(uCentralProtocol::ID)) {
poco_error(Logger(), fmt::format("({}): Invalid RPC response.", SerialNumberStr));
} else {
uint64_t ID = Payload->get(uCentralProtocol::ID);
poco_debug(Logger(),fmt::format("({}): Processing {} response.", SerialNumberStr, ID));
if (ID > 1) {
std::lock_guard Lock(LocalMutex_);
auto RPC = OutStandingRequests_.find(ID);
if (RPC == OutStandingRequests_.end() ||
RPC->second.SerialNumber != Resp->SerialNumber_) {
poco_debug(Logger(),
fmt::format("({}): RPC {} completed.", SerialNumberStr, ID));
} else {
std::chrono::duration<double, std::milli> rpc_execution_time =
std::chrono::high_resolution_clock::now() -
RPC->second.submitted;
StorageService()->CommandCompleted(RPC->second.UUID, Payload,
rpc_execution_time, true);
if (RPC->second.rpc_entry) {
RPC->second.rpc_entry->set_value(Payload);
}
poco_debug(Logger(),
fmt::format("({}): Received RPC answer {}. Command={}",
SerialNumberStr, ID, RPC->second.Command));
OutStandingRequests_.erase(ID);
}
std::vector<GWObjects::CommandDetails> Commands;
if(StorageService()->GetReadyToExecuteCommands(0,200,Commands))
{
for(auto & Cmd: Commands)
{
if(!Running_)
break;
try {
Poco::JSON::Parser P;
bool Sent;
Logger().information(Poco::format("Parsing: %s", Cmd.UUID));
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
Logger().information(Poco::format("Parsed: %s", Cmd.UUID));
auto Result = PostCommandDisk( Cmd.SerialNumber,
Cmd.Command,
*Params,
Cmd.UUID,
Sent);
if(Sent) {
StorageService()->SetCommandExecuted(Cmd.UUID);
Logger().information(Poco::format("%s: Sent command '%s-%s'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
} else {
Logger().information(Poco::format("%s: Could not send command '%s-%s'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
}
} catch (const Poco::Exception &E) {
Logger().information(Poco::format("%s: Failed command '%s-%s'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
Logger().log(E);
StorageService()->SetCommandExecuted(Cmd.UUID);
} catch (...) {
Logger().information(Poco::format("%s: Exception - hard fail - Failed command '%s-%s'", Cmd.SerialNumber, Cmd.Command, Cmd.UUID));
StorageService()->SetCommandExecuted(Cmd.UUID);
}
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),"Exception occurred during run.");
}
NextMsg = ResponseQueue_.waitDequeueNotification();
}
poco_information(Logger(),"RPC Command processor stopping.");
}
}
}
}
}
int CommandManager::Start() {
poco_notice(Logger(),"Starting...");
ManagerThread.start(*this);
JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onJanitorTimer);
JanitorTimer_.setStartInterval( 10000 );
JanitorTimer_.setPeriodicInterval(10 * 60 * 1000); // 1 hours
JanitorTimer_.start(*JanitorCallback_, MicroServiceTimerPool());
CommandRunnerCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onCommandRunnerTimer);
CommandRunnerTimer_.setStartInterval( 10000 );
CommandRunnerTimer_.setPeriodicInterval(30 * 1000); // 1 hours
CommandRunnerTimer_.start(*CommandRunnerCallback_, MicroServiceTimerPool());
Logger().notice("Starting...");
ManagerThread.start(*this);
JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onTimer);
Timer_.setStartInterval( 10000 );
Timer_.setPeriodicInterval(5 * 60 * 1000); // 1 hours
Timer_.start(*JanitorCallback_);
return 0;
}
void CommandManager::Stop() {
poco_notice(Logger(),"Stopping...");
Logger().notice("Stopping...");
Running_ = false;
JanitorTimer_.stop();
CommandRunnerTimer_.stop();
ResponseQueue_.wakeUpAll();
Timer_.stop();
ManagerThread.wakeUp();
ManagerThread.join();
poco_notice(Logger(),"Stopped...");
}
void CommandManager::WakeUp() {
poco_notice(Logger(),"Waking up...");
Logger().notice("Waking up...");
ManagerThread.wakeUp();
}
void CommandManager::onJanitorTimer([[maybe_unused]] Poco::Timer & timer) {
std::lock_guard Lock(LocalMutex_);
Utils::SetThreadName("cmd:janitor");
Poco::Logger & MyLogger = Poco::Logger::get("CMD-MGR-JANITOR");
auto now = std::chrono::high_resolution_clock::now();
for(auto request=OutStandingRequests_.begin();request!=OutStandingRequests_.end();) {
std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
if(delta > 10min) {
MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.",
request->second.UUID,
request->second.Command,
Utils::IntToSerialNumber(request->second.SerialNumber)));
request = OutStandingRequests_.erase(request);
void CommandManager::onTimer(Poco::Timer & timer) {
std::lock_guard G(Mutex_);
Logger().information("Removing expired commands: start");
auto Now = std::chrono::high_resolution_clock::now();
for(auto i=OutStandingRequests_.begin();i!=OutStandingRequests_.end();) {
std::chrono::duration<double, std::milli> delta = Now - i->second->submitted;
if(delta > 120000ms) {
i = OutStandingRequests_.erase(i);
} else {
++request;
++i;
}
}
poco_information(MyLogger,
fmt::format("Outstanding-requests {}", OutStandingRequests_.size()));
Logger().information("Removing expired commands: done");
}
bool CommandManager::IsCommandRunning(const std::string &C) {
std::lock_guard Lock(LocalMutex_);
for (const auto &request : OutStandingRequests_) {
if (request.second.UUID == C) {
return true;
}
}
return false;
}
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand( const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool oneway_rpc,
bool disk_only,
bool & Sent) {
void CommandManager::onCommandRunnerTimer([[maybe_unused]] Poco::Timer &timer) {
Utils::SetThreadName("cmd:schdlr");
Poco::Logger &MyLogger = Poco::Logger::get("CMD-MGR-SCHEDULER");
poco_trace(MyLogger,"Scheduler starting.");
try {
StorageService()->RemovedExpiredCommands();
StorageService()->RemoveTimedOutCommands();
std::vector<GWObjects::CommandDetails> Commands;
if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
poco_trace(MyLogger,fmt::format("Scheduler about to process {} commands.", Commands.size()));
for (auto &Cmd : Commands) {
if (!Running_) {
poco_warning(MyLogger,"Scheduler quitting because service is stopping.");
break;
}
poco_trace(
MyLogger, fmt::format("{}: Serial={} Command={} Starting processing.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
try {
// Skip an already running command
if(IsCommandRunning(Cmd.UUID))
continue;
auto now = Utils::Now();
// 2 hour timeout for commands
if ((now - Cmd.Submitted) > (1 * 60 * 60)) {
poco_information(
MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandTimedOut(Cmd.UUID);
continue;
}
if (!AP_WS_Server()->Connected(
Utils::SerialNumberToInt(Cmd.SerialNumber))) {
poco_trace(
MyLogger,
fmt::format(
"{}: Serial={} Command={} Device is not connected.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
continue;
}
std::string ExecutingCommand, ExecutingUUID;
if (CommandRunningForDevice(Utils::SerialNumberToInt(Cmd.SerialNumber),
ExecutingUUID, ExecutingCommand)) {
poco_trace(
MyLogger,
fmt::format(
"{}: Serial={} Command={} Device is already busy with command {} (Command={})."
, Cmd.UUID, Cmd.SerialNumber, Cmd.Command,ExecutingUUID, ExecutingCommand));
continue;
}
Poco::JSON::Parser P;
bool Sent;
poco_information(MyLogger, fmt::format("{}: Serial={} Command={} Preparing execution.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
auto Result = PostCommandDisk(Next_RPC_ID(), Cmd.SerialNumber, Cmd.Command,
*Params, Cmd.UUID, Sent);
if (Sent) {
StorageService()->SetCommandExecuted(Cmd.UUID);
poco_debug(MyLogger,
fmt::format("{}: Serial={} Command={} Sent.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
} else {
poco_debug(MyLogger,
fmt::format("{}: Serial={} Command={} Re-queued command.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
}
} catch (const Poco::Exception &E) {
poco_debug(MyLogger,
fmt::format("{}: Serial={} Command={} Failed. Command marked as completed.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
MyLogger.log(E);
StorageService()->SetCommandExecuted(Cmd.UUID);
} catch (...) {
poco_debug(MyLogger,
fmt::format("{}: Serial={} Command={} Hard failure. Command marked as completed.",
Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
StorageService()->SetCommandExecuted(Cmd.UUID);
}
}
}
} catch (Poco::Exception &E) {
MyLogger.log(E);
} catch (...) {
poco_warning(MyLogger,"Exception during command processing.");
}
poco_trace(MyLogger,"Scheduler done.");
}
std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(
uint64_t RPCID,
const std::string &SerialNumber,
const std::string &Command,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool oneway_rpc,
bool disk_only,
bool & Sent) {
auto SerialNumberInt = Utils::SerialNumberToInt(SerialNumber);
Sent=false;
if(!DeviceRegistry()->Connected(SerialNumber)) {
return nullptr;
}
std::stringstream ToSend;
auto Object = std::make_shared<RpcObject>();
CommandInfo Idx;
Idx.Id = oneway_rpc ? 1 : RPCID;
Idx.SerialNumber = SerialNumberInt;
Idx.Command = Command;
Idx.UUID = UUID;
CommandTagIndex Idx;
{
std::lock_guard M(Mutex_);
if (oneway_rpc)
Idx.Id = 1;
else
Idx.Id = ++Id_;
Idx.SerialNumber = SerialNumber;
Poco::JSON::Object CompleteRPC;
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
CompleteRPC.set(uCentralProtocol::ID, RPCID);
CompleteRPC.set(uCentralProtocol::METHOD, Command);
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
Idx.rpc_entry = disk_only ? nullptr : std::make_shared<CommandManager::promise_type_t>();
Poco::JSON::Object CompleteRPC;
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
CompleteRPC.set(uCentralProtocol::ID, Idx.Id);
CompleteRPC.set(uCentralProtocol::METHOD, Method);
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
Logger().information(
Poco::format("(%s): Sending command '%s', ID: %lu", SerialNumber, Method, Idx.Id));
poco_debug(Logger(), fmt::format("{}: Sending command. ID: {}", UUID, RPCID));
if(AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())) {
if(!oneway_rpc) {
std::lock_guard M(Mutex_);
OutStandingRequests_[RPCID] = Idx;
Object->submitted = std::chrono::high_resolution_clock::now();
Object->uuid = UUID;
if(disk_only) {
Object->rpc_entry = nullptr;
} else {
Object->rpc_entry = std::make_shared<CommandManager::promise_type_t>();
}
poco_debug(Logger(), fmt::format("{}: Sent command. ID: {}", UUID, RPCID));
Sent=true;
return Idx.rpc_entry;
OutStandingRequests_[Idx] = Object;
}
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPCID));
if(DeviceRegistry()->SendFrame(SerialNumber, ToSend.str())) {
Sent=true;
return Object->rpc_entry;
}
return nullptr;
}
void CommandManager::PostCommandResult(const std::string &SerialNumber, Poco::JSON::Object::Ptr Obj) {
if(!Obj->has(uCentralProtocol::ID)){
Logger().error(Poco::format("(%s): Invalid RPC response.",SerialNumber));
return;
}
uint64_t ID = Obj->get(uCentralProtocol::ID);
if(ID<2) {
Logger().error(Poco::format("(%s): Ignoring RPC response.",SerialNumber));
return;
}
std::lock_guard G(Mutex_);
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
auto RPC = OutStandingRequests_.find(Idx);
if (RPC == OutStandingRequests_.end()) {
Logger().warning(Poco::format("(%s): Outdated RPC %lu", SerialNumber, ID));
return;
}
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - RPC->second->submitted;
StorageService()->CommandCompleted(RPC->second->uuid, Obj, rpc_execution_time, true);
if(RPC->second->rpc_entry) {
RPC->second->rpc_entry->set_value(Obj);
}
Logger().information(Poco::format("(%s): Received RPC answer %lu", SerialNumber, ID));
}
} // namespace

View File

@@ -13,75 +13,58 @@
#include <map>
#include <utility>
#include <functional>
#include <shared_mutex>
#include "Poco/JSON/Object.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Timer.h"
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
#include "framework/SubSystemServer.h"
#include "fmt/format.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "RESTObjects//RESTAPI_GWobjects.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RPCResponseNotification: public Poco::Notification {
public:
RPCResponseNotification(std::uint64_t ser,
Poco::JSON::Object::Ptr pl) :
SerialNumber_(ser),
Payload_(std::move(pl))
{
}
std::uint64_t SerialNumber_;
Poco::JSON::Object::Ptr Payload_;
struct CommandTagIndex {
uint64_t Id=0;
std::string SerialNumber;
};
inline bool operator <(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
if(lhs.Id<rhs.Id)
return true;
if(lhs.Id>rhs.Id)
return false;
return lhs.SerialNumber<rhs.SerialNumber;
}
class CommandManager : public SubSystemServer, Poco::Runnable {
inline bool operator ==(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
if(lhs.Id == rhs.Id && lhs.SerialNumber == rhs.SerialNumber)
return true;
return false;
}
class CommandManager : public SubSystemServer, Poco::Runnable {
public:
using objtype_t = Poco::JSON::Object::Ptr;
using promise_type_t = std::promise<objtype_t>;
struct CommandInfo {
std::uint64_t Id=0;
std::uint64_t SerialNumber=0;
std::string Command;
std::string UUID;
typedef Poco::JSON::Object::Ptr objtype_t;
typedef std::promise<objtype_t> promise_type_t;
struct RpcObject {
std::string uuid;
std::chrono::time_point<std::chrono::high_resolution_clock> submitted = std::chrono::high_resolution_clock::now();
std::shared_ptr<promise_type_t> rpc_entry;
};
struct RPCResponse {
std::uint64_t serialNumber;
Poco::JSON::Object::Ptr payload;
explicit RPCResponse(std::uint64_t ser, Poco::JSON::Object::Ptr pl)
:
serialNumber(ser),
payload(std::move(pl)) {
}
};
int Start() override;
void Stop() override;
void WakeUp();
inline void PostCommandResult(const std::string &SerialNumber, Poco::JSON::Object::Ptr Obj) {
ResponseQueue_.enqueueNotification(new RPCResponseNotification(Utils::SerialNumberToInt(SerialNumber),std::move(Obj)));
}
void PostCommandResult(const std::string &SerialNumber, Poco::JSON::Object::Ptr Obj);
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(uint64_t RPC_ID,
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool & Sent) {
return PostCommand(RPC_ID, SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -89,14 +72,12 @@ namespace OpenWifi {
}
std::shared_ptr<promise_type_t> PostCommandDisk(
uint64_t RPC_ID,
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool & Sent) {
return PostCommand(RPC_ID,
SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -104,13 +85,12 @@ namespace OpenWifi {
}
std::shared_ptr<promise_type_t> PostCommand(
uint64_t RPC_ID,
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool & Sent) {
return PostCommand(RPC_ID, SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -119,14 +99,12 @@ namespace OpenWifi {
}
std::shared_ptr<promise_type_t> PostCommandOneWay(
uint64_t RPC_ID,
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool & Sent) {
return PostCommand(RPC_ID,
SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -134,8 +112,6 @@ namespace OpenWifi {
false, Sent );
}
bool IsCommandRunning(const std::string &C);
void run() override;
static auto instance() {
@@ -144,52 +120,17 @@ namespace OpenWifi {
}
inline bool Running() const { return Running_; }
void onJanitorTimer(Poco::Timer & timer);
void onCommandRunnerTimer(Poco::Timer & timer);
inline uint64_t Next_RPC_ID() { return ++Id_; }
void RemovePendingCommand(std::uint64_t Id) {
std::unique_lock Lock(LocalMutex_);
OutStandingRequests_.erase(Id);
}
inline bool CommandRunningForDevice(std::uint64_t SerialNumber, std::string & uuid, std::string &command) {
std::lock_guard Lock(LocalMutex_);
for(const auto &[Request,Command]:OutStandingRequests_) {
if(Command.SerialNumber==SerialNumber) {
uuid = Command.UUID;
command = Command.Command;
return true;
}
}
return false;
}
inline void ClearQueue(std::uint64_t SerialNumber) {
std::lock_guard Lock(LocalMutex_);
for(auto Request = OutStandingRequests_.begin(); Request != OutStandingRequests_.end() ; ) {
if(Request->second.SerialNumber==SerialNumber)
Request = OutStandingRequests_.erase(Request);
else
++Request;
}
}
void onTimer(Poco::Timer & timer);
private:
mutable std::recursive_mutex LocalMutex_;
std::atomic_bool Running_ = false;
Poco::Thread ManagerThread;
std::atomic_uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
std::map<std::uint64_t , CommandInfo> OutStandingRequests_;
Poco::Timer JanitorTimer_;
uint64_t Id_=3; // do not start @1. We ignore ID=1 & 0 is illegal..
std::map<CommandTagIndex,std::shared_ptr<RpcObject>> OutStandingRequests_;
Poco::Timer Timer_;
std::unique_ptr<Poco::TimerCallback<CommandManager>> JanitorCallback_;
Poco::Timer CommandRunnerTimer_;
std::unique_ptr<Poco::TimerCallback<CommandManager>> CommandRunnerCallback_;
Poco::NotificationQueue ResponseQueue_;
std::shared_ptr<promise_type_t> PostCommand(
uint64_t RPCID,
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,

View File

@@ -7,6 +7,7 @@
#include <map>
#include <string>
#include <mutex>
#include "framework/MicroService.h"
namespace OpenWifi {
class ConfigurationCache {

View File

@@ -6,28 +6,26 @@
// Arilia Wireless Inc.
//
#include <boost/algorithm/string.hpp>
#include "Poco/Util/Application.h"
#include "Poco/Util/Option.h"
#include "Poco/Environment.h"
#include "Poco/Net/SSLManager.h"
#include "AP_WS_Server.h"
#include "CentralConfig.h"
#include "CommandManager.h"
#include "Daemon.h"
#include "DeviceRegistry.h"
#include "FileUploader.h"
#include "FindCountry.h"
#include "OUIServer.h"
#include "RADIUS_proxy_server.h"
#include "SerialNumberCache.h"
#include "StorageArchiver.h"
#include "StorageService.h"
#include "TelemetryStream.h"
#include "VenueBroadcaster.h"
#include "WS_Server.h"
#include "framework/ConfigurationValidator.h"
#include "framework/MicroService.h"
#include "FindCountry.h"
#include "rttys/RTTYS_server.h"
#include "framework/UI_WebSocketClientServer.h"
#include "UI_GW_WebSocketNotifications.h"
namespace OpenWifi {
class Daemon *Daemon::instance() {
@@ -40,17 +38,15 @@ namespace OpenWifi {
StorageService(),
SerialNumberCache(),
ConfigurationValidator(),
UI_WebSocketClientServer(),
OUIServer(),
FindCountryFromIP(),
DeviceRegistry(),
CommandManager(),
FileUploader(),
StorageArchiver(),
TelemetryStream(),
RTTYS_server(),
RADIUS_proxy_server(),
VenueBroadcaster(),
AP_WS_Server()
WebSocketServer()
});
return &instance;
}
@@ -88,13 +84,15 @@ namespace OpenWifi {
{"wallys_dr40x9","AP"}
};
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
void Daemon::initialize() {
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning",false);
DeviceTypes_ = DefaultDeviceTypes;
WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
}
void MicroServicePostInitialization() {
Daemon()->initialize();
}
[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string & Id ) const {
for(const auto &[DeviceType,Type]:DeviceTypes_)
{
@@ -103,33 +101,19 @@ namespace OpenWifi {
}
return "AP";
}
void DaemonPostInitialization(Poco::Util::Application &self) {
Daemon()->PostInitialization(self);
GWWebSocketNotifications::Register();
}
}
int main(int argc, char **argv) {
int ExitCode;
try {
Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr);
auto App = OpenWifi::Daemon::instance();
ExitCode = App->run(argc, argv);
Poco::Net::SSLManager::instance().shutdown();
} catch (Poco::Exception &exc) {
ExitCode = Poco::Util::Application::EXIT_SOFTWARE;
std::cout << exc.displayText() << std::endl;
} catch (std::exception &exc) {
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
std::cout << exc.what() << std::endl;
} catch (...) {
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
std::cout << "Exception on closure" << std::endl;
}
std::cout << "Exitcode: " << ExitCode << std::endl;
return ExitCode;
auto App = OpenWifi::Daemon::instance();
auto ExitCode = App->run(argc, argv);
return ExitCode;
} catch (Poco::Exception &exc) {
std::cerr << exc.displayText() << std::endl;
return Poco::Util::Application::EXIT_SOFTWARE;
}
}
// end of namespace

View File

@@ -14,20 +14,27 @@
#include <vector>
#include <set>
#include "framework/MicroServiceNames.h"
#include "framework/MicroService.h"
#include "Poco/Util/Application.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/UUIDGenerator.h"
#include "Poco/ErrorHandler.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/Crypto/CipherFactory.h"
#include "Poco/Crypto/Cipher.h"
#include "Dashboard.h"
#include "framework/MicroService.h"
#include "framework/OpenWifiTypes.h"
#include "GwWebSocketClient.h"
namespace OpenWifi {
[[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owgw.properties";
[[maybe_unused]] static const char * vDAEMON_ROOT_ENV_VAR = "OWGW_ROOT";
[[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWGW_CONFIG";
[[maybe_unused]] static const char * vDAEMON_APP_NAME = uSERVICE_GATEWAY.c_str();
[[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 10000;
static const char * vDAEMON_PROPERTIES_FILENAME = "owgw.properties";
static const char * vDAEMON_ROOT_ENV_VAR = "OWGW_ROOT";
static const char * vDAEMON_CONFIG_ENV_VAR = "OWGW_CONFIG";
static const char * vDAEMON_APP_NAME = uSERVICE_GATEWAY.c_str();
static const uint64_t vDAEMON_BUS_TIMER = 10000;
class Daemon : public MicroService {
public:
@@ -41,18 +48,17 @@ namespace OpenWifi {
bool AutoProvisioning() const { return AutoProvisioning_ ; }
[[nodiscard]] std::string IdentifyDevice(const std::string & Compatible) const;
void initialize();
static Daemon *instance();
inline DeviceDashboard & GetDashboard() { return DB_; }
Poco::Logger & Log() { return Poco::Logger::get(AppName()); }
void PostInitialization(Poco::Util::Application &self);
private:
bool AutoProvisioning_ = false;
std::vector<std::pair<std::string,std::string>> DeviceTypes_;
DeviceDashboard DB_;
std::unique_ptr<GwWebSocketClient> WebSocketProcessor_;
};
inline Daemon * Daemon() { return Daemon::instance(); }
void DaemonPostInitialization(Poco::Util::Application &self);
}

View File

@@ -3,12 +3,12 @@
//
#include "Dashboard.h"
#include "DeviceRegistry.h"
#include "StorageService.h"
#include "framework/utils.h"
namespace OpenWifi {
void DeviceDashboard::Create() {
uint64_t Now = Utils::Now();
uint64_t Now = std::time(nullptr);
if(LastRun_==0 || (Now-LastRun_)>120) {
DB_.reset();

150
src/DeviceRegistry.cpp Normal file
View File

@@ -0,0 +1,150 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
//
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#include "DeviceRegistry.h"
#include "WS_Server.h"
#include "OUIServer.h"
namespace OpenWifi {
int DeviceRegistry::Start() {
std::lock_guard Guard(Mutex_);
Logger().notice("Starting ");
return 0;
}
void DeviceRegistry::Stop() {
std::lock_guard Guard(Mutex_);
Logger().notice("Stopping ");
}
bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device == Devices_.end())
return false;
Statistics = Device->second->LastStats;
return true;
}
void DeviceRegistry::SetStatistics(uint64_t SerialNumber, const std::string &Statistics) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device != Devices_.end())
{
Device->second->Conn_.LastContact = time(nullptr);
Device->second->LastStats = Statistics;
}
}
bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device == Devices_.end())
return false;
State = Device->second->Conn_;
return true;
}
void DeviceRegistry::SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device != Devices_.end())
{
Device->second->Conn_.LastContact = time(nullptr);
Device->second->Conn_ = State;
}
}
bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device != Devices_.end()) {
CheckData = Device->second->LastHealthcheck;
return true;
}
return false;
}
void DeviceRegistry::SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck & CheckData) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device != Devices_.end())
{
Device->second->LastHealthcheck = CheckData;
}
}
std::shared_ptr<DeviceRegistry::ConnectionEntry> DeviceRegistry::Register(uint64_t SerialNumber, WSConnection *Ptr, uint64_t & ConnectionId )
{
std::lock_guard Guard(Mutex_);
const auto & E = Devices_[SerialNumber] = std::make_shared<ConnectionEntry>();
E->WSConn_ = Ptr;
E->Conn_.LastContact = std::time(nullptr);
E->Conn_.Connected = true ;
E->Conn_.UUID = 0 ;
E->Conn_.MessageCount = 0 ;
E->Conn_.Address = "";
E->Conn_.TX = 0 ;
E->Conn_.RX = 0;
E->Conn_.VerifiedCertificate = GWObjects::CertificateValidation::NO_CERTIFICATE;
ConnectionId = E->ConnectionId = ++Id_;
return E;
}
bool DeviceRegistry::Connected(uint64_t SerialNumber) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device == Devices_.end())
return false;
return Device->second->Conn_.Connected;
}
void DeviceRegistry::UnRegister(uint64_t SerialNumber, uint64_t ConnectionId) {
std::lock_guard Guard(Mutex_);
auto It = Devices_.find(SerialNumber);
if(It!=Devices_.end()) {
if(It->second->ConnectionId == ConnectionId)
Devices_.erase(SerialNumber);
}
}
bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
try {
return Device->second->WSConn_->Send(Payload);
} catch (...) {
Logger().debug(Poco::format("Could not send data to device '%s'", SerialNumber));
Device->second->Conn_.Address = "";
Device->second->WSConn_ = nullptr;
Device->second->Conn_.Connected = false;
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
}
}
return false;
}
void DeviceRegistry::SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device!=Devices_.end()) {
Device->second->Conn_.PendingUUID = PendingUUID;
}
}
} // namespace

118
src/DeviceRegistry.h Normal file
View File

@@ -0,0 +1,118 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
//
#pragma once
#include "Poco/JSON/Object.h"
#include "RESTObjects//RESTAPI_GWobjects.h"
#include "framework/MicroService.h"
// class uCentral::WebSocket::WSConnection;
namespace OpenWifi {
class WSConnection;
class DeviceRegistry : public SubSystemServer {
public:
struct ConnectionEntry {
WSConnection * WSConn_ = nullptr;
GWObjects::ConnectionState Conn_;
std::string LastStats;
GWObjects::HealthCheck LastHealthcheck;
uint64_t ConnectionId=0;
};
static auto instance() {
static auto instance_ = new DeviceRegistry;
return instance_;
}
int Start() override;
void Stop() override;
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) {
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
}
bool GetStatistics(uint64_t SerialNumber, std::string & Statistics);
inline void SetStatistics(const std::string &SerialNumber, const std::string &Statistics) {
return SetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
}
void SetStatistics(uint64_t SerialNumber, const std::string &stats);
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) {
return GetState(Utils::SerialNumberToInt(SerialNumber), State);
}
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State);
inline void SetState(const std::string & SerialNumber, const GWObjects::ConnectionState & State) {
return SetState(Utils::SerialNumberToInt(SerialNumber), State);
}
void SetState(uint64_t SerialNumber, const GWObjects::ConnectionState & State);
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) {
return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
}
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData);
inline void SetHealthcheck(const std::string &SerialNumber, const GWObjects::HealthCheck &H) {
return SetHealthcheck(Utils::SerialNumberToInt(SerialNumber),H);
}
void SetHealthcheck(uint64_t SerialNumber, const GWObjects::HealthCheck &H);
std::shared_ptr<ConnectionEntry> Register(uint64_t SerialNumber, WSConnection *Conn, uint64_t & ConnectionId);
inline void UnRegister(const std::string & SerialNumber, uint64_t ConnectionId) {
return UnRegister(Utils::SerialNumberToInt(SerialNumber),ConnectionId);
}
void UnRegister(uint64_t SerialNumber, uint64_t ConnectionId);
inline bool Connected(const std::string & SerialNumber) {
return Connected(Utils::SerialNumberToInt(SerialNumber));
}
bool Connected(uint64_t SerialNumber);
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) {
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
}
bool SendFrame(uint64_t SerialNumber, const std::string & Payload);
inline void SetPendingUUID(const std::string & SerialNumber, uint64_t PendingUUID) {
return SetPendingUUID(Utils::SerialNumberToInt(SerialNumber), PendingUUID);
}
void SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID);
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(const std::string & SerialNumber) {
return GetDeviceConnection(Utils::SerialNumberToInt(SerialNumber));
}
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(uint64_t SerialNumber) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
return Device->second;
}
return nullptr;
}
private:
inline static std::atomic_uint64_t Id_=1;
std::map<uint64_t ,std::shared_ptr<ConnectionEntry>> Devices_;
DeviceRegistry() noexcept:
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
}
};
inline auto DeviceRegistry() { return DeviceRegistry::instance(); }
} // namespace

View File

@@ -7,35 +7,31 @@
//
#include <iostream>
#include <fstream>
#include <cstdio>
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/DynamicAny.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/Net/PartHandler.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/Net/MultipartReader.h"
#include "Poco/CountingStream.h"
#include "Poco/StreamCopier.h"
#include "Poco/Exception.h"
#include "Poco/File.h"
#include "Poco/StringTokenizer.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/ow_constants.h"
#include "framework/utils.h"
#include "FileUploader.h"
#include "StorageService.h"
#include "fmt/format.h"
#include "framework/MicroService.h"
namespace OpenWifi {
static const std::string URI_BASE{"/v1/upload/"};
int FileUploader::Start() {
poco_notice(Logger(),"Starting.");
Logger().notice("Starting.");
Poco::File UploadsDir(MicroServiceConfigPath("openwifi.fileuploader.path","/tmp"));
Poco::File UploadsDir(MicroService::instance().ConfigPath("openwifi.fileuploader.path","/tmp"));
Path_ = UploadsDir.path();
if(!UploadsDir.exists()) {
try {
@@ -45,78 +41,47 @@ namespace OpenWifi {
Path_ = "/tmp";
}
}
for(const auto & Svr: ConfigServersList_) {
if(MicroServiceNoAPISecurity()) {
poco_notice(Logger(), fmt::format("Starting: {}:{}",Svr.Address(),Svr.Port()));
std::string l{"Starting: " +
Svr.Address() + ":" + std::to_string(Svr.Port()) +
" key:" + Svr.KeyFile() +
" cert:" + Svr.CertFile()};
Logger().information(l);
auto Sock{Svr.CreateSocket(Logger())};
auto Sock{Svr.CreateSecureSocket(Logger())};
auto Params = new Poco::Net::HTTPServerParams;
Params->setMaxThreads(16);
Params->setMaxQueued(100);
Params->setName("ws:upldr");
Svr.LogCert(Logger());
if(!Svr.RootCA().empty())
Svr.LogCas(Logger());
if (FullName_.empty()) {
std::string TmpName =
MicroServiceConfigGetString("openwifi.fileuploader.uri", "");
if (TmpName.empty()) {
FullName_ =
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
} else {
FullName_ = TmpName + URI_BASE;
}
poco_information(Logger(),fmt::format("Uploader URI base is '{}'", FullName_));
}
auto Params = new Poco::Net::HTTPServerParams;
Params->setMaxThreads(16);
Params->setMaxQueued(100);
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
Params->setName("file-upldr");
NewServer->start();
Servers_.push_back(std::move(NewServer));
} else {
std::string l{"Starting: " + Svr.Address() + ":" + std::to_string(Svr.Port()) +
" key:" + Svr.KeyFile() + " cert:" + Svr.CertFile()};
poco_information(Logger(),l);
if(FullName_.empty()) {
std::string TmpName = MicroService::instance().ConfigGetString("openwifi.fileuploader.uri","");
if(TmpName.empty()) {
FullName_ =
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
} else {
FullName_ = TmpName + URI_BASE ;
}
Logger().information(Poco::format("Uploader URI base is '%s'", FullName_));
}
auto Sock{Svr.CreateSecureSocket(Logger())};
Svr.LogCert(Logger());
if (!Svr.RootCA().empty())
Svr.LogCas(Logger());
auto Params = new Poco::Net::HTTPServerParams;
Params->setMaxThreads(16);
Params->setMaxQueued(100);
Params->setName("ws:upldr");
if (FullName_.empty()) {
std::string TmpName =
MicroServiceConfigGetString("openwifi.fileuploader.uri", "");
if (TmpName.empty()) {
FullName_ =
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
} else {
FullName_ = TmpName + URI_BASE;
}
poco_information(Logger(), fmt::format("Uploader URI base is '{}'", FullName_));
}
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(
new FileUpLoaderRequestHandlerFactory(Logger()), Sock, Params);
NewServer->start();
Servers_.push_back(std::move(NewServer));
}
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new FileUpLoaderRequestHandlerFactory(Logger()), Pool_, Sock, Params);
NewServer->start();
Servers_.push_back(std::move(NewServer));
}
MaxSize_ = 1000 * MicroServiceConfigGetInt("openwifi.fileuploader.maxsize", 10000);
MaxSize_ = 1000 * MicroService::instance().ConfigGetInt("openwifi.fileuploader.maxsize", 10000);
return 0;
}
void FileUploader::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
MicroServiceLoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
void FileUploader::reinitialize(Poco::Util::Application &self) {
MicroService::instance().LoadConfigurationFile();
Logger().information("Reinitializing.");
Stop();
Start();
}
@@ -126,158 +91,146 @@ namespace OpenWifi {
}
// if you pass in an empty UUID, it will just clean the list and not add it.
bool FileUploader::AddUUID( const std::string & UUID, std::chrono::seconds WaitTimeInSeconds, const std::string &Type) {
bool FileUploader::AddUUID( const std::string & UUID) {
std::lock_guard Guard(Mutex_);
uint64_t now = Utils::Now();
auto Func=[now](const UploadId &I) -> bool {
return (now > I.Expires);
};
OutStandingUploads_.erase(std::remove_if(OutStandingUploads_.begin(),OutStandingUploads_.end(),Func),OutStandingUploads_.end());
OutStandingUploads_.emplace_back(UploadId{UUID, now + WaitTimeInSeconds.count(), Type});
uint64_t Now = time(nullptr) ;
// remove old stuff...
for(auto i=OutStandingUploads_.cbegin();i!=OutStandingUploads_.end();) {
if ((Now-i->second) > (60 * 30))
OutStandingUploads_.erase(i++);
else
++i;
}
if(!UUID.empty())
OutStandingUploads_[UUID] = Now;
return true;
}
bool FileUploader::ValidRequest(const std::string &UUID) {
std::lock_guard Guard(Mutex_);
auto Func = [UUID](const UploadId &P) -> bool {
return (P.UUID==UUID);
};
return std::find_if(OutStandingUploads_.begin(), OutStandingUploads_.end(), Func) != end(OutStandingUploads_);
return OutStandingUploads_.find(UUID)!=OutStandingUploads_.end();
}
void FileUploader::RemoveRequest(const std::string &UUID) {
std::lock_guard Guard(Mutex_);
auto Func = [UUID](const UploadId &P) -> bool {
return (P.UUID==UUID);
};
OutStandingUploads_.erase(std::remove_if(OutStandingUploads_.begin(),OutStandingUploads_.end(),Func),OutStandingUploads_.end());
OutStandingUploads_.erase(UUID);
}
class FileUploaderPartHandler2 : public Poco::Net::PartHandler {
public:
FileUploaderPartHandler2(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
Id_(std::move(Id)),
Logger_(Logger),
OutputStream_(ofs){
}
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
std::string Disposition;
Poco::Net::NameValueCollection Parameters;
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
class FileUploaderPartHandler: public Poco::Net::PartHandler
{
public:
FileUploaderPartHandler(std::string UUID, Poco::Logger & Logger):
UUID_(std::move(UUID)),
Logger_(Logger)
{
}
void handlePart(const Poco::Net::MessageHeader& Header, std::istream& Stream) override
{
try {
Name_ = "(unnamed)";
if (Header.has("Content-Disposition")) {
std::string Disposition;
Poco::Net::NameValueCollection Parameters;
Poco::Net::MessageHeader::splitParameters(Header["Content-Disposition"],
Disposition, Parameters);
Name_ = Parameters.get("filename", "(unnamed)");
}
std::string FinalFileName = FileUploader()->Path() + "/" + UUID_;
Logger().information(Poco::format("FILE-UPLOADER: uploading trace for %s", FinalFileName));
Poco::CountingInputStream InputStream(Stream);
std::ofstream OutputStream(FinalFileName, std::ofstream::out);
Poco::StreamCopier::copyStream(InputStream, OutputStream);
Poco::File TmpFile(FinalFileName);
Length_ = TmpFile.getSize();
if (Length_ < FileUploader()->MaxSize()) {
Good_=true;
} else {
TmpFile.remove();
Error_ = "File is too large.";
}
return;
} catch (const Poco::Exception &E ) {
Logger().log(E);
Error_ = std::string("Upload caused an internal error: ") + E.what() ;
}
Poco::CountingInputStream InputStream(Stream);
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
Length_ = OutputStream_.str().size();
}
[[nodiscard]] uint64_t Length() const { return Length_; }
[[nodiscard]] std::string &Name() { return Name_; }
[[nodiscard]] std::string &ContentType() { return FileType_; }
private:
uint64_t Length_ = 0;
std::string FileType_;
std::string Name_;
std::string Id_;
Poco::Logger &Logger_;
std::stringstream &OutputStream_;
[[nodiscard]] uint64_t Length() const { return Length_; }
[[nodiscard]] const std::string& Name() const { return Name_; }
[[nodiscard]] bool Good() const { return Good_; }
std::string & Error() { return Error_; }
inline Poco::Logger & Logger() { return Logger_; }
private:
uint64_t Length_=0;
bool Good_=false;
std::string Name_;
std::string UUID_;
std::string Error_;
Poco::Logger & Logger_;
};
inline Poco::Logger & Logger() { return Logger_; };
};
class FormRequestHandler: public Poco::Net::HTTPRequestHandler
{
public:
explicit FormRequestHandler(std::string UUID, Poco::Logger & L, const std::string &Type):
explicit FormRequestHandler(std::string UUID, Poco::Logger & L):
UUID_(std::move(UUID)),
Logger_(L),
Type_(Type)
Logger_(L)
{
}
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) final {
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override
{
try {
FileUploaderPartHandler partHandler(UUID_,Logger());
Utils::SetThreadName("FileUploader");
const auto ContentType = Request.getContentType();
const auto Tokens = Poco::StringTokenizer(ContentType,";",Poco::StringTokenizer::TOK_TRIM);
Poco::Net::HTMLForm form(Request, Request.stream(), partHandler);
poco_debug(Logger(),fmt::format("{}: Preparing to upload trace file.",UUID_));
Poco::JSON::Object Answer;
Response.setChunkedTransferEncoding(true);
Response.setContentType("application/json");
try {
if (Poco::icompare(Tokens[0], "multipart/form-data") == 0 ||
Poco::icompare(Tokens[0], "multipart/mixed") == 0) {
const auto &BoundaryTokens =
Poco::StringTokenizer(Tokens[1], "=", Poco::StringTokenizer::TOK_TRIM);
if (BoundaryTokens[0] == "boundary") {
const std::string &Boundary = BoundaryTokens[1];
Poco::Net::MultipartReader Reader(Request.stream(), Boundary);
bool Done = false;
while (!Done) {
Poco::Net::MessageHeader Hdr;
Reader.nextPart(Hdr);
const auto PartContentType = Hdr.get("Content-Type", "");
if (PartContentType == "application/octet-stream") {
std::stringstream FileContent;
Poco::StreamCopier::copyStream(Reader.stream(), FileContent);
Answer.set("filename", UUID_);
Answer.set("error", 0);
poco_debug(Logger(),fmt::format("{}: File uploaded.", UUID_));
StorageService()->AttachFileDataToCommand(UUID_, FileContent, Type_);
std::ostream &ResponseStream = Response.send();
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
return;
} else {
std::stringstream OO;
Poco::StreamCopier::copyStream(Reader.stream(), OO);
}
if (!Reader.hasNextPart())
Done = true;
}
}
Poco::JSON::Object Answer;
if (partHandler.Good()) {
Answer.set("filename", UUID_);
Answer.set("error", 0);
StorageService()->AttachFileToCommand(UUID_);
} else {
Answer.set("filename", UUID_);
Answer.set("error", 13);
Answer.set("errorText", partHandler.Error() );
StorageService()->CancelWaitFile(UUID_, partHandler.Error() );
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_debug(Logger(),"Exception while receiving trace file.");
}
poco_debug(Logger(),fmt::format("{}: Failed to upload trace file.",UUID_));
std::string Error{"Trace file rejected"};
StorageService()->CancelWaitFile(UUID_, Error);
Answer.set("filename", UUID_);
Answer.set("error", 13);
Answer.set("errorText", "Attached file is too large");
StorageService()->CancelWaitFile(UUID_, Error);
std::ostream &ResponseStream = Response.send();
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
}
std::ostream &ResponseStream = Response.send();
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
return;
}
catch( const Poco::Exception & E )
{
Logger().warning(Poco::format("Error occurred while performing upload. Error='%s'",E.displayText()));
}
catch( ... )
{
}
}
inline Poco::Logger & Logger() { return Logger_; }
private:
std::string UUID_;
Poco::Logger & Logger_;
std::string Type_;
};
Poco::Net::HTTPRequestHandler *FileUpLoaderRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest & Request) {
poco_debug(Logger(),fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
if(Request.getMethod()!=Poco::Net::HTTPRequest::HTTP_POST ||
Request.getURI().size()<(URI_BASE.size()+36)) {
poco_warning(Logger(),fmt::format("ILLEGAL-REQUEST({}): {} {}. Dropped.", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
return nullptr;
}
Logger().debug(Poco::format("REQUEST(%s): %s %s", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
// The UUID should be after the /v1/upload/ part...
auto UUIDLocation = Request.getURI().find_first_of(URI_BASE);
@@ -285,38 +238,25 @@ namespace OpenWifi {
if( UUIDLocation != std::string::npos )
{
auto UUID = Request.getURI().substr(UUIDLocation+URI_BASE.size());
FileUploader::UploadId E;
if(FileUploader()->Find(UUID,E))
if(FileUploader()->ValidRequest(UUID))
{
// make sure we do not allow anyone else to overwrite our file
FileUploader()->RemoveRequest(UUID);
return new FormRequestHandler(UUID,Logger(),E.Type);
return new FormRequestHandler(UUID,Logger());
}
else
{
poco_warning(Logger(),fmt::format("Unknown UUID={}",UUID));
Logger().warning(Poco::format("Unknown UUID=%s",UUID));
}
}
return nullptr;
}
bool FileUploader::Find(const std::string &UUID, UploadId &V) {
std::lock_guard G(Mutex_);
for(const auto &E:OutStandingUploads_) {
if (E.UUID == UUID) {
V = E;
return true;
}
}
return false;
}
void FileUploader::Stop() {
poco_notice(Logger(),"Stopping...");
Logger().notice("Stopping ");
for( const auto & svr : Servers_ )
svr->stopAll(true);
svr->stop();
Servers_.clear();
poco_notice(Logger(),"Stopped...");
}
} // Namespace

View File

@@ -13,24 +13,17 @@
#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "framework/SubSystemServer.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class FileUploader : public SubSystemServer {
public:
struct UploadId {
std::string UUID;
std::uint64_t Expires;
std::string Type;
};
int Start() override;
void Stop() override;
void reinitialize(Poco::Util::Application &self) override;
const std::string & FullName();
bool AddUUID( const std::string & UUID, std::chrono::seconds WaitTimeInSecond, const std::string &Type);
bool AddUUID( const std::string & UUID);
bool ValidRequest(const std::string & UUID);
void RemoveRequest(const std::string &UUID);
const std::string & Path() { return Path_; };
@@ -42,16 +35,17 @@ namespace OpenWifi {
[[nodiscard]] inline uint64_t MaxSize() const { return MaxSize_; }
bool Find(const std::string &UUID, UploadId &V);
private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
std::string FullName_;
std::list<UploadId> OutStandingUploads_;
std::string Path_;
uint64_t MaxSize_=10000000;
Poco::ThreadPool Pool_;
std::string FullName_;
std::map<std::string,uint64_t> OutStandingUploads_;
std::string Path_;
uint64_t MaxSize_=10000000;
explicit FileUploader() noexcept:
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader")
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader"),
Pool_("FileUpLoaderPool")
{
}
};
@@ -59,13 +53,10 @@ namespace OpenWifi {
class FileUpLoaderRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
explicit FileUpLoaderRequestHandlerFactory(Poco::Logger &L) :
Logger_(L) {
}
Logger_(L){}
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &request) override;
inline Poco::Logger & Logger() {
return Logger_;
}
inline Poco::Logger & Logger() { return Logger_; }
private:
Poco::Logger & Logger_;
};

View File

@@ -4,11 +4,8 @@
#pragma once
#include "framework/MicroService.h"
#include "Poco/Net/IPAddress.h"
#include "framework/SubSystemServer.h"
#include "framework/MicroServiceFuncs.h"
#include "nlohmann/json.hpp"
namespace OpenWifi {
@@ -26,7 +23,7 @@ namespace OpenWifi {
public:
static std::string Name() { return "ipinfo"; }
inline bool Init() override {
Key_ = MicroServiceConfigGetString("iptocountry.ipinfo.token", "");
Key_ = MicroService::instance().ConfigGetString("iptocountry.ipinfo.token", "");
return !Key_.empty();
}
@@ -58,7 +55,7 @@ namespace OpenWifi {
public:
static std::string Name() { return "ipdata"; }
inline bool Init() override {
Key_ = MicroServiceConfigGetString("iptocountry.ipdata.apikey", "");
Key_ = MicroService::instance().ConfigGetString("iptocountry.ipdata.apikey", "");
return !Key_.empty();
}
@@ -88,7 +85,7 @@ namespace OpenWifi {
public:
static std::string Name() { return "ip2location"; }
inline bool Init() override {
Key_ = MicroServiceConfigGetString("iptocountry.ip2location.apikey", "");
Key_ = MicroService::instance().ConfigGetString("iptocountry.ip2location.apikey", "");
return !Key_.empty();
}
@@ -136,22 +133,18 @@ namespace OpenWifi {
}
inline int Start() final {
poco_notice(Logger(),"Starting...");
ProviderName_ = MicroServiceConfigGetString("iptocountry.provider","");
ProviderName_ = MicroService::instance().ConfigGetString("iptocountry.provider","");
if(!ProviderName_.empty()) {
Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(ProviderName_);
if(Provider_!= nullptr) {
Enabled_ = Provider_->Init();
}
}
Default_ = MicroServiceConfigGetString("iptocountry.default", "US");
Default_ = MicroService::instance().ConfigGetString("iptocountry.default", "US");
return 0;
}
inline void Stop() final {
poco_notice(Logger(),"Stopping...");
// Nothing to do - just to provide the same look at the others.
poco_notice(Logger(),"Stopped...");
}
[[nodiscard]] static inline std::string ReformatAddress(const std::string & I )

View File

@@ -1,63 +0,0 @@
//
// Created by stephane bourque on 2022-04-28.
//
#include "GwWebSocketClient.h"
#include "SerialNumberCache.h"
namespace OpenWifi {
GwWebSocketClient::GwWebSocketClient(Poco::Logger &Logger):
Logger_(Logger){
UI_WebSocketClientServer()->SetProcessor(this);
}
GwWebSocketClient::~GwWebSocketClient() {
UI_WebSocketClientServer()->SetProcessor(nullptr);
}
void GwWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ) {
try {
if (O->has("command")) {
auto Command = O->get("command").toString();
if (Command == "serial_number_search" && O->has("serial_prefix")) {
ws_command_serial_number_search(O,Done,Answer);
} else if (Command=="exit") {
ws_command_exit(O,Done,Answer);
} else {
ws_command_invalid(O, Done, Answer);
}
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
}
void GwWebSocketClient::ws_command_serial_number_search(const Poco::JSON::Object::Ptr &O,
bool &Done, std::string &Answer) {
Done = false;
auto Prefix = O->get("serial_prefix").toString();
if (!Prefix.empty() && Prefix.length() < 13) {
std::vector<uint64_t> Numbers;
SerialNumberCache()->FindNumbers(Prefix, 50, Numbers);
Poco::JSON::Array Arr;
for (const auto &i : Numbers)
Arr.add(Utils::int_to_hex(i));
Poco::JSON::Object RetObj;
RetObj.set("serialNumbers", Arr);
std::ostringstream SS;
Poco::JSON::Stringifier::stringify(RetObj, SS);
Answer = SS.str();
}
}
void GwWebSocketClient::ws_command_exit([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
Done = true;
Answer = R"lit({ "closing" : "Goodbye! Aurevoir! Hasta la vista!" })lit";
}
void GwWebSocketClient::ws_command_invalid([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
Done = false;
Answer = std::string{R"lit({ "error" : "invalid command" })lit"};
}
}

View File

@@ -1,23 +0,0 @@
//
// Created by stephane bourque on 2022-04-28.
//
#pragma once
#include "framework/UI_WebSocketClientServer.h"
namespace OpenWifi {
class GwWebSocketClient : public UI_WebSocketClientProcessor {
public:
explicit GwWebSocketClient(Poco::Logger &Logger);
virtual ~GwWebSocketClient();
virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done );
void ws_command_serial_number_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
void ws_command_exit( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
void ws_command_invalid( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
private:
Poco::Logger & Logger_;
inline Poco::Logger & Logger() { return Logger_; }
};
}

View File

@@ -5,76 +5,54 @@
#include <fstream>
#include <vector>
#include "OUIServer.h"
#include "Poco/String.h"
#include "Poco/StringTokenizer.h"
#include "Poco/URIStreamOpener.h"
#include "Poco/StreamCopier.h"
#include "Poco/URI.h"
#include "Poco/File.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
#include "fmt/format.h"
#include "OUIServer.h"
#include "framework/MicroService.h"
namespace OpenWifi {
int OUIServer::Start() {
Running_ = true;
LatestOUIFileName_ = MicroServiceDataDirectory() + "/newOUIFile.txt";
CurrentOUIFileName_ = MicroServiceDataDirectory() + "/current_oui.txt";
bool Recovered = false;
Poco::File OuiFile(CurrentOUIFileName_);
if(OuiFile.exists()) {
std::unique_lock Lock(LocalMutex_);
Recovered = ProcessFile(CurrentOUIFileName_,OUIs_);
if(Recovered) {
poco_notice(Logger(),
fmt::format("Recovered last OUI file - {}", CurrentOUIFileName_));
}
} else {
poco_notice(Logger(),
fmt::format("No existing OUIFile.", CurrentOUIFileName_));
}
UpdaterCallBack_ = std::make_unique<Poco::TimerCallback<OUIServer>>(*this, &OUIServer::onTimer);
if(Recovered) {
Timer_.setStartInterval(60 * 60 * 1000); // first run in 1 hour
} else {
Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
}
Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
Timer_.setPeriodicInterval(7 * 24 * 60 * 60 * 1000);
Timer_.start(*UpdaterCallBack_, MicroServiceTimerPool());
Timer_.start(*UpdaterCallBack_);
return 0;
}
void OUIServer::Stop() {
poco_notice(Logger(),"Stopping...");
Running_=false;
Timer_.stop();
poco_notice(Logger(),"Stopped...");
}
void OUIServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
MicroServiceLoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
void OUIServer::reinitialize(Poco::Util::Application &self) {
MicroService::instance().LoadConfigurationFile();
Logger().information("Reinitializing.");
Stop();
Start();
}
bool OUIServer::GetFile(const std::string &FileName) {
try {
LastUpdate_ = Utils::Now();
poco_information(Logger(), fmt::format("Start: Retrieving OUI file: {}",MicroServiceConfigGetString("oui.download.uri","")));
Logger().information(Poco::format("Start: Retrieving OUI file: %s",MicroService::instance().ConfigGetString("oui.download.uri")));
std::unique_ptr<std::istream> pStr(
Poco::URIStreamOpener::defaultOpener().open(MicroServiceConfigGetString("oui.download.uri","")));
Poco::URIStreamOpener::defaultOpener().open(MicroService::instance().ConfigGetString("oui.download.uri")));
std::ofstream OS;
Poco::File F(FileName);
if(F.exists())
F.remove();
OS.open(FileName);
Poco::StreamCopier::copyStream(*pStr, OS);
OS.close();
poco_information(Logger(), fmt::format("Done: Retrieving OUI file: {}",MicroServiceConfigGetString("oui.download.uri","")));
Logger().information(Poco::format("Done: Retrieving OUI file: %s",MicroService::instance().ConfigGetString("oui.download.uri")));
return true;
} catch (const Poco::Exception &E) {
Logger().log(E);
@@ -102,7 +80,7 @@ namespace OpenWifi {
auto MAC = Utils::SerialNumberToOUI(Tokens[0]);
if (MAC > 0) {
std::string Manufacturer;
for (size_t i = 2; i < Tokens.count(); i++)
for (auto i = 2; i < Tokens.count(); i++)
Manufacturer += Tokens[i] + " ";
auto M = Poco::trim(Manufacturer);
if (!M.empty())
@@ -118,58 +96,38 @@ namespace OpenWifi {
return false;
}
void OUIServer::onTimer([[maybe_unused]] Poco::Timer & timer) {
Utils::SetThreadName("ouisvr-timer");
void OUIServer::onTimer(Poco::Timer & timer) {
if(Updating_)
return;
Updating_ = true;
poco_information(Logger(),"Starting to process OUI file...");
// fetch data from server, if not available, just use the file we already have.
Poco::File Current(CurrentOUIFileName_);
if(Current.exists()) {
if((Utils::Now()-Current.getLastModified().epochTime()) < (7*24*60*60)) {
if(!Initialized_) {
if(ProcessFile(CurrentOUIFileName_, OUIs_)) {
Initialized_ = true;
Updating_=false;
poco_information(Logger(), "Using cached file.");
return;
}
} else {
Updating_=false;
return;
}
}
}
std::string LatestOUIFileName{ MicroService::instance().DataDir() + "/newOUIFile.txt"};
std::string CurrentOUIFileName{ MicroService::instance().DataDir() + "/current_oui.txt"};
OUIMap TmpOUIs;
if(GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
std::unique_lock G(LocalMutex_);
if(GetFile(LatestOUIFileName) && ProcessFile(LatestOUIFileName, TmpOUIs)) {
std::lock_guard G(Mutex_);
OUIs_ = std::move(TmpOUIs);
LastUpdate_ = Utils::Now();
Poco::File F1(CurrentOUIFileName_);
LastUpdate_ = std::time(nullptr);
Poco::File F1(CurrentOUIFileName);
if(F1.exists())
F1.remove();
Poco::File F2(LatestOUIFileName_);
F2.renameTo(CurrentOUIFileName_);
poco_information(Logger(), fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
Poco::File F2(LatestOUIFileName);
F2.renameTo(CurrentOUIFileName);
Logger().information(Poco::format("New OUI file %s downloaded.",LatestOUIFileName));
} else if(OUIs_.empty()) {
if(ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
LastUpdate_ = Utils::Now();
std::unique_lock G(LocalMutex_);
if(ProcessFile(CurrentOUIFileName, TmpOUIs)) {
LastUpdate_ = std::time(nullptr);
std::lock_guard G(Mutex_);
OUIs_ = std::move(TmpOUIs);
}
}
Initialized_=true;
Updating_ = false;
poco_information(Logger(),"Done processing OUI file...");
}
std::string OUIServer::GetManufacturer(const std::string &MAC) {
std::shared_lock Lock(LocalMutex_);
std::lock_guard Guard(Mutex_);
auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
if(Manufacturer != OUIs_.end())
return Manufacturer->second;

View File

@@ -4,10 +4,7 @@
#pragma once
#include <shared_mutex>
#include "framework/SubSystemServer.h"
#include "framework/MicroService.h"
#include "Poco/Timer.h"
namespace OpenWifi {
@@ -33,15 +30,13 @@ namespace OpenWifi {
[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
private:
std::shared_mutex LocalMutex_;
uint64_t LastUpdate_ = 0 ;
bool Initialized_ = false;
bool ValidFile_=false;
OUIMap OUIs_;
volatile std::atomic_bool Updating_=false;
volatile std::atomic_bool Running_=false;
std::atomic_bool Updating_=false;
std::atomic_bool Running_=false;
Poco::Timer Timer_;
std::unique_ptr<Poco::TimerCallback<OUIServer>> UpdaterCallBack_;
std::string LatestOUIFileName_,CurrentOUIFileName_;
OUIServer() noexcept:
SubSystemServer("OUIServer", "OUI-SVR", "ouiserver")

File diff suppressed because it is too large Load Diff

View File

@@ -1,673 +0,0 @@
//
// Created by stephane bourque on 2022-06-20.
//
#pragma once
#include <list>
#include <string>
#include <iostream>
#include <iomanip>
#include "Poco/HMACEngine.h"
#include "Poco/MD5Engine.h"
#include "Poco/StringTokenizer.h"
namespace OpenWifi::RADIUS {
#define RADCMD_ACCESS_REQ 1 /* Access-Request */
#define RADCMD_ACCESS_ACC 2 /* Access-Accept */
#define RADCMD_ACCESS_REJ 3 /* Access-Reject */
#define RADCMD_ACCOUN_REQ 4 /* Accounting-Request */
#define RADCMD_ACCOUN_RES 5 /* Accounting-Response */
#define RADCMD_ACCOUN_STATUS 6 /* Accounting-Status */
#define RADCMD_PASSWORD_REQUEST 7 /* Password-Request [RFC3575] */
#define RADCMD_PASSWORD_ACK 8 /* Password-Ack [RFC3575] */
#define RADCMD_PASSWORD_REJECT 9 /* Password-Reject [RFC3575] */
#define RADCMD_ACCOUN_MESSAGE 10 /* Accounting-Message [RFC3575] */
#define RADCMD_RES_FREE_REQ 21 /* Resource-Free-Request [RFC3575] */
#define RADCMD_RES_FREE_RES 22 /* Resource-Free-Response [RFC3575] */
#define RADCMD_RES_QUERY_REQ 23 /* Resource-Query-Request [RFC3575] */
#define RADCMD_RES_QUERY_RES 24 /* Resource-Query-Response [RFC3575] */
#define RADCMD_RES_ALT_RECLAIM_REQ 25 /* Alternate-Resource-Reclaim-Request [RFC3575] */
#define RADCMD_ACCESS_CHA 11 /* Access-Challenge */
#define RADCMD_STATUS_SER 12 /* Status-Server */
#define RADCMD_STATUS_CLI 13 /* Status-Client */
#define RADCMD_DISCON_REQ 40 /* Disconnect-Request */
#define RADCMD_DISCON_ACK 41 /* Disconnect-ACK */
#define RADCMD_DISCON_NAK 42 /* Disconnect-NAK */
#define RADCMD_COA_REQ 43 /* CoA-Request */
#define RADCMD_COA_ACK 44 /* CoA-ACK */
#define RADCMD_COA_NAK 45 /* CoA-NAK */
#define RADCMD_RESERVED 255 /* Reserved */
/*
21 Resource-Free-Request [RFC3575]
22 Resource-Free-Response [RFC3575]
23 Resource-Query-Request [RFC3575]
24 Resource-Query-Response [RFC3575]
25 Alternate-Resource-Reclaim-Request [RFC3575]
26 NAS-Reboot-Request [RFC3575]
27 NAS-Reboot-Response [RFC3575]
28 Reserved
29 Next-Passcode [RFC3575]
30 New-Pin [RFC3575]
31 Terminate-Session [RFC3575]
32 Password-Expired [RFC3575]
33 Event-Request [RFC3575]
34 Event-Response [RFC3575]
35-39 Unassigned
40 Disconnect-Request [RFC3575][RFC5176]
41 Disconnect-ACK [RFC3575][RFC5176]
42 Disconnect-NAK [RFC3575][RFC5176]
43 CoA-Request [RFC3575][RFC5176]
44 CoA-ACK [RFC3575][RFC5176]
45 CoA-NAK [RFC3575][RFC5176]
46-49 Unassigned
50 IP-Address-Allocate [RFC3575]
51 IP-Address-Release [RFC3575]
52 Protocol-Error [RFC7930]
53-249 Unassigned
250-253 Experimental Use [RFC3575]
254 Reserved [RFC3575]
255 Reserved [RFC3575]
*/
struct tok {
uint cmd;
const char * name;
};
/*
Radius commands
char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
"", //!< 0
"Access-Request",
"Access-Accept",
"Access-Reject",
"Accounting-Request",
"Accounting-Response",
"Accounting-Status",
"Password-Request",
"Password-Accept",
"Password-Reject",
"Accounting-Message", //!< 10
"Access-Challenge",
"Status-Server",
"Status-Client",
"14",
"15",
"16",
"17",
"18",
"19",
"20", //!< 20
"Resource-Free-Request",
"Resource-Free-Response",
"Resource-Query-Request",
"Resource-Query-Response",
"Alternate-Resource-Reclaim-Request",
"NAS-Reboot-Request",
"NAS-Reboot-Response",
"28",
"Next-Passcode",
"New-Pin", //!< 30
"Terminate-Session",
"Password-Expired",
"Event-Request",
"Event-Response",
"35",
"36",
"37",
"38",
"39",
"Disconnect-Request", //!< 40
"Disconnect-ACK",
"Disconnect-NAK",
"CoA-Request",
"CoA-ACK",
"CoA-NAK",
"46",
"47",
"48",
"49",
"IP-Address-Allocate",
"IP-Address-Release", //!< 50
};
*/
static const struct tok radius_command_values[] = {
{ RADCMD_ACCESS_REQ, "Access-Request" },
{ RADCMD_ACCESS_ACC, "Access-Accept" },
{ RADCMD_ACCESS_REJ, "Access-Reject" },
{ RADCMD_ACCOUN_REQ, "Accounting-Request" },
{ RADCMD_ACCOUN_RES, "Accounting-Response" },
{ RADCMD_ACCESS_CHA, "Access-Challenge" },
{ RADCMD_STATUS_SER, "Status-Server" },
{ RADCMD_STATUS_CLI, "Status-Client" },
{ RADCMD_DISCON_REQ, "Disconnect-Request" },
{ RADCMD_DISCON_ACK, "Disconnect-ACK" },
{ RADCMD_DISCON_NAK, "Disconnect-NAK" },
{ RADCMD_COA_REQ, "CoA-Request" },
{ RADCMD_COA_ACK, "CoA-ACK" },
{ RADCMD_COA_NAK, "CoA-NAK" },
{ RADCMD_RESERVED, "Reserved" },
{ RADCMD_ACCOUN_STATUS, "Accounting-Status"},
{ RADCMD_PASSWORD_REQUEST, "Password-Request"},
{ RADCMD_PASSWORD_ACK, "Password-Ack"},
{ RADCMD_PASSWORD_REJECT, "Password-Reject"},
{ RADCMD_ACCOUN_MESSAGE, "Accounting-Message"},
{ RADCMD_RES_FREE_REQ, "Resource-Free-Request"},
{ RADCMD_RES_FREE_RES, "Resource-Free-Response"},
{ RADCMD_RES_QUERY_REQ, "Resource-Query-Request"},
{ RADCMD_RES_QUERY_RES, "Resource-Query-Response"},
{ RADCMD_RES_ALT_RECLAIM_REQ, "Alternate-Resource-Reclaim-Request"},
{ 0, nullptr}
};
static const struct tok radius_attribute_names[] = {
{1,"User-Name"},
{2,"User-Password"},
{3,"CHAP-Password"},
{4,"NAS-IP Address"},
{5,"NAS-Port"},
{6,"Service-Type"},
{7,"Framed-Protocol"},
{8,"Framed-IP-Address"},
{9,"Framed-IP-Netmask"},
{10,"Framed-Routing"},
{11,"Filter-Id"},
{12,"Framed-MTU"},
{13,"Framed-Compression"},
{14,"Login-IP-Host"},
{15,"Login-Service"},
{16,"Login-TCP-Port"},
{18,"Reply-Message"},
{19,"Callback-Number"},
{20,"Callback-ID"},
{22,"Framed-Route"},
{23,"Framed-IPX-Network"},
{24,"State"},
{25,"Class"},
{26,"Vendor-Specific"},
{27,"Session-Timeout"},
{28,"Idle-Timeout"},
{29,"Termination-Action"},
{30,"Called-Station-Id"},
{31,"Calling-Station-Id"},
{32,"NAS-Identifier"},
{33,"Proxy-State"},
{34,"Login-LAT-Service"},
{35,"Login-LAT-Node"},
{36,"Login-LAT-Group"},
{37,"Framed-AppleTalk-Link"},
{38,"Framed-AppleTalk-Network"},
{39,"Framed-AppleTalk-Zone"},
{40,"Acct-Status-Type"},
{41,"Acct-Delay-Time"},
{42,"Acct-Input-Octets"},
{43,"Acct-Output-Octets"},
{44,"Acct-Session-Id"},
{45,"Acct-Authentic"},
{46,"Acct-Session-Time"},
{47,"Acct-Input-Packets"},
{48,"Acct-Output-Packets"},
{49,"Acct-Terminate-Cause"},
{50,"Acct-Multi-Session-Id"},
{51,"Acct-Link-Count"},
{52,"Acct-Input-Gigawords"},
{53,"Acct-Output-Gigawords"},
{55,"Event-Timestamp"},
{60,"CHAP-Challenge"},
{61,"NAS-Port-Type"},
{62,"Port-Limit"},
{63,"Login-LAT-Port"},
{64,"Tunnel-Type3"},
{65,"Tunnel-Medium-Type1"},
{66,"Tunnel-Client-Endpoint"},
{67,"Tunnel-Server-Endpoint1"},
{68,"Acct-Tunnel-Connection-ID"},
{69,"Tunnel-Password1"},
{70,"ARAP-Password"},
{71,"ARAP-Features"},
{72,"ARAP-Zone-Access"},
{73,"ARAP-Security"},
{74,"ARAP-Security-Data"},
{75,"Password-Retry"},
{76,"Prompt"},
{77,"Connect-Info"},
{78,"Configuration-Token"},
{79,"EAP-Message"},
{80,"Message-Authenticator"},
{81,"Tunnel-Private-Group-ID"},
{82,"Tunnel-Assignment-ID1"},
{83,"Tunnel-Preference"},
{84,"ARAP-Challenge-Response"},
{85,"Acct-Interim-Interval"},
{86,"Acct-Tunnel-Packets-Lost"},
{87,"NAS-Port-ID"},
{88,"Framed-Pool"},
{90,"Tunnel-Client-Auth-ID"},
{91,"Tunnel-Server-Auth-ID"},
{0, nullptr}
};
#pragma pack(push,1)
struct RadiusAttribute {
unsigned char type{0};
uint16_t pos{0};
unsigned len{0};
};
struct RawRadiusPacket {
unsigned char code{1};
unsigned char identifier{0};
uint16_t rawlen{0};
unsigned char authenticator[16]{0};
unsigned char attributes[4096]{0};
};
#pragma pack(pop)
constexpr unsigned char Access_Request = 1;
constexpr unsigned char Access_Accept = 2;
constexpr unsigned char Access_Reject = 3;
constexpr unsigned char Access_Challenge = 11;
constexpr unsigned char Accounting_Request = 4;
constexpr unsigned char Accounting_Response = 5;
constexpr unsigned char Accounting_Status = 6;
constexpr unsigned char Accounting_Message = 10;
constexpr unsigned char Disconnect_Request = 40;
constexpr unsigned char Disconnect_ACK = 41;
constexpr unsigned char Disconnect_NAK = 42;
constexpr unsigned char CoA_Request = 43;
constexpr unsigned char CoA_ACK = 44;
constexpr unsigned char CoA_NAK = 45;
inline bool IsAuthentication(unsigned char t) {
return (t == RADIUS::Access_Request ||
t == RADIUS::Access_Accept ||
t == RADIUS::Access_Challenge ||
t == RADIUS::Access_Reject);
}
inline bool IsAccounting(unsigned char t) {
return (t == RADIUS::Accounting_Request ||
t == RADIUS::Accounting_Response ||
t == RADIUS::Accounting_Status ||
t == RADIUS::Accounting_Message);
}
inline bool IsAuthority(unsigned char t) {
return (t == RADIUS::Disconnect_Request ||
t == RADIUS::Disconnect_ACK ||
t == RADIUS::Disconnect_NAK ||
t == RADIUS::CoA_Request ||
t == RADIUS::CoA_ACK ||
t == RADIUS::CoA_NAK);
}
inline const char * CommandName(uint cmd) {
auto cmds = radius_command_values;
while(cmds->cmd && (cmds->cmd!=cmd))
cmds++;
if(cmds->cmd==cmd) return cmds->name;
return "Unknown";
}
inline const char * AttributeName(uint cmd) {
auto cmds = radius_attribute_names;
while(cmds->cmd && (cmds->cmd!=cmd))
cmds++;
if(cmds->cmd==cmd) return cmds->name;
return "Unknown";
}
//
// From: https://github.com/Telecominfraproject/wlan-dictionary/blob/main/dictionary.tip
//
static const uint32_t TIP_vendor_id = 58888;
static const unsigned char TIP_serial = 1;
static const unsigned char TIP_AAAipaddr = 2;
static const unsigned char TIP_AAAipv6addr = 3;
using AttributeList = std::list<RadiusAttribute>;
inline std::ostream &operator<<(std::ostream &os, AttributeList const &P) {
for(const auto &attr:P) {
os << "\tAttr: " << (uint16_t) attr.type << " Size: " << (uint16_t) attr.len << std::endl;
}
return os;
}
inline bool ParseRadius(uint32_t offset, const unsigned char *Buffer, uint16_t Size, AttributeList &Attrs) {
Attrs.clear();
uint16_t pos=0;
auto x=25;
while(pos<Size && x) {
RadiusAttribute Attr{ .type=Buffer[pos], .pos=(uint16_t)(pos+2+offset), .len=(unsigned int)(Buffer[pos+1]-2)};
if(pos+Attr.len<=Size) {
Attrs.emplace_back(Attr);
} else {
std::cout << "Bad parse1: " << (uint32_t) (pos+Attr.len) << " S:" << Size << std::endl;
return false;
}
if(Buffer[pos+1]==0) {
std::cout << "Bad parse2: " << (uint32_t) (pos+Attr.len) << " S:" << Size << std::endl;
return false;
}
pos+=Buffer[pos+1];
x--;
}
return true;
}
class RadiusPacket {
public:
explicit RadiusPacket(const Poco::Buffer<char> & Buf) {
if(Buf.size() >= sizeof(RawRadiusPacket)) {
Valid_ = false;
return;
}
memcpy((void *)&P_,Buf.begin(), Buf.size());
Size_=Buf.size();
Valid_ = (Size_== htons(P_.rawlen));
if(Valid_)
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
}
explicit RadiusPacket(const unsigned char *buffer, uint16_t size) {
if(size >= sizeof(RawRadiusPacket)) {
Valid_ = false;
return;
}
memcpy((void *)&P_,buffer, size);
Size_=size;
Valid_ = (Size_== htons(P_.rawlen));
if(Valid_)
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
}
explicit RadiusPacket(const std::string &p) {
if(p.size() >= sizeof(RawRadiusPacket)) {
Valid_ = false;
return;
}
memcpy((void *)&P_,(const unsigned char*) p.c_str(), p.size());
Size_=p.size();
Valid_ = (Size_== htons(P_.rawlen));
if(Valid_)
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
}
explicit RadiusPacket(const RadiusPacket &P) {
Valid_ = P.Valid_;
Size_ = P.Size_;
P_ = P.P_;
Attrs_ = P.Attrs_;
}
explicit RadiusPacket() = default;
unsigned char * Buffer() { return (unsigned char *)&P_; }
[[nodiscard]] uint16_t BufferLen() const { return sizeof(P_);}
void Evaluate(uint16_t size) {
Size_ = size;
Valid_ = ParseRadius(0,(unsigned char *)&P_.attributes[0],Size_-20,Attrs_);
}
[[nodiscard]] uint16_t Len() const { return htons(P_.rawlen); }
[[nodiscard]] uint16_t Size() const { return Size_; }
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
inline bool IsAuthentication() {
return (P_.code == RADIUS::Access_Request ||
P_.code == RADIUS::Access_Accept ||
P_.code == RADIUS::Access_Challenge ||
P_.code == RADIUS::Access_Reject ||
P_.code == RADCMD_RES_FREE_REQ ||
P_.code == RADCMD_RES_FREE_RES ||
P_.code == RADCMD_RES_QUERY_REQ ||
P_.code == RADCMD_RES_QUERY_RES ||
P_.code == RADCMD_RES_ALT_RECLAIM_REQ);
}
inline bool IsAccounting() {
return (P_.code == RADIUS::Accounting_Request ||
P_.code == RADIUS::Accounting_Response ||
P_.code == RADIUS::Accounting_Status ||
P_.code == RADIUS::Accounting_Message);
}
inline bool IsAuthority() {
return (P_.code == RADIUS::Disconnect_Request ||
P_.code == RADIUS::Disconnect_ACK ||
P_.code == RADIUS::Disconnect_NAK ||
P_.code == RADIUS::CoA_Request ||
P_.code == RADIUS::CoA_ACK ||
P_.code == RADIUS::CoA_NAK);
}
void Log(std::ostream &os) {
uint16_t p = 0;
while(p<Size_) {
os << std::setfill('0') << std::setw(4) << p << ": ";
uint16_t v=0;
while(v<16 && p+v<Size_) {
os << std::setfill('0') << std::setw(2) << std::right << std::hex << (uint16_t )((const unsigned char *)&P_)[p+v] << " ";
v++;
}
os << std::endl;
p+=16;
}
os << std::dec << std::endl << std::endl;
Print(os);
}
inline const char * PacketType() {
return CommandName(P_.code);
}
inline int PacketTypeInt() {
return (int)(P_.code);
}
void ComputeMessageAuthenticator(const std::string &secret) {
RawRadiusPacket P = P_;
if(P_.code==1) {
unsigned char OldAuthenticator[16]{0};
for (const auto &attr : Attrs_) {
if (attr.type == 80) {
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
memset(&P.attributes[attr.pos], 0, 16);
}
}
unsigned char NewAuthenticator[16]{0};
Poco::HMACEngine<Poco::MD5Engine> H(secret);
H.update((const unsigned char *)&P, Size_);
auto digest = H.digest();
int p = 0;
for (const auto &i : digest)
NewAuthenticator[p++] = i;
if (memcmp(OldAuthenticator, NewAuthenticator, 16) == 0) {
std::cout << "Authenticator match..." << std::endl;
} else {
std::cout << "Authenticator MIS-match..." << std::endl;
for (const auto &attr : Attrs_) {
if (attr.type == 80) {
memcpy(&P_.attributes[attr.pos], NewAuthenticator, 16);
}
}
}
}
}
bool VerifyMessageAuthenticator(const std::string &secret) {
RawRadiusPacket P = P_;
if(P_.code==1) {
unsigned char OldAuthenticator[16]{0};
for (const auto &attr : Attrs_) {
if (attr.type == 80) {
memcpy(OldAuthenticator, &P_.attributes[attr.pos], 16);
memset(&P.attributes[attr.pos], 0, 16);
}
}
unsigned char NewAuthenticator[16]{0};
Poco::HMACEngine<Poco::MD5Engine> H(secret);
H.update((const unsigned char *)&P, Size_);
auto digest = H.digest();
int p = 0;
for (const auto &i : digest)
NewAuthenticator[p++] = i;
return memcmp(OldAuthenticator, NewAuthenticator, 16) == 0;
}
return true;
}
static void BufLog(std::ostream & os, const char * pre, const unsigned char *b, uint s) {
uint16_t p = 0;
while(p<s) {
os << pre << std::setfill('0') << std::setw(4) << p << ": ";
uint16_t v=0;
while(v<16 && p+v<s) {
os << std::setfill('0') << std::setw(2) << std::right << std::hex << (uint16_t )b[p+v] << " ";
v++;
}
os << std::endl;
p+=16;
}
os << std::dec ;
}
inline void Print(std::ostream &os) {
os << "Packet type: (" << (uint) P_.code << ") " << CommandName(P_.code) << std::endl;
os << " Identifier: " << (uint) P_.identifier << std::endl;
os << " Length: " << Size_ << std::endl;
os << " Authenticator: " ;
BufLog(os, "", P_.authenticator, sizeof(P_.authenticator));
os << " Attributes: " << std::endl;
for(const auto &attr:Attrs_) {
os << " " << std::setfill(' ') << "(" << std::setw(4) << (uint) attr.type << ") " << AttributeName(attr.type) << " Len:" << attr.len << std::endl;
BufLog(os, " " , &P_.attributes[attr.pos], attr.len);
}
os << std::dec << std::endl << std::endl;
}
std::string ExtractSerialNumberTIP() {
std::string R;
for(const auto &attribute:Attrs_) {
if(attribute.type==26) {
AttributeList VendorAttributes;
uint32_t VendorId = htonl( *(const uint32_t *)&(P_.attributes[attribute.pos]));
// std::cout << VendorId << std::endl;
if(VendorId==TIP_vendor_id && attribute.len>(4+2)) {
if (ParseRadius(attribute.pos + 4, &P_.attributes[attribute.pos + 4], attribute.len - 4 - 2,
VendorAttributes)) {
// std::cout << VendorAttributes << std::endl;
for (const auto &vendorAttr: VendorAttributes) {
if (vendorAttr.type == TIP_serial) {
for (uint16_t i = 0; i < vendorAttr.len; i++) {
if (P_.attributes[vendorAttr.pos + i] == '-')
continue;
R += (char) P_.attributes[vendorAttr.pos + i];
}
return R;
}
}
}
}
}
}
return R;
}
std::string ExtractSerialNumberFromProxyState() {
std::string Result;
for(const auto &attribute:Attrs_) {
if(attribute.type==33) {
const char * SN = (const char *)&P_.attributes[attribute.pos];
auto i=0;
while(*SN!=':' && i<12) {
Result+=*SN++;
i++;
}
return Result;
}
}
return Result;
}
std::string ExtractProxyStateDestination() {
std::string Result;
for(const auto &attribute:Attrs_) {
if(attribute.type==33 && attribute.len>2) {
std::string Attr33;
// format is serial:IP:port:interface
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
auto Parts = Poco::StringTokenizer(Attr33,":");
if(Parts.count()==4)
return Parts[1]+":"+Parts[2];
return Result;
}
}
return Result;
}
std::string ExtractCallingStationID() {
std::string Result;
for(const auto &attribute:Attrs_) {
if(attribute.type==31 && attribute.len>2) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
return Result;
}
}
return Result;
}
std::string ExtractCalledStationID() {
std::string Result;
for(const auto &attribute:Attrs_) {
if(attribute.type==30 && attribute.len>2) {
Result.assign((const char *)(const char *)&P_.attributes[attribute.pos],attribute.len-2);
return Result;
}
}
return Result;
}
[[nodiscard]] std::string UserName() const {
for(const auto &attr:Attrs_) {
if(attr.type==1) {
std::string user_name{(const char *)&P_.attributes[attr.pos],attr.len};
return user_name;
}
}
return "";
}
private:
RawRadiusPacket P_;
uint16_t Size_{0};
AttributeList Attrs_;
bool Valid_=false;
};
inline std::ostream &operator<<(std::ostream &os, RadiusPacket const &P) {
os << P.Attrs_ ;
return os;
}
}

View File

@@ -1,665 +0,0 @@
//
// Created by stephane bourque on 2022-05-18.
//
#include "Poco/JSON/Parser.h"
#include "RADIUS_proxy_server.h"
#include "RADIUS_helpers.h"
#include "AP_WS_Server.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
const int SMALLEST_RADIUS_PACKET = 20+19+4;
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799;
int RADIUS_proxy_server::Start() {
ConfigFilename_ = MicroServiceDataDirectory()+"/radius_pool_config.json";
Poco::File Config(ConfigFilename_);
enabled_ = MicroServiceConfigGetBool("radius.proxy.enable",false);
if(!enabled_ && !Config.exists()) {
StopRADSECServers();
return 0;
}
poco_notice(Logger(),"Starting...");
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);
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);
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);
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);
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);
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);
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();
// start RADSEC servers...
StopRADSECServers();
StartRADSECServers();
RadiusReactorThread_.start(RadiusReactor_);
Utils::SetThreadName(RadiusReactorThread_,"rad:reactor");
running_ = true;
return 0;
}
void RADIUS_proxy_server::Stop() {
poco_information(Logger(),"Stopping...");
if(enabled_ && running_) {
RadiusReactor_.removeEventHandler(
*AuthenticationSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_.removeEventHandler(
*AuthenticationSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
RadiusReactor_.removeEventHandler(
*AccountingSocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_.removeEventHandler(
*AccountingSocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
RadiusReactor_.removeEventHandler(
*CoASocketV4_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
RadiusReactor_.removeEventHandler(
*CoASocketV6_,
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
StopRADSECServers();
RadiusReactor_.stop();
RadiusReactorThread_.join();
enabled_=false;
running_=false;
}
poco_information(Logger(),"Stopped...");
}
void RADIUS_proxy_server::StartRADSECServers() {
for(const auto &pool:PoolList_.pools) {
for(const auto &entry:pool.authConfig.servers) {
if(entry.radsec) {
StartRADSECServer(entry);
}
}
}
}
void RADIUS_proxy_server::StopRADSECServers() {
RADSECservers_.clear();
}
void RADIUS_proxy_server::StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E) {
RADSECservers_[ Poco::Net::SocketAddress(E.ip,0) ] = std::make_unique<RADSEC_server>(RadiusReactor_,E);
}
void RADIUS_proxy_server::OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(),"Accounting: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if(SerialNumber.empty()) {
poco_warning(Logger(),"Accounting: missing serial number.");
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 RADIUS_proxy_server::OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(),"Authentication: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
if(SerialNumber.empty()) {
poco_warning(Logger(),"Authentication: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(Logger(), fmt::format("Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber,P.Buffer(),P.Size());
}
void RADIUS_proxy_server::OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
Poco::Net::SocketAddress Sender;
RADIUS::RadiusPacket P;
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(),P.BufferLen());
if(ReceiveSize<SMALLEST_RADIUS_PACKET) {
poco_warning(Logger(),"CoA/DM: bad packet received.");
return;
}
P.Evaluate(ReceiveSize);
auto SerialNumber = P.ExtractSerialNumberTIP();
if(SerialNumber.empty()) {
poco_warning(Logger(),"CoA/DM: missing serial number.");
return;
}
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
poco_debug(Logger(), fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",SerialNumber, CalledStationID, CallingStationID));
AP_WS_Server()->SendRadiusCoAData(SerialNumber,P.Buffer(),P.Size());
}
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size) {
if(Pools_.empty() || !enabled_)
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
auto Destination = P.ExtractProxyStateDestination();
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC);
if (UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
auto DestinationServer = RADSECservers_.find(RSP);
if (DestinationServer != end(RADSECservers_)) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
size);
}
} else {
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
AccountingSocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
AccountingSocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format(
"ACCT: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
}
auto AllSent =
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
: *AccountingSocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(),
fmt::format("{}: Could not send Accounting packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending Accounting Packet to {}, CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(),
CalledStationID, CallingStationID));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),fmt::format("Bad RADIUS ACCT Packet from {}. Dropped.",serialNumber));
}
}
bool RADIUS_proxy_server::SendData( Poco::Net::DatagramSocket & Sock, const unsigned char *buf , std::size_t size, const Poco::Net::SocketAddress &S) {
return Sock.sendTo(buf, size, S)==(int)size;
}
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber, const char *buffer, std::size_t size) {
if(Pools_.empty() || !enabled_)
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
auto Destination = P.ExtractProxyStateDestination();
auto CallingStationID = P.ExtractCallingStationID();
auto CalledStationID = P.ExtractCalledStationID();
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC);
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 &&
AuthenticationSocketV4_ == nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
AuthenticationSocketV6_ == nullptr)) {
poco_debug(
Logger(),
fmt::format("AUTH: Trying to use RADIUS GW PROXY but not configured. Device={}",
serialNumber));
return;
}
auto AllSent =
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AuthenticationSocketV4_
: *AuthenticationSocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(),
fmt::format("{}: Could not send Authentication packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending Authentication Packet to {}, CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(),
CalledStationID, CallingStationID));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),fmt::format("Bad RADIUS AUTH Packet from {}. Dropped.",serialNumber));
}
}
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size) {
if(Pools_.empty() || !enabled_)
return;
try {
RADIUS::RadiusPacket P((unsigned char *)buffer,size);
auto Destination = P.ExtractProxyStateDestination();
if(Destination.empty()) {
Destination = "0.0.0.0:0";
}
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
bool UseRADSEC = false;
auto FinalDestination = Route(radius_type::coa, Dst, P, UseRADSEC);
if(UseRADSEC) {
Poco::Net::SocketAddress RSP(FinalDestination.host(),0);
auto DestinationServer = RADSECservers_.find(RSP);
if(DestinationServer!=end(RADSECservers_)) {
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer, size);
}
} else {
if( (Dst.family() == Poco::Net::SocketAddress::IPv4 && CoASocketV4_== nullptr) ||
(Dst.family() == Poco::Net::SocketAddress::IPv6 && CoASocketV6_== nullptr)) {
poco_debug(Logger(),fmt::format("CoA: Trying to use RADIUS GW PROXY but not configured. Device={}",serialNumber));
return;
}
auto AllSent = SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_
: *CoASocketV6_,
(const unsigned char *)buffer, size, FinalDestination);
if (!AllSent)
poco_error(Logger(),fmt::format("{}: Could not send CoA packet packet to {}.",
serialNumber, Destination));
else
poco_debug(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
FinalDestination.toString()));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_warning(Logger(),fmt::format("Bad RADIUS CoA/DM Packet from {}. Dropped.",serialNumber));
}
}
void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault) {
uint64_t TotalV4=0, TotalV6=0;
for(const auto &server:Config.servers) {
Poco::Net::IPAddress a;
if(!Poco::Net::IPAddress::tryParse(server.ip,a)) {
poco_error(Logger(),fmt::format("RADIUS-PARSE Config: server address {} is nto a valid address in v4 or v6. Entry skipped.",server.ip));
continue;
}
auto S = Poco::Net::SocketAddress(fmt::format("{}:{}",server.ip,server.port));
Destination D{
.Addr = S,
.state = 0,
.step = 0,
.weight = server.weight,
.available = true,
.strategy = Config.strategy,
.monitor = Config. monitor,
.monitorMethod = Config.monitorMethod,
.methodParameters = Config.methodParameters,
.useAsDefault = setAsDefault,
.useRADSEC = server.radsec,
.realms = server.radsecRealms
};
if(setAsDefault && D.useRADSEC)
defaultIsRADSEC_ = true;
if(S.family()==Poco::Net::IPAddress::IPv4) {
TotalV4 += server.weight;
V4.push_back(D);
} else {
TotalV6 += server.weight;
V6.push_back(D);
}
}
for(auto &i:V4) {
if(TotalV4==0) {
i.step = 1000;
} else {
i.step = 1000 - ((1000 * i.weight) / TotalV4);
}
}
for(auto &i:V6) {
if(TotalV6==0) {
i.step = 1000;
} else {
i.step = 1000 - ((1000 * i.weight) / TotalV6);
}
}
}
void RADIUS_proxy_server::ParseConfig() {
try {
Poco::File F(ConfigFilename_);
std::lock_guard G(Mutex_);
if(F.exists()) {
std::ifstream ifs(ConfigFilename_,std::ios_base::binary);
Poco::JSON::Parser P;
auto RawConfig = P.parse(ifs).extract<Poco::JSON::Object::Ptr>();
GWObjects::RadiusProxyPoolList RPC;
if(RPC.from_json(RawConfig)) {
ResetConfig();
PoolList_ = RPC;
for(const auto &pool:RPC.pools) {
RadiusPool NewPool;
ParseServerList(pool.authConfig, NewPool.AuthV4, NewPool.AuthV6, pool.useByDefault);
ParseServerList(pool.acctConfig, NewPool.AcctV4, NewPool.AcctV6, pool.useByDefault);
ParseServerList(pool.coaConfig, NewPool.CoaV4, NewPool.CoaV6, pool.useByDefault);
Pools_.push_back(NewPool);
}
} else {
poco_warning(Logger(),fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
}
} else {
poco_warning(Logger(),fmt::format("No configuration file '{}' exists.",ConfigFilename_));
}
} catch (const Poco::Exception &E) {
Logger().log(E);
} catch (...) {
poco_error(Logger(),fmt::format("Error while parsing configuration file '{}'",ConfigFilename_));
}
}
static bool RealmMatch(const std::string &user_realm, const std::string & realm) {
if(realm.find_first_of('*') == std::string::npos)
return user_realm == realm;
return realm.find(user_realm) != std::string::npos;
}
Poco::Net::SocketAddress RADIUS_proxy_server::DefaultRoute(radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
// find the realm...
auto UserName = P.UserName();
if(!UserName.empty()) {
auto UserTokens = Poco::StringTokenizer(UserName, "@");
auto UserRealm = ((UserTokens.count() > 1) ? UserTokens[1] : UserName);
Poco::toLowerInPlace(UserRealm);
for(const auto &pool:Pools_) {
for(const auto &server:pool.AuthV4) {
if(!server.realms.empty()) {
for(const auto &realm:server.realms) {
if (RealmMatch(UserRealm,realm)) {
std::cout << "Realm match..." << std::endl;
UseRADSEC = true;
return server.Addr;
}
}
}
}
}
}
if(defaultIsRADSEC_) {
UseRADSEC = true;
return (IsV4 ? Pools_[defaultPoolIndex_].AuthV4[0].Addr : Pools_[defaultPoolIndex_].AuthV6[0].Addr );
}
switch(rtype) {
case radius_type::auth: {
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AuthV4
: Pools_[defaultPoolIndex_].AuthV6,
RequestedAddress);
}
case radius_type::acct:
default: {
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].AcctV4
: Pools_[defaultPoolIndex_].AcctV6,
RequestedAddress);
}
case radius_type::coa: {
return ChooseAddress(IsV4 ? Pools_[defaultPoolIndex_].CoaV4
: Pools_[defaultPoolIndex_].CoaV6,
RequestedAddress);
}
}
}
Poco::Net::SocketAddress RADIUS_proxy_server::Route([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC) {
std::lock_guard G(Mutex_);
if(Pools_.empty()) {
UseRADSEC = false;
return RequestedAddress;
}
bool IsV4 = RequestedAddress.family()==Poco::Net::SocketAddress::IPv4;
bool useDefault;
useDefault = IsV4 ? RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv4) : RequestedAddress.host() == Poco::Net::IPAddress::wildcard(Poco::Net::IPAddress::IPv6) ;
if(useDefault) {
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
}
auto isAddressInPool = [&](const std::vector<Destination> & D, bool &UseRADSEC) -> bool {
for(const auto &entry:D)
if(entry.Addr.host()==RequestedAddress.host()) {
UseRADSEC = entry.useRADSEC;
return true;
}
return false;
};
for(auto &i:Pools_) {
switch(rtype) {
case radius_type::coa: {
if (isAddressInPool((IsV4 ? i.CoaV4 : i.CoaV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.CoaV4 : i.CoaV6, RequestedAddress);
}
} break;
case radius_type::auth: {
if (isAddressInPool((IsV4 ? i.AuthV4 : i.AuthV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AuthV4 : i.AuthV6, RequestedAddress);
}
} break;
case radius_type::acct: {
if (isAddressInPool((IsV4 ? i.AcctV4 : i.AcctV6), UseRADSEC)) {
return ChooseAddress(IsV4 ? i.AcctV4 : i.AcctV6, RequestedAddress);
}
} break;
}
}
UseRADSEC = false;
return RequestedAddress;
}
Poco::Net::SocketAddress RADIUS_proxy_server::ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress) {
if(Pool.size()==1) {
return Pool[0].Addr;
}
if (Pool[0].strategy == "weighted") {
bool found = false;
uint64_t cur_state = std::numeric_limits<uint64_t>::max();
std::size_t pos = 0, index = 0;
for (auto &i : Pool) {
if (!i.available) {
i.state += i.step;
continue;
}
if (i.state < cur_state) {
index = pos;
cur_state = i.state;
found = true;
}
pos++;
}
if (!found) {
return OriginalAddress;
}
Pool[index].state += Pool[index].step;
return Pool[index].Addr;
} else if (Pool[0].strategy == "round_robin") {
bool found = false;
uint64_t cur_state = std::numeric_limits<uint64_t>::max();
std::size_t pos = 0, index = 0;
for (auto &i : Pool) {
if (!i.available) {
i.state += 1;
continue;
}
if (i.state < cur_state) {
index = pos;
cur_state = i.state;
found = true;
}
pos++;
}
if (!found) {
return OriginalAddress;
}
Pool[index].state += 1;
return Pool[index].Addr;
} else if (Pool[0].strategy == "random") {
if (Pool.size() > 1) {
return Pool[std::rand() % Pool.size()].Addr;
} else {
return OriginalAddress;
}
}
return OriginalAddress;
}
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
std::lock_guard G(Mutex_);
PoolList_ = C;
Poco::JSON::Object Disk;
C.to_json(Disk);
std::ofstream ofs(ConfigFilename_, std::ios_base::trunc | std::ios_base::binary );
Disk.stringify(ofs);
ofs.close();
if(!running_) {
Start();
}
ParseConfig();
}
void RADIUS_proxy_server::ResetConfig() {
PoolList_.pools.clear();
Pools_.clear();
defaultPoolIndex_=0;
}
void RADIUS_proxy_server::DeleteConfig() {
std::lock_guard G(Mutex_);
try {
Poco::File F(ConfigFilename_);
if (F.exists())
F.remove();
} catch (...) {
}
ResetConfig();
Stop();
}
void RADIUS_proxy_server::GetConfig(GWObjects::RadiusProxyPoolList &C) {
std::lock_guard G(Mutex_);
C = PoolList_;
}
}

View File

@@ -1,113 +0,0 @@
//
// Created by stephane bourque on 2022-05-18.
//
#pragma once
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketReactor.h"
#include "framework/SubSystemServer.h"
#include "RADSEC_server.h"
namespace OpenWifi {
enum class radius_type {
auth, acct, coa
};
class RADIUS_proxy_server : public SubSystemServer {
public:
inline static auto instance() {
static auto instance_= new RADIUS_proxy_server;
return instance_;
}
int Start() final;
void Stop() final;
inline bool Enabled() const { return enabled_; }
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void SendAccountingData(const std::string &serialNumber, const char *buffer, std::size_t size);
void SendAuthenticationData(const std::string &serialNumber, const char *buffer, std::size_t size);
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
void DeleteConfig();
void GetConfig(GWObjects::RadiusProxyPoolList &C);
void StartRADSECServers();
void StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E);
void StopRADSECServers();
struct Destination {
Poco::Net::SocketAddress Addr;
uint64_t state = 0;
uint64_t step = 0;
uint64_t weight=0;
bool available = true;
std::string strategy;
bool monitor=false;
std::string monitorMethod;
std::vector<std::string> methodParameters;
bool useAsDefault=false;
bool useRADSEC=false;
std::vector<std::string> realms;
};
private:
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
Poco::Net::SocketReactor RadiusReactor_;
Poco::Thread RadiusReactorThread_;
GWObjects::RadiusProxyPoolList PoolList_;
std::string ConfigFilename_;
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSEC_server>> RADSECservers_;
struct RadiusPool {
std::vector<Destination> AuthV4;
std::vector<Destination> AuthV6;
std::vector<Destination> AcctV4;
std::vector<Destination> AcctV6;
std::vector<Destination> CoaV4;
std::vector<Destination> CoaV6;
};
std::vector<RadiusPool> Pools_;
uint defaultPoolIndex_=0;
bool enabled_=false;
bool defaultIsRADSEC_=false;
std::atomic_bool running_=false;
RADIUS_proxy_server() noexcept:
SubSystemServer("RADIUS-PROXY", "RADIUS-PROXY", "radius.proxy")
{
}
static bool SendData( Poco::Net::DatagramSocket & Sock, const unsigned char *buf , std::size_t size, const Poco::Net::SocketAddress &S);
void ParseConfig();
void ResetConfig();
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
void ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, std::vector<Destination> &V4, std::vector<Destination> &V6, bool setAsDefault);
static Poco::Net::SocketAddress ChooseAddress(std::vector<Destination> &Pool, const Poco::Net::SocketAddress & OriginalAddress);
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype, const Poco::Net::SocketAddress &RequestedAddress, const RADIUS::RadiusPacket &P, bool &UseRADSEC);
};
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
}

View File

@@ -1,272 +0,0 @@
//
// Created by stephane bourque on 2022-08-15.
//
#pragma once
#include <iostream>
#include <fstream>
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/Context.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Net/NetException.h"
#include "Poco/TemporaryFile.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
#include "RADIUS_helpers.h"
#include "AP_WS_Server.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)))
{
ReconnectThread_.start(*this);
}
~RADSEC_server() {
if(ReconnectThread_.isRunning()) {
Stop();
}
}
inline void Stop() {
TryAgain_ = false;
Disconnect();
ReconnectThread_.wakeUp();
ReconnectThread_.join();
}
inline void run() final {
while(TryAgain_) {
if(!Connected_) {
std::unique_lock G(Mutex_);
Connect();
}
Poco::Thread::trySleep(3000);
}
}
inline bool SendData(const std::string &serial_number, const unsigned char *buffer, int length) {
try {
if (Connected_) {
RADIUS::RadiusPacket P(buffer, length);
// std::cout << serial_number << " Sending " << P.PacketType() << " " << length << " bytes" << std::endl;
int sent_bytes;
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
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 (...) {
}
return false;
}
inline void onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
unsigned char Buffer[4096];
try {
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer,sizeof(Buffer));
if(NumberOfReceivedBytes>40) {
RADIUS::RadiusPacket P(Buffer,NumberOfReceivedBytes);
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_,
fmt::format("Invalid AUTH packet received in proxy dropped. No serial number Source={}",
Socket_->address().toString()));
}
} 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_,
fmt::format("Invalid ACCT packet received in proxy dropped. No serial number Source={}",
Socket_->address().toString()));
}
} else if (P.IsAuthority()) {
}
} else {
Disconnect();
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
Disconnect();
}
}
inline void onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
std::cout << "onError" << std::endl;
Disconnect();
}
inline void onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
std::cout << "onShutdown" << std::endl;
Disconnect();
}
inline bool Connect() {
if(TryAgain_) {
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
std::vector<Poco::TemporaryFile> CaCertFiles_;
DecodeFile(CertFile_.path(), Server_.radsecCert);
DecodeFile(KeyFile_.path(), Server_.radsecKey);
for(auto &cert:Server_.radsecCacerts) {
CaCertFiles_.emplace_back(Poco::TemporaryFile(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(),""));
for(const auto &ca:CaCertFiles_) {
Poco::Crypto::X509Certificate cert(ca.path());
SecureContext->addCertificateAuthority(cert);
}
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
try {
poco_information(Logger_, "Attempting to connect");
Socket_->connect(Destination, Poco::Timespan(100, 0));
Socket_->completeHandshake();
Socket_->verifyPeerCertificate();
if(Socket_->havePeerCertificate()) {
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(Socket_->peerCertificate());
}
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
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));
Socket_->setBlocking(false);
Socket_->setNoDelay(true);
Socket_->setKeepAlive(true);
Connected_ = true;
poco_information(Logger_,fmt::format("Connected. CN={}",CommonName()));
return true;
} catch (const Poco::Net::NetException &E) {
poco_information(Logger_,"Could not connect.");
Logger_.log(E);
} catch (const Poco::Exception &E) {
poco_information(Logger_,"Could not connect.");
Logger_.log(E);
} catch (...) {
poco_information(Logger_,"Could not connect.");
}
}
return false;
}
inline void Disconnect() {
if(Connected_) {
std::unique_lock G(Mutex_);
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<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));
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 Mutex_;
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;
};
}

View File

@@ -1,41 +1,36 @@
//
// Created by stephane bourque on 2021-06-28.
//
#include <cctype>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <future>
#include <numeric>
#include <chrono>
#include "RESTAPI_RPC.h"
#include "CommandManager.h"
#include "AP_WS_Server.h"
#include "DeviceRegistry.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_Handler.h"
#include "ParseWifiScan.h"
#include "framework/utils.h"
#include "framework/uCentral_Protocol.h"
namespace OpenWifi::RESTAPI_RPC {
void SetCommandStatus(GWObjects::CommandDetails &Cmd,
[[maybe_unused]] Poco::Net::HTTPServerRequest &Request,
[[maybe_unused]] Poco::Net::HTTPServerResponse &Response,
RESTAPIHandler *Handler,
OpenWifi::Storage::CommandExecutionType Status,
[[maybe_unused]] Poco::Logger &Logger) {
Poco::Net::HTTPServerRequest &Request,
Poco::Net::HTTPServerResponse &Response,
RESTAPIHandler *Handler,
OpenWifi::Storage::CommandExecutionType Status,
Poco::Logger &Logger) {
if (StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Status)) {
Poco::JSON::Object RetObj;
Cmd.to_json(RetObj);
if(Handler!= nullptr)
return Handler->ReturnObject(RetObj);
return;
return Handler->ReturnObject(RetObj);
}
if(Handler!= nullptr)
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
}
void WaitForCommand(uint64_t RPCID,
bool RetryLater,
GWObjects::CommandDetails &Cmd,
void WaitForCommand(GWObjects::CommandDetails &Cmd,
Poco::JSON::Object & Params,
Poco::Net::HTTPServerRequest &Request,
Poco::Net::HTTPServerResponse &Response,
@@ -44,118 +39,87 @@ namespace OpenWifi::RESTAPI_RPC {
RESTAPIHandler * Handler,
Poco::Logger &Logger) {
Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID, RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
// if the command should be executed in the future, or if the device is not connected,
// then we should just add the command to
// the DB and let it figure out when to deliver the command.
auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
if (Cmd.RunAt || (!AP_WS_Server()->Connected(SerialNumberInt) && RetryLater)) {
Logger.information(fmt::format("{},{}: Command will be run in the future or when device is connected again.", Cmd.UUID, RPCID));
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
if (Cmd.RunAt || !DeviceRegistry()->Connected(Cmd.SerialNumber)) {
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
return;
} else if ((!AP_WS_Server()->Connected(SerialNumberInt) && !RetryLater)){
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
}
Cmd.Executed = Utils::Now();
Cmd.Executed = std::time(nullptr);
bool Sent;
std::chrono::time_point<std::chrono::high_resolution_clock> rpc_submitted = std::chrono::high_resolution_clock::now();
std::shared_ptr<CommandManager::promise_type_t> rpc_endpoint =
CommandManager()->PostCommand(RPCID, Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
CommandManager()->PostCommand(Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, Sent);
if(RetryLater && (!Sent || rpc_endpoint== nullptr)) {
Logger.information(fmt::format("{},{}: Pending completion. Device is not connected.", Cmd.UUID, RPCID));
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
}
if (Sent && rpc_endpoint!= nullptr) {
std::future<CommandManager::objtype_t> rpc_future(rpc_endpoint->get_future());
auto rpc_result = rpc_future.wait_for(WaitTimeInMs);
if (rpc_result == std::future_status::ready && rpc_future.valid()) {
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - rpc_submitted;
auto rpc_answer = rpc_future.get();
if (rpc_answer) {
if (rpc_answer->has("result") && rpc_answer->isObject("result")) {
auto ResultFields =
rpc_answer->get("result").extract<Poco::JSON::Object::Ptr>();
if (ResultFields->has("status") && ResultFields->isObject("status")) {
auto StatusInnerObj =
ResultFields->get("status").extract<Poco::JSON::Object::Ptr>();
if (StatusInnerObj->has("error"))
Cmd.ErrorCode = StatusInnerObj->get("error");
if (StatusInnerObj->has("text"))
Cmd.ErrorText = StatusInnerObj->get("text").toString();
std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(rpc_answer->get("result"),
ResultText);
Cmd.Results = ResultText.str();
Cmd.Status = "completed";
Cmd.Completed = time(nullptr);
Cmd.executionTime = rpc_execution_time.count();
if(!RetryLater && !Sent) {
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
}
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
Cmd.WaitingForFile = 0;
Cmd.AttachDate = Cmd.AttachSize = 0;
Cmd.AttachType = "";
}
Logger.information(fmt::format("{},{}: Command sent.", Cmd.UUID, RPCID));
std::future<CommandManager::objtype_t> rpc_future(rpc_endpoint->get_future());
auto rpc_result = rpc_future.wait_for(WaitTimeInMs);
if (rpc_result == std::future_status::ready) {
std::chrono::duration<double, std::milli> rpc_execution_time = std::chrono::high_resolution_clock::now() - rpc_submitted;
auto rpc_answer = rpc_future.get();
if (!rpc_answer->has(uCentralProtocol::RESULT) || !rpc_answer->isObject(uCentralProtocol::RESULT)) {
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
Logger.information(fmt::format("{},{}: Invalid response. Missing result.", Cmd.UUID, RPCID));
return;
}
// Add the completed command to the database...
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::COMMAND_COMPLETED);
auto ResultFields = rpc_answer->get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
if (!ResultFields->has(uCentralProtocol::STATUS) || !ResultFields->isObject(uCentralProtocol::STATUS)) {
Cmd.executionTime = rpc_execution_time.count();
if(Cmd.Command=="ping") {
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_COMPLETED, Logger);
Logger.information(fmt::format("{},{}: Invalid response from device (ping: fix override). Missing status.", Cmd.UUID, RPCID));
} else {
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
Logger.information(fmt::format("{},{}: Invalid response from device. Missing status.", Cmd.UUID,RPCID));
if (ObjectToReturn) {
Handler->ReturnObject(*ObjectToReturn);
} else {
Poco::JSON::Object O;
Cmd.to_json(O);
Handler->ReturnObject(O);
}
Logger.information(Poco::format("Command(%s): completed in %8.3fms.", Cmd.UUID, Cmd.executionTime));
return;
} else {
SetCommandStatus(Cmd, Request, Response, Handler,
Storage::COMMAND_FAILED, Logger);
Logger.information(Poco::format(
"Invalid response for command '%s'. Missing status.", Cmd.UUID));
return;
}
} else {
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED,
Logger);
Logger.information(Poco::format(
"Invalid response for command '%s'. Missing status.", Cmd.UUID));
return;
}
}
return;
}
auto StatusInnerObj = ResultFields->get(uCentralProtocol::STATUS).extract<Poco::JSON::Object::Ptr>();
if (StatusInnerObj->has(uCentralProtocol::ERROR))
Cmd.ErrorCode = StatusInnerObj->get(uCentralProtocol::ERROR);
if (StatusInnerObj->has(uCentralProtocol::TEXT))
Cmd.ErrorText = StatusInnerObj->get(uCentralProtocol::TEXT).toString();
std::stringstream ResultText;
if(rpc_answer->has(uCentralProtocol::RESULT)) {
if(Cmd.Command==uCentralProtocol::WIFISCAN) {
auto ScanObj = rpc_answer->get(uCentralProtocol::RESULT).extract<Poco::JSON::Object::Ptr>();
ParseWifiScan(ScanObj, ResultText, Logger);
} else {
Poco::JSON::Stringifier::stringify(
rpc_answer->get(uCentralProtocol::RESULT), ResultText);
}
} if (rpc_answer->has(uCentralProtocol::RESULT_64)) {
uint64_t sz=0;
if(rpc_answer->has(uCentralProtocol::RESULT_SZ))
sz=rpc_answer->get(uCentralProtocol::RESULT_SZ);
std::string UnCompressedData;
Utils::ExtractBase64CompressedData(rpc_answer->get(uCentralProtocol::RESULT_64).toString(),
UnCompressedData,sz);
Poco::JSON::Stringifier::stringify(UnCompressedData, ResultText);
}
Cmd.Results = ResultText.str();
Cmd.Status = "completed";
Cmd.Completed = Utils::Now();
Cmd.executionTime = rpc_execution_time.count();
if (Cmd.ErrorCode && (Cmd.Command == uCentralProtocol::TRACE || Cmd.Command == uCentralProtocol::SCRIPT)) {
Cmd.WaitingForFile = 0;
Cmd.AttachDate = Cmd.AttachSize = 0;
Cmd.AttachType = "";
}
// Add the completed command to the database...
StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Storage::CommandExecutionType::COMMAND_COMPLETED);
if (ObjectToReturn && Handler) {
Handler->ReturnObject(*ObjectToReturn);
} else if (rpc_result == std::future_status::timeout) {
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_TIMEDOUT,
Logger);
} else {
Poco::JSON::Object O;
Cmd.to_json(O);
if(Handler)
Handler->ReturnObject(O);
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
}
Logger.information( fmt::format("{},{}: Completed in {:.3f}ms.", Cmd.UUID, RPCID, Cmd.executionTime));
return;
}
CommandManager()->RemovePendingCommand(RPCID);
if(RetryLater) {
Logger.information(fmt::format("{},{}: Pending completion.", Cmd.UUID, RPCID));
SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_PENDING, Logger);
} else {
Logger.information(fmt::format("{},{}: Command canceled. Device is not connected. Command will not be retried.", Cmd.UUID, RPCID));
return SetCommandStatus(Cmd, Request, Response, Handler, Storage::CommandExecutionType::COMMAND_FAILED, Logger);
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
}
}
}

View File

@@ -14,23 +14,20 @@
#include "Poco/File.h"
#include "Poco/JSON/Object.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "RESTObjects//RESTAPI_GWobjects.h"
#include "StorageService.h"
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi::RESTAPI_RPC {
void WaitForCommand(
uint64_t RPCID,
bool RetryLater,
GWObjects::CommandDetails &Cmd,
Poco::JSON::Object & Params,
Poco::Net::HTTPServerRequest &Request,
Poco::Net::HTTPServerResponse &Response,
std::chrono::milliseconds WaitTimeInMs,
Poco::JSON::Object * ObjectToReturn,
RESTAPIHandler * Handler,
Poco::Logger &Logger);
void WaitForCommand( GWObjects::CommandDetails &Cmd,
Poco::JSON::Object & Params,
Poco::Net::HTTPServerRequest &Request,
Poco::Net::HTTPServerResponse &Response,
std::chrono::milliseconds WaitTimeInMs,
Poco::JSON::Object * ObjectToReturn,
RESTAPIHandler * Handler,
Poco::Logger &Logger);
void SetCommandStatus( GWObjects::CommandDetails &Cmd,
Poco::Net::HTTPServerRequest &Request,

View File

@@ -6,17 +6,20 @@
// Arilia Wireless Inc.
//
#include <ctime>
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/Stringifier.h"
#include "RESTAPI_blacklist.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/utils.h"
#include "framework/RESTAPI_errors.h"
#include "framework/RESTAPI_protocol.h"
namespace OpenWifi {
void RESTAPI_blacklist::DoDelete() {
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::NormalizeMac(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
@@ -34,7 +37,7 @@ namespace OpenWifi {
void RESTAPI_blacklist::DoGet() {
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::NormalizeMac(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
@@ -49,14 +52,14 @@ namespace OpenWifi {
}
void RESTAPI_blacklist::DoPost() {
auto Obj = ParseStream();
const auto &Obj = ParsedBody_;
GWObjects::BlackListedDevice D;
if(!D.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(D.serialNumber.empty() || !Utils::NormalizeMac(D.serialNumber)) {
if(D.serialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
@@ -66,7 +69,7 @@ namespace OpenWifi {
}
D.author = UserInfo_.userinfo.email;
D.created = Utils::Now();
D.created = std::time(nullptr);
if(StorageService()->AddBlackListDevice(D)) {
GWObjects::BlackListedDevice CreatedDevice;
@@ -82,11 +85,12 @@ namespace OpenWifi {
void RESTAPI_blacklist::DoPut() {
auto SerialNumber = Poco::toLower(GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""));
if(!Utils::NormalizeMac(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
const auto &Obj = ParsedBody_;
auto Obj = ParseStream();
GWObjects::BlackListedDevice Existing;
if(!StorageService()->GetBlackListDevice(SerialNumber, Existing)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);

View File

@@ -8,12 +8,12 @@
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_blacklist : public RESTAPIHandler {
public:
RESTAPI_blacklist(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server , uint64_t TransactionId , bool Internal)
RESTAPI_blacklist(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server , uint64_t TransactionId , bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_POST,
@@ -23,7 +23,7 @@ namespace OpenWifi {
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/blacklist/{serialNumber}"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/blacklist/{serialNumber}"};}
void DoGet() final;
void DoDelete() final;
void DoPost() final;

View File

@@ -4,19 +4,19 @@
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_blacklist_list : public RESTAPIHandler {
public:
RESTAPI_blacklist_list(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
RESTAPI_blacklist_list(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & 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/blacklist"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/blacklist"};}
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

View File

@@ -8,7 +8,7 @@
namespace OpenWifi {
void RESTAPI_capabilities_handler::DoGet() {
CapabilitiesCache_t Caps = CapabilitiesCache()->AllCapabilities();
CapabilitiesCache_t Caps = CapabilitiesCache().AllCapabilities();
Poco::JSON::Array ObjArr;
for(const auto &[deviceType,capabilities]:Caps) {

View File

@@ -4,19 +4,19 @@
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_capabilities_handler : public RESTAPIHandler {
public:
RESTAPI_capabilities_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
RESTAPI_capabilities_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & 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/capabilities"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/capabilities"};}
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

View File

@@ -9,15 +9,12 @@
#include "RESTAPI_command.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_errors.h"
#include "framework/RESTAPI_protocol.h"
namespace OpenWifi {
void RESTAPI_command::DoGet() {
auto CommandUUID = GetBinding(RESTAPI::Protocol::COMMANDUUID, "");
if(!Utils::ValidUUID(CommandUUID)) {
return NotFound();
}
GWObjects::CommandDetails Command;
if (StorageService()->GetCommand(CommandUUID, Command)) {
Poco::JSON::Object RetObj;
@@ -28,23 +25,20 @@ namespace OpenWifi {
}
void RESTAPI_command::DoDelete() {
auto CommandUUID = GetBinding(RESTAPI::Protocol::COMMANDUUID, "");
if(CommandUUID.empty()) {
auto UUID = GetBinding(RESTAPI::Protocol::COMMANDUUID, "");
if(UUID.empty()) {
return BadRequest(RESTAPI::Errors::MissingUUID);
}
if(!Utils::ValidUUID(CommandUUID)) {
return NotFound();
}
GWObjects::CommandDetails C;
if(!StorageService()->GetCommand(CommandUUID, C)) {
if(!StorageService()->GetCommand(UUID, C)) {
return NotFound();
}
if (StorageService()->DeleteCommand(CommandUUID)) {
if (StorageService()->DeleteCommand(UUID)) {
return OK();
}
return InternalError(RESTAPI::Errors::NoRecordsDeleted);
return InternalError();
}
}

View File

@@ -8,12 +8,12 @@
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_command : public RESTAPIHandler {
public:
RESTAPI_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
RESTAPI_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_DELETE,
@@ -21,7 +21,7 @@ class RESTAPI_command : public RESTAPIHandler {
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/command/{commandUUID}"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/command/{commandUUID}"};}
void DoGet() final;
void DoDelete() final;
void DoPost() final {};

View File

@@ -8,15 +8,12 @@
#include "RESTAPI_commands.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_errors.h"
#include "framework/RESTAPI_protocol.h"
namespace OpenWifi {
void RESTAPI_commands::DoGet() {
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::NormalizeMac(SerialNumber)) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
std::vector<GWObjects::CommandDetails> Commands;
if (QB_.Newest) {
StorageService()->GetNewestCommands(SerialNumber, QB_.Limit, Commands);
@@ -37,13 +34,13 @@ namespace OpenWifi {
void RESTAPI_commands::DoDelete() {
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::NormalizeMac(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
if (StorageService()->DeleteCommands(SerialNumber, QB_.StartDate, QB_.EndDate)) {
return OK();
}
InternalError(RESTAPI::Errors::NoRecordsDeleted);
InternalError();
}
}

View File

@@ -8,12 +8,12 @@
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_commands : public RESTAPIHandler {
public:
RESTAPI_commands(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
RESTAPI_commands(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_DELETE,
@@ -21,7 +21,7 @@ namespace OpenWifi {
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/commands"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/commands"};}
void DoGet() final;
void DoDelete() final;
void DoPost() final {};

View File

@@ -12,14 +12,13 @@
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_errors.h"
#include "framework/RESTAPI_protocol.h"
#include "framework/ConfigurationValidator.h"
#include "framework/orm.h"
#include "framework/utils.h"
namespace OpenWifi {
void RESTAPI_default_configuration::DoGet() {
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
GWObjects::DefaultConfiguration DefConfig;
if (StorageService()->GetDefaultConfiguration(Name, DefConfig)) {
Poco::JSON::Object Obj;
@@ -30,7 +29,7 @@ namespace OpenWifi {
}
void RESTAPI_default_configuration::DoDelete() {
std::string Name = ORM::Escape(GetBinding(RESTAPI::Protocol::NAME, ""));
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
if(Name.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
@@ -49,17 +48,17 @@ namespace OpenWifi {
}
if(StorageService()->DefaultConfigurationAlreadyExists(Name)) {
return BadRequest(RESTAPI::Errors::DefConfigNameExists);
return BadRequest("Configuration name already exists.");
}
const auto &Obj = ParsedBody_;
auto Obj = ParseStream();
GWObjects::DefaultConfiguration DefConfig;
if (!DefConfig.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(DefConfig.Models.empty()) {
return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty);
return BadRequest("modelIds cannot be empty");
}
std::string Error;
@@ -67,7 +66,7 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
}
DefConfig.Created = DefConfig.LastModified = Utils::Now();
DefConfig.Created = DefConfig.LastModified = std::time(nullptr);
if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) {
return OK();
}
@@ -78,7 +77,7 @@ namespace OpenWifi {
void RESTAPI_default_configuration::DoPut() {
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
const auto &Obj = ParsedBody_;
auto Obj = ParseStream();
GWObjects::DefaultConfiguration NewConfig;
if (!NewConfig.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
@@ -97,7 +96,7 @@ namespace OpenWifi {
Existing.Configuration = NewConfig.Configuration;
}
Existing.LastModified = Utils::Now();
Existing.LastModified = std::time(nullptr);
AssignIfPresent(Obj,"description",Existing.Description);
if(Obj->has("modelIds"))
Existing.Models = NewConfig.Models;

View File

@@ -8,12 +8,12 @@
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_default_configuration : public RESTAPIHandler {
public:
RESTAPI_default_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
RESTAPI_default_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST,
@@ -22,7 +22,7 @@ namespace OpenWifi {
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/default_configuration/{name}"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/default_configuration/{name}"};}
void DoGet() final;
void DoDelete() final;
void DoPost() final;

View File

@@ -11,7 +11,7 @@
#include "RESTAPI_default_configurations.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_protocol.h"
namespace OpenWifi {
void RESTAPI_default_configurations::DoGet() {

View File

@@ -8,19 +8,19 @@
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_default_configurations : public RESTAPIHandler {
public:
RESTAPI_default_configurations(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
RESTAPI_default_configurations(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & 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_configurations"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/default_configurations"};}
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

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