mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralfms.git
synced 2025-10-29 18:02:20 +00:00
Compare commits
18 Commits
v2.10.0-RC
...
v2.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8466e0e025 | ||
|
|
a408d0d128 | ||
|
|
fb2f53c63d | ||
|
|
b018dc70ef | ||
|
|
42d44b056e | ||
|
|
7d9d5b4d15 | ||
|
|
7fc77e529b | ||
|
|
e8986d84b4 | ||
|
|
f54fd2b411 | ||
|
|
86f3754c7e | ||
|
|
4223cb8146 | ||
|
|
260927a3eb | ||
|
|
bb571ad11a | ||
|
|
bd0fbfd6d2 | ||
|
|
33ba7b2323 | ||
|
|
28cbc79890 | ||
|
|
0137d8ee66 | ||
|
|
1ca77de37e |
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owfms VERSION 2.10.0)
|
||||
project(owfms VERSION 2.11.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -61,7 +61,7 @@ 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_definitions(-DPOCO_LOG_DEBUG="1")
|
||||
add_definitions(-DPOCO_LOG_DEBUG="1" -DBOOST_NO_CXX98_FUNCTION_BASE=1)
|
||||
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
|
||||
49
Dockerfile
49
Dockerfile
@@ -1,6 +1,9 @@
|
||||
ARG DEBIAN_VERSION=11.5-slim
|
||||
ARG POCO_VERSION=poco-tip-v2
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
ARG VALIJASON_VERSION=tip-v1
|
||||
ARG APP_NAME=owfms
|
||||
ARG APP_HOME_DIR=/openwifi
|
||||
|
||||
FROM debian:$DEBIAN_VERSION AS build-base
|
||||
|
||||
@@ -38,14 +41,17 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS owfms-build
|
||||
FROM build-base AS app-build
|
||||
|
||||
ADD CMakeLists.txt build /owfms/
|
||||
ADD overlays /owfms/overlays
|
||||
ADD cmake /owfms/cmake
|
||||
ADD src /owfms/src
|
||||
ADD .git /owfms/.git
|
||||
ARG APP_NAME
|
||||
|
||||
ADD CMakeLists.txt build /${APP_NAME}/
|
||||
ADD overlays /${APP_NAME}/overlays
|
||||
ADD cmake /${APP_NAME}/cmake
|
||||
ADD src /${APP_NAME}/src
|
||||
ADD .git /${APP_NAME}/.git
|
||||
ARG VCPKG_VERSION=2022.11.14
|
||||
|
||||
RUN git clone --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg && \
|
||||
./vcpkg/bootstrap-vcpkg.sh && \
|
||||
mkdir /vcpkg/custom-triplets && \
|
||||
@@ -58,23 +64,28 @@ COPY --from=poco-build /usr/local/lib /usr/local/lib
|
||||
COPY --from=cppkafka-build /usr/local/include /usr/local/include
|
||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
|
||||
|
||||
WORKDIR /owfms
|
||||
WORKDIR /${APP_NAME}
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR /owfms/cmake-build
|
||||
WORKDIR /${APP_NAME}/cmake-build
|
||||
RUN cmake -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM debian:$DEBIAN_VERSION
|
||||
|
||||
ENV OWFMS_USER=owfms \
|
||||
OWFMS_ROOT=/owfms-data \
|
||||
OWFMS_CONFIG=/owfms-data
|
||||
ARG APP_NAME
|
||||
ARG APP_HOME_DIR
|
||||
|
||||
RUN useradd "$OWFMS_USER"
|
||||
ENV APP_NAME=$APP_NAME \
|
||||
APP_USER=$APP_NAME \
|
||||
APP_ROOT=/$APP_NAME-data \
|
||||
APP_CONFIG=/$APP_NAME-data \
|
||||
APP_HOME_DIR=$APP_HOME_DIR
|
||||
|
||||
RUN mkdir /openwifi
|
||||
RUN mkdir -p "$OWFMS_ROOT" "$OWFMS_CONFIG" && \
|
||||
chown "$OWFMS_USER": "$OWFMS_ROOT" "$OWFMS_CONFIG"
|
||||
RUN useradd $APP_USER
|
||||
|
||||
RUN mkdir $APP_HOME_DIR
|
||||
RUN mkdir -p "$APP_ROOT" "$APP_CONFIG" && \
|
||||
chown "$APP_USER": "$APP_ROOT" "$APP_CONFIG"
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
||||
@@ -83,14 +94,14 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
COPY readiness_check /readiness_check
|
||||
COPY test_scripts/curl/cli /cli
|
||||
|
||||
COPY owfms.properties.tmpl /
|
||||
COPY $APP_NAME.properties.tmpl /
|
||||
COPY docker-entrypoint.sh /
|
||||
COPY wait-for-postgres.sh /
|
||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
|
||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
|
||||
|
||||
COPY --from=owfms-build /owfms/cmake-build/owfms /openwifi/owfms
|
||||
COPY --from=owfms-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
|
||||
COPY --from=app-build /$APP_NAME/cmake-build/$APP_NAME $APP_HOME_DIR/$APP_NAME
|
||||
COPY --from=app-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
|
||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/ /usr/local/lib/
|
||||
COPY --from=poco-build /poco/cmake-build/lib/ /usr/local/lib/
|
||||
|
||||
@@ -99,4 +110,4 @@ RUN ldconfig
|
||||
EXPOSE 16004 17004 16104
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["/openwifi/owfms"]
|
||||
CMD ${APP_HOME_DIR}/${APP_NAME}
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owfms:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owfms
|
||||
tag: main
|
||||
tag: v2.11.0
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
|
||||
@@ -353,6 +353,33 @@ components:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
SystemResources:
|
||||
type: object
|
||||
properties:
|
||||
numberOfFileDescriptors:
|
||||
type: integer
|
||||
format: int64
|
||||
currRealMem:
|
||||
type: integer
|
||||
format: int64
|
||||
peakRealMem:
|
||||
type: integer
|
||||
format: int64
|
||||
currVirtMem:
|
||||
type: integer
|
||||
format: int64
|
||||
peakVirtMem:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
SystemCommandResults:
|
||||
type: object
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemResources'
|
||||
- $ref: '#/components/schemas/SystemInfoResults'
|
||||
- $ref: '#/components/schemas/StringList'
|
||||
- $ref: '#/components/schemas/TagValuePairList'
|
||||
|
||||
SystemCommandSetLogLevel:
|
||||
type: object
|
||||
properties:
|
||||
@@ -743,19 +770,19 @@ paths:
|
||||
operationId: getFirmwareAge
|
||||
parameters:
|
||||
- in: query
|
||||
description: The exact current verion of the firmware on that device.
|
||||
description: The exact current version of the firmware on that device.
|
||||
name: revision
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
description: The exact current verion of the firmware on that device.
|
||||
description: The exact current version of the firmware on that device.
|
||||
name: deviceType
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
description: Specify lits of serial numbers to retrive age for
|
||||
description: Specify list of serial numbers to retrieve age for
|
||||
name: select
|
||||
schema:
|
||||
type: string
|
||||
@@ -925,16 +952,12 @@ paths:
|
||||
type: string
|
||||
enum:
|
||||
- info
|
||||
- extraConfiguration
|
||||
- resources
|
||||
required: true
|
||||
|
||||
responses:
|
||||
200:
|
||||
description: Successfull command execution
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemInfoResults'
|
||||
$ref: '#/components/schemas/SystemCommandResults'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace OpenWifi {
|
||||
Response.set("Connection", "keep-alive");
|
||||
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
std::ostream &Answer = Response.send();
|
||||
Answer << "process Alive and kicking!";
|
||||
Answer << ALBHealthCheckServer()->CallbackText();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace OpenWifi {
|
||||
inline static std::atomic_uint64_t req_id_ = 1;
|
||||
};
|
||||
|
||||
typedef std::string ALBHealthMessageCallback();
|
||||
|
||||
class ALBHealthCheckServer : public SubSystemServer {
|
||||
public:
|
||||
ALBHealthCheckServer();
|
||||
@@ -48,10 +50,22 @@ namespace OpenWifi {
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
inline void RegisterExtendedHealthMessage(ALBHealthMessageCallback *F) {
|
||||
Callback_=F;
|
||||
};
|
||||
|
||||
inline std::string CallbackText() {
|
||||
if(Callback_== nullptr) {
|
||||
return "process Alive and kicking!";
|
||||
} else {
|
||||
return Callback_();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::HTTPServer> Server_;
|
||||
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
|
||||
ALBHealthMessageCallback *Callback_= nullptr;
|
||||
int Port_ = 0;
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
};
|
||||
|
||||
@@ -34,9 +34,17 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"strict": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"uuid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"public_ip_lookup": {
|
||||
"type": "string",
|
||||
"format": "uc-fqdn"
|
||||
},
|
||||
"unit": {
|
||||
"$ref": "#/$defs/unit"
|
||||
},
|
||||
@@ -110,6 +118,20 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"random-password": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"beacon-advertisement": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device-name": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"device-serial": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"network-id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -218,6 +240,52 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"interface.ssid.encryption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"proto": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"owe",
|
||||
"owe-transition",
|
||||
"psk",
|
||||
"psk2",
|
||||
"psk-mixed",
|
||||
"psk2-radius",
|
||||
"wpa",
|
||||
"wpa2",
|
||||
"wpa-mixed",
|
||||
"sae",
|
||||
"sae-mixed",
|
||||
"wpa3",
|
||||
"wpa3-192",
|
||||
"wpa3-mixed"
|
||||
],
|
||||
"examples": [
|
||||
"psk2"
|
||||
]
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"maxLength": 63,
|
||||
"minLength": 8
|
||||
},
|
||||
"ieee80211w": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"optional",
|
||||
"required"
|
||||
],
|
||||
"default": "disabled"
|
||||
},
|
||||
"key-caching": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -634,26 +702,6 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"type": "string",
|
||||
"format": "uc-timeout",
|
||||
"default": "6h"
|
||||
},
|
||||
"relay-server": {
|
||||
"type": "string",
|
||||
"format": "ipv4",
|
||||
"example": "192.168.2.1"
|
||||
},
|
||||
"circuit-id-format": {
|
||||
"type": "string",
|
||||
"example": [
|
||||
"\\{Interface\\}:\\{VLAN-Id\\}:\\{SSID\\}:\\{Model\\}:\\{Name\\}:\\{AP-MAC\\}:\\{Location\\}",
|
||||
"\\{AP-MAC\\};\\{SSID\\};\\{Crypto\\}",
|
||||
"\\{Name\\} \\{ESSID\\}"
|
||||
]
|
||||
},
|
||||
"remote-id-format": {
|
||||
"type": "string",
|
||||
"example": [
|
||||
"\\{Client-MAC-hex\\} \\{SSID\\}",
|
||||
"\\{AP-MAC-hex\\} \\{SSID\\}"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -732,7 +780,8 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dynamic",
|
||||
"static"
|
||||
"static",
|
||||
"none"
|
||||
],
|
||||
"examples": [
|
||||
"static"
|
||||
@@ -1022,52 +1071,6 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
]
|
||||
},
|
||||
"interface.ssid.encryption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"proto": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"owe",
|
||||
"owe-transition",
|
||||
"psk",
|
||||
"psk2",
|
||||
"psk-mixed",
|
||||
"psk2-radius",
|
||||
"wpa",
|
||||
"wpa2",
|
||||
"wpa-mixed",
|
||||
"sae",
|
||||
"sae-mixed",
|
||||
"wpa3",
|
||||
"wpa3-192",
|
||||
"wpa3-mixed"
|
||||
],
|
||||
"examples": [
|
||||
"psk2"
|
||||
]
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"maxLength": 63,
|
||||
"minLength": 8
|
||||
},
|
||||
"ieee80211w": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"optional",
|
||||
"required"
|
||||
],
|
||||
"default": "disabled"
|
||||
},
|
||||
"key-caching": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"interface.ssid.multi-psk": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1232,6 +1235,32 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"secondary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"host": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"examples": [
|
||||
1812
|
||||
]
|
||||
},
|
||||
"secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"request-attribute": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1309,6 +1338,25 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"value": "Example Operator"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"maximum": 255,
|
||||
"minimum": 1
|
||||
},
|
||||
"hex-value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"id": 32,
|
||||
"value": "0a0b0c0d"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1658,6 +1706,236 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.click": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "click-to-continue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.radius": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "radius"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.credentials": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "credentials"
|
||||
},
|
||||
"credentials": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.uam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "uam"
|
||||
},
|
||||
"uam-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 3990
|
||||
},
|
||||
"uam-secret": {
|
||||
"type": "string"
|
||||
},
|
||||
"uam-server": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasid": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasmac": {
|
||||
"type": "string"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"ssid": {
|
||||
"type": "string"
|
||||
},
|
||||
"mac-format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"aabbccddeeff",
|
||||
"aa-bb-cc-dd-ee-ff",
|
||||
"aa:bb:cc:dd:ee:ff",
|
||||
"AABBCCDDEEFF",
|
||||
"AA:BB:CC:DD:EE:FF",
|
||||
"AA-BB-CC-DD-EE-FF"
|
||||
]
|
||||
},
|
||||
"final-redirect-url": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"default",
|
||||
"uam"
|
||||
]
|
||||
},
|
||||
"mac-auth": {
|
||||
"type": "boolean",
|
||||
"default": "default"
|
||||
},
|
||||
"radius-gw-proxy": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive": {
|
||||
"allOf": [
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.click"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.radius"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.credentials"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.uam"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"walled-garden-fqdn": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"walled-garden-ipaddr": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "uc-ip"
|
||||
}
|
||||
},
|
||||
"web-root": {
|
||||
"type": "string",
|
||||
"format": "uc-base64"
|
||||
},
|
||||
"idle-timeout": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"session-timeout": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"interface.ssid": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1710,6 +1988,10 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"isolate-clients": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"strict-forwarding": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"power-save": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -1757,6 +2039,11 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.",
|
||||
"type": "string"
|
||||
},
|
||||
"tip-information-element": {
|
||||
"decription": "The device will broadcast the TIP vendor IE inside its beacons if this option is enabled.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"fils-discovery-interval": {
|
||||
"type": "integer",
|
||||
"default": 20,
|
||||
@@ -1778,7 +2065,14 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"$ref": "#/$defs/interface.ssid.rate-limit"
|
||||
},
|
||||
"roaming": {
|
||||
"$ref": "#/$defs/interface.ssid.roaming"
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/interface.ssid.roaming"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
},
|
||||
"radius": {
|
||||
"$ref": "#/$defs/interface.ssid.radius"
|
||||
@@ -1795,6 +2089,9 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"access-control-list": {
|
||||
"$ref": "#/$defs/interface.ssid.acl"
|
||||
},
|
||||
"captive": {
|
||||
"$ref": "#/$defs/service.captive"
|
||||
},
|
||||
"hostapd-bss-raw": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1962,6 +2259,17 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
]
|
||||
}
|
||||
},
|
||||
"vlan-awareness": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"first": {
|
||||
"type": "integer"
|
||||
},
|
||||
"last": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"vlan": {
|
||||
"$ref": "#/$defs/interface.vlan"
|
||||
},
|
||||
@@ -2084,6 +2392,10 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"examples": [
|
||||
"01234567890123456789012345678901"
|
||||
]
|
||||
},
|
||||
"mutual-tls": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2155,6 +2467,24 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"radius",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"port-filter": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
{
|
||||
"LAN1": null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"server-certificate": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2166,6 +2496,77 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
"items": {
|
||||
"$ref": "#/$defs/interface.ssid.radius.local-user"
|
||||
}
|
||||
},
|
||||
"radius": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nas-identifier": {
|
||||
"type": "string"
|
||||
},
|
||||
"auth-server-addr": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-server-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"examples": [
|
||||
1812
|
||||
]
|
||||
},
|
||||
"auth-server-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server-addr": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-server-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"examples": [
|
||||
1813
|
||||
]
|
||||
},
|
||||
"acct-server-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"coa-server-addr": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"coa-server-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"examples": [
|
||||
1814
|
||||
]
|
||||
},
|
||||
"coa-server-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2489,6 +2890,12 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"classifier": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -2693,236 +3100,6 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.click": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "click-to-continue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.radius": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "radius"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.credentials": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "credentials"
|
||||
},
|
||||
"credentials": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive.uam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"auth-mode": {
|
||||
"type": "string",
|
||||
"const": "uam"
|
||||
},
|
||||
"uam-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 3990
|
||||
},
|
||||
"uam-secret": {
|
||||
"type": "string"
|
||||
},
|
||||
"uam-server": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasid": {
|
||||
"type": "string"
|
||||
},
|
||||
"nasmac": {
|
||||
"type": "string"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"auth-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"auth-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-server": {
|
||||
"type": "string",
|
||||
"format": "uc-host",
|
||||
"examples": [
|
||||
"192.168.1.10"
|
||||
]
|
||||
},
|
||||
"acct-port": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 1024,
|
||||
"default": 1812
|
||||
},
|
||||
"acct-secret": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"secret"
|
||||
]
|
||||
},
|
||||
"acct-interval": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"ssid": {
|
||||
"type": "string"
|
||||
},
|
||||
"mac-format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"aabbccddeeff",
|
||||
"aa-bb-cc-dd-ee-ff",
|
||||
"aa:bb:cc:dd:ee:ff",
|
||||
"AABBCCDDEEFF",
|
||||
"AA:BB:CC:DD:EE:FF",
|
||||
"AA-BB-CC-DD-EE-FF"
|
||||
]
|
||||
},
|
||||
"final-redirect-url": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"default",
|
||||
"uam"
|
||||
]
|
||||
},
|
||||
"mac-auth": {
|
||||
"type": "boolean",
|
||||
"default": "default"
|
||||
},
|
||||
"radius-gw-proxy": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.captive": {
|
||||
"allOf": [
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.click"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.radius"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.credentials"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/service.captive.uam"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"walled-garden-fqdn": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"walled-garden-ipaddr": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "uc-ip"
|
||||
}
|
||||
},
|
||||
"web-root": {
|
||||
"type": "string",
|
||||
"format": "uc-base64"
|
||||
},
|
||||
"idle-timeout": {
|
||||
"type": "integer",
|
||||
"default": 600
|
||||
},
|
||||
"session-timeout": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"service.gps": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2941,6 +3118,50 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
}
|
||||
}
|
||||
},
|
||||
"service.dhcp-relay": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"select-ports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vlans": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vlan": {
|
||||
"type": "number"
|
||||
},
|
||||
"relay-server": {
|
||||
"type": "string",
|
||||
"format": "uc-ip"
|
||||
},
|
||||
"circuit-id-format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"vlan-id",
|
||||
"ap-mac",
|
||||
"ssid"
|
||||
],
|
||||
"default": "vlan-id"
|
||||
},
|
||||
"remote-id-format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"vlan-id",
|
||||
"ap-mac",
|
||||
"ssid"
|
||||
],
|
||||
"default": "ap-mac"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"service": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -3000,6 +3221,9 @@ static std::string DefaultUCentralSchema = R"foo(
|
||||
},
|
||||
"gps": {
|
||||
"$ref": "#/$defs/service.gps"
|
||||
},
|
||||
"dhcp-relay": {
|
||||
"$ref": "#/$defs/service.dhcp-relay"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,18 +14,18 @@ namespace OpenWifi {
|
||||
void EventBusManager::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("fmwk:EventMgr");
|
||||
auto Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN));
|
||||
auto Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN));
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
|
||||
false);
|
||||
while (Running_) {
|
||||
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
|
||||
if (!Running_)
|
||||
break;
|
||||
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE));
|
||||
Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE));
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(),
|
||||
Msg, false);
|
||||
}
|
||||
Msg = std::make_shared<std::string>(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE));
|
||||
Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE));
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
|
||||
false);
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "cppkafka/utils/consumer_dispatcher.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -99,9 +100,12 @@ namespace OpenWifi {
|
||||
try {
|
||||
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
|
||||
if (Msg != nullptr) {
|
||||
Producer.produce(cppkafka::MessageBuilder(Msg->Topic())
|
||||
.key(Msg->Key())
|
||||
.payload(Msg->Payload()));
|
||||
auto NewMessage = cppkafka::MessageBuilder(Msg->Topic());
|
||||
NewMessage.key(Msg->Key());
|
||||
NewMessage.partition(0);
|
||||
NewMessage.payload(Msg->Payload());
|
||||
Producer.produce(NewMessage);
|
||||
Producer.flush();
|
||||
}
|
||||
} catch (const cppkafka::HandleException &E) {
|
||||
poco_warning(Logger_,
|
||||
@@ -156,43 +160,49 @@ namespace OpenWifi {
|
||||
}
|
||||
});
|
||||
|
||||
bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false);
|
||||
auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 20);
|
||||
// bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false);
|
||||
// auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 100);
|
||||
|
||||
Types::StringVec Topics;
|
||||
KafkaManager()->Topics(Topics);
|
||||
std::for_each(Topics_.begin(),Topics_.end(),
|
||||
[&](const std::string & T) { Topics.emplace_back(T); });
|
||||
Consumer.subscribe(Topics);
|
||||
|
||||
Running_ = true;
|
||||
while (Running_) {
|
||||
try {
|
||||
std::vector<cppkafka::Message> MsgVec =
|
||||
Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100));
|
||||
for (auto const &Msg : MsgVec) {
|
||||
if (!Msg)
|
||||
continue;
|
||||
if (Msg.get_error()) {
|
||||
if (!Msg.is_eof()) {
|
||||
poco_error(Logger_,
|
||||
fmt::format("Error: {}", Msg.get_error().to_string()));
|
||||
std::vector<cppkafka::Message> MsgVec;
|
||||
|
||||
Dispatcher_ = std::make_unique<cppkafka::ConsumerDispatcher>(Consumer);
|
||||
|
||||
Dispatcher_->run(
|
||||
// Callback executed whenever a new message is consumed
|
||||
[&](cppkafka::Message msg) {
|
||||
// Print the key (if any)
|
||||
std::lock_guard G(ConsumerMutex_);
|
||||
auto It = Notifiers_.find(msg.get_topic());
|
||||
if (It != Notifiers_.end()) {
|
||||
const auto &FL = It->second;
|
||||
for (const auto &[CallbackFunc, _] : FL) {
|
||||
try {
|
||||
CallbackFunc(msg.get_key(), msg.get_payload());
|
||||
} catch(const Poco::Exception &E) {
|
||||
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
if (!AutoCommit)
|
||||
Consumer.async_commit(Msg);
|
||||
continue;
|
||||
}
|
||||
KafkaManager()->Dispatch(Msg.get_topic().c_str(), Msg.get_key(), std::make_shared<std::string>(Msg.get_payload()));
|
||||
if (!AutoCommit)
|
||||
Consumer.async_commit(Msg);
|
||||
}
|
||||
} catch (const cppkafka::HandleException &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("Caught a Kafka exception (consumer): {}", E.what()));
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_, "std::exception");
|
||||
Consumer.commit(msg);
|
||||
},
|
||||
// Whenever there's an error (other than the EOF soft error)
|
||||
[&Logger_](cppkafka::Error error) {
|
||||
poco_warning(Logger_,fmt::format("Error: {}", error.to_string()));
|
||||
},
|
||||
// Whenever EOF is reached on a partition, print this
|
||||
[&Logger_](cppkafka::ConsumerDispatcher::EndOfFile, const cppkafka::TopicPartition& topic_partition) {
|
||||
poco_debug(Logger_,fmt::format("Partition {} EOF", topic_partition.get_partition()));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Consumer.unsubscribe();
|
||||
poco_information(Logger_, "Stopped...");
|
||||
}
|
||||
@@ -213,14 +223,13 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void KafkaProducer::Produce(const char *Topic, const std::string &Key,
|
||||
const std::shared_ptr<std::string> Payload) {
|
||||
const std::string &Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
|
||||
}
|
||||
|
||||
void KafkaConsumer::Start() {
|
||||
if (!Running_) {
|
||||
Running_ = true;
|
||||
Worker_.start(*this);
|
||||
}
|
||||
}
|
||||
@@ -228,29 +237,16 @@ namespace OpenWifi {
|
||||
void KafkaConsumer::Stop() {
|
||||
if (Running_) {
|
||||
Running_ = false;
|
||||
Worker_.wakeUp();
|
||||
if(Dispatcher_) {
|
||||
Dispatcher_->stop();
|
||||
}
|
||||
Worker_.join();
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Start() {
|
||||
if (!Running_) {
|
||||
Running_ = true;
|
||||
Worker_.start(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Stop() {
|
||||
if (Running_) {
|
||||
Running_ = false;
|
||||
Queue_.wakeUpAll();
|
||||
Worker_.join();
|
||||
}
|
||||
}
|
||||
|
||||
auto KafkaDispatcher::RegisterTopicWatcher(const std::string &Topic,
|
||||
std::uint64_t KafkaConsumer::RegisterTopicWatcher(const std::string &Topic,
|
||||
Types::TopicNotifyFunction &F) {
|
||||
std::lock_guard G(Mutex_);
|
||||
std::lock_guard G(ConsumerMutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if (It == Notifiers_.end()) {
|
||||
Types::TopicNotifyFunctionList L;
|
||||
@@ -259,11 +255,12 @@ namespace OpenWifi {
|
||||
} else {
|
||||
It->second.emplace(It->second.end(), std::make_pair(F, FunctionId_));
|
||||
}
|
||||
Topics_.insert(Topic);
|
||||
return FunctionId_++;
|
||||
}
|
||||
|
||||
void KafkaDispatcher::UnregisterTopicWatcher(const std::string &Topic, int Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
void KafkaConsumer::UnregisterTopicWatcher(const std::string &Topic, int Id) {
|
||||
std::lock_guard G(ConsumerMutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if (It != Notifiers_.end()) {
|
||||
Types::TopicNotifyFunctionList &L = It->second;
|
||||
@@ -275,56 +272,17 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Dispatch(const char *Topic, const std::string &Key,
|
||||
const std::shared_ptr<std::string> Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if (It != Notifiers_.end()) {
|
||||
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::run() {
|
||||
Poco::Logger &Logger_ =
|
||||
Poco::Logger::create("KAFKA-DISPATCHER", KafkaManager()->Logger().getChannel());
|
||||
poco_information(Logger_, "Starting...");
|
||||
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
||||
Utils::SetThreadName("kafka:dispatch");
|
||||
while (Note && Running_) {
|
||||
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
|
||||
if (Msg != nullptr) {
|
||||
auto It = Notifiers_.find(Msg->Topic());
|
||||
if (It != Notifiers_.end()) {
|
||||
const auto &FL = It->second;
|
||||
for (const auto &[CallbackFunc, _] : FL) {
|
||||
CallbackFunc(Msg->Key(), Msg->Payload());
|
||||
}
|
||||
}
|
||||
}
|
||||
Note = Queue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger_, "Stopped...");
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Topics(std::vector<std::string> &T) {
|
||||
T.clear();
|
||||
for (const auto &[TopicName, _] : Notifiers_)
|
||||
T.push_back(TopicName);
|
||||
}
|
||||
|
||||
int KafkaManager::Start() {
|
||||
if (!KafkaEnabled_)
|
||||
return 0;
|
||||
ConsumerThr_.Start();
|
||||
ProducerThr_.Start();
|
||||
Dispatcher_.Start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void KafkaManager::Stop() {
|
||||
if (KafkaEnabled_) {
|
||||
poco_information(Logger(), "Stopping...");
|
||||
Dispatcher_.Stop();
|
||||
ProducerThr_.Stop();
|
||||
ConsumerThr_.Stop();
|
||||
poco_information(Logger(), "Stopped...");
|
||||
@@ -333,39 +291,28 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void KafkaManager::PostMessage(const char *topic, const std::string &key,
|
||||
const std::shared_ptr<std::string> PayLoad, bool WrapMessage) {
|
||||
const std::string & PayLoad, bool WrapMessage) {
|
||||
if (KafkaEnabled_) {
|
||||
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::Dispatch(const char *Topic, const std::string &Key,
|
||||
const std::shared_ptr<std::string> Payload) {
|
||||
Dispatcher_.Dispatch(Topic, Key, Payload);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::shared_ptr<std::string> KafkaManager::WrapSystemId(const std::shared_ptr<std::string> PayLoad) {
|
||||
*PayLoad = SystemInfoWrapper_ + *PayLoad + "}";
|
||||
return PayLoad;
|
||||
}
|
||||
|
||||
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic,
|
||||
Types::TopicNotifyFunction &F) {
|
||||
void KafkaManager::PostMessage(const char *topic, const std::string &key,
|
||||
const Poco::JSON::Object &Object, bool WrapMessage) {
|
||||
if (KafkaEnabled_) {
|
||||
return Dispatcher_.RegisterTopicWatcher(Topic, F);
|
||||
} else {
|
||||
return 0;
|
||||
std::ostringstream ObjectStr;
|
||||
Object.stringify(ObjectStr);
|
||||
ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(ObjectStr.str()) : ObjectStr.str());
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
|
||||
if (KafkaEnabled_) {
|
||||
Dispatcher_.UnregisterTopicWatcher(Topic, Id);
|
||||
}
|
||||
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
|
||||
return fmt::format( R"lit({{ "system" : {{ "id" : {},
|
||||
"host" : "{}" }},
|
||||
"payload" : {} }})lit", MicroServiceID(),
|
||||
MicroServicePrivateEndPoint(), PayLoad ) ;
|
||||
}
|
||||
|
||||
void KafkaManager::Topics(std::vector<std::string> &T) { Dispatcher_.Topics(T); }
|
||||
|
||||
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList &partitions) {
|
||||
poco_information(
|
||||
Logger(), fmt::format("Partition assigned: {}...", partitions.front().get_partition()));
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "framework/KafkaTopics.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
@@ -18,17 +18,17 @@ namespace OpenWifi {
|
||||
|
||||
class KafkaMessage : public Poco::Notification {
|
||||
public:
|
||||
KafkaMessage(const char * Topic, const std::string &Key, const std::shared_ptr<std::string> Payload)
|
||||
: Topic_(Topic), Key_(Key), Payload_(std::move(Payload)) {}
|
||||
KafkaMessage(const char * Topic, const std::string &Key, const std::string &Payload)
|
||||
: Topic_(Topic), Key_(Key), Payload_(Payload) {}
|
||||
|
||||
inline const char * Topic() { return Topic_; }
|
||||
inline const std::string &Key() { return Key_; }
|
||||
inline const std::string &Payload() { return *Payload_; }
|
||||
inline const std::string &Payload() { return Payload_; }
|
||||
|
||||
private:
|
||||
const char *Topic_;
|
||||
std::string Key_;
|
||||
std::shared_ptr<std::string> Payload_;
|
||||
std::string Payload_;
|
||||
};
|
||||
|
||||
class KafkaProducer : public Poco::Runnable {
|
||||
@@ -36,10 +36,10 @@ namespace OpenWifi {
|
||||
void run() override;
|
||||
void Start();
|
||||
void Stop();
|
||||
void Produce(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
|
||||
void Produce(const char *Topic, const std::string &Key, const std::string & Payload);
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
std::mutex Mutex_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
Poco::NotificationQueue Queue_;
|
||||
@@ -47,33 +47,22 @@ namespace OpenWifi {
|
||||
|
||||
class KafkaConsumer : public Poco::Runnable {
|
||||
public:
|
||||
void run() override;
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Poco::Thread Worker_;
|
||||
std::mutex ConsumerMutex_;
|
||||
Types::NotifyTable Notifiers_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
};
|
||||
uint64_t FunctionId_ = 1;
|
||||
std::unique_ptr<cppkafka::ConsumerDispatcher> Dispatcher_;
|
||||
std::set<std::string> Topics_;
|
||||
|
||||
class KafkaDispatcher : public Poco::Runnable {
|
||||
public:
|
||||
void Start();
|
||||
void Stop();
|
||||
auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
|
||||
void run() override;
|
||||
friend class KafkaManager;
|
||||
std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
|
||||
void UnregisterTopicWatcher(const std::string &Topic, int Id);
|
||||
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
|
||||
void run() override;
|
||||
void Topics(std::vector<std::string> &T);
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Types::NotifyTable Notifiers_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
uint64_t FunctionId_ = 1;
|
||||
Poco::NotificationQueue Queue_;
|
||||
};
|
||||
|
||||
class KafkaManager : public SubSystemServer {
|
||||
@@ -92,20 +81,24 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
|
||||
void PostMessage(const char *topic, const std::string &key,
|
||||
const std::shared_ptr<std::string> PayLoad, bool WrapMessage = true);
|
||||
void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr<std::string> Payload);
|
||||
[[nodiscard]] const std::shared_ptr<std::string> WrapSystemId(const std::shared_ptr<std::string> PayLoad);
|
||||
const std::string &PayLoad, bool WrapMessage = true);
|
||||
void PostMessage(const char *topic, const std::string &key,
|
||||
const Poco::JSON::Object &Object, bool WrapMessage = true);
|
||||
|
||||
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
|
||||
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
|
||||
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
|
||||
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);
|
||||
void Topics(std::vector<std::string> &T);
|
||||
inline std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
|
||||
return ConsumerThr_.RegisterTopicWatcher(Topic,F);
|
||||
}
|
||||
inline void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
|
||||
return ConsumerThr_.UnregisterTopicWatcher(Topic,Id);
|
||||
}
|
||||
|
||||
private:
|
||||
bool KafkaEnabled_ = false;
|
||||
std::string SystemInfoWrapper_;
|
||||
KafkaProducer ProducerThr_;
|
||||
KafkaConsumer ConsumerThr_;
|
||||
KafkaDispatcher Dispatcher_;
|
||||
|
||||
void PartitionAssignment(const cppkafka::TopicPartitionList &partitions);
|
||||
void PartitionRevocation(const cppkafka::TopicPartitionList &partitions);
|
||||
|
||||
@@ -129,6 +129,8 @@ namespace OpenWifi {
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(), "Bad bus message.");
|
||||
std::ostringstream os;
|
||||
Object->stringify(std::cout);
|
||||
}
|
||||
|
||||
auto i = Services_.begin();
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "framework/ALBserver.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
const std::string &MicroServiceDataDirectory() { return MicroService::instance().DataDir(); }
|
||||
|
||||
@@ -123,4 +125,8 @@ namespace OpenWifi {
|
||||
return MicroService::instance().AllowExternalMicroServices();
|
||||
}
|
||||
|
||||
void MicroServiceALBCallback( std::string Callback()) {
|
||||
return ALBHealthCheckServer()->RegisterExtendedHealthMessage(Callback);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -53,4 +53,5 @@ namespace OpenWifi {
|
||||
std::string MicroServiceGetPublicAPIEndPoint();
|
||||
void MicroServiceDeleteOverrideConfiguration();
|
||||
bool AllowExternalMicroServices();
|
||||
void MicroServiceALBCallback( std::string Callback());
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace OpenWifi::Types {
|
||||
typedef std::string UUID_t;
|
||||
typedef std::vector<UUID_t> UUIDvec_t;
|
||||
typedef std::map<std::string, std::map<uint32_t, uint64_t>> Counted3DMapSII;
|
||||
typedef std::vector<int64_t> IntList;
|
||||
typedef std::vector<uint64_t> UIntList;
|
||||
typedef std::vector<double> DoubleList;
|
||||
|
||||
struct MicroServiceMeta {
|
||||
uint64_t Id = 0;
|
||||
|
||||
@@ -574,7 +574,37 @@ namespace OpenWifi {
|
||||
Poco::JSON::Stringifier::stringify(Object, Answer);
|
||||
}
|
||||
|
||||
inline void ReturnRawJSON(const std::string &json_doc) {
|
||||
inline void ReturnObject(const std::vector<std::string> &Strings) {
|
||||
Poco::JSON::Array Arr;
|
||||
for(const auto &String:Strings) {
|
||||
Arr.add(String);
|
||||
}
|
||||
std::ostringstream os;
|
||||
Arr.stringify(os);
|
||||
return ReturnRawJSON(os.str());
|
||||
}
|
||||
|
||||
template<class T> void ReturnObject(const std::vector<T> &Objects) {
|
||||
Poco::JSON::Array Arr;
|
||||
for(const auto &Object:Objects) {
|
||||
Poco::JSON::Object O;
|
||||
Object.to_json(O);
|
||||
Arr.add(O);
|
||||
}
|
||||
std::ostringstream os;
|
||||
Arr.stringify(os);
|
||||
return ReturnRawJSON(os.str());
|
||||
}
|
||||
|
||||
template<class T> void ReturnObject(const T &Object) {
|
||||
Poco::JSON::Object O;
|
||||
Object.to_json(O);
|
||||
std::ostringstream os;
|
||||
O.stringify(os);
|
||||
return ReturnRawJSON(os.str());
|
||||
}
|
||||
|
||||
inline void ReturnRawJSON(const std::string &json_doc) {
|
||||
PrepareResponse();
|
||||
if (Request != nullptr) {
|
||||
// can we compress ???
|
||||
|
||||
@@ -24,50 +24,63 @@ namespace OpenWifi {
|
||||
Server, TransactionId, Internal) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/system"}; }
|
||||
|
||||
inline void DoGet() {
|
||||
inline void DoGet() final {
|
||||
std::string Arg;
|
||||
if (HasParameter("command", Arg) && Arg == "info") {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
|
||||
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
|
||||
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
|
||||
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
|
||||
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
|
||||
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
|
||||
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
|
||||
if (HasParameter("command", Arg)) {
|
||||
if (Arg == "info") {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
|
||||
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
|
||||
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
|
||||
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
|
||||
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
|
||||
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
|
||||
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
|
||||
|
||||
Poco::JSON::Array Certificates;
|
||||
auto SubSystems = MicroServiceGetFullSubSystems();
|
||||
std::set<std::string> CertNames;
|
||||
Poco::JSON::Array Certificates;
|
||||
auto SubSystems = MicroServiceGetFullSubSystems();
|
||||
std::set<std::string> CertNames;
|
||||
|
||||
for (const auto &i : SubSystems) {
|
||||
auto Hosts = i->HostSize();
|
||||
for (uint64_t j = 0; j < Hosts; ++j) {
|
||||
auto CertFileName = i->Host(j).CertFile();
|
||||
if (!CertFileName.empty()) {
|
||||
Poco::File F1(CertFileName);
|
||||
if (F1.exists()) {
|
||||
auto InsertResult = CertNames.insert(CertFileName);
|
||||
if (InsertResult.second) {
|
||||
Poco::JSON::Object Inner;
|
||||
Poco::Path F(CertFileName);
|
||||
Inner.set("filename", F.getFileName());
|
||||
Poco::Crypto::X509Certificate C(CertFileName);
|
||||
auto ExpiresOn = C.expiresOn();
|
||||
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
|
||||
Certificates.add(Inner);
|
||||
for (const auto &i : SubSystems) {
|
||||
auto Hosts = i->HostSize();
|
||||
for (uint64_t j = 0; j < Hosts; ++j) {
|
||||
auto CertFileName = i->Host(j).CertFile();
|
||||
if (!CertFileName.empty()) {
|
||||
Poco::File F1(CertFileName);
|
||||
if (F1.exists()) {
|
||||
auto InsertResult = CertNames.insert(CertFileName);
|
||||
if (InsertResult.second) {
|
||||
Poco::JSON::Object Inner;
|
||||
Poco::Path F(CertFileName);
|
||||
Inner.set("filename", F.getFileName());
|
||||
Poco::Crypto::X509Certificate C(CertFileName);
|
||||
auto ExpiresOn = C.expiresOn();
|
||||
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
|
||||
Certificates.add(Inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Answer.set("certificates", Certificates);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
if (Arg == "extraConfiguration") {
|
||||
Poco::JSON::Object Answer;
|
||||
MicroServiceGetExtraConfiguration(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
if (Arg == "resources") {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set("numberOfFileDescriptors", Utils::get_open_fds());
|
||||
std::uint64_t currRealMem, peakRealMem, currVirtMem, peakVirtMem;
|
||||
Utils::getMemory(currRealMem, peakRealMem, currVirtMem, peakVirtMem);
|
||||
Answer.set("currRealMem", currRealMem);
|
||||
Answer.set("peakRealMem", peakRealMem);
|
||||
Answer.set("currVirtMem", currVirtMem);
|
||||
Answer.set("peakVirtMem", peakVirtMem);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
Answer.set("certificates", Certificates);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
if (GetBoolParameter("extraConfiguration")) {
|
||||
Poco::JSON::Object Answer;
|
||||
MicroServiceGetExtraConfiguration(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,15 @@
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include <RESTObjects/RESTAPI_SecurityObjects.h>
|
||||
|
||||
namespace OpenWifi::RESTAPI_utils {
|
||||
|
||||
inline bool IsRootOrAdmin(const SecurityObjects::UserInfo &UI) {
|
||||
return UI.userRole==SecurityObjects::ROOT ||
|
||||
UI.userRole==SecurityObjects::ADMIN;
|
||||
}
|
||||
|
||||
inline void EmbedDocument(const std::string &ObjName, Poco::JSON::Object &Obj,
|
||||
const std::string &ObjStr) {
|
||||
std::string D = ObjStr.empty() ? "{}" : ObjStr;
|
||||
@@ -95,6 +102,20 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
Obj.set(Field, A);
|
||||
}
|
||||
|
||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::DoubleList &V) {
|
||||
Poco::JSON::Array A;
|
||||
for (const auto &i : V)
|
||||
A.add(i);
|
||||
Obj.set(Field, A);
|
||||
}
|
||||
|
||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::IntList &V) {
|
||||
Poco::JSON::Array A;
|
||||
for (const auto &i : V)
|
||||
A.add(i);
|
||||
Obj.set(Field, A);
|
||||
}
|
||||
|
||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::TagList &V) {
|
||||
Poco::JSON::Array A;
|
||||
for (const auto &i : V)
|
||||
@@ -277,6 +298,28 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
}
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
|
||||
Types::DoubleList &Value) {
|
||||
if (Obj->isArray(Field) && !Obj->isNull(Field)) {
|
||||
Value.clear();
|
||||
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
|
||||
for (const auto &i : *A) {
|
||||
Value.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
|
||||
Types::IntList &Value) {
|
||||
if (Obj->isArray(Field) && !Obj->isNull(Field)) {
|
||||
Value.clear();
|
||||
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
|
||||
for (const auto &i : *A) {
|
||||
Value.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field,
|
||||
std::vector<T> &Value) {
|
||||
|
||||
@@ -22,9 +22,8 @@ namespace OpenWifi {
|
||||
|
||||
class StorageClass : public SubSystemServer {
|
||||
public:
|
||||
StorageClass() noexcept : SubSystemServer("StorageClass", "STORAGE-SVR", "storage") {}
|
||||
|
||||
int Start() override {
|
||||
inline int Start() override {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
Logger().notice("Starting.");
|
||||
@@ -40,17 +39,22 @@ namespace OpenWifi {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Stop() override { Pool_->shutdown(); }
|
||||
inline void Stop() override { Pool_->shutdown(); }
|
||||
|
||||
DBType Type() const { return dbType_; };
|
||||
|
||||
StorageClass() noexcept : SubSystemServer("StorageClass", "STORAGE-SVR", "storage") {
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
inline int Setup_SQLite();
|
||||
inline int Setup_MySQL();
|
||||
inline int Setup_PostgreSQL();
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Poco::Data::SessionPool> Pool_;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Poco::Data::SessionPool> Pool_;
|
||||
Poco::Data::SQLite::Connector SQLiteConn_;
|
||||
Poco::Data::PostgreSQL::Connector PostgresConn_;
|
||||
Poco::Data::MySQL::Connector MySQLConn_;
|
||||
@@ -81,7 +85,7 @@ namespace OpenWifi {
|
||||
// Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8,
|
||||
// (int)NumSessions,
|
||||
// (int)IdleTime));
|
||||
Pool_ = std::make_unique<Poco::Data::SessionPool>(SQLiteConn_.name(), DBName, 8,
|
||||
Pool_ = std::make_shared<Poco::Data::SessionPool>(SQLiteConn_.name(), DBName, 8,
|
||||
(int)NumSessions, (int)IdleTime);
|
||||
return 0;
|
||||
}
|
||||
@@ -102,7 +106,7 @@ namespace OpenWifi {
|
||||
";compress=true;auto-reconnect=true";
|
||||
|
||||
Poco::Data::MySQL::Connector::registerConnector();
|
||||
Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_.name(), ConnectionStr, 8,
|
||||
Pool_ = std::make_shared<Poco::Data::SessionPool>(MySQLConn_.name(), ConnectionStr, 8,
|
||||
NumSessions, IdleTime);
|
||||
|
||||
return 0;
|
||||
@@ -126,7 +130,7 @@ namespace OpenWifi {
|
||||
" connect_timeout=" + ConnectionTimeout;
|
||||
|
||||
Poco::Data::PostgreSQL::Connector::registerConnector();
|
||||
Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_.name(), ConnectionStr, 8,
|
||||
Pool_ = std::make_shared<Poco::Data::SessionPool>(PostgresConn_.name(), ConnectionStr, 8,
|
||||
NumSessions, IdleTime);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace OpenWifi {
|
||||
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
|
||||
P.dhUse2048Bits = true;
|
||||
P.caLocation = cas_;
|
||||
// P.securityLevel =
|
||||
|
||||
auto Context = Poco::AutoPtr<Poco::Net::Context>(
|
||||
new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
|
||||
@@ -53,7 +54,6 @@ namespace OpenWifi {
|
||||
|
||||
Context->useCertificate(Cert);
|
||||
Context->addChainCertificate(Root);
|
||||
|
||||
Context->addCertificateAuthority(Root);
|
||||
|
||||
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
|
||||
@@ -76,18 +76,18 @@ namespace OpenWifi {
|
||||
L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_));
|
||||
}
|
||||
|
||||
SSL_CTX_set_verify(SSLCtx, SSL_VERIFY_PEER, nullptr);
|
||||
SSL_CTX_set_verify(SSLCtx, level_==Poco::Net::Context::VERIFY_NONE ? SSL_VERIFY_NONE : SSL_VERIFY_PEER, nullptr);
|
||||
|
||||
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
|
||||
SSL_CTX_set_client_CA_list(SSLCtx, SSL_load_client_CA_file(client_cas_.c_str()));
|
||||
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
|
||||
}
|
||||
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
|
||||
SSL_CTX_dane_enable(SSLCtx);
|
||||
|
||||
Context->enableSessionCache();
|
||||
Context->setSessionCacheSize(0);
|
||||
Context->setSessionTimeout(60);
|
||||
Context->enableExtendedCertificateVerification(true);
|
||||
Context->enableExtendedCertificateVerification( level_!= Poco::Net::Context::VERIFY_NONE );
|
||||
Context->disableStatelessSessionResumption();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace OpenWifi {
|
||||
};
|
||||
}
|
||||
|
||||
#define DBGLINE std::cout << __LINE__ << ":" << __FILE__ << ", " << __func__ << std::endl;
|
||||
namespace OpenWifi::RESTAPI::Errors {
|
||||
struct msg {
|
||||
uint64_t err_num;
|
||||
@@ -401,6 +402,23 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
1171, "Command not supported on simulated device."
|
||||
};
|
||||
|
||||
static const struct msg VenuesNameAlreadyExists {
|
||||
1172, "The venue name already exists."
|
||||
};
|
||||
|
||||
static const struct msg InvalidGlobalReachAccount {
|
||||
1173, "Invalid Global Reach account information."
|
||||
};
|
||||
static const struct msg CannotCreateCSR {
|
||||
1174, "Cannot create a CSR certificate."
|
||||
};
|
||||
|
||||
static const struct msg DefFirmwareNameExists { 1175, "Firmware name already exists." };
|
||||
|
||||
static const struct msg NotAValidECKey { 1176, "Not a valid Signing Key." };
|
||||
|
||||
static const struct msg NotAValidRadiusPoolType { 1177, "Not a valid RADIUS pool type." };
|
||||
|
||||
static const struct msg SimulationDoesNotExist {
|
||||
7000, "Simulation Instance ID does not exist."
|
||||
};
|
||||
|
||||
@@ -3,10 +3,17 @@
|
||||
//
|
||||
|
||||
#include "Poco/Path.h"
|
||||
|
||||
#include "Poco/TemporaryFile.h"
|
||||
#include "Poco/Crypto/ECKey.h"
|
||||
#include "framework/AppServiceRegistry.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenWifi::Utils {
|
||||
|
||||
bool NormalizeMac(std::string &Mac) {
|
||||
@@ -27,6 +34,10 @@ namespace OpenWifi::Utils {
|
||||
std::all_of(Serial.begin(), Serial.end(), [](auto i) { return std::isxdigit(i); }));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool ValidSerialNumbers(const std::vector<std::string> &numbers) {
|
||||
return std::all_of(numbers.begin(),numbers.end(),[](auto &number) {return ValidSerialNumber(number);});
|
||||
}
|
||||
|
||||
[[nodiscard]] bool ValidUUID(const std::string &UUID) {
|
||||
if (UUID.size() > 36)
|
||||
return false;
|
||||
@@ -128,6 +139,15 @@ namespace OpenWifi::Utils {
|
||||
return std::regex_match(Hostname, HostNameRegex);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool ValidNumber(const std::string &number, bool isSigned)
|
||||
{
|
||||
static std::regex IntRegex("^-?[0-9]\\d*(\\.\\d+)?$");
|
||||
if(!isSigned) {
|
||||
IntRegex = "^[0-9]\\d*(\\.\\d+)?$";
|
||||
}
|
||||
return std::regex_match(number, IntRegex);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string ToHex(const std::vector<unsigned char> &B) {
|
||||
std::string R;
|
||||
R.reserve(B.size() * 2);
|
||||
@@ -595,4 +615,251 @@ namespace OpenWifi::Utils {
|
||||
return DT.timestamp().epochTime();
|
||||
}
|
||||
|
||||
static std::string FileToString(const std::string &Filename) {
|
||||
std::ifstream ifs(Filename.c_str(),std::ios_base::in|std::ios_base::binary);
|
||||
std::ostringstream os;
|
||||
Poco::StreamCopier::copyStream(ifs,os);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results) {
|
||||
int ret = 0;
|
||||
RSA *r = nullptr;
|
||||
BIGNUM *bne = nullptr;
|
||||
|
||||
int nVersion = 0;
|
||||
unsigned long e = RSA_F4;
|
||||
|
||||
X509_REQ *x509_req = nullptr;
|
||||
X509_NAME *x509_name = nullptr;
|
||||
EVP_PKEY *pKey = nullptr;
|
||||
// RSA *tem = nullptr;
|
||||
// BIO *bio_err = nullptr;
|
||||
|
||||
const char *szCountry = Parameters.Country.c_str();
|
||||
const char *szProvince = Parameters.Province.c_str();
|
||||
const char *szCity = Parameters.City.c_str();
|
||||
const char *szOrganization = Parameters.Organization.c_str();
|
||||
const char *szCommon = Parameters.CommonName.c_str();
|
||||
|
||||
Poco::TemporaryFile CsrPath, PubKey, PrivateKey;
|
||||
std::string Result;
|
||||
std::ifstream ifs;
|
||||
std::ostringstream ss;
|
||||
BIO *bp_public = nullptr,
|
||||
*bp_private = nullptr,
|
||||
*bp_csr = nullptr;
|
||||
|
||||
// 1. generate rsa key
|
||||
bne = BN_new();
|
||||
ret = BN_set_word(bne,e);
|
||||
if(ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
r = RSA_new();
|
||||
ret = RSA_generate_key_ex(r, Parameters.bits, bne, nullptr);
|
||||
if(ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
bp_public = BIO_new_file(PubKey.path().c_str(), "w+");
|
||||
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
|
||||
if(ret != 1) {
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
bp_private = BIO_new_file(PrivateKey.path().c_str(), "w+");
|
||||
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
|
||||
if(ret != 1) {
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
// 2. set version of x509 req
|
||||
x509_req = X509_REQ_new();
|
||||
ret = X509_REQ_set_version(x509_req, nVersion);
|
||||
if (ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
// 3. set subject of x509 req
|
||||
x509_name = X509_REQ_get_subject_name(x509_req);
|
||||
|
||||
ret = X509_NAME_add_entry_by_txt(x509_name,"C", MBSTRING_ASC, (const unsigned char*)szCountry, -1, -1, 0);
|
||||
if (ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
ret = X509_NAME_add_entry_by_txt(x509_name,"ST", MBSTRING_ASC, (const unsigned char*)szProvince, -1, -1, 0);
|
||||
if (ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
ret = X509_NAME_add_entry_by_txt(x509_name,"L", MBSTRING_ASC, (const unsigned char*)szCity, -1, -1, 0);
|
||||
if (ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
ret = X509_NAME_add_entry_by_txt(x509_name,"O", MBSTRING_ASC, (const unsigned char*)szOrganization, -1, -1, 0);
|
||||
if (ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
ret = X509_NAME_add_entry_by_txt(x509_name,"CN", MBSTRING_ASC, (const unsigned char*)szCommon, -1, -1, 0);
|
||||
if (ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
// 4. set public key of x509 req
|
||||
pKey = EVP_PKEY_new();
|
||||
EVP_PKEY_assign_RSA(pKey, r);
|
||||
r = nullptr; // will be free rsa when EVP_PKEY_free(pKey)
|
||||
|
||||
ret = X509_REQ_set_pubkey(x509_req, pKey);
|
||||
if (ret != 1){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
// 5. set sign key of x509 req
|
||||
ret = X509_REQ_sign(x509_req, pKey, EVP_sha1()); // return x509_req->signature->length
|
||||
if (ret <= 0){
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
bp_csr = BIO_new_file(CsrPath.path().c_str(),"w");
|
||||
ret = PEM_write_bio_X509_REQ(bp_csr, x509_req);
|
||||
|
||||
// 6. free
|
||||
free_all:
|
||||
X509_REQ_free(x509_req);
|
||||
BIO_free_all(bp_csr);
|
||||
BIO_free_all(bp_public);
|
||||
BIO_free_all(bp_private);
|
||||
|
||||
EVP_PKEY_free(pKey);
|
||||
BN_free(bne);
|
||||
if(ret==1) {
|
||||
Results.CSR = FileToString(CsrPath.path());
|
||||
Results.PrivateKey = FileToString(PrivateKey.path());
|
||||
Results.PublicKey = FileToString(PubKey.path());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool VerifyECKey(const std::string &key) {
|
||||
try {
|
||||
Poco::TemporaryFile F;
|
||||
|
||||
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
|
||||
of << key;
|
||||
of.close();
|
||||
|
||||
auto Key = Poco::SharedPtr<Poco::Crypto::ECKey>(
|
||||
new Poco::Crypto::ECKey("", F.path(),""));
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VerifyRSAKey([[
|
||||
maybe_unused]] const std::string &key) {
|
||||
try {
|
||||
Poco::TemporaryFile F;
|
||||
|
||||
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
|
||||
of << key;
|
||||
of.close();
|
||||
|
||||
auto Key = Poco::SharedPtr<Poco::Crypto::RSAKey>(
|
||||
new Poco::Crypto::RSAKey("", F.path(),""));
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidX509Certificate([[
|
||||
maybe_unused]] const std::string &Cert) {
|
||||
try {
|
||||
Poco::TemporaryFile F;
|
||||
std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
|
||||
of << Cert;
|
||||
of.close();
|
||||
|
||||
auto Key = Poco::SharedPtr<Poco::Crypto::X509Certificate>(
|
||||
new Poco::Crypto::X509Certificate(F.path()));
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidX509Certificate([[
|
||||
maybe_unused]] const std::vector<std::string> &Certs) {
|
||||
auto F = [](const std::string &C) -> bool { return ValidX509Certificate(C); };
|
||||
return std::all_of(Certs.begin(),Certs.end(), F);
|
||||
}
|
||||
|
||||
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase) {
|
||||
// Define character sets for each category
|
||||
const std::string lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
|
||||
const std::string uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const std::string digitChars = "0123456789";
|
||||
const std::string specialChars = "!@#$%^&*()_+[]{}|;:,.<>?";
|
||||
|
||||
// Check if parameters are valid
|
||||
if (minLength < 1 || minLength > maxLength || minLowercase + minUppercase + numDigits + minSpecial > maxLength) {
|
||||
return "Invalid parameters";
|
||||
}
|
||||
|
||||
// Initialize random seed
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
|
||||
// Initialize the password string
|
||||
std::string password;
|
||||
|
||||
// Generate the required number of each character type
|
||||
for (int i = 0; i < minLowercase; ++i) {
|
||||
password += lowercaseChars[g() % lowercaseChars.length()];
|
||||
}
|
||||
for (int i = 0; i < minUppercase; ++i) {
|
||||
password += uppercaseChars[g() % uppercaseChars.length()];
|
||||
}
|
||||
for (int i = 0; i < numDigits; ++i) {
|
||||
password += digitChars[g() % digitChars.length()];
|
||||
}
|
||||
for (int i = 0; i < minSpecial; ++i) {
|
||||
password += specialChars[g() % specialChars.length()];
|
||||
}
|
||||
|
||||
// Calculate how many more characters are needed
|
||||
int remainingLength = maxLength - (int)password.length();
|
||||
|
||||
// Generate random characters to fill the remaining length
|
||||
for (int i = 0; i < remainingLength; ++i) {
|
||||
int category = g() % 4; // Randomly select a category
|
||||
if (category == 0) {
|
||||
password += lowercaseChars[g() % lowercaseChars.length()];
|
||||
} else if (category == 1) {
|
||||
password += uppercaseChars[g() % uppercaseChars.length()];
|
||||
} else if (category == 2) {
|
||||
password += digitChars[g() % digitChars.length()];
|
||||
} else {
|
||||
password += specialChars[g() % specialChars.length()];
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle the password to randomize the character order
|
||||
std::shuffle(password.begin(), password.end(),g);
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
} // namespace OpenWifi::Utils
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/Base64Encoder.h"
|
||||
#include "Poco/File.h"
|
||||
@@ -68,8 +70,10 @@ namespace OpenWifi::Utils {
|
||||
};
|
||||
|
||||
[[nodiscard]] bool ValidSerialNumber(const std::string &Serial);
|
||||
[[nodiscard]] bool ValidSerialNumbers(const std::vector<std::string> &Serial);
|
||||
[[nodiscard]] bool ValidUUID(const std::string &UUID);
|
||||
[[nodiscard]] bool ValidHostname(const std::string &hostname);
|
||||
[[nodiscard]] bool ValidNumber(const std::string &number, bool isSigned);
|
||||
|
||||
template <typename... Args> std::string ComputeHash(Args &&...args) {
|
||||
Poco::SHA2Engine E;
|
||||
@@ -180,4 +184,84 @@ namespace OpenWifi::Utils {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline std::uint64_t GetValue(FILE *file) {
|
||||
unsigned long v=0;
|
||||
char factor[32];
|
||||
if(fscanf(file, " %lu %31s", &v, factor)==2) {
|
||||
switch (factor[0]) {
|
||||
case 'k':
|
||||
return v * 1000;
|
||||
case 'M':
|
||||
return v * 1000000;
|
||||
case 'G':
|
||||
return v * 1000000000;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
inline bool getMemory(
|
||||
std::uint64_t &currRealMem, std::uint64_t &peakRealMem,
|
||||
std::uint64_t &currVirtMem, std::uint64_t &peakVirtMem) {
|
||||
|
||||
// stores each word in status file
|
||||
char buffer[1024] = "";
|
||||
|
||||
currRealMem = peakRealMem = currVirtMem = peakVirtMem = 0;
|
||||
|
||||
// linux file contains this-process info
|
||||
FILE * file = std::fopen("/proc/self/status", "r");
|
||||
if (file == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the entire file, recording mems in kB
|
||||
while (fscanf(file, " %1023s", buffer) == 1) {
|
||||
|
||||
if (strcmp(buffer, "VmRSS:") == 0) {
|
||||
currRealMem= GetValue(file);
|
||||
} else if (strcmp(buffer, "VmHWM:") == 0) {
|
||||
peakRealMem= GetValue(file);
|
||||
} else if (strcmp(buffer, "VmSize:") == 0) {
|
||||
currVirtMem= GetValue(file);
|
||||
} else if (strcmp(buffer, "VmPeak:") == 0) {
|
||||
peakVirtMem= GetValue(file);
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline int get_open_fds() {
|
||||
DIR *dp = opendir("/proc/self/fd");
|
||||
struct dirent *de;
|
||||
int count = -3; // '.', '..', dp
|
||||
|
||||
if (dp == nullptr)
|
||||
return -1;
|
||||
while ((de = readdir(dp)) != nullptr)
|
||||
count++;
|
||||
(void)closedir(dp);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
struct CSRCreationParameters {
|
||||
std::string Country, Province, City,
|
||||
Organization, CommonName;
|
||||
int bits=2048;
|
||||
};
|
||||
|
||||
struct CSRCreationResults {
|
||||
std::string CSR, PublicKey, PrivateKey;
|
||||
};
|
||||
|
||||
bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results);
|
||||
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase);
|
||||
bool VerifyECKey(const std::string &key);
|
||||
bool VerifyRSAKey(const std::string &key);
|
||||
bool ValidX509Certificate(const std::string &Cert);
|
||||
bool ValidX509Certificate(const std::vector<std::string> &Certs);
|
||||
|
||||
} // namespace OpenWifi::Utils
|
||||
|
||||
Reference in New Issue
Block a user