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
165 changed files with 9177 additions and 21778 deletions

View File

@@ -13,7 +13,6 @@ on:
pull_request:
branches:
- master
- 'release/*'
defaults:
run:
@@ -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
@@ -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@v2
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

@@ -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@v2
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.7.0)
project(owgw VERSION 2.5.0)
set(CMAKE_CXX_STANDARD 17)
@@ -30,13 +30,6 @@ 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} describe --always --tags
@@ -49,11 +42,14 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
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
@@ -79,10 +73,11 @@ add_executable( owgw
src/framework/KafkaTopics.h
src/framework/MicroService.h
src/framework/OpenWifiTypes.h
src/framework/MicroServiceErrorHandler.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/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
@@ -102,15 +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/DeviceRegistry.cpp src/DeviceRegistry.h
src/CommandManager.cpp src/CommandManager.h
src/CentralConfig.cpp src/CentralConfig.h
src/FileUploader.cpp src/FileUploader.h
@@ -121,20 +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/framework/WebSocketClientNotifications.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/RADSECserver.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)
@@ -145,15 +128,12 @@ 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)

View File

@@ -1,23 +1,15 @@
ARG DEBIAN_VERSION=11.4-slim
ARG POCO_VERSION=poco-tip-v1
ARG FMTLIB_VERSION=9.0.0
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
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
@@ -26,26 +18,10 @@ RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS fmtlib-build
ARG FMTLIB_VERSION
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
WORKDIR /fmtlib
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make 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
@@ -56,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
@@ -81,8 +55,6 @@ COPY --from=cppkafka-build /usr/local/include /usr/local/include
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
COPY --from=fmtlib-build /usr/local/include /usr/local/include
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
WORKDIR /owgw
RUN mkdir cmake-build
@@ -90,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
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
@@ -112,16 +84,13 @@ 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
EXPOSE 15002 16002 16003 17002 16102
ENTRYPOINT ["/docker-entrypoint.sh"]

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

@@ -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,7 +264,7 @@ 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" : {
@@ -305,7 +277,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> ,
@@ -321,7 +293,7 @@ The device should answer:
#### 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" : {
@@ -334,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> ,
@@ -348,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" : {
@@ -405,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>
@@ -426,7 +358,7 @@ The device should answer:
#### 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.
```json
```
{ "jsonrpc" : "2.0" ,
"method" : "perform" ,
"params" : {
@@ -440,7 +372,7 @@ and the controller.
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -463,7 +395,7 @@ The device should answer with teh above message. The `error` value should be int
#### 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" : {
@@ -480,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> ,
@@ -506,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" : {
@@ -514,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> ,
@@ -546,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" : {
@@ -560,7 +490,7 @@ message will be returned "soon".
```
The device should answer:
```json
```
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
@@ -576,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" : {
@@ -590,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> ,
@@ -606,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" : {
@@ -619,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> ,
@@ -633,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" : {
@@ -648,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" : {
@@ -666,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> ,
@@ -682,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" : {
@@ -693,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> ,
@@ -704,41 +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">,
"script" : <text blob containing the script>,
"timeout" : <max timeout in seconds, default is 30>,
"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
@@ -749,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
```

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
@@ -132,18 +123,18 @@ brew install apr-util
brew install boost
brew install yaml-cpp
brew install postgresql
brew install unixodbc
brew install librdkafka
brew install nlohmann-json
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
git clone https://github.com/stephb9959/poco
cd poco
mkdir cmake-build
mkdir cmake-build
cd cmake-build
cmake ..
cmake --build . --config Release
cmake --build . --config Release -j
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
@@ -151,15 +142,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
@@ -266,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.
@@ -578,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.

2
build
View File

@@ -1 +1 @@
148
171

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>

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 "$@"

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: v2.7.0
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,12 +258,11 @@ 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
logging.path: $OWGW_ROOT/logs
logging.level: information
logging.level: debug
# Archiving
archiver.enabled: "true"
archiver.schedule: 03:00
@@ -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,19 +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
DeviceWithStatus:
type: object
@@ -177,31 +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
DeviceList:
type: object
@@ -294,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:
@@ -488,31 +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:
- uci
- ucode
- shell
script:
type: string
scriptId:
type: string
format: uuid
when:
type: integer
format: int64
default: 0
FactoryRequest:
type: object
properties:
@@ -979,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
@@ -1056,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:
@@ -1198,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
@@ -1230,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:
@@ -2116,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:
@@ -2583,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:

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,41 +0,0 @@
/* Frame (255 bytes) */
static const unsigned char pkt41[255] = {
0x14, 0x98, 0x77, 0x71, 0xc6, 0xe7, 0x34, 0xef, /* ..wq..4. */
0xb6, 0xaf, 0x4a, 0x5c, 0x08, 0x00, 0x45, 0x00, /* ..J\..E. */
0x00, 0xf1, 0x87, 0x50, 0x00, 0x00, 0x40, 0x11, /* ...P..@. */
0x0c, 0xdf, 0xc0, 0xa8, 0xb2, 0x1b, 0xc0, 0xa8, /* ........ */
0xb2, 0x60, 0xc3, 0xfe, 0x07, 0x14, 0x00, 0xdd, /* .`...... */
0x26, 0x63, 0x01, 0x04, 0x00, 0xd5, 0xcc, 0x29, /* &c.....) */
0x82, 0x36, 0xd6, 0x57, 0x3d, 0xa7, 0xd5, 0x62, /* .6.W=..b */
0x70, 0x12, 0x00, 0xc0, 0xf2, 0x19, 0x01, 0x03, /* p....... */
0x61, 0x1e, 0x1c, 0x33, 0x34, 0x2d, 0x45, 0x46, /* a..34-EF */
0x2d, 0x42, 0x36, 0x2d, 0x41, 0x46, 0x2d, 0x34, /* -B6-AF-4 */
0x41, 0x2d, 0x36, 0x30, 0x3a, 0x4f, 0x70, 0x65, /* A-60:Ope */
0x6e, 0x57, 0x69, 0x66, 0x69, 0x3d, 0x06, 0x00, /* nWifi=.. */
0x00, 0x00, 0x13, 0x06, 0x06, 0x00, 0x00, 0x00, /* ........ */
0x02, 0x05, 0x06, 0x00, 0x00, 0x00, 0x01, 0x1f, /* ........ */
0x13, 0x42, 0x36, 0x2d, 0x43, 0x34, 0x2d, 0x30, /* .B6-C4-0 */
0x36, 0x2d, 0x30, 0x39, 0x2d, 0x31, 0x35, 0x2d, /* 6-09-15- */
0x42, 0x37, 0x4d, 0x18, 0x43, 0x4f, 0x4e, 0x4e, /* B7M.CONN */
0x45, 0x43, 0x54, 0x20, 0x35, 0x34, 0x4d, 0x62, /* ECT 54Mb */
0x70, 0x73, 0x20, 0x38, 0x30, 0x32, 0x2e, 0x31, /* ps 802.1 */
0x31, 0x61, 0x2c, 0x12, 0x33, 0x42, 0x45, 0x44, /* 1a,.3BED */
0x37, 0x32, 0x39, 0x30, 0x44, 0x30, 0x43, 0x38, /* 7290D0C8 */
0x35, 0x36, 0x44, 0x33, 0xba, 0x06, 0x00, 0x0f, /* 56D3.... */
0xac, 0x04, 0xbb, 0x06, 0x00, 0x0f, 0xac, 0x04, /* ........ */
0xbc, 0x06, 0x00, 0x0f, 0xac, 0x05, 0xbd, 0x06, /* ........ */
0x00, 0x0f, 0xac, 0x06, 0x1a, 0x1b, 0x00, 0x00, /* ........ */
0xe6, 0x08, 0x47, 0x15, 0x01, 0x13, 0x33, 0x34, /* ..G...34 */
0x2d, 0x65, 0x66, 0x2d, 0x62, 0x36, 0x2d, 0x61, /* -ef-b6-a */
0x66, 0x2d, 0x34, 0x61, 0x2d, 0x35, 0x63, 0x0c, /* f-4a-5c. */
0x06, 0x00, 0x00, 0x05, 0x78, 0x4f, 0x08, 0x02, /* ....xO.. */
0x01, 0x00, 0x06, 0x01, 0x61, 0x50, 0x12, 0x20, /* ....aP. */
0x9c, 0xae, 0xe5, 0xe3, 0x77, 0xaf, 0x0b, 0x1b, /* ....w... */
0xaf, 0x0e, 0xb5, 0x08, 0x82, 0x9e, 0xeb /* ....... */
};
/* Reassembled EAP (6 bytes) */
static const unsigned char pkt41_1[6] = {
0x02, 0x01, 0x00, 0x06, 0x01, 0x61 /* .....a */
};

View File

@@ -1 +0,0 @@
192.168.178.1

Binary file not shown.

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>

View File

@@ -1,814 +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/zlib.h"
#include "AP_WS_Server.h"
#include "CentralConfig.h"
#include "CommandManager.h"
#include "ConfigurationCache.h"
#include "StorageService.h"
#include "TelemetryStream.h"
#include "framework/WebSocketClientNotifications.h"
#include "Poco/Net/WebSocketImpl.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,
std::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;
}
class ThreadedCounter {
public:
ThreadedCounter(bool T, std::atomic_uint64_t &C) :
C_(C),
Threaded_(T) {
if(Threaded_) {
C_++;
}
}
~ThreadedCounter() {
if(Threaded_ && C_>0) {
C_--;
}
}
private:
std::atomic_uint64_t &C_;
bool Threaded_;
};
bool AP_WS_Connection::ValidatedDevice() {
if(DeviceValidated_)
return true;
if(!Valid_)
return false;
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 = OpenWifi::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(SerialNumber_)) {
poco_warning(
Logger_,
fmt::format("TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
CId_, State_.sessionId , CN_));
EndConnection();
return false;
}
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, OpenWifi::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() {
std::cout << "Deleting session=" << State_.sessionId << std::endl;
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)
WebSocketClientNotificationDeviceDisconnected(SerialNumber_);
}
}
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 = MicroService::CreateUUID();
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()->NextRPCId(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
WebSocketClientNotificationDeviceConfigurationChange(D.SerialNumber, UUID, UpgradedUUID);
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(std::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", 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(std::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(std::uint64_t RPCID, uint64_t Interval,
uint64_t LifeTime) {
std::unique_lock Lock(TelemetryMutex_);
TelemetryWebSocketRefCount_++;
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
auto TelemetryWebSocketTimer = LifeTime + OpenWifi::Now();
TelemetryWebSocketTimer_ = std::max(TelemetryWebSocketTimer, TelemetryWebSocketTimer_);
UpdateCounts();
if (!TelemetryReporting_) {
TelemetryReporting_ = true;
return StartTelemetry(RPCID);
}
return true;
}
bool AP_WS_Connection::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t Interval, uint64_t LifeTime) {
std::unique_lock Lock(TelemetryMutex_);
TelemetryKafkaRefCount_++;
TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
auto TelemetryKafkaTimer = LifeTime + OpenWifi::Now();
TelemetryKafkaTimer_ = std::max(TelemetryKafkaTimer, TelemetryKafkaTimer_);
UpdateCounts();
if (!TelemetryReporting_) {
TelemetryReporting_ = true;
return StartTelemetry(RPCID);
}
return true;
}
bool AP_WS_Connection::StopWebSocketTelemetry(std::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(std::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 = OpenWifi::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);
State_.MessageCount++;
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, OpenWifi::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,128 +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"
namespace OpenWifi {
class AP_WS_Connection {
static constexpr int BufSize = 256000;
public:
explicit AP_WS_Connection( Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response,
std::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(const 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(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryWebSocketTimer);
bool SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryKafkaTimer);
bool StopWebSocketTelemetry(std::uint64_t RPCID);
bool StopKafkaTelemetry(std::uint64_t RPCID);
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 DeviceRegistry;
friend class AP_WS_Server;
private:
// std::recursive_mutex LocalMutex_;
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_;
std::atomic_bool TelemetryReporting_ = false;
std::atomic_uint64_t TelemetryWebSocketRefCount_ = 0;
std::atomic_uint64_t TelemetryKafkaRefCount_ = 0;
uint64_t TelemetryWebSocketTimer_ = 0;
uint64_t TelemetryKafkaTimer_ = 0 ;
uint64_t TelemetryInterval_ = 0;
std::atomic_uint64_t TelemetryWebSocketPackets_=0;
std::atomic_uint64_t TelemetryKafkaPackets_=0;
GWObjects::ConnectionState State_;
std::string LastStats_;
GWObjects::HealthCheck LastHealthcheck_;
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};
bool Threaded_=false;
std::atomic_flag Dead_=false;
std::atomic_bool DeviceValidated_=false;
std::atomic_bool Valid_=false;
static inline std::atomic_uint64_t ConcurrentStartingDevices_=0;
bool StartTelemetry(std::uint64_t RPCID);
bool StopTelemetry(std::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,129 +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 "framework/WebSocketClientNotifications.h"
#include "Daemon.h"
#include "CentralConfig.h"
#include "CommandManager.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 CapabilitiesString = ParamsObj->get(uCentralProtocol::CAPABILITIES).toString();
Config::Capabilities Caps(CapabilitiesString);
Compatible_ = Caps.Compatible();
SerialNumber_ = Serial;
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
CommandManager()->ClearQueue(SerialNumberInt_);
AP_WS_Server()->SetSessionDetails(State_.sessionId,SerialNumberInt_);
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);
}
State_.locale = FindCountryFromIP()->Get(IP);
GWObjects::Device DeviceInfo;
auto DeviceExists = StorageService()->GetDevice(SerialNumber_,DeviceInfo);
if (Daemon()->AutoProvisioning() && !DeviceExists) {
StorageService()->CreateDefaultDevice(SerialNumber_, CapabilitiesString, Firmware,
Compatible_, PeerAddress_);
} else if (DeviceExists) {
StorageService()->UpdateDeviceCapabilities(SerialNumber_, CapabilitiesString,
Compatible_);
bool Updated = false;
if(!Firmware.empty() && Firmware!=DeviceInfo.Firmware) {
DeviceInfo.Firmware = Firmware;
Updated = true;
WebSocketClientNotificationDeviceFirmwareUpdated(SerialNumber_, Firmware);
}
if(DeviceInfo.locale != State_.locale) {
DeviceInfo.locale = State_.locale;
Updated = true;
}
if(Compatible_ != DeviceInfo.DeviceType) {
DeviceInfo.DeviceType = Compatible_;
Updated = true;
}
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();
}
}
}
WebSocketClientNotificationDeviceConnected(SerialNumber_);
// 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, OpenWifi::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,34 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.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,25 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.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,71 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.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 = OpenWifi::Now();
Check.UUID = UUID;
Check.Data = CheckData;
Check.Sanity = Sanity;
StorageService()->AddHealthCheckData(Check);
if (!request_uuid.empty()) {
StorageService()->SetCommandResult(request_uuid, CheckData);
}
LastHealthcheck_ = Check;
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
ParamsObj->set("timestamp", OpenWifi::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,41 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.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,62 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "CommandManager.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 = MicroService::CreateUUID();
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()->NextRPCId(),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,67 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "StorageService.h"
#include "framework/WebSocketClientNotifications.h"
#include "StateUtils.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;
LastStats_ = StateStr;
GWObjects::Statistics Stats{
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
Stats.Recorded = OpenWifi::Now();
StorageService()->AddStatisticsData(Stats);
if (!request_uuid.empty()) {
StorageService()->SetCommandResult(request_uuid, StateStr);
}
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
State_.Associations_5G);
if (KafkaManager()->Enabled()) {
Poco::JSON::Stringifier Stringify;
std::ostringstream OS;
Stringify.condense(ParamsObj, OS);
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
}
WebSocketNotification<WebNotificationSingleDevice> N;
N.content.serialNumber = SerialNumber_;
N.type = "device_statistics";
WebSocketClientServer()->SendNotification(N);
} else {
poco_warning(Logger_, fmt::format("STATE({}): Invalid request. Missing serial, uuid, or state", CId_));
}
}
}

View File

@@ -1,54 +0,0 @@
//
// Created by stephane bourque on 2022-07-26.
//
#include "AP_WS_Connection.h"
#include "TelemetryStream.h"
#include "CommandManager.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;
}
if (TelemetryReporting_) {
if (ParamsObj->has("data")) {
auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
Payload->set("timestamp", OpenWifi::Now());
std::ostringstream SS;
Payload->stringify(SS);
auto now=OpenWifi::Now();
if (TelemetryWebSocketRefCount_) {
if(now<TelemetryWebSocketTimer_) {
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
TelemetryWebSocketPackets_++;
State_.websocketPackets = TelemetryWebSocketPackets_;
TelemetryStream()->UpdateEndPoint(SerialNumberInt_, SS.str());
} else {
StopWebSocketTelemetry(CommandManager()->NextRPCId());
}
}
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()->NextRPCId());
}
}
} 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()->NextRPCId());
}
}
}

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,410 +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/JSON/Array.h"
#include "Poco/Net/Context.h"
#include "AP_WS_Server.h"
#include "AP_WS_Connection.h"
#include "ConfigurationCache.h"
#include "TelemetryStream.h"
#include "framework/WebSocketClientNotifications.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_ = MicroService::instance().ConfigGetBool("openwifi.certificates.allowmismatch",true);
MismatchDepth_ = MicroService::instance().ConfigGetInt("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 = MicroService::instance().ConfigGetString("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_ = MicroService::instance().ConfigGetString("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_, MicroService::instance().TimerPool());
Running_ = true;
return 0;
}
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
std::lock_guard Lock(LocalMutex_);
if(Garbage_.size()>0) {
std::cout << "Removing " << Garbage_.size() << " old connections." << std::endl;
Garbage_.clear();
}
static std::uint64_t last_log = OpenWifi::Now();
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
std::uint64_t total_connected_time=0;
auto now = OpenWifi::Now();
for (auto connection=SerialNumbers_.begin(); connection!=SerialNumbers_.end();) {
if(connection->second.second== nullptr) {
connection++;
continue;
}
if (connection->second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - connection->second.second->State_.started);
connection++;
} else {
NumberOfConnectingDevices_++;
connection++;
}
}
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_));
}
WebSocketClientNotificationNumberOfConnections(NumberOfConnectedDevices_,
AverageDeviceConnectionTime_,
NumberOfConnectingDevices_);
}
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(std::uint64_t SerialNumber, std::string &Statistics) const {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
return false;
Statistics = Device->second.second->LastStats_;
return true;
}
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
return false;
State = Device->second.second->State_;
return true;
}
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
return false;
CheckData = Device->second.second->LastHealthcheck_;
return true;
}
void AP_WS_Server::SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber) {
std::lock_guard Lock(LocalMutex_);
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.first);
return;
}
}
bool AP_WS_Server::EndSession(std::uint64_t session_id, std::uint64_t serial_number) {
std::unique_lock G(LocalMutex_);
auto Session = Sessions_.find(session_id);
if(Session==end(Sessions_))
return false;
Garbage_.push_back(Session->second.first);
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) const {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
return false;
return Device->second.second->State_.Connected;
}
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string & Payload) const {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
// std::cout << "Device connection pointer: " << (std::uint64_t) Device->second.second << std::endl;
return Device->second.second->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(std::uint64_t RPCID, uint64_t SerialNumber) {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
return;
Device->second.second->StopWebSocketTelemetry(RPCID);
}
void AP_WS_Server::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
return;
Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
}
void AP_WS_Server::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
return;
Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
}
void AP_WS_Server::StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
std::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
return;
Device->second.second->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::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_)|| Device->second.second== nullptr)
return;
Device->second.second->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::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
return Device->second.second->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::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
return Device->second.second->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::lock_guard Lock(LocalMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
return Device->second.second->SendRadiusCoAData(buffer,size);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
}
return false;
}
} //namespace

View File

@@ -1,203 +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 "framework/MicroService.h"
#include "Poco/AutoPtr.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/ParallelSocketAcceptor.h"
#include "Poco/Net/SocketAcceptor.h"
#include "Poco/Timer.h"
#include "AP_WS_Connection.h"
#include "AP_WS_ReactorPool.h"
namespace OpenWifi {
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
public:
explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t id)
: Logger_(L),
id_(id){
};
void handleRequest(Poco::Net::HTTPServerRequest &request,
Poco::Net::HTTPServerResponse &response) override;
private:
Poco::Logger &Logger_;
std::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 std::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 std::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(std::uint64_t session_id, std::shared_ptr<AP_WS_Connection> Connection ) {
std::lock_guard Lock(LocalMutex_);
Sessions_[session_id] = std::make_pair(std::move(Connection),false);
}
inline std::shared_ptr<AP_WS_Connection> FindConnection(std::uint64_t session_id) const {
std::lock_guard Lock(LocalMutex_);
auto Connection = Sessions_.find(session_id);
if(Connection!=end(Sessions_))
return Connection->second.first;
return nullptr;
}
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) const {
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
}
bool GetStatistics(std::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(std::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(std::uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) 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(std::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(std::uint64_t connection_id, uint64_t SerialNumber);
bool EndSession(std::uint64_t connection_id, std::uint64_t serial_number);
void SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
void StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
void SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
void StopKafkaTelemetry(std::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( std::uint64_t & Connections, std::uint64_t & AverageConnectionTime, std::uint64_t & NumberOfConnectingDevices) const {
Connections = NumberOfConnectedDevices_;
AverageConnectionTime = AverageDeviceConnectionTime_;
NumberOfConnectingDevices = NumberOfConnectingDevices_;
}
private:
mutable std::recursive_mutex LocalMutex_;
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<std::uint64_t, std::pair<std::shared_ptr<AP_WS_Connection>,bool>> Sessions_;
std::map<std::uint64_t, std::pair<std::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

@@ -5,7 +5,6 @@
#pragma once
#include "framework/MicroService.h"
#include "nlohmann/json.hpp"
namespace OpenWifi {

View File

@@ -7,148 +7,115 @@
//
#include <fstream>
#include "framework/MicroService.h"
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#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 {

View File

@@ -8,277 +8,176 @@
#include <algorithm>
#include "framework/MicroService.h"
#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/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) {
const Poco::JSON::Object &Payload = Resp->Payload_;
const std::string &SerialNumber = Resp->SerialNumber_;
std::ostringstream SS;
Payload.stringify(SS);
if (!Payload.has(uCentralProtocol::ID)) {
poco_error(Logger(), fmt::format("({}): Invalid RPC response.", SerialNumber));
} else {
uint64_t ID = Payload.get(uCentralProtocol::ID);
poco_debug(Logger(),fmt::format("({}): Processing {} response.", SerialNumber, ID));
if (ID > 1) {
std::lock_guard Lock(LocalMutex_);
auto RPC = OutStandingRequests_.find(ID);
if (RPC == OutStandingRequests_.end() ||
RPC->second.SerialNumber !=
Utils::SerialNumberToInt(Resp->SerialNumber_)) {
poco_debug(Logger(),
fmt::format("({}): RPC {} completed.", SerialNumber, 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={}",
SerialNumber, 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_, MicroService::instance().TimerPool());
CommandRunnerCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onCommandRunnerTimer);
CommandRunnerTimer_.setStartInterval( 10000 );
CommandRunnerTimer_.setPeriodicInterval(30 * 1000); // 1 hours
CommandRunnerTimer_.start(*CommandRunnerCallback_, MicroService::instance().TimerPool());
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 = OpenWifi::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(NextRPCId(), 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,73 +13,58 @@
#include <map>
#include <utility>
#include <functional>
#include <shared_mutex>
#include "framework/MicroService.h"
#include "Poco/JSON/Object.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Timer.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "RESTObjects//RESTAPI_GWobjects.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class RPCResponseNotification: public Poco::Notification {
public:
RPCResponseNotification(const std::string &ser,
const Poco::JSON::Object &pl) :
SerialNumber_(ser),
Payload_(pl)
{
}
std::string SerialNumber_;
Poco::JSON::Object 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:
typedef Poco::JSON::Object objtype_t;
typedef Poco::JSON::Object::Ptr objtype_t;
typedef std::promise<objtype_t> promise_type_t;
struct CommandInfo {
std::uint64_t Id=0;
std::uint64_t SerialNumber=0;
std::string Command;
std::string UUID;
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::string serialNumber;
Poco::JSON::Object payload;
explicit RPCResponse(const std::string &ser, const Poco::JSON::Object &pl)
:
serialNumber(ser),
payload(pl) {
}
};
int Start() override;
void Stop() override;
void WakeUp();
inline void PostCommandResult(const std::string &SerialNumber, const Poco::JSON::Object &Obj) {
// RPCResponseQueue_->Write(RPCResponse{.serialNumber=SerialNumber, .payload = Obj});
ResponseQueue_.enqueueNotification(new RPCResponseNotification(SerialNumber,Obj));
}
void PostCommandResult(const std::string &SerialNumber, Poco::JSON::Object::Ptr Obj);
std::shared_ptr<promise_type_t> PostCommandOneWayDisk(uint64_t RPCID,
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(RPCID, SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -87,14 +72,12 @@ namespace OpenWifi {
}
std::shared_ptr<promise_type_t> PostCommandDisk(
uint64_t RPCID,
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool & Sent) {
return PostCommand(RPCID,
SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -102,13 +85,12 @@ namespace OpenWifi {
}
std::shared_ptr<promise_type_t> PostCommand(
uint64_t RPCID,
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool & Sent) {
return PostCommand(RPCID, SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -117,14 +99,12 @@ namespace OpenWifi {
}
std::shared_ptr<promise_type_t> PostCommandOneWay(
uint64_t RPCID,
const std::string &SerialNumber,
const std::string &Method,
const Poco::JSON::Object &Params,
const std::string &UUID,
bool & Sent) {
return PostCommand(RPCID,
SerialNumber,
return PostCommand(SerialNumber,
Method,
Params,
UUID,
@@ -132,8 +112,6 @@ namespace OpenWifi {
false, Sent );
}
bool IsCommandRunning(const std::string &C);
void run() override;
static auto instance() {
@@ -142,53 +120,17 @@ namespace OpenWifi {
}
inline bool Running() const { return Running_; }
void onJanitorTimer(Poco::Timer & timer);
void onCommandRunnerTimer(Poco::Timer & timer);
void onRPCAnswer(bool& b);
inline uint64_t NextRPCId() { 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

@@ -6,27 +6,25 @@
// Arilia Wireless Inc.
//
#include "framework/MicroService.h"
#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"
namespace OpenWifi {
@@ -40,18 +38,15 @@ namespace OpenWifi {
StorageService(),
SerialNumberCache(),
ConfigurationValidator(),
WebSocketClientServer(),
OUIServer(),
FindCountryFromIP(),
// DeviceRegistry(),
DeviceRegistry(),
CommandManager(),
FileUploader(),
StorageArchiver(),
TelemetryStream(),
RTTYS_server(),
RADIUS_proxy_server(),
VenueBroadcaster(),
AP_WS_Server()
WebSocketServer()
});
return &instance;
}
@@ -89,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_)
{
@@ -107,25 +104,16 @@ namespace OpenWifi {
}
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,8 +14,6 @@
#include <vector>
#include <set>
#include "framework/MicroService.h"
#include "Poco/Util/Application.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
@@ -27,16 +25,16 @@
#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:
@@ -50,20 +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(); }
inline void DaemonPostInitialization(Poco::Util::Application &self) {
Daemon()->PostInitialization(self);
}
}

View File

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

View File

@@ -7,258 +7,144 @@
//
#include "Poco/JSON/Object.h"
#include "AP_WS_Server.h"
#include "DeviceRegistry.h"
#include "CommandManager.h"
#include "Poco/JSON/Parser.h"
#include "framework/WebSocketClientNotifications.h"
#include "DeviceRegistry.h"
#include "WS_Server.h"
#include "OUIServer.h"
namespace OpenWifi {
int DeviceRegistry::Start() {
std::lock_guard Guard(Mutex_);
poco_notice(Logger(),"Starting");
ArchiverCallback_ = std::make_unique<Poco::TimerCallback<DeviceRegistry>>(*this,&DeviceRegistry::onConnectionJanitor);
Timer_.setStartInterval(60 * 1000);
Timer_.setPeriodicInterval(20 * 1000); // every minute
Timer_.start(*ArchiverCallback_, MicroService::instance().TimerPool());
return 0;
Logger().notice("Starting ");
return 0;
}
void DeviceRegistry::Stop() {
poco_notice(Logger(),"Stopping...");
std::lock_guard Guard(Mutex_);
Timer_.stop();
poco_notice(Logger(),"Stopped...");
Logger().notice("Stopping ");
}
void DeviceRegistry::onConnectionJanitor([[maybe_unused]] Poco::Timer &timer) {
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;
}
static std::uint64_t last_log = OpenWifi::Now();
void DeviceRegistry::SetStatistics(uint64_t SerialNumber, const std::string &Statistics) {
std::lock_guard Guard(Mutex_);
std::shared_lock Guard(LocalMutex_);
auto Device = Devices_.find(SerialNumber);
if(Device != Devices_.end())
{
Device->second->Conn_.LastContact = time(nullptr);
Device->second->LastStats = Statistics;
}
}
NumberOfConnectedDevices_ = 0;
NumberOfConnectingDevices_ = 0;
AverageDeviceConnectionTime_ = 0;
std::uint64_t total_connected_time=0;
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;
auto now = OpenWifi::Now();
for (auto connection=SerialNumbers_.begin(); connection!=SerialNumbers_.end();) {
State = Device->second->Conn_;
return true;
}
if(connection->second.second== nullptr) {
connection++;
continue;
}
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;
}
}
if (connection->second.second->State_.Connected) {
NumberOfConnectedDevices_++;
total_connected_time += (now - connection->second.second->State_.started);
connection++;
} else {
NumberOfConnectingDevices_++;
connection++;
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;
}
}
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_));
}
WebSocketClientNotificationNumberOfConnections(NumberOfConnectedDevices_,
AverageDeviceConnectionTime_,
NumberOfConnectingDevices_);
}
bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) const {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
return false;
Statistics = Device->second.second->LastStats_;
return true;
}
bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
return false;
State = Device->second.second->State_;
return true;
}
bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
return false;
CheckData = Device->second.second->LastHealthcheck_;
return true;
}
bool DeviceRegistry::EndSession(std::uint64_t connection_id, std::uint64_t serial_number) {
std::unique_lock G(LocalMutex_);
auto Connection = SerialNumbers_.find(serial_number);
if (Connection == end(SerialNumbers_)) {
return false;
}
if (Connection->second.first != connection_id) {
return false;
}
SerialNumbers_.erase(Connection);
return true;
}
void DeviceRegistry::SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber) {
auto Connection = AP_WS_Server()->FindConnection(connection_id);
if(Connection== nullptr)
return;
std::unique_lock G(LocalMutex_);
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
if( (CurrentSerialNumber==SerialNumbers_.end()) ||
(CurrentSerialNumber->second.first<connection_id)) {
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Connection);
return;
}
}
bool DeviceRegistry::Connected(uint64_t SerialNumber) const {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
return false;
return Device->second.second->State_.Connected;
}
bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) const {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
// std::cout << "Device connection pointer: " << (std::uint64_t) Device->second.second << std::endl;
return Device->second.second->Send(Payload);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber)));
}
return false;
}
void DeviceRegistry::StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
return;
Device->second.second->StopWebSocketTelemetry(RPCID);
}
void DeviceRegistry::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
return;
Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
}
void DeviceRegistry::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
return;
Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
}
void DeviceRegistry::StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
return;
Device->second.second->StopKafkaTelemetry(RPCID);
}
void DeviceRegistry::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_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(SerialNumber);
if(Device==end(SerialNumbers_)|| Device->second.second== nullptr)
return;
Device->second.second->GetTelemetryParameters(TelemetryRunning,
TelemetryInterval,
TelemetryWebSocketTimer,
TelemetryKafkaTimer,
TelemetryWebSocketCount,
TelemetryKafkaCount,
TelemetryWebSocketPackets,
TelemetryKafkaPackets);
}
bool DeviceRegistry::SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
return Device->second.second->SendRadiusAccountingData(buffer,size);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
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;
}
return false;
}
bool DeviceRegistry::SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
return Device->second.second->SendRadiusAuthenticationData(buffer,size);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
}
return false;
}
bool DeviceRegistry::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
std::shared_lock Guard(LocalMutex_);
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
return false;
try {
return Device->second.second->SendRadiusCoAData(buffer,size);
} catch (...) {
poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
}
return false;
}
} // namespace

View File

@@ -8,23 +8,25 @@
#pragma once
#include <shared_mutex>
#include "Poco/JSON/Object.h"
#include "RESTObjects//RESTAPI_GWobjects.h"
#include "framework/MicroService.h"
#include "Poco/JSON/Object.h"
#include "Poco/Timer.h"
#include "RESTObjects//RESTAPI_GWobjects.h"
// class uCentral::WebSocket::WSConnection;
namespace OpenWifi {
class AP_WS_Connection;
class WSConnection;
class DeviceRegistry : public SubSystemServer {
public:
DeviceRegistry() noexcept:
SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
}
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;
@@ -34,68 +36,80 @@ namespace OpenWifi {
int Start() override;
void Stop() override;
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) const {
inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) {
return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
}
bool GetStatistics(std::uint64_t SerialNumber, std::string & Statistics) const;
bool GetStatistics(uint64_t SerialNumber, std::string & Statistics);
inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) const {
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(std::uint64_t SerialNumber, GWObjects::ConnectionState & State) const;
bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State);
inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) const {
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(std::uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const ;
bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData);
bool Connected(uint64_t SerialNumber) const ;
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);
inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) const {
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(std::uint64_t SerialNumber, const std::string & Payload) const ;
bool SendFrame(uint64_t SerialNumber, const std::string & Payload);
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);
inline void SetPendingUUID(const std::string & SerialNumber, uint64_t PendingUUID) {
return SetPendingUUID(Utils::SerialNumberToInt(SerialNumber), PendingUUID);
}
void SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID);
void SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber);
bool EndSession(std::uint64_t connection_id, std::uint64_t serial_number);
[[nodiscard]] inline std::shared_ptr<ConnectionEntry> GetDeviceConnection(const std::string & SerialNumber) {
return GetDeviceConnection(Utils::SerialNumberToInt(SerialNumber));
}
void SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
void StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
void SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
void StopKafkaTelemetry(std::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 onConnectionJanitor(Poco::Timer & timer);
inline void AverageDeviceStatistics( std::uint64_t & Connections, std::uint64_t & AverageConnectionTime, std::uint64_t & NumberOfConnectingDevices) const {
Connections = NumberOfConnectedDevices_;
AverageConnectionTime = AverageDeviceConnectionTime_;
NumberOfConnectingDevices = NumberOfConnectingDevices_;
[[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:
mutable std::shared_mutex LocalMutex_;
std::map<std::uint64_t, std::pair<std::uint64_t,std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
std::unique_ptr<Poco::TimerCallback<DeviceRegistry>> ArchiverCallback_;
Poco::Timer Timer_;
Poco::Thread ConnectionJanitor_;
std::atomic_uint64_t NumberOfConnectedDevices_=0;
std::atomic_uint64_t AverageDeviceConnectionTime_=0;
std::atomic_uint64_t NumberOfConnectingDevices_=0;
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(); }

View File

@@ -7,28 +7,29 @@
//
#include <iostream>
#include "framework/MicroService.h"
#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 "FileUploader.h"
#include "StorageService.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(MicroService::instance().ConfigPath("openwifi.fileuploader.path","/tmp"));
Path_ = UploadsDir.path();
@@ -40,68 +41,37 @@ namespace OpenWifi {
Path_ = "/tmp";
}
}
for(const auto & Svr: ConfigServersList_) {
if(MicroService::instance().NoAPISecurity()) {
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 =
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;
}
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 =
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;
}
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 * MicroService::instance().ConfigGetInt("openwifi.fileuploader.maxsize", 10000);
@@ -109,9 +79,9 @@ namespace OpenWifi {
return 0;
}
void FileUploader::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
void FileUploader::reinitialize(Poco::Util::Application &self) {
MicroService::instance().LoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
Logger().information("Reinitializing.");
Stop();
Start();
}
@@ -124,18 +94,18 @@ namespace OpenWifi {
bool FileUploader::AddUUID( const std::string & UUID) {
std::lock_guard Guard(Mutex_);
uint64_t now = OpenWifi::Now();
uint64_t Now = time(nullptr) ;
// remove old stuff...
for(auto i=OutStandingUploads_.begin();i!=OutStandingUploads_.end();) {
if ((now-i->second) > (60 * 30))
i = OutStandingUploads_.erase(i);
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;
OutStandingUploads_[UUID] = Now;
return true;
}
@@ -151,39 +121,64 @@ namespace OpenWifi {
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
{
@@ -194,71 +189,40 @@ namespace OpenWifi {
{
}
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("{}: Trace file uploaded.", UUID_));
StorageService()->AttachFileDataToCommand(UUID_, FileContent);
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_;
@@ -266,13 +230,7 @@ namespace OpenWifi {
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);
@@ -288,18 +246,17 @@ namespace OpenWifi {
}
else
{
poco_warning(Logger(),fmt::format("Unknown UUID={}",UUID));
Logger().warning(Poco::format("Unknown UUID=%s",UUID));
}
}
return nullptr;
}
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

@@ -8,13 +8,12 @@
#pragma once
#include "framework/MicroService.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "framework/MicroService.h"
namespace OpenWifi {
@@ -38,13 +37,15 @@ namespace OpenWifi {
private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
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")
{
}
};

View File

@@ -5,7 +5,6 @@
#pragma once
#include "framework/MicroService.h"
#include "Poco/Net/IPAddress.h"
#include "nlohmann/json.hpp"
@@ -134,7 +133,6 @@ namespace OpenWifi {
}
inline int Start() final {
poco_notice(Logger(),"Starting...");
ProviderName_ = MicroService::instance().ConfigGetString("iptocountry.provider","");
if(!ProviderName_.empty()) {
Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(ProviderName_);
@@ -147,9 +145,6 @@ namespace OpenWifi {
}
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,66 +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){
WebSocketClientServer()->SetProcessor(this);
}
GwWebSocketClient::~GwWebSocketClient() {
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/MicroService.h"
namespace OpenWifi {
class GwWebSocketClient : public 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,10 +5,13 @@
#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 "OUIServer.h"
@@ -18,59 +21,38 @@ namespace OpenWifi {
int OUIServer::Start() {
Running_ = true;
LatestOUIFileName_ = MicroService::instance().DataDir() + "/newOUIFile.txt";
CurrentOUIFileName_ = MicroService::instance().DataDir() + "/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_, MicroService::instance().TimerPool());
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) {
void OUIServer::reinitialize(Poco::Util::Application &self) {
MicroService::instance().LoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
Logger().information("Reinitializing.");
Stop();
Start();
}
bool OUIServer::GetFile(const std::string &FileName) {
try {
LastUpdate_ = OpenWifi::Now();
poco_information(Logger(), fmt::format("Start: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("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(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: {}",MicroService::instance().ConfigGetString("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);
@@ -98,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())
@@ -114,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((OpenWifi::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_ = OpenWifi::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_ = OpenWifi::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,8 +4,6 @@
#pragma once
#include <shared_mutex>
#include "framework/MicroService.h"
#include "Poco/Timer.h"
@@ -32,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,672 +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"
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,603 +0,0 @@
//
// Created by stephane bourque on 2022-05-18.
//
#include "RADIUS_proxy_server.h"
#include "RADIUS_helpers.h"
#include "AP_WS_Server.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_ = MicroService::instance().DataDir()+"/radius_pool_config.json";
Poco::File Config(ConfigFilename_);
enabled_ = MicroService::instance().ConfigGetBool("radius.proxy.enable",false);
if(!enabled_ && !Config.exists())
return 0;
enabled_ = true;
Poco::Net::SocketAddress AuthSockAddrV4(Poco::Net::AddressFamily::IPv4,
MicroService::instance().ConfigGetInt("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,
MicroService::instance().ConfigGetInt("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,
MicroService::instance().ConfigGetInt("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,
MicroService::instance().ConfigGetInt("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,
MicroService::instance().ConfigGetInt("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,
MicroService::instance().ConfigGetInt("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...
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));
for(auto &[_,radsec_server]:RADSECservers_)
radsec_server->Stop();
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::StartRADSECServer(const GWObjects::RadiusProxyServerEntry &E) {
RADSECservers_[ Poco::Net::SocketAddress(E.ip,0) ] = std::make_unique<RADSECserver>(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_information(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_information(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_information(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())
return;
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 {
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_information(Logger(), fmt::format(
"{}: Sending Accounting Packet to {}, CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(), CalledStationID, CallingStationID));
}
}
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())
return;
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 {
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_information(Logger(), fmt::format("{}: Sending Authentication Packet to {}, CalledStationID: {}, CallingStationID:{}",
serialNumber, FinalDestination.toString(),
CalledStationID, CallingStationID));
}
}
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size) {
if(Pools_.empty())
return;
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 {
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_information(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
FinalDestination.toString()));
}
}
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;
}
}
return DefaultRoute(rtype, RequestedAddress, P, UseRADSEC);
}
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,111 +0,0 @@
//
// Created by stephane bourque on 2022-05-18.
//
#pragma once
#include "framework/MicroService.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketReactor.h"
#include "RADSECserver.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);
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<RADSECserver>> 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,251 +0,0 @@
//
// Created by stephane bourque on 2022-08-15.
//
#pragma once
#include <iostream>
#include <fstream>
#include "framework/MicroService.h"
#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 "RADIUS_helpers.h"
#include "AP_WS_Server.h"
namespace OpenWifi {
class RADSECserver : public Poco::Runnable {
public:
RADSECserver(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)))
{
ReconnectorThr_.start(*this);
}
inline void run() final {
while(TryAgain_) {
if(!Connected_) {
std::unique_lock G(Mutex_);
Connect();
}
Poco::Thread::trySleep(1000);
}
}
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)) {
Logger_.debug(fmt::format("{}: {} Sending {} bytes", serial_number,
P.PacketType(), length));
sent_bytes = Socket_->sendBytes(buffer, length);
} else {
Logger_.debug(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);
// P.Log(std::cout);
// std::cout << "RADSEC: " << P.PacketType() << " " << (int) P.PacketTypeInt() << " Received " << NumberOfReceivedBytes << " bytes" << std::endl;
if (P.IsAuthentication()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
Logger_.debug(fmt::format("{}: {} Received {} bytes.", SerialNumber, P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAuthenticationData(
SerialNumber, Buffer,
NumberOfReceivedBytes);
} else if (P.IsAccounting()) {
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
Logger_.debug(fmt::format("{}: {} Received {} bytes.", SerialNumber, P.PacketType(), NumberOfReceivedBytes));
AP_WS_Server()->SendRadiusAccountingData(
SerialNumber, Buffer,
NumberOfReceivedBytes);
} 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_(MicroService::instance().DataDir());
Poco::TemporaryFile KeyFile_(MicroService::instance().DataDir());
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(MicroService::instance().DataDir()));
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);
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADSECserver, Poco::Net::ReadableNotification>(
*this, &RADSECserver::onData));
Reactor_.addEventHandler(
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ErrorNotification>(
*this, &RADSECserver::onError));
Reactor_.addEventHandler(
*Socket_,
Poco::NObserver<RADSECserver, Poco::Net::ShutdownNotification>(
*this, &RADSECserver::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<RADSECserver, Poco::Net::ReadableNotification>(
*this, &RADSECserver::onData));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ErrorNotification>(
*this, &RADSECserver::onError));
Reactor_.removeEventHandler(
*Socket_, Poco::NObserver<RADSECserver, Poco::Net::ShutdownNotification>(
*this, &RADSECserver::onShutdown));
Connected_ = false;
}
poco_information(Logger_,"Disconnecting.");
}
inline void Stop() {
TryAgain_ = false;
Disconnect();
ReconnectorThr_.wakeUp();
ReconnectorThr_.join();
}
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::shared_mutex Mutex_;
Poco::Net::SocketReactor &Reactor_;
GWObjects::RadiusProxyServerEntry Server_;
Poco::Logger &Logger_;
std::atomic_bool Connected_=false;
std::atomic_bool TryAgain_=true;
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
Poco::Thread ReconnectorThr_;
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
};
}

View File

@@ -1,39 +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 "ParseWifiScan.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,
@@ -42,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 = OpenWifi::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 = OpenWifi::Now();
Cmd.executionTime = rpc_execution_time.count();
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
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/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

@@ -12,13 +12,14 @@
#include "Poco/JSON/Stringifier.h"
#include "RESTAPI_blacklist.h"
#include "StorageService.h"
#include "framework/ow_constants.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);
}
@@ -36,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);
}
@@ -51,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);
}
@@ -68,7 +69,7 @@ namespace OpenWifi {
}
D.author = UserInfo_.userinfo.email;
D.created = OpenWifi::Now();
D.created = std::time(nullptr);
if(StorageService()->AddBlackListDevice(D)) {
GWObjects::BlackListedDevice CreatedDevice;
@@ -84,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

@@ -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

@@ -16,7 +16,7 @@ namespace OpenWifi {
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

@@ -16,7 +16,7 @@ namespace OpenWifi {
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

@@ -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

@@ -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,13 +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"
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;
@@ -29,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);
}
@@ -48,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;
@@ -66,7 +66,7 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
}
DefConfig.Created = DefConfig.LastModified = OpenWifi::Now();
DefConfig.Created = DefConfig.LastModified = std::time(nullptr);
if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) {
return OK();
}
@@ -77,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);
@@ -96,7 +96,7 @@ namespace OpenWifi {
Existing.Configuration = NewConfig.Configuration;
}
Existing.LastModified = OpenWifi::Now();
Existing.LastModified = std::time(nullptr);
AssignIfPresent(Obj,"description",Existing.Description);
if(Obj->has("modelIds"))
Existing.Models = NewConfig.Models;

View File

@@ -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

@@ -20,7 +20,7 @@ class RESTAPI_default_configurations : public RESTAPIHandler {
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 {};

View File

@@ -14,7 +14,7 @@ namespace OpenWifi {
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_OPTIONS}, Server, TransactionId,Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/deviceDashboard"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/deviceDashboard"};}
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_protocol.h"
namespace OpenWifi {
class RESTAPI_device_commandHandler : public RESTAPIHandler {
@@ -31,32 +31,28 @@ namespace OpenWifi {
void GetStatistics();
void DeleteStatistics();
void GetStatus();
void ExecuteCommand();
void Configure();
void GetChecks();
void DeleteChecks();
void ExecuteCommand(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Configure(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Upgrade(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Reboot(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Factory(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void LEDs(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Trace(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void MakeRequest(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void WifiScan(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void EventQueue(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Rtty(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Telemetry(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Ping(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout);
void Upgrade();
void Reboot();
void Factory();
void LEDs();
void Trace();
void MakeRequest();
void WifiScan();
void EventQueue();
void Rtty();
void Telemetry();
void Ping();
static auto PathName() { return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/device/{serialNumber}/{command}"}; };
void DoGet() final;
void DoDelete() final;
void DoPost() final;
void DoPut() final {};
void CallCanceled(const char * Cmd,const std::string &UUID, uint64_t RPC, const OpenWifi::RESTAPI::Errors::msg & Err);
void CallCanceled(const char * Cmd, const OpenWifi::RESTAPI::Errors::msg &Err, const std::string & Details="");
inline bool ValidateParameters() {
Command_ = GetBinding(RESTAPI::Protocol::COMMAND, "");
if (Command_.empty()) {
@@ -70,8 +66,6 @@ namespace OpenWifi {
}
private:
std::string SerialNumber_,
Command_;
std::uint64_t SerialNumberInt_=0;
std::string SerialNumber_, Command_;
};
}

View File

@@ -13,14 +13,15 @@
#include "StorageService.h"
#include "framework/ConfigurationValidator.h"
#include "framework/MicroService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_errors.h"
#include "framework/RESTAPI_protocol.h"
#include "RESTAPI_device_helper.h"
namespace OpenWifi {
void RESTAPI_device_handler::DoGet() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::NormalizeMac(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
@@ -42,7 +43,7 @@ namespace OpenWifi {
void RESTAPI_device_handler::DoDelete() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::NormalizeMac(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
@@ -86,17 +87,17 @@ namespace OpenWifi {
void RESTAPI_device_handler::DoPost() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::NormalizeMac(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
const auto &Obj = ParsedBody_;
std::string Arg;
if(HasParameter("validateOnly",Arg) && Arg=="true") {
if(!Obj->has("configuration")) {
return BadRequest(RESTAPI::Errors::MustHaveConfigElement);
auto Body = ParseStream();
if(!Body->has("configuration")) {
return BadRequest("Must have 'configuration' element.");
}
auto Config=Obj->get("configuration").toString();
auto Config=Body->get("configuration").toString();
Poco::JSON::Object Answer;
std::string Error;
auto Res = ValidateUCentralConfiguration(Config, Error);
@@ -107,19 +108,16 @@ namespace OpenWifi {
}
if (!Utils::ValidSerialNumber(SerialNumber)) {
Logger_.warning(fmt::format("CREATE-DEVICE({}): Illegal serial number.", SerialNumber));
Logger_.warning(Poco::format("CREATE-DEVICE(%s): Illegal serial number.", SerialNumber));
return BadRequest( RESTAPI::Errors::InvalidSerialNumber);
}
auto Obj = ParseStream();
GWObjects::Device Device;
if (!Device.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(!Utils::NormalizeMac(Device.SerialNumber)) {
return BadRequest( RESTAPI::Errors::InvalidSerialNumber);
}
if(SerialNumber!=Device.SerialNumber) {
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
}
@@ -129,13 +127,11 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
}
for(auto &i:Device.Notes) {
for(auto &i:Device.Notes)
i.createdBy = UserInfo_.userinfo.email;
i.created = OpenWifi::Now();
}
Config::Config NewConfig(Device.Configuration);
Device.UUID = OpenWifi::Now();
Device.UUID = std::time(nullptr);
NewConfig.SetUUID(Device.UUID);
Device.Configuration = NewConfig.get();
@@ -153,11 +149,11 @@ namespace OpenWifi {
void RESTAPI_device_handler::DoPut() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
if(!Utils::ValidSerialNumber(SerialNumber)) {
if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
}
const auto &Obj = ParsedBody_;
auto Obj = ParseStream();
GWObjects::Device NewDevice;
if (!NewDevice.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
@@ -174,7 +170,7 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
}
Config::Config NewConfig(NewDevice.Configuration);
uint64_t NewConfigUUID = OpenWifi::Now();
uint64_t NewConfigUUID = std::time(nullptr);
NewConfig.SetUUID(NewConfigUUID);
Existing.Configuration = NewConfig.get();
Existing.UUID = NewConfigUUID;
@@ -183,16 +179,13 @@ namespace OpenWifi {
AssignIfPresent(Obj, "venue", Existing.Venue);
AssignIfPresent(Obj, "owner", Existing.Owner);
AssignIfPresent(Obj, "location", Existing.Location);
AssignIfPresent(Obj, "subscriber", Existing.subscriber);
AssignIfPresent(Obj, "entity", Existing.entity);
for(auto &i:NewDevice.Notes) {
i.createdBy = UserInfo_.userinfo.email;
i.created = OpenWifi::Now();
Existing.Notes.push_back(i);
}
Existing.LastConfigurationChange = OpenWifi::Now();
Existing.LastConfigurationChange = std::time(nullptr);
if (StorageService()->UpdateDevice(Existing)) {
SetCurrentConfigurationID(SerialNumber, Existing.UUID);
Poco::JSON::Object DevObj;

View File

@@ -24,7 +24,7 @@ namespace OpenWifi {
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/device/{serialNumber}"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/device/{serialNumber}"}; };
void DoGet() final;
void DoDelete() final;
void DoPost() final;

View File

@@ -6,17 +6,17 @@
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "StorageService.h"
#include "AP_WS_Server.h"
#include "DeviceRegistry.h"
namespace OpenWifi {
inline void CompleteDeviceInfo(const GWObjects::Device & Device, Poco::JSON::Object & Answer) {
GWObjects::ConnectionState CS;
AP_WS_Server()->GetState(Device.SerialNumber,CS);
DeviceRegistry()->GetState(Device.SerialNumber,CS);
GWObjects::HealthCheck HC;
AP_WS_Server()->GetHealthcheck(Device.SerialNumber, HC);
DeviceRegistry()->GetHealthcheck(Device.SerialNumber, HC);
std::string Stats;
AP_WS_Server()->GetStatistics(Device.SerialNumber, Stats);
DeviceRegistry()->GetStatistics(Device.SerialNumber, Stats);
Poco::JSON::Object DeviceInfo;
Device.to_json(DeviceInfo);

View File

@@ -11,78 +11,14 @@
#include "RESTAPI_devices_handler.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_device_helper.h"
#include "Poco/StringTokenizer.h"
#include "framework/orm.h"
#include "AP_WS_Server.h"
namespace OpenWifi {
bool PrepareOrderBy(const std::string &OrderByListRaw, std::string &OrderByString) {
auto OrderByList = ORM::Escape(OrderByListRaw);
auto items = Poco::StringTokenizer(OrderByList,",");
std::string ItemList;
Types::StringVec Fields;
StorageService()->GetDeviceDbFieldList(Fields);
std::set<std::string> FieldNames;
for(const auto &field:Fields)
FieldNames.insert(Poco::toLower(field));
for(const auto &i:items) {
auto T = Poco::StringTokenizer(i,":");
if(T.count()!=2) {
return false;
}
if(T[1]!="a" && T[1]!="d") {
return false;
}
if(!ItemList.empty())
ItemList += " , ";
auto hint = FieldNames.find(Poco::toLower(T[0]));
if(hint==FieldNames.end()) {
return false;
}
ItemList += T[0] + (T[1]=="a" ? " ASC" : " DESC");
}
if(!ItemList.empty()) {
OrderByString = " ORDER BY " + ItemList;
}
return true;
}
void RESTAPI_devices_handler::DoGet() {
if(GetBoolParameter("connectionStatistics")) {
GWObjects::DeviceConnectionStatistics DCS;
Poco::JSON::Object Answer;
AP_WS_Server()->AverageDeviceStatistics(DCS.connectedDevices,DCS.averageConnectionTime, DCS.connectingDevices);
DCS.to_json(Answer);
return ReturnObject(Answer);
}
if(GetBoolParameter("orderSpec")) {
Types::StringVec Fields;
StorageService()->GetDeviceDbFieldList(Fields);
std::sort(Fields.begin(),Fields.end());
Poco::JSON::Object Answer;
RESTAPI_utils::field_to_json(Answer,"list",Fields);
return ReturnObject(Answer);
}
std::string OrderBy{" ORDER BY serialNumber ASC "}, Arg;
if(HasParameter("orderBy",Arg)) {
if(!PrepareOrderBy(Arg,OrderBy)) {
return BadRequest(RESTAPI::Errors::InvalidLOrderBy);
}
}
auto serialOnly = GetBoolParameter(RESTAPI::Protocol::SERIALONLY, false);
auto deviceWithStatus = GetBoolParameter(RESTAPI::Protocol::DEVICEWITHSTATUS, false);
auto completeInfo = GetBoolParameter("completeInfo",false);
@@ -92,8 +28,6 @@ namespace OpenWifi {
Poco::JSON::Array Objects;
for (auto &i : SelectedRecords()) {
auto SerialNumber = i;
if(!Utils::ValidSerialNumber(i))
continue;
GWObjects::Device D;
if (StorageService()->GetDevice(SerialNumber, D)) {
if(completeInfo) {
@@ -110,7 +44,7 @@ namespace OpenWifi {
}
} else {
Logger_.error(
fmt::format("DEVICE({}): device in select cannot be found.", i));
Poco::format("DEVICE(%s): device in select cannot be found.", i));
}
}
if (deviceWithStatus)
@@ -125,7 +59,7 @@ namespace OpenWifi {
}
} else if (serialOnly) {
std::vector<std::string> SerialNumbers;
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers, OrderBy);
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers);
Poco::JSON::Array Objects;
for (const auto &i : SerialNumbers) {
Objects.add(i);
@@ -133,7 +67,7 @@ namespace OpenWifi {
RetObj.set(RESTAPI::Protocol::SERIALNUMBERS, Objects);
} else {
std::vector<GWObjects::Device> Devices;
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices, OrderBy);
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices);
Poco::JSON::Array Objects;
for (const auto &i : Devices) {
Poco::JSON::Object Obj;

View File

@@ -20,7 +20,7 @@ namespace OpenWifi {
Server,
TransactionId,
Internal){};
static auto PathName() { return std::list<std::string>{"/api/v1/devices"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/devices"}; };
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

View File

@@ -12,7 +12,8 @@
#include "Poco/File.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_errors.h"
#include "framework/RESTAPI_protocol.h"
#include <fstream>
namespace OpenWifi {
@@ -20,12 +21,15 @@ namespace OpenWifi {
auto UUID = GetBinding(RESTAPI::Protocol::FILEUUID, "");
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
// does the file exist
Poco::File DownloadFile(FileUploader()->Path() + "/" + UUID);
std::string FileType;
std::string FileContent;
if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType)) {
if (!StorageService()->GetAttachedFile(UUID, SerialNumber, DownloadFile.path(), FileType)) {
return NotFound();
}
SendFileContent(FileContent,"pcap",UUID+".pcap");
SendFile(DownloadFile, UUID);
DownloadFile.remove();
}
void RESTAPI_file::DoDelete() {

View File

@@ -21,7 +21,7 @@ namespace OpenWifi {
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/file/{uuid}"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/file/{uuid}"};}
void DoGet() final;
void DoDelete() final;
void DoPost() final {};

View File

@@ -16,7 +16,7 @@ class RESTAPI_iptocountry_handler : public RESTAPIHandler {
Server,
TransactionId,
Internal){};
static auto PathName() { return std::list<std::string>{"/api/v1/iptocountry"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/iptocountry"}; };
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

View File

@@ -14,7 +14,7 @@ namespace OpenWifi {
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/ouis"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/ouis"};}
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

View File

@@ -1,70 +0,0 @@
//
// Created by stephane bourque on 2022-05-20.
//
#include "RESTAPI_radiusProxyConfig_handler.h"
#include "RESTObjects/RESTAPI_GWobjects.h"
#include "RADIUS_proxy_server.h"
namespace OpenWifi {
void RESTAPI_radiusProxyConfig_handler::DoGet() {
GWObjects::RadiusProxyPoolList C;
RADIUS_proxy_server()->GetConfig(C);
Poco::JSON::Object Answer;
C.to_json(Answer);
return ReturnObject(Answer);
}
void RESTAPI_radiusProxyConfig_handler::DoDelete() {
if(!Internal_ && (UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
RADIUS_proxy_server()->DeleteConfig();
return OK();
}
void RESTAPI_radiusProxyConfig_handler::DoPut() {
if(!Internal_ && (UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
GWObjects::RadiusProxyPoolList C;
if(!C.from_json(ParsedBody_) || C.pools.empty()) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
// Logically validate the config.
for(const auto &pool:C.pools) {
if(pool.name.empty()) {
return BadRequest(RESTAPI::Errors::PoolNameInvalid);
}
for(const auto &config:{pool.acctConfig,pool.authConfig,pool.coaConfig}) {
if(config.strategy!="random" && config.strategy!="round_robin" && config.strategy!="weighted") {
return BadRequest(RESTAPI::Errors::InvalidRadiusProxyStrategy);
}
if(config.monitorMethod!="none" && config.monitorMethod!="https" && config.monitorMethod!="radius") {
return BadRequest(RESTAPI::Errors::InvalidRadiusProxyMonitorMethod);
}
if(config.servers.empty()) {
return BadRequest(RESTAPI::Errors::MustHaveAtLeastOneRadiusServer);
}
for(auto &server:config.servers) {
Poco::Net::IPAddress Addr;
if(!Poco::Net::IPAddress::tryParse(server.ip,Addr) || server.port==0) {
return BadRequest(RESTAPI::Errors::InvalidRadiusServerEntry);
}
if(config.strategy=="weighted" && server.weight==0) {
return BadRequest(RESTAPI::Errors::InvalidRadiusServerWeigth);
}
}
}
}
RADIUS_proxy_server()->SetConfig(C);
return ReturnObject(*ParsedBody_);
}
}

View File

@@ -1,27 +0,0 @@
//
// Created by stephane bourque on 2022-05-20.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_radiusProxyConfig_handler : public RESTAPIHandler {
public:
RESTAPI_radiusProxyConfig_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_DELETE,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/radiusProxyConfig"}; }
void DoGet() final;
void DoDelete() final;
void DoPost() final{};
void DoPut() final;
};
}

View File

@@ -16,16 +16,18 @@
#include "RESTAPI/RESTAPI_devices_handler.h"
#include "RESTAPI/RESTAPI_file.h"
#include "RESTAPI/RESTAPI_ouis.h"
#include "RESTAPI/RESTAPI_capabilities_handler.h"
#include "RESTAPI/RESTAPI_telemetryWebSocket.h"
#include "RESTAPI/RESTAPI_webSocketServer.h"
#include "RESTAPI/RESTAPI_iptocountry_handler.h"
#include "RESTAPI/RESTAPI_radiusProxyConfig_handler.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const char *Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
Poco::Thread::current()->setName("ExtWebServerThread_" + std::to_string(TransactionId));
return RESTAPI_Router<
RESTAPI_devices_handler,
RESTAPI_device_handler,
@@ -42,13 +44,13 @@ namespace OpenWifi {
RESTAPI_blacklist,
RESTAPI_blacklist_list,
RESTAPI_iptocountry_handler,
RESTAPI_radiusProxyConfig_handler,
RESTAPI_capabilities_handler, RESTAPI_telemetryWebSocket>(Path,Bindings,L, S, TransactionId);
}
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const char *Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
Poco::Thread::current()->setName("IntWebServerThread_" + std::to_string(TransactionId));
return RESTAPI_Router_I<
RESTAPI_devices_handler,
RESTAPI_device_handler,
@@ -61,7 +63,6 @@ namespace OpenWifi {
RESTAPI_file,
RESTAPI_blacklist,
RESTAPI_iptocountry_handler,
RESTAPI_radiusProxyConfig_handler,
RESTAPI_blacklist_list>(Path,Bindings,L, S, TransactionId);
}
}

View File

@@ -25,23 +25,14 @@ void RESTAPI_telemetryWebSocket::DoGet() {
}
}
if(!Utils::NormalizeMac(SNum)) {
return BadRequest(RESTAPI::Errors::InvalidSerialNumber);
}
auto SerialNumber = Utils::SerialNumberToInt(SNum);
if(!TelemetryStream()->IsValidEndPoint(SerialNumber,UUID)) {
Logger_.warning(fmt::format("Illegal telemetry request for S: {}, UUID: {}", SerialNumber, UUID));
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
Response->setContentLength(0);
Response->send();
Logger_.warning(Poco::format("Illegal telemetry request for S: %s, UUID: %s", SerialNumber, UUID));
return;
}
auto WS = std::make_unique<Poco::Net::WebSocket>(*Request, *Response);
new TelemetryClient(UUID, SerialNumber, std::move(WS), TelemetryStream()->NextReactor(), Logger_);
auto WS = Poco::SharedPtr<Poco::Net::WebSocket>( new Poco::Net::WebSocket(*Request, *Response));
new TelemetryClient(UUID, SerialNumber, WS, TelemetryStream()->NextReactor(), Logger_);
} catch (const Poco::Net::WebSocketException &E) {
Logger_.log(E);
switch (E.code()) {
@@ -58,21 +49,7 @@ void RESTAPI_telemetryWebSocket::DoGet() {
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
Response->setContentLength(0);
Response->send();
return;
} catch (...) {
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
Response->setContentLength(0);
Response->send();
return;
}
} else {
SetCommonHeaders(true);
Response->setStatus(Poco::Net::HTTPResponse::HTTP_METHOD_NOT_ALLOWED);
Response->send();
return;
}
}
}

View File

@@ -14,7 +14,7 @@ namespace OpenWifi {
std::vector<std::string>{ Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal, false) {}
static auto PathName() { return std::list<std::string>{"/api/v1/ws_telemetry"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/ws_telemetry"};}
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};

View File

@@ -0,0 +1,152 @@
//
// Created by stephane bourque on 2021-08-12.
//
#include "Poco/Net/WebSocket.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/Stringifier.h"
#include "RESTAPI_webSocketServer.h"
#include "SerialNumberCache.h"
#include "framework/MicroService.h"
namespace OpenWifi {
void RESTAPI_webSocketServer::DoGet() {
// try and upgrade this session to websocket...
if(Request->find("Upgrade") != Request->end() && Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
try
{
Poco::Net::WebSocket WS(*Request, *Response);
int flags;
int n;
bool Authenticated=false;
bool Done=false;
do
{
Poco::Buffer<char> IncomingFrame(0);
n = WS.receiveFrame(IncomingFrame, flags);
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
switch(Op) {
case Poco::Net::WebSocket::FRAME_OP_PING: {
WS.sendFrame("", 0,
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
}
break;
case Poco::Net::WebSocket::FRAME_OP_PONG: {
}
break;
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
IncomingFrame.append(0);
if(!Authenticated) {
std::string Frame{IncomingFrame.begin()};
auto Tokens = Utils::Split(Frame,':');
bool Expired=false, Contacted = false;
if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
Authenticated=true;
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
WS.sendFrame(S.c_str(),S.size());
} else {
std::string S{"Invalid token. Closing connection."};
WS.sendFrame(S.c_str(),S.size());
Done=true;
}
} else {
try {
Poco::JSON::Parser P;
auto Obj = P.parse(IncomingFrame.begin())
.extract<Poco::JSON::Object::Ptr>();
std::string Answer;
if(Process(Obj, Answer)) {
if (!Answer.empty())
WS.sendFrame(Answer.c_str(), Answer.size());
else {
WS.sendFrame("{}", 2);
}
} else {
Done=true;
}
} catch (const Poco::JSON::JSONException & E) {
Logger_.log(E);
}
}
}
break;
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
Done=true;
}
break;
default:
{
}
}
}
while (!Done && (n > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE));
}
catch (const Poco::Net::WebSocketException & E)
{
Logger_.log(E);
switch (E.code())
{
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION:
Response->set("Sec-WebSocket-Version", Poco::Net::WebSocket::WEBSOCKET_VERSION);
// fallthrough
case Poco::Net::WebSocket::WS_ERR_NO_HANDSHAKE:
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_VERSION:
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_KEY:
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
Response->setContentLength(0);
Response->send();
break;
}
}
catch (const Poco::Exception &E) {
Logger_.log(E);
}
catch (...) {
}
} else {
return BadRequest("Client does not support a websocket connection.");
}
}
bool RESTAPI_webSocketServer::Process(const Poco::JSON::Object::Ptr &O, std::string &Answer ) {
try {
if (O->has("command")) {
auto Command = O->get("command").toString();
if (Command == "serial_number_search" && O->has("serial_prefix")) {
auto Prefix = O->get("serial_prefix").toString();
uint64_t HowMany = 50;
if (O->has("howMany"))
HowMany = O->get("howMany");
Logger_.information(Poco::format("serial_number_search: %s", Prefix));
if (!Prefix.empty() && Prefix.length() < 13) {
std::vector<uint64_t> Numbers;
SerialNumberCache()->FindNumbers(Prefix, HowMany, Numbers);
Poco::JSON::Array A;
for (const auto &i : Numbers)
A.add(Utils::IntToSerialNumber(i));
Poco::JSON::Object AO;
AO.set("serialNumbers", A);
AO.set("command","serial_number_search");
std::ostringstream SS;
Poco::JSON::Stringifier::stringify(AO, SS);
Answer = SS.str();
}
}
}
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
}

View File

@@ -0,0 +1,25 @@
//
// Created by stephane bourque on 2021-08-12.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_webSocketServer : public RESTAPIHandler {
public:
RESTAPI_webSocketServer(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,false) {}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/ws"};}
void DoGet() final;
void DoDelete() final {};
void DoPost() final {};
void DoPut() final {};
private:
bool Process(const Poco::JSON::Object::Ptr &O, std::string &Answer);
};
}

View File

@@ -1,624 +0,0 @@
//
// Created by stephane bourque on 2022-01-10.
//
#include "RESTAPI_AnalyticsObjects.h"
#include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::AnalyticsObjects {
void Report::reset() {
}
void Report::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
}
void VenueInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"name",name);
field_to_json(Obj,"description",description);
field_to_json(Obj,"retention",retention);
field_to_json(Obj,"interval",interval);
field_to_json(Obj,"monitorSubVenues",monitorSubVenues);
}
bool VenueInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name);
field_from_json(Obj,"description",description);
field_from_json(Obj,"retention",retention);
field_from_json(Obj,"interval",interval);
field_from_json(Obj,"monitorSubVenues",monitorSubVenues);
return true;
} catch(...) {
}
return false;
}
void BoardInfo::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj,"venueList",venueList);
}
bool BoardInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj,"venueList",venueList);
return true;
} catch(...) {
}
return false;
}
void DeviceInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"boardId",boardId);
field_to_json(Obj,"type",type);
field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"deviceType",deviceType);
field_to_json(Obj,"lastContact",lastContact);
field_to_json(Obj,"lastPing",lastPing);
field_to_json(Obj,"lastState",lastState);
field_to_json(Obj,"lastFirmware",lastFirmware);
field_to_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate);
field_to_json(Obj,"lastConnection",lastConnection);
field_to_json(Obj,"lastDisconnection",lastDisconnection);
field_to_json(Obj,"pings",pings);
field_to_json(Obj,"states",states);
field_to_json(Obj,"connected",connected);
field_to_json(Obj,"connectionIp",connectionIp);
field_to_json(Obj,"associations_2g",associations_2g);
field_to_json(Obj,"associations_5g",associations_5g);
field_to_json(Obj,"associations_6g",associations_6g);
field_to_json(Obj,"health",health);
field_to_json(Obj,"lastHealth",lastHealth);
field_to_json(Obj,"locale",locale);
field_to_json(Obj,"uptime",uptime);
field_to_json(Obj,"memory",memory);
}
bool DeviceInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"boardId",boardId);
field_from_json(Obj,"type",type);
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"deviceType",deviceType);
field_from_json(Obj,"lastContact",lastContact);
field_from_json(Obj,"lastPing",lastPing);
field_from_json(Obj,"lastState",lastState);
field_from_json(Obj,"lastFirmware",lastFirmware);
field_from_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate);
field_from_json(Obj,"lastConnection",lastConnection);
field_from_json(Obj,"lastDisconnection",lastDisconnection);
field_from_json(Obj,"pings",pings);
field_from_json(Obj,"states",states);
field_from_json(Obj,"connected",connected);
field_from_json(Obj,"connectionIp",connectionIp);
field_from_json(Obj,"associations_2g",associations_2g);
field_from_json(Obj,"associations_5g",associations_5g);
field_from_json(Obj,"associations_6g",associations_6g);
field_from_json(Obj,"health",health);
field_from_json(Obj,"lastHealth",lastHealth);
field_from_json(Obj,"locale",locale);
field_from_json(Obj,"uptime",uptime);
field_from_json(Obj,"memory",memory);
return true;
} catch(...) {
}
return false;
}
void DeviceInfoList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"devices",devices);
}
bool DeviceInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"devices",devices);
return true;
} catch(...) {
}
return false;
}
void UE_rate::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"bitrate",bitrate);
field_to_json(Obj,"mcs",mcs);
field_to_json(Obj,"nss",nss);
field_to_json(Obj,"ht",ht);
field_to_json(Obj,"sgi",sgi);
field_to_json(Obj,"chwidth",chwidth);
}
bool UE_rate::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"bitrate",bitrate);
field_from_json(Obj,"mcs",mcs);
field_from_json(Obj,"nss",nss);
field_from_json(Obj,"ht",ht);
field_from_json(Obj,"sgi",sgi);
field_from_json(Obj,"chwidth",chwidth);
return true;
} catch(...) {
}
return false;
}
void UETimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"station",station);
field_to_json(Obj,"rssi",rssi);
field_to_json(Obj,"tx_bytes",tx_bytes);
field_to_json(Obj,"rx_bytes",rx_bytes);
field_to_json(Obj,"tx_duration",tx_duration);
field_to_json(Obj,"rx_packets",rx_packets);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"tx_retries",tx_retries);
field_to_json(Obj,"tx_failed",tx_failed);
field_to_json(Obj,"connected",connected);
field_to_json(Obj,"inactive",inactive);
field_to_json(Obj,"tx_rate",tx_rate);
field_to_json(Obj,"rx_rate",rx_rate);
// field_to_json(Obj, "tidstats", tidstats);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
field_to_json(Obj,"tx_failed_delta",tx_failed_delta);
field_to_json(Obj,"tx_retries_delta",tx_retries_delta);
field_to_json(Obj,"tx_duration_delta",tx_duration_delta);
}
bool UETimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"station",station);
field_from_json(Obj,"rssi",rssi);
field_from_json(Obj,"tx_bytes",tx_bytes);
field_from_json(Obj,"rx_bytes",rx_bytes);
field_from_json(Obj,"tx_duration",tx_duration);
field_from_json(Obj,"rx_packets",rx_packets);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"tx_retries",tx_retries);
field_from_json(Obj,"tx_failed",tx_failed);
field_from_json(Obj,"connected",connected);
field_from_json(Obj,"inactive",inactive);
field_from_json(Obj,"tx_rate",tx_rate);
field_from_json(Obj,"rx_rate",rx_rate);
// field_from_json(Obj,"tidstats",tidstats);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
field_from_json(Obj,"tx_failed_delta",tx_failed_delta);
field_from_json(Obj,"tx_retries_delta",tx_retries_delta);
field_from_json(Obj,"tx_duration_delta",tx_duration_delta);
return true;
} catch(...) {
}
return false;
}
void APTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"collisions",collisions);
field_to_json(Obj,"multicast",multicast);
field_to_json(Obj,"rx_bytes",rx_bytes);
field_to_json(Obj,"rx_dropped",rx_dropped);
field_to_json(Obj,"rx_errors",rx_errors);
field_to_json(Obj,"rx_packets",rx_packets);
field_to_json(Obj,"tx_bytes",tx_bytes);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"tx_dropped",tx_dropped);
field_to_json(Obj,"tx_errors",tx_errors);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_to_json(Obj,"rx_dropped_delta",rx_dropped_delta);
field_to_json(Obj,"tx_dropped_delta",tx_dropped_delta);
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
field_to_json(Obj,"rx_errors_delta",rx_errors_delta);
field_to_json(Obj,"tx_errors_delta",tx_errors_delta);
}
bool APTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"collisions",collisions);
field_from_json(Obj,"multicast",multicast);
field_from_json(Obj,"rx_bytes",rx_bytes);
field_from_json(Obj,"rx_dropped",rx_dropped);
field_from_json(Obj,"rx_errors",rx_errors);
field_from_json(Obj,"rx_packets",rx_packets);
field_from_json(Obj,"tx_bytes",tx_bytes);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"tx_dropped",tx_dropped);
field_from_json(Obj,"tx_errors",tx_errors);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_from_json(Obj,"rx_dropped_delta",rx_dropped_delta);
field_from_json(Obj,"tx_dropped_delta",tx_dropped_delta);
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
field_from_json(Obj,"rx_errors_delta",rx_errors_delta);
field_from_json(Obj,"tx_errors_delta",tx_errors_delta);
return true;
} catch(...) {
}
return false;
}
void TIDstat_entry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"rx_msdu",rx_msdu);
field_to_json(Obj,"tx_msdu",tx_msdu);
field_to_json(Obj,"tx_msdu_failed",tx_msdu_failed);
field_to_json(Obj,"tx_msdu_retries",tx_msdu_retries);
}
bool TIDstat_entry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"rx_msdu",rx_msdu);
field_from_json(Obj,"tx_msdu",tx_msdu);
field_from_json(Obj,"tx_msdu_failed",tx_msdu_failed);
field_from_json(Obj,"tx_msdu_retries",tx_msdu_retries);
return true;
} catch(...) {
}
return false;
}
void RadioTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"band",band);
field_to_json(Obj,"channel_width",channel_width);
field_to_json(Obj,"active_ms",active_ms);
field_to_json(Obj,"busy_ms",busy_ms);
field_to_json(Obj,"receive_ms",receive_ms);
field_to_json(Obj,"transmit_ms",transmit_ms);
field_to_json(Obj,"tx_power",tx_power);
field_to_json(Obj,"channel",channel);
field_to_json(Obj,"temperature",temperature);
field_to_json(Obj,"noise",noise);
field_to_json(Obj,"active_pct",active_pct);
field_to_json(Obj,"busy_pct",busy_pct);
field_to_json(Obj,"receive_pct",receive_pct);
field_to_json(Obj,"transmit_pct",transmit_pct);
}
bool RadioTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"band",band);
field_from_json(Obj,"channel_width",channel_width);
field_from_json(Obj,"active_ms",active_ms);
field_from_json(Obj,"busy_ms",busy_ms);
field_from_json(Obj,"receive_ms",receive_ms);
field_from_json(Obj,"transmit_ms",transmit_ms);
field_from_json(Obj,"tx_power",tx_power);
field_from_json(Obj,"channel",channel);
field_from_json(Obj,"temperature",temperature);
field_from_json(Obj,"noise",noise);
field_from_json(Obj,"active_pct",active_pct);
field_from_json(Obj,"busy_pct",busy_pct);
field_from_json(Obj,"receive_pct",receive_pct);
field_from_json(Obj,"transmit_pct",transmit_pct);
return true;
} catch(...) {
}
return false;
}
void AveragePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"min",min);
field_to_json(Obj,"max",max);
field_to_json(Obj,"avg",avg);
}
bool AveragePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"min",min);
field_from_json(Obj,"max",max);
field_from_json(Obj,"avg",avg);
return true;
} catch(...) {
}
return false;
}
void SSIDTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"bssid",bssid);
field_to_json(Obj,"mode",mode);
field_to_json(Obj,"ssid",ssid);
field_to_json(Obj,"band",band);
field_to_json(Obj,"channel",channel);
field_to_json(Obj,"associations",associations);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
}
bool SSIDTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"bssid",bssid);
field_from_json(Obj,"mode",mode);
field_from_json(Obj,"ssid",ssid);
field_from_json(Obj,"band",band);
field_from_json(Obj,"channel",channel);
field_from_json(Obj,"associations",associations);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"boardId",boardId);
field_to_json(Obj,"timestamp",timestamp);
field_to_json(Obj,"ap_data",ap_data);
field_to_json(Obj,"ssid_data",ssid_data);
field_to_json(Obj,"radio_data",radio_data);
field_to_json(Obj,"device_info",device_info);
field_to_json(Obj,"serialNumber",serialNumber);
}
bool DeviceTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"boardId",boardId);
field_from_json(Obj,"timestamp",timestamp);
field_from_json(Obj,"ap_data",ap_data);
field_from_json(Obj,"ssid_data",ssid_data);
field_from_json(Obj,"radio_data",radio_data);
field_from_json(Obj,"device_info",device_info);
field_from_json(Obj,"serialNumber",serialNumber);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePointAnalysis::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"noise",noise);
field_to_json(Obj,"temperature",temperature);
field_to_json(Obj,"active_pct",active_pct);
field_to_json(Obj,"busy_pct",busy_pct);
field_to_json(Obj,"receive_pct",receive_pct);
field_to_json(Obj,"transmit_pct",transmit_pct);
field_to_json(Obj,"tx_power",tx_power);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
}
bool DeviceTimePointAnalysis::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"noise",noise);
field_from_json(Obj,"temperature",temperature);
field_from_json(Obj,"active_pct",active_pct);
field_from_json(Obj,"busy_pct",busy_pct);
field_from_json(Obj,"receive_pct",receive_pct);
field_from_json(Obj,"transmit_pct",transmit_pct);
field_from_json(Obj,"tx_power",tx_power);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePointList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"points",points);
field_to_json(Obj,"stats",stats);
}
bool DeviceTimePointList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"points",points);
field_from_json(Obj,"stats",stats);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePointStats::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"firstPoint",firstPoint);
field_to_json(Obj,"lastPoint",lastPoint);
field_to_json(Obj,"count",count);
}
bool DeviceTimePointStats::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"firstPoint",firstPoint);
field_from_json(Obj,"lastPoint",lastPoint);
field_from_json(Obj,"count",count);
return true;
} catch(...) {
}
return false;
}
void WifiClientRate::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"bitrate",bitrate);
field_to_json(Obj,"chwidth",chwidth);
field_to_json(Obj,"mcs",mcs);
field_to_json(Obj,"nss",nss);
field_to_json(Obj,"vht",vht);
}
bool WifiClientRate::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"bitrate",bitrate);
field_from_json(Obj,"chwidth",chwidth);
field_from_json(Obj,"mcs",mcs);
field_from_json(Obj,"nss",nss);
field_from_json(Obj,"vht",vht);
return true;
} catch(...) {
}
return false;
}
void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"timestamp",timestamp);
field_to_json(Obj,"station_id",station_id);
field_to_json(Obj,"bssid",bssid);
field_to_json(Obj,"ssid",ssid);
field_to_json(Obj,"rssi",rssi);
field_to_json(Obj,"rx_bitrate",rx_bitrate);
field_to_json(Obj,"rx_chwidth",rx_chwidth);
field_to_json(Obj,"rx_mcs",rx_mcs);
field_to_json(Obj,"rx_nss",rx_nss);
field_to_json(Obj,"rx_vht",rx_vht);
field_to_json(Obj,"tx_bitrate",tx_bitrate);
field_to_json(Obj,"tx_chwidth",tx_chwidth);
field_to_json(Obj,"tx_mcs",tx_mcs);
field_to_json(Obj,"tx_nss",tx_nss);
field_to_json(Obj,"tx_vht",tx_vht);
field_to_json(Obj,"rx_bytes",rx_bytes);
field_to_json(Obj,"tx_bytes",tx_bytes);
field_to_json(Obj,"rx_duration",rx_duration);
field_to_json(Obj,"tx_duration",tx_duration);
field_to_json(Obj,"rx_packets",rx_packets);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"ipv4",ipv4);
field_to_json(Obj,"ipv6",ipv6);
field_to_json(Obj,"channel_width",channel_width);
field_to_json(Obj,"noise",noise);
field_to_json(Obj,"tx_power",tx_power);
field_to_json(Obj,"channel",channel);
field_to_json(Obj,"active_ms",active_ms);
field_to_json(Obj,"busy_ms",busy_ms);
field_to_json(Obj,"receive_ms",receive_ms);
field_to_json(Obj,"mode",mode);
field_to_json(Obj,"ack_signal",ack_signal);
field_to_json(Obj,"ack_signal_avg",ack_signal_avg);
field_to_json(Obj,"connected",connected);
field_to_json(Obj,"inactive",inactive);
field_to_json(Obj,"tx_retries",tx_retries);
field_to_json(Obj,"venue_id",venue_id);
}
bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"timestamp",timestamp);
field_from_json(Obj,"station_id",station_id);
field_from_json(Obj,"bssid",bssid);
field_from_json(Obj,"ssid",ssid);
field_from_json(Obj,"rssi",rssi);
field_from_json(Obj,"rx_bitrate",rx_bitrate);
field_from_json(Obj,"rx_chwidth",rx_chwidth);
field_from_json(Obj,"rx_mcs",rx_mcs);
field_from_json(Obj,"rx_nss",rx_nss);
field_from_json(Obj,"rx_vht",rx_vht);
field_from_json(Obj,"tx_bitrate",tx_bitrate);
field_from_json(Obj,"tx_chwidth",tx_chwidth);
field_from_json(Obj,"tx_mcs",tx_mcs);
field_from_json(Obj,"tx_nss",tx_nss);
field_from_json(Obj,"tx_vht",tx_vht);
field_from_json(Obj,"rx_bytes",rx_bytes);
field_from_json(Obj,"tx_bytes",tx_bytes);
field_from_json(Obj,"rx_duration",rx_duration);
field_from_json(Obj,"tx_duration",tx_duration);
field_from_json(Obj,"rx_packets",rx_packets);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"ipv4",ipv4);
field_from_json(Obj,"ipv6",ipv6);
field_from_json(Obj,"channel_width",channel_width);
field_from_json(Obj,"noise",noise);
field_from_json(Obj,"tx_power",tx_power);
field_from_json(Obj,"channel",channel);
field_from_json(Obj,"active_ms",active_ms);
field_from_json(Obj,"busy_ms",busy_ms);
field_from_json(Obj,"receive_ms",receive_ms);
field_from_json(Obj,"mode",mode);
field_from_json(Obj,"ack_signal",ack_signal);
field_from_json(Obj,"ack_signal_avg",ack_signal_avg);
field_from_json(Obj,"connected",connected);
field_from_json(Obj,"inactive",inactive);
field_from_json(Obj,"tx_retries",tx_retries);
field_from_json(Obj,"venue_id",venue_id);
return true;
} catch(...) {
}
return false;
}
}

View File

@@ -1,422 +0,0 @@
//
// Created by stephane bourque on 2022-01-10.
//
#pragma once
#include "RESTAPI_ProvObjects.h"
#include <vector>
namespace OpenWifi {
namespace AnalyticsObjects {
struct Report {
uint64_t snapShot = 0;
void reset();
void to_json(Poco::JSON::Object &Obj) const;
};
struct VenueInfo {
OpenWifi::Types::UUID_t id;
std::string name;
std::string description;
uint64_t retention = 0;
uint64_t interval = 0;
bool monitorSubVenues = false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct BoardInfo {
ProvObjects::ObjectInfo info;
std::vector<VenueInfo> venueList;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
inline bool operator<(const BoardInfo &bb) const {
return info.id < bb.info.id;
}
inline bool operator==(const BoardInfo &bb) const {
return info.id == bb.info.id;
}
};
struct DeviceInfo {
std::string boardId;
std::string type;
std::string serialNumber;
std::string deviceType;
uint64_t lastContact = 0 ;
uint64_t lastPing = 0;
uint64_t lastState = 0;
std::string lastFirmware;
uint64_t lastFirmwareUpdate = 0;
uint64_t lastConnection = 0;
uint64_t lastDisconnection = 0;
uint64_t pings = 0;
uint64_t states = 0;
bool connected = false;
std::string connectionIp;
uint64_t associations_2g = 0;
uint64_t associations_5g = 0;
uint64_t associations_6g = 0;
uint64_t health = 0;
uint64_t lastHealth = 0;
std::string locale;
uint64_t uptime = 0;
double memory = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceInfoList {
std::vector<DeviceInfo> devices;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum wifi_band {
band_2g = 0, band_5g = 1, band_6g = 2
};
struct TIDstat_entry {
uint64_t rx_msdu = 0,
tx_msdu = 0,
tx_msdu_failed = 0,
tx_msdu_retries = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct UE_rate {
uint64_t bitrate=0;
uint64_t mcs=0;
uint64_t nss=0;
bool ht=false;
bool sgi=false;
uint64_t chwidth=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct AveragePoint {
double min = 0.0,
max = 0.0,
avg = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct UETimePoint {
std::string station;
int64_t rssi = 0;
uint64_t tx_bytes = 0,
rx_bytes = 0,
tx_duration = 0,
rx_packets = 0,
tx_packets = 0,
tx_retries = 0,
tx_failed = 0,
connected = 0,
inactive = 0;
double tx_bytes_bw = 0.0 ,
rx_bytes_bw = 0.0 ,
tx_packets_bw = 0.0 ,
rx_packets_bw = 0.0 ,
tx_failed_pct = 0.0 ,
tx_retries_pct = 0.0 ,
tx_duration_pct = 0.0;
uint64_t tx_bytes_delta = 0,
rx_bytes_delta = 0,
tx_duration_delta = 0,
rx_packets_delta = 0,
tx_packets_delta = 0,
tx_retries_delta = 0,
tx_failed_delta = 0;
UE_rate tx_rate,
rx_rate;
std::vector<TIDstat_entry> tidstats;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum SSID_MODES {
unknown = 0,
ap,
mesh,
sta,
wds_ap,
wds_sta,
wds_repeater
};
inline SSID_MODES SSID_Mode(const std::string &m) {
if (m == "ap")
return ap;
if (m == "sta")
return sta;
if (m == "mesh")
return mesh;
if (m == "wds-ap")
return wds_ap;
if (m == "wds-sta")
return wds_sta;
if (m == "wds-repeater")
return wds_repeater;
return unknown;
}
struct SSIDTimePoint {
std::string bssid,
mode,
ssid;
uint64_t band=0,
channel=0;
std::vector<UETimePoint> associations;
AveragePoint tx_bytes_bw,
rx_bytes_bw,
tx_packets_bw,
rx_packets_bw,
tx_failed_pct,
tx_retries_pct,
tx_duration_pct;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct APTimePoint {
uint64_t collisions = 0,
multicast = 0,
rx_bytes = 0,
rx_dropped = 0,
rx_errors = 0,
rx_packets = 0,
tx_bytes = 0,
tx_dropped = 0,
tx_errors = 0,
tx_packets = 0;
double tx_bytes_bw = 0.0 ,
rx_bytes_bw = 0.0 ,
rx_dropped_pct = 0.0,
tx_dropped_pct = 0.0,
rx_packets_bw = 0.0,
tx_packets_bw = 0.0,
rx_errors_pct = 0.0 ,
tx_errors_pct = 0.0;
uint64_t tx_bytes_delta = 0,
rx_bytes_delta = 0 ,
rx_dropped_delta = 0,
tx_dropped_delta = 0,
rx_packets_delta = 0,
tx_packets_delta = 0,
rx_errors_delta = 0,
tx_errors_delta = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadioTimePoint {
uint64_t band = 0,
channel_width = 0;
uint64_t active_ms = 0,
busy_ms = 0,
receive_ms = 0,
transmit_ms = 0,
tx_power = 0,
channel = 0;
int64_t temperature = 0,
noise = 0;
double active_pct = 0.0 ,
busy_pct = 0.0,
receive_pct = 0.0,
transmit_pct = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceTimePoint {
std::string id;
std::string boardId;
uint64_t timestamp = 0;
APTimePoint ap_data;
std::vector<SSIDTimePoint> ssid_data;
std::vector<RadioTimePoint> radio_data;
AnalyticsObjects::DeviceInfo device_info;
std::string serialNumber;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
inline bool operator<(const DeviceTimePoint &rhs) const {
if(timestamp < rhs.timestamp)
return true;
if(timestamp > rhs.timestamp)
return false;
if(device_info.serialNumber < rhs.device_info.serialNumber)
return true;
return false;
}
inline bool operator==(const DeviceTimePoint &rhs) const {
return timestamp==rhs.timestamp && device_info.serialNumber==rhs.device_info.serialNumber;
}
inline bool operator>(const DeviceTimePoint &rhs) const {
if(timestamp > rhs.timestamp)
return true;
if(timestamp < rhs.timestamp)
return false;
if(device_info.serialNumber > rhs.device_info.serialNumber)
return true;
return false;
}
};
struct DeviceTimePointAnalysis {
uint64_t timestamp;
AveragePoint noise;
AveragePoint temperature;
AveragePoint active_pct;
AveragePoint busy_pct;
AveragePoint receive_pct;
AveragePoint transmit_pct;
AveragePoint tx_power;
AveragePoint tx_bytes_bw;
AveragePoint rx_bytes_bw;
AveragePoint rx_dropped_pct;
AveragePoint tx_dropped_pct;
AveragePoint rx_packets_bw;
AveragePoint tx_packets_bw;
AveragePoint rx_errors_pct;
AveragePoint tx_errors_pct;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceTimePointList {
std::vector<DeviceTimePoint> points;
std::vector<DeviceTimePointAnalysis> stats;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct BandwidthAnalysisEntry {
uint64_t timestamp = 0;
};
struct BandwidthAnalysis {
};
struct AverageValueSigned {
int64_t peak=0, avg=0, low=0;
};
struct AverageValueUnsigned {
uint64_t peak=0, avg=0, low=0;
};
struct RadioAnalysis {
uint64_t timestamp=0;
AverageValueSigned noise, temperature;
AverageValueUnsigned active_ms,
busy_ms,
transmit_ms,
receive_ms;
};
struct DeviceTimePointStats {
uint64_t firstPoint=0;
uint64_t lastPoint=0;
uint64_t count=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct WifiClientRate {
uint32_t bitrate=0;
uint32_t chwidth=0;
uint16_t mcs=0;
uint16_t nss=0;
bool vht=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct WifiClientHistory {
uint64_t timestamp=OpenWifi::Now();
std::string station_id;
std::string bssid;
std::string ssid;
int64_t rssi=0;
uint32_t rx_bitrate=0;
uint32_t rx_chwidth=0;
uint16_t rx_mcs=0;
uint16_t rx_nss=0;
bool rx_vht=false;
uint32_t tx_bitrate=0;
uint32_t tx_chwidth=0;
uint16_t tx_mcs=0;
uint16_t tx_nss=0;
bool tx_vht=false;
uint64_t rx_bytes=0;
uint64_t tx_bytes=0;
uint64_t rx_duration=0;
uint64_t tx_duration=0;
uint64_t rx_packets=0;
uint64_t tx_packets=0;
std::string ipv4;
std::string ipv6;
uint64_t channel_width=0;
int64_t noise=0;
uint64_t tx_power=0;
uint64_t channel=0;
uint64_t active_ms=0;
uint64_t busy_ms=0;
uint64_t receive_ms=0;
std::string mode;
int64_t ack_signal=0;
int64_t ack_signal_avg=0;
uint64_t connected=0;
uint64_t inactive=0;
uint64_t tx_retries=0;
std::string venue_id;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
}

View File

@@ -3,206 +3,176 @@
//
#include "RESTAPI_CertObjects.h"
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::CertObjects {
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"type", type);
field_to_json(Obj,"status", status);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"devid", devid);
field_to_json(Obj,"cas", cas);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonName", commonName);
field_to_json(Obj,"certificateId", certificateId);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"revoked", revoked);
field_to_json(Obj,"revokeCount", revokeCount);
field_to_json(Obj,"synched", synched);
}
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"type", type);
field_from_json(Obj,"status", status);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"devid", devid);
field_from_json(Obj,"cas", cas);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonName", commonName);
field_from_json(Obj,"certificateId", certificateId);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"revoked", revoked);
field_from_json(Obj,"revokeCount", revokeCount);
field_from_json(Obj,"synched", synched);
return true;
} catch (...) {
namespace OpenWifi {
namespace CertObjects {
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"type", type);
field_to_json(Obj,"status", status);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"devid", devid);
field_to_json(Obj,"cas", cas);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonName", commonName);
field_to_json(Obj,"certificateId", certificateId);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"revoked", revoked);
field_to_json(Obj,"revokeCount", revokeCount);
}
return false;
}
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"defaultRedirector", defaultRedirector);
field_to_json(Obj,"apiKey", apiKey);
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_to_json(Obj,"organization", organization);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"suspended", suspended);
field_to_json(Obj,"deleted", deleted);
field_to_json(Obj,"notes", notes);
}
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"defaultRedirector", defaultRedirector);
field_from_json(Obj,"apiKey", apiKey);
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_from_json(Obj,"organization", organization);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"suspended", suspended);
field_from_json(Obj,"deleted", deleted);
field_from_json(Obj,"notes", notes);
return true;
} catch (...) {
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"type", type);
field_from_json(Obj,"status", status);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"devid", devid);
field_from_json(Obj,"cas", cas);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonName", commonName);
field_from_json(Obj,"certificateId", certificateId);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"revoked", revoked);
field_from_json(Obj,"revokeCount", revokeCount);
return true;
} catch (...) {
}
return false;
}
return false;
}
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"jobHistory", jobHistory);
field_to_json(Obj,"notes", notes);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
field_to_json(Obj,"modified", modified);
}
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"jobHistory", jobHistory);
field_from_json(Obj,"notes", notes);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
field_from_json(Obj,"modified", modified);
return true;
} catch (...) {
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"defaultRedirector", defaultRedirector);
field_to_json(Obj,"apiKey", apiKey);
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_to_json(Obj,"organization", organization);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"suspended", suspended);
field_to_json(Obj,"deleted", deleted);
field_to_json(Obj,"notes", notes);
}
return false;
}
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"completedNames", completedNames);
field_to_json(Obj,"errorNames", errorNames);
field_to_json(Obj,"status", status);
field_to_json(Obj,"command", command);
field_to_json(Obj,"parameters", parameters);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
}
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"completedNames", completedNames);
field_from_json(Obj,"errorNames", errorNames);
field_from_json(Obj,"status", status);
field_from_json(Obj,"command", command);
field_from_json(Obj,"parameters", parameters);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
return true;
} catch (...) {
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"defaultRedirector", defaultRedirector);
field_from_json(Obj,"apiKey", apiKey);
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_from_json(Obj,"organization", organization);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"suspended", suspended);
field_from_json(Obj,"deleted", deleted);
field_from_json(Obj,"notes", notes);
return true;
} catch (...) {
}
return false;
}
return false;
}
void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "year", year);
field_to_json(Obj, "activeCerts", activeCerts);
field_to_json(Obj, "revokedCerts", revokedCerts);
}
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"jobHistory", jobHistory);
field_to_json(Obj,"notes", notes);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
field_to_json(Obj,"modified", modified);
}
void Dashboard::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"snapshot", snapshot);
field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts);
field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts);
field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization);
field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization);
field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors);
field_to_json(Obj,"deviceTypes", deviceTypes);
field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts);
field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear);
}
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"jobHistory", jobHistory);
field_from_json(Obj,"notes", notes);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
field_from_json(Obj,"modified", modified);
return true;
} catch (...) {
}
return false;
}
void Dashboard::reset() {
snapshot=0;
numberOfRevokedCerts = numberOfIssuedCerts = 0;
activeCertsPerOrganization.clear();
revokedCertsPerOrganization.clear();
numberOfRedirectors.clear();
deviceTypes.clear();
monthlyNumberOfCerts.clear();
monthlyNumberOfCertsPerOrgPerYear.clear();
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"completedNames", completedNames);
field_to_json(Obj,"errorNames", errorNames);
field_to_json(Obj,"status", status);
field_to_json(Obj,"command", command);
field_to_json(Obj,"parameters", parameters);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
}
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"completedNames", completedNames);
field_from_json(Obj,"errorNames", errorNames);
field_from_json(Obj,"status", status);
field_from_json(Obj,"command", command);
field_from_json(Obj,"parameters", parameters);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
return true;
} catch (...) {
}
return false;
}
}
}

View File

@@ -5,118 +5,97 @@
#pragma once
#include <string>
#include "framework/MicroService.h"
#include "framework/OpenWifiTypes.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi::CertObjects {
namespace OpenWifi {
struct CertificateEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string type;
std::string status;
std::string certificate;
std::string key;
std::string devid;
std::string cas;
std::string manufacturer;
std::string model;
std::string redirector;
std::string commonName;
std::string certificateId;
OpenWifi::Types::UUID_t batch;
uint64_t created = 0;
uint64_t modified = 0;
uint64_t revoked = 0;
uint64_t revokeCount = 0;
uint64_t synched = 0;
namespace CertObjects {
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct CertificateEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string type;
std::string status;
std::string certificate;
std::string key;
std::string devid;
std::string cas;
std::string manufacturer;
std::string model;
std::string redirector;
std::string commonName;
std::string certificateId;
OpenWifi::Types::UUID_t batch;
uint64_t created = 0;
uint64_t modified = 0;
uint64_t revoked = 0;
uint64_t revokeCount = 0;
struct EntityEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string defaultRedirector;
std::string apiKey;
std::string serverEnrollmentProfile;
std::string clientEnrollmentProfile;
std::string organization;
SecurityObjects::NoteInfoVec notes;
bool suspended=false;
bool deleted=false;
uint64_t created = 0 ;
uint64_t modified = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct EntityEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string defaultRedirector;
std::string apiKey;
std::string serverEnrollmentProfile;
std::string clientEnrollmentProfile;
std::string organization;
SecurityObjects::NoteInfoVec notes;
bool suspended=false;
bool deleted=false;
uint64_t created = 0 ;
uint64_t modified = 0 ;
struct BatchEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string manufacturer;
std::string model;
std::string redirector;
std::vector<std::string> commonNames;
std::vector<std::string> jobHistory;
SecurityObjects::NoteInfoVec notes;
uint64_t submitted = 0 ;
uint64_t started = 0 ;
uint64_t completed = 0 ;
uint64_t modified = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct BatchEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string manufacturer;
std::string model;
std::string redirector;
std::vector<std::string> commonNames;
std::vector<std::string> jobHistory;
SecurityObjects::NoteInfoVec notes;
uint64_t submitted = 0 ;
uint64_t started = 0 ;
uint64_t completed = 0 ;
uint64_t modified = 0 ;
struct JobEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
OpenWifi::Types::UUID_t batch;
std::string command;
OpenWifi::Types::StringVec commonNames;
OpenWifi::Types::StringVec completedNames;
OpenWifi::Types::StringVec errorNames;
Types::StringPairVec parameters;
std::string status;
uint64_t submitted=0;
uint64_t started=0;
uint64_t completed=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DashBoardYearlyStats {
uint64_t year=0;
OpenWifi::Types::Counted3DMapSII activeCerts;
OpenWifi::Types::Counted3DMapSII revokedCerts;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
uint64_t snapshot=0;
uint64_t numberOfIssuedCerts=0;
uint64_t numberOfRevokedCerts=0;
OpenWifi::Types::CountedMap activeCertsPerOrganization;
OpenWifi::Types::CountedMap revokedCertsPerOrganization;
OpenWifi::Types::CountedMap numberOfRedirectors;
OpenWifi::Types::CountedMap deviceTypes;
OpenWifi::Types::CountedMap monthlyNumberOfCerts;
std::vector<DashBoardYearlyStats> monthlyNumberOfCertsPerOrgPerYear;
void to_json(Poco::JSON::Object &Obj) const;
void reset();
};
struct JobEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
OpenWifi::Types::UUID_t batch;
std::string command;
OpenWifi::Types::StringVec commonNames;
OpenWifi::Types::StringVec completedNames;
OpenWifi::Types::StringVec errorNames;
Types::StringPairVec parameters;
std::string status;
uint64_t submitted=0;
uint64_t started=0;
uint64_t completed=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
}

View File

@@ -233,10 +233,10 @@ namespace OpenWifi::FMSObjects {
UnknownFirmwares_.clear();
totalSecondsOld_.clear();
numberOfDevices = 0 ;
snapshot = OpenWifi::Now();
snapshot = std::time(nullptr);
}
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
bool DeviceReport::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
return true;
@@ -245,65 +245,4 @@ namespace OpenWifi::FMSObjects {
}
return false;
}
void DeviceInformation::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "serialNumber",serialNumber);
field_to_json(Obj, "history", history);
field_to_json(Obj, "currentFirmware", currentFirmware);
field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate);
field_to_json(Obj, "latestFirmware", latestFirmware);
field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate);
field_to_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable);
field_to_json(Obj, "latestFirmwareURI",latestFirmwareURI);
}
bool DeviceInformation::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber",serialNumber);
field_from_json(Obj, "history", history);
field_from_json(Obj, "currentFirmware", currentFirmware);
field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate);
field_from_json(Obj, "latestFirmware", latestFirmware);
field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate);
field_from_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable);
field_from_json(Obj, "latestFirmwareURI",latestFirmwareURI);
return true;
} catch(...) {
}
return false;
}
void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "serialNumber",serialNumber);
field_to_json(Obj, "revision", revision);
field_to_json(Obj, "upgraded", upgraded);
}
bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber",serialNumber);
field_from_json(Obj, "revision", revision);
field_from_json(Obj, "upgraded", upgraded);
return true;
} catch(...) {
}
return false;
}
void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "devices",devices);
}
bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "devices",devices);
return true;
} catch(...) {
}
return false;
}
}

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