mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-11-01 11:17:52 +00:00
Compare commits
424 Commits
release/v2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
691d3399f8 | ||
|
|
6542726ac3 | ||
|
|
4bc753f8b5 | ||
|
|
e3a513fa6a | ||
|
|
b151239a5c | ||
|
|
862dab38d1 | ||
|
|
ee2e9a19c0 | ||
|
|
8b28fa0435 | ||
|
|
aeef70a121 | ||
|
|
42c421ec12 | ||
|
|
98bfb4b24d | ||
|
|
6b64089f55 | ||
|
|
1f6e42b57c | ||
|
|
f857d61377 | ||
|
|
66d580d047 | ||
|
|
567c671c22 | ||
|
|
9e3735ced8 | ||
|
|
18b169e517 | ||
|
|
cab0d8aee6 | ||
|
|
680b6a16e3 | ||
|
|
218694872f | ||
|
|
6ae1eeb2ea | ||
|
|
f537e701a0 | ||
|
|
d4dfb7b620 | ||
|
|
446cbf270f | ||
|
|
06ffee27b1 | ||
|
|
fa3c325bfa | ||
|
|
182a442582 | ||
|
|
3b7a24ea30 | ||
|
|
1c5909613f | ||
|
|
8e5e51a52a | ||
|
|
b4699e9178 | ||
|
|
438309714f | ||
|
|
a9130eeb75 | ||
|
|
33068fca9e | ||
|
|
d329151f6c | ||
|
|
ec846006bb | ||
|
|
bd48079a8d | ||
|
|
242261de0a | ||
|
|
31a4edead5 | ||
|
|
f7b697f219 | ||
|
|
e020da75fc | ||
|
|
89702f56e0 | ||
|
|
0ac97442c0 | ||
|
|
e38b4c8a13 | ||
|
|
9c5bbee834 | ||
|
|
a5d1eebe6d | ||
|
|
ee14f064c8 | ||
|
|
dbf52c1f23 | ||
|
|
9dc6a6bf97 | ||
|
|
1c0556f8bf | ||
|
|
d298139525 | ||
|
|
a37c961f5b | ||
|
|
75bcbd748c | ||
|
|
b6eba2a96d | ||
|
|
17082803d4 | ||
|
|
26b9a96506 | ||
|
|
5ce8dae9ec | ||
|
|
7da135c1e5 | ||
|
|
50ee4ba5cb | ||
|
|
3a8109d7ad | ||
|
|
56232966ec | ||
|
|
1ecf98d712 | ||
|
|
f5b60ced61 | ||
|
|
e4d141bb8e | ||
|
|
25b4288050 | ||
|
|
82430c2d5d | ||
|
|
7b68ec0536 | ||
|
|
839f4fec44 | ||
|
|
c4178209bb | ||
|
|
79ab67db50 | ||
|
|
00bc77feea | ||
|
|
4f00d77d2b | ||
|
|
c679d4ac40 | ||
|
|
4a150a9fcb | ||
|
|
83eb603f0a | ||
|
|
38bc0f0d69 | ||
|
|
e7362c2020 | ||
|
|
9c9987e190 | ||
|
|
4ac7b6ba0b | ||
|
|
f9ee19af91 | ||
|
|
cd2ab8660f | ||
|
|
b9f00f6603 | ||
|
|
596cfd49e1 | ||
|
|
b3deba5606 | ||
|
|
a97d49a06b | ||
|
|
b1be0604d6 | ||
|
|
b29f7f7dc4 | ||
|
|
132b31b06b | ||
|
|
3114ff8a32 | ||
|
|
9c5aeda5dd | ||
|
|
783ec99930 | ||
|
|
0c661b8b93 | ||
|
|
9d7f4da504 | ||
|
|
a3b6e7c315 | ||
|
|
451680cd5a | ||
|
|
7be48c3cfc | ||
|
|
b59d1cb4da | ||
|
|
c3a709c2b9 | ||
|
|
5d89107827 | ||
|
|
3c15c6dc4f | ||
|
|
7b33a692b2 | ||
|
|
b118dcbcec | ||
|
|
02a0eef44a | ||
|
|
c7ed7fb264 | ||
|
|
1d88bb50d9 | ||
|
|
3b613ea159 | ||
|
|
d00d409fca | ||
|
|
8382818e2d | ||
|
|
ed4670d239 | ||
|
|
cca3619e91 | ||
|
|
9a834c29a2 | ||
|
|
2b06a0bcf6 | ||
|
|
03dabed878 | ||
|
|
e133a9c3ab | ||
|
|
23b33fab20 | ||
|
|
909b4c889e | ||
|
|
a04c5336d2 | ||
|
|
4df1bf985d | ||
|
|
26a89f3eb5 | ||
|
|
b055711993 | ||
|
|
fcdb7423ef | ||
|
|
f286d5fb48 | ||
|
|
0d70601c64 | ||
|
|
a493defc99 | ||
|
|
fb3e1288ae | ||
|
|
ce52e05104 | ||
|
|
920b922121 | ||
|
|
3732cfd07e | ||
|
|
9e772b8c91 | ||
|
|
92252d09dc | ||
|
|
28636c3e1e | ||
|
|
8e44f1e85c | ||
|
|
b77d40fbf8 | ||
|
|
574172b8bf | ||
|
|
794b31591d | ||
|
|
66aee07105 | ||
|
|
86685f17d6 | ||
|
|
08f683c15a | ||
|
|
7fea477f55 | ||
|
|
f22b3e3995 | ||
|
|
3a1011a662 | ||
|
|
6595b37ae4 | ||
|
|
05b6a9474b | ||
|
|
1de94be447 | ||
|
|
aa8486c71b | ||
|
|
e75d3cfdbb | ||
|
|
1a0a6d4a70 | ||
|
|
071922c555 | ||
|
|
4e4b69e672 | ||
|
|
3d8f7c1162 | ||
|
|
2bf60dbb3f | ||
|
|
44bc27e9d4 | ||
|
|
f328a72b85 | ||
|
|
4cbceb9366 | ||
|
|
921267c00a | ||
|
|
d63cbce602 | ||
|
|
094bba4747 | ||
|
|
5bee5b1372 | ||
|
|
45357ad567 | ||
|
|
8e984a8f0e | ||
|
|
4e7babc25f | ||
|
|
1acabd4986 | ||
|
|
d839646dd8 | ||
|
|
31b52f9bd2 | ||
|
|
97bc19b949 | ||
|
|
c252e6c5c7 | ||
|
|
cef012c333 | ||
|
|
6513980525 | ||
|
|
adc055f3e8 | ||
|
|
6d991e5a48 | ||
|
|
ec5031ca83 | ||
|
|
19e4e92d92 | ||
|
|
37feb6a44c | ||
|
|
2aaab1207b | ||
|
|
7896b071da | ||
|
|
e073576692 | ||
|
|
65ad9ff96e | ||
|
|
08e7900889 | ||
|
|
8554481186 | ||
|
|
2b246fe1ee | ||
|
|
bd37534223 | ||
|
|
aa862d3fcf | ||
|
|
c6c6eaa4a5 | ||
|
|
ffe86a3994 | ||
|
|
52123f7dcc | ||
|
|
e430c522ba | ||
|
|
93c236aa79 | ||
|
|
c802e35c12 | ||
|
|
a59d49e096 | ||
|
|
5756d59519 | ||
|
|
35aa6fb99d | ||
|
|
fa6d0aa714 | ||
|
|
91147f3fbb | ||
|
|
15f3eaa02e | ||
|
|
6305e92399 | ||
|
|
3714fd5f05 | ||
|
|
19497b88ce | ||
|
|
6a35dc93bf | ||
|
|
8004aa6676 | ||
|
|
2c654d3471 | ||
|
|
df67141a98 | ||
|
|
071330d7f8 | ||
|
|
90f23dca73 | ||
|
|
500688edb7 | ||
|
|
222b98d019 | ||
|
|
915a2c936d | ||
|
|
e1bf6a9ab7 | ||
|
|
58fc925a2f | ||
|
|
3dda87b41f | ||
|
|
a5fe59086a | ||
|
|
c66b936c1e | ||
|
|
0e763cf034 | ||
|
|
eb441d71aa | ||
|
|
082153a229 | ||
|
|
25a03ca801 | ||
|
|
0d549137de | ||
|
|
40e814cab8 | ||
|
|
e40d53f3e5 | ||
|
|
607507ce9a | ||
|
|
b3ec5b1e81 | ||
|
|
c52d3c92f6 | ||
|
|
d1216a8ac4 | ||
|
|
c27f0390f8 | ||
|
|
052d379e2b | ||
|
|
4eda1b813f | ||
|
|
5364adf509 | ||
|
|
3b5580a525 | ||
|
|
644918fa14 | ||
|
|
8cdd398a6e | ||
|
|
9f7f4683df | ||
|
|
1c6e35fa8b | ||
|
|
af17823df0 | ||
|
|
0cff2163bb | ||
|
|
0a5fe39bde | ||
|
|
c42feca957 | ||
|
|
d3c5b17733 | ||
|
|
30bc8e8283 | ||
|
|
336c94a25a | ||
|
|
84f42e5a7d | ||
|
|
17752fdefe | ||
|
|
ef300b0349 | ||
|
|
9c4ecb6165 | ||
|
|
efd099b6fa | ||
|
|
15805dcaf6 | ||
|
|
e5ed1750cc | ||
|
|
87d74568f2 | ||
|
|
0cca3caa9b | ||
|
|
1d22e1153f | ||
|
|
f3ccc49647 | ||
|
|
46fb410108 | ||
|
|
fc680a6bc4 | ||
|
|
246f9c8aad | ||
|
|
3f06f00a88 | ||
|
|
0288d905b7 | ||
|
|
135b63c021 | ||
|
|
12e07fa65f | ||
|
|
567c2d1514 | ||
|
|
b9bd768ca6 | ||
|
|
f2dec010ee | ||
|
|
329d8d4441 | ||
|
|
d4dbbeb54b | ||
|
|
b1c6884d49 | ||
|
|
3ffa35bb14 | ||
|
|
bd06722948 | ||
|
|
8c70ec5280 | ||
|
|
6c13d845f1 | ||
|
|
77cc0b250b | ||
|
|
a3c424d8fe | ||
|
|
3f834a967b | ||
|
|
4120aefcd4 | ||
|
|
909ee66ef0 | ||
|
|
c3ad34d84b | ||
|
|
fbb9f40529 | ||
|
|
5f6300bb17 | ||
|
|
0bcfb26579 | ||
|
|
5b199bc4f5 | ||
|
|
4c6fb85542 | ||
|
|
63993789ca | ||
|
|
cc9d4c5f68 | ||
|
|
50fa1de62c | ||
|
|
14ef6608d6 | ||
|
|
8e48d30d6a | ||
|
|
46c6321674 | ||
|
|
77f67fe545 | ||
|
|
ceda1fc8f6 | ||
|
|
5b1a4fb9c0 | ||
|
|
2ddc0d3117 | ||
|
|
2cfc6c30e9 | ||
|
|
0318b475f5 | ||
|
|
c5c2dc1a1e | ||
|
|
7b899adb88 | ||
|
|
aa472ed79e | ||
|
|
1778912264 | ||
|
|
142bc4f271 | ||
|
|
a01d006d4e | ||
|
|
135a195081 | ||
|
|
ef7cb883fb | ||
|
|
2e361a41d7 | ||
|
|
84281ec58e | ||
|
|
3560871f44 | ||
|
|
b072f1e2ab | ||
|
|
72173ed4b5 | ||
|
|
ff53d4ba2e | ||
|
|
81721b4a61 | ||
|
|
3619be1832 | ||
|
|
a8fc823b94 | ||
|
|
a8a33013be | ||
|
|
9560f908a6 | ||
|
|
8400b8cfcb | ||
|
|
82897f5b76 | ||
|
|
4b472fd112 | ||
|
|
ecb6312f0f | ||
|
|
0aba846277 | ||
|
|
5be884ef98 | ||
|
|
10c890a196 | ||
|
|
0974abd510 | ||
|
|
8dbbfc3298 | ||
|
|
c981ae14ee | ||
|
|
97547068d7 | ||
|
|
16cc443786 | ||
|
|
7d8e15bf66 | ||
|
|
3f60c5abc6 | ||
|
|
d85fb32af9 | ||
|
|
030991f13c | ||
|
|
142541180f | ||
|
|
9bd48bf029 | ||
|
|
8581048528 | ||
|
|
6cfb0ae975 | ||
|
|
45561de44b | ||
|
|
2fccfd756e | ||
|
|
df42837a76 | ||
|
|
4bc1ac1aef | ||
|
|
77ee9d48d0 | ||
|
|
7154cca4b9 | ||
|
|
77732bdb95 | ||
|
|
7a8a05d77d | ||
|
|
aa2c28355b | ||
|
|
b6cb5d003b | ||
|
|
c93acdf54a | ||
|
|
0c5e0d649e | ||
|
|
1757440cfe | ||
|
|
c3ccfe455e | ||
|
|
66ec7745bb | ||
|
|
531c51dd64 | ||
|
|
227ec2dc96 | ||
|
|
50c5c76484 | ||
|
|
7a567e400b | ||
|
|
148eabdbc2 | ||
|
|
94ae20ce65 | ||
|
|
fd80f02f0b | ||
|
|
943cdd5010 | ||
|
|
36a5f4a5da | ||
|
|
e0e8cc1295 | ||
|
|
d7bad290e9 | ||
|
|
06766d2ed9 | ||
|
|
913a3e4ce1 | ||
|
|
4e713e4471 | ||
|
|
cb10ea6a7f | ||
|
|
f5095b9f79 | ||
|
|
8a69089513 | ||
|
|
ba6c657587 | ||
|
|
177deb8cd2 | ||
|
|
1dfc478d0e | ||
|
|
f077fb7fad | ||
|
|
0dc1be1f41 | ||
|
|
e1a0864b68 | ||
|
|
222c796eee | ||
|
|
15fe0df04a | ||
|
|
ad1a3c694c | ||
|
|
04be75f037 | ||
|
|
8cd26ce8cb | ||
|
|
525f53aaa9 | ||
|
|
ab95733067 | ||
|
|
35f4e26ca4 | ||
|
|
14f63cb324 | ||
|
|
0962c8383a | ||
|
|
891965a321 | ||
|
|
4d2adc3c3a | ||
|
|
24eb4079d7 | ||
|
|
53010fca84 | ||
|
|
6f3079ab0a | ||
|
|
c73a7c6c09 | ||
|
|
bb60fef3d6 | ||
|
|
b52766d23a | ||
|
|
6f9a9471c3 | ||
|
|
992c169ac7 | ||
|
|
ba8a932b36 | ||
|
|
13dc97d35b | ||
|
|
0ef01e5547 | ||
|
|
138b236832 | ||
|
|
a0d4606c22 | ||
|
|
a5200e46b7 | ||
|
|
2d3866a987 | ||
|
|
0251b40287 | ||
|
|
1e2f215902 | ||
|
|
8184027534 | ||
|
|
a43841b867 | ||
|
|
c391ea2f04 | ||
|
|
111faaa80d | ||
|
|
687cbcd0a4 | ||
|
|
c48665d4c5 | ||
|
|
c873681adc | ||
|
|
cb64f8a809 | ||
|
|
0d8be1fd46 | ||
|
|
e496f71e7d | ||
|
|
de7c8b687a | ||
|
|
61e346e0bf | ||
|
|
67bf9ca8c6 | ||
|
|
14b7fc8a0e | ||
|
|
546d6f9ee0 | ||
|
|
fe74fdecf9 | ||
|
|
c53a67edd5 | ||
|
|
5207f1e1a0 | ||
|
|
53aa2f05d2 | ||
|
|
2405b9fe95 | ||
|
|
bc14bf28bf | ||
|
|
878e705db5 | ||
|
|
be62022344 | ||
|
|
432434a377 | ||
|
|
60860ad9de | ||
|
|
29d6f2dda1 | ||
|
|
330b4176f2 | ||
|
|
75b76bb380 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -21,7 +21,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
DOCKER_REGISTRY_USERNAME: ucentral
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -11,7 +11,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
helm-package:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||
HELM_REPO_USERNAME: ucentral
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -21,10 +21,12 @@ _deps
|
||||
/docker-compose/.env
|
||||
/docker-compose/.env_*
|
||||
/cmake-build/
|
||||
/uploads/
|
||||
test_scripts/curl/token.json
|
||||
.vscode/c_cpp_properties.json
|
||||
test_scripts/curl/result.json
|
||||
*.swp
|
||||
helm/charts/*
|
||||
!helm/charts/.gitkeep
|
||||
/portal-test/
|
||||
/src/ow_version.h
|
||||
.vscode/*
|
||||
|
||||
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
@@ -6,3 +6,5 @@
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# GitHub Copilot persisted chat sessions
|
||||
/copilot/chatSessions
|
||||
|
||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.9 (wlan-cloud-ucentralgw)" />
|
||||
</component>
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
<component name="CidrRootsConfiguration">
|
||||
<excludeRoots>
|
||||
|
||||
62
BUILDING.md
62
BUILDING.md
@@ -1,5 +1,5 @@
|
||||
# Building from source
|
||||
In order to build the OWGW, you will need to install its dependencies, which includes the following:
|
||||
In order to build OWGW, you will need to install its dependencies, which includes the following:
|
||||
- cmake
|
||||
- boost
|
||||
- POCO 1.10.1 or later
|
||||
@@ -12,43 +12,43 @@ In order to build the OWGW, you will need to install its dependencies, which inc
|
||||
|
||||
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/Telecominfraproject/wlan-cloud-lib-poco). Building
|
||||
Poco may take several minutes depending on the platform you are building on.
|
||||
|
||||
## Ubuntu
|
||||
These instructions have proven to work on Ubuntu 20.4.
|
||||
```bash
|
||||
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
|
||||
sudo apt install git cmake g++ libssl-dev libmariadb-dev \
|
||||
libpq-dev libaprutil1-dev apache2-dev libboost-all-dev \
|
||||
librdkafka-dev // default-libmysqlclient-dev \
|
||||
nlohmann-json-dev
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/AriliaWireless/valijson --branch tip-v1
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
|
||||
cd valijson
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
|
||||
cd fmtlib
|
||||
@@ -57,56 +57,59 @@ cd cmake-build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j 8
|
||||
cd ../..
|
||||
```
|
||||
|
||||
## Fedora
|
||||
The following instructions have proven to work on Fedora 33
|
||||
```bash
|
||||
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
|
||||
sudo yum install yaml-cpp-devel lua-devel
|
||||
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel \
|
||||
yaml-cpp-devel lua-devel
|
||||
sudo dnf install postgresql.x86_64 librdkafka-devel
|
||||
sudo dnf install postgresql-devel json-devel
|
||||
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
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/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/AriliaWireless/valijson --branch tip-v1
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
|
||||
cd valijson
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make
|
||||
cd ../..
|
||||
```
|
||||
|
||||
## macOS Build
|
||||
@@ -125,7 +128,7 @@ brew install openssl \
|
||||
nlohmann-json \
|
||||
fmt
|
||||
|
||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
pushd poco
|
||||
mkdir cmake-build
|
||||
push cmake-build
|
||||
@@ -135,7 +138,7 @@ sudo cmake --build . --target install
|
||||
popd
|
||||
popd
|
||||
|
||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
|
||||
pushd cppkafka
|
||||
mkdir cmake-build
|
||||
pushd cmake-build
|
||||
@@ -145,10 +148,10 @@ sudo cmake --build . --target install
|
||||
popd
|
||||
popd
|
||||
|
||||
git clone https://github.com/AriliaWireless/valijson --branch tip-v1
|
||||
cd valijson
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
|
||||
pushd valijson
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
pushd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
@@ -171,20 +174,23 @@ support. You can build with only SQLite support by not installing the packages f
|
||||
adding -DSMALL_BUILD=1 on the cmake build line.
|
||||
|
||||
```bash
|
||||
sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev libboost-all-dev libyaml-cpp-dev
|
||||
git clone https://github.com/stephb9959/poco
|
||||
sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev \
|
||||
libboost-all-dev libyaml-cpp-dev
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
|
||||
cd wlan-cloud-ucentralgw
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake -DSMALL_BUILD=1 ..
|
||||
make
|
||||
cd ../..
|
||||
```
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owgw VERSION 2.11.0)
|
||||
project(owgw VERSION 4.1.1)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
if(UNIX AND APPLE)
|
||||
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
|
||||
@@ -148,6 +149,7 @@ add_executable( owgw
|
||||
src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h
|
||||
src/RESTAPI/RESTAPI_regulatory.cpp src/RESTAPI/RESTAPI_regulatory.h
|
||||
src/RESTAPI/RESTAPI_radiussessions_handler.cpp src/RESTAPI/RESTAPI_radiussessions_handler.h
|
||||
|
||||
src/storage/storage_blacklist.cpp src/storage/storage_tables.cpp src/storage/storage_logs.cpp
|
||||
src/storage/storage_command.cpp src/storage/storage_healthcheck.cpp src/storage/storage_statistics.cpp
|
||||
src/storage/storage_device.cpp src/storage/storage_capabilities.cpp src/storage/storage_defconfig.cpp
|
||||
@@ -175,7 +177,7 @@ add_executable( owgw
|
||||
src/SDKcalls.cpp
|
||||
src/SDKcalls.h
|
||||
src/StateUtils.cpp src/StateUtils.h
|
||||
src/AP_WS_ReactorPool.h
|
||||
src/AP_WS_Reactor_Pool.h
|
||||
src/AP_WS_Connection.h
|
||||
src/AP_WS_Connection.cpp
|
||||
src/TelemetryClient.h src/TelemetryClient.cpp
|
||||
@@ -199,7 +201,7 @@ add_executable( owgw
|
||||
src/AP_WS_Process_deviceupdate.cpp
|
||||
src/AP_WS_Process_telemetry.cpp
|
||||
src/AP_WS_Process_venuebroadcast.cpp
|
||||
src/RADSEC_server.h
|
||||
src/RADIUS_Destination.h
|
||||
src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h
|
||||
src/framework/RESTAPI_SystemConfiguration.h
|
||||
src/ScriptManager.cpp src/ScriptManager.h
|
||||
@@ -211,7 +213,8 @@ add_executable( owgw
|
||||
src/RegulatoryInfo.cpp src/RegulatoryInfo.h
|
||||
src/RADIUSSessionTracker.cpp src/RADIUSSessionTracker.h
|
||||
src/libs/Scheduler.h src/libs/InterruptableSleep.h src/libs/ctpl_stl.h src/libs/Cron.h
|
||||
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h)
|
||||
src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h
|
||||
src/AP_WS_LookForUpgrade.cpp)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
|
||||
@@ -223,14 +226,17 @@ INSTALL(TARGETS owgw
|
||||
|
||||
target_link_libraries(owgw PUBLIC
|
||||
${Poco_LIBRARIES}
|
||||
${ZLIB_LIBRARIES})
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(owgw PUBLIC
|
||||
${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
|
||||
CppKafka::cppkafka
|
||||
fmt::fmt
|
||||
)
|
||||
${MySQL_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
CppKafka::cppkafka
|
||||
fmt::fmt
|
||||
resolv
|
||||
)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(owgw PUBLIC PocoJSON)
|
||||
endif()
|
||||
|
||||
25
Dockerfile
25
Dockerfile
@@ -1,7 +1,7 @@
|
||||
ARG DEBIAN_VERSION=11.5-slim
|
||||
ARG POCO_VERSION=poco-tip-v2
|
||||
ARG DEBIAN_VERSION=bookworm
|
||||
ARG POCO_VERSION=poco-tip-v4-tag
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
ARG VALIJASON_VERSION=tip-v1
|
||||
ARG VALIJASON_VERSION=tip-v1.0.2
|
||||
ARG APP_NAME=owgw
|
||||
ARG APP_HOME_DIR=/openwifi
|
||||
|
||||
@@ -17,8 +17,8 @@ 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/Telecominfraproject/wlan-cloud-lib-poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch ${POCO_VERSION} /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -31,8 +31,8 @@ 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/Telecominfraproject/wlan-cloud-lib-cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -45,8 +45,8 @@ FROM build-base AS valijson-build
|
||||
|
||||
ARG VALIJASON_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/valijson/git/refs/tags/${VALIJASON_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/valijson --branch ${VALIJASON_VERSION} /valijson
|
||||
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-valijson/git/refs/tags/${VALIJASON_VERSION} version.json
|
||||
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch ${VALIJASON_VERSION} /valijson
|
||||
|
||||
WORKDIR /valijson
|
||||
RUN mkdir cmake-build
|
||||
@@ -87,6 +87,11 @@ ENV APP_NAME=$APP_NAME \
|
||||
APP_CONFIG=/$APP_NAME-data \
|
||||
APP_HOME_DIR=$APP_HOME_DIR
|
||||
|
||||
# This is for legacy
|
||||
ENV OWGW_USER=$APP_USER \
|
||||
OWGW_ROOT=$APP_ROOT \
|
||||
OWGW_CONFIG=$APP_CONFIG
|
||||
|
||||
RUN useradd $APP_USER
|
||||
|
||||
RUN mkdir $APP_HOME_DIR
|
||||
@@ -95,7 +100,7 @@ RUN mkdir -p $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 \
|
||||
libmariadb-dev-compat libpq5 unixodbc postgresql-client libfmt7 sqlite3
|
||||
libmariadb-dev-compat libpq5 unixodbc postgresql-client libfmt9 sqlite3
|
||||
|
||||
COPY readiness_check /readiness_check
|
||||
COPY test_scripts/curl/cli /cli
|
||||
|
||||
245
PROTOCOL.md
245
PROTOCOL.md
@@ -306,8 +306,54 @@ The device should answer:
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to apply a given fixed configuration
|
||||
|
||||
Controller sends this command when it requires the device to apply fixed configuration, eg. country code. The device
|
||||
should respond with message indicating failure or success.
|
||||
|
||||
```json
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "fixedconfig",
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"when" : Optional - <UTC time when to apply this config, 0 means immediate, this is a suggestion>
|
||||
"country" : "<country-code>"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If AP supports compressed configuration feature by inidcating `compress_cmd=true` in its capabilities, controller
|
||||
will send a compressed configuration message where configuration payload (i.e. contents of `params`) is compressed
|
||||
and encoded in base64 format:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "configure",
|
||||
"params" : {
|
||||
"compress_64" : "<b64 encoded zlib compressed payload>",
|
||||
"compress_sz" : "<size of uncompressed data in bytes>"
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0",
|
||||
"result" : {
|
||||
"serial": <serial number>,
|
||||
"status": {
|
||||
"error": 0 or an error number,
|
||||
"text": <description of the error or success, eg. "Applied fixed config, rebooting">
|
||||
},
|
||||
"uuid": <UUID>
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
##### The Answer
|
||||
The device can answer and tell the controller it has rejected certain parts of the config and potentially replaced them with
|
||||
appropriate values. This could be used to allow a device to replace frequencies for the regions it is located in. The device
|
||||
@@ -355,6 +401,39 @@ The device should answer:
|
||||
- 1 : the device is busy but will reboot soon. `text` may indicate why.
|
||||
- 2 : the device will not reboot. `text` contains information as to why.
|
||||
|
||||
#### Controller wants to power-cycle PoE port(s)
|
||||
Controller sends this command to power-cycle 1 or more PoE ports
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "powercycle" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"ports" : [ { "name" : "Ethernet1", "cycle" : 5000}, { "name" : "Ethernet8", "cycle" : 10000 } ],
|
||||
"when" : Optional - <UTC time when to reboot, 0 mean immediately, this is a suggestion>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : 0 or an error number,
|
||||
"text" : [ "Error 1" , "Error 2" ],
|
||||
"when" : <time when this will be performed as UTC seconds>,
|
||||
},
|
||||
"id" : <same id from request>
|
||||
}
|
||||
```
|
||||
|
||||
###### Error codes
|
||||
- 0 : is rebooting at `when` seconds.
|
||||
- 1 : the device is busy but will reboot soon. `text` may indicate why.
|
||||
- 2 : the device will not reboot. `text` contains information as to why.
|
||||
|
||||
#### Controller wants the device to upgrade its firmware
|
||||
Controller sends this command when it believes the device should upgrade its firmware.
|
||||
```json
|
||||
@@ -775,6 +854,172 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to replace its certificates
|
||||
Controller sends this command to run a predefined script. Extreme care must be taken.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "certupdate" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"certificates" : <BASE64 encoded tar file of the cert package from the certificate portal>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
"txt" : <text describing the error or success>
|
||||
},
|
||||
"id" : <same number as request>
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to perform re-enrollment
|
||||
Controller sends this command to trigger re-enrollment, i.e. update of operational certificate. Extreme care must be taken.
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "reenroll" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"when" : Optional - <UTC time when to apply this config, 0 mean immediate, this is a suggestion>
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
"txt" : <text describing the error or success>
|
||||
},
|
||||
"id" : <same number as request>
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller wants the device to switch to another controller
|
||||
Controller sends this when the device should change the controller it connects to without looking up a new redirector.
|
||||
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "transfer" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"server" : <controller hostname>,
|
||||
"port" : <controller port number (integer)>,
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
"txt" : <text describing the error or success>
|
||||
},
|
||||
"id" : <same number as request>
|
||||
}
|
||||
```
|
||||
|
||||
### RRM AP device commands
|
||||
The following command is used to send RRM commands to an AP. RRM commands are send to an AP, however the
|
||||
controller will not or cannot verify if they have been sent or the action was performed.
|
||||
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "rrm" ,
|
||||
"params" : {
|
||||
"serial" : <serial number>,
|
||||
"actions" : [ array of actions. Each possible action is defined next]
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```json
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
|
||||
"txt" : <text describing the error or success>
|
||||
},
|
||||
"id" : <same number as request>
|
||||
}
|
||||
```
|
||||
|
||||
#### RRM Roam action
|
||||
|
||||
##### Kick
|
||||
```json
|
||||
{
|
||||
"action" : "kick" ,
|
||||
"addr" : <mac if the client that shall be kicked> ,
|
||||
"reason": <number>, (default: 5, https://www.cisco.com/assets/sol/sb/WAP371_Emulators/WAP371_Emulator_v1-0-1-5/help/Apx_ReasonCodes2.html)
|
||||
"ban_time": <number> (seconds, optional)
|
||||
}
|
||||
```
|
||||
|
||||
##### Channel Switch Announcement
|
||||
```json
|
||||
{
|
||||
"action" : "channel_switch" ,
|
||||
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
|
||||
"channel" : <number> (HT/HW mode will be retained upon issuing the CSA)
|
||||
}
|
||||
```
|
||||
|
||||
##### Change TX-Power
|
||||
```json
|
||||
{
|
||||
"action" : "tx_power" ,
|
||||
"bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
|
||||
"level" : <number> (DBm inside the positive number space)
|
||||
}
|
||||
```
|
||||
|
||||
##### Beacon Scan
|
||||
```json
|
||||
{
|
||||
"action" : "beacon_request" ,
|
||||
"addr" : <mac if the client that shall perform the scan> ,
|
||||
"ssid": <string>, (the SSID the client shall scan for on all frequencies),
|
||||
"channel": <number> (the channel that shall be scanned)
|
||||
}
|
||||
```
|
||||
|
||||
##### BSS Transition
|
||||
```json
|
||||
{
|
||||
"action" : "bss_transition" ,
|
||||
"addr" : <mac if the client that shall perform the roam> ,
|
||||
"neighbors": [ <string> ], (an array of BSSIDs the client shall consider as roamin candidates)
|
||||
}
|
||||
```
|
||||
|
||||
##### Update neighbours
|
||||
```json
|
||||
{
|
||||
"action" : "neighbors" ,
|
||||
"bssid" : <mac of the SSID> , (the SSID of the specific VAP)
|
||||
"neighbors": [ [ <BSS>, <ssid>, <neighbor report> ] ]
|
||||
}
|
||||
```
|
||||
|
||||
### `rtty server`
|
||||
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
|
||||
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\${APP_ROOT}/uploads"} \
|
||||
FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
|
||||
FILEUPLOADER_MAXSIZE=${FILEUPLOADER_MAXSIZE:-"10000"} \
|
||||
SERVICE_KEY=${SERVICE_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
|
||||
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
|
||||
SYSTEM_DATA=${SYSTEM_DATA:-"\${APP_ROOT}/data"} \
|
||||
@@ -76,6 +77,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
|
||||
IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
|
||||
DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
|
||||
LOGGING_LEVEL=${LOGGING_LEVEL:-"information"} \
|
||||
envsubst < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
|
||||
fi
|
||||
|
||||
|
||||
85
ols_samples/sample1.json
Normal file
85
ols_samples/sample1.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet0",
|
||||
"Ethernet1",
|
||||
"Ethernet2",
|
||||
"Ethernet3",
|
||||
"Ethernet4",
|
||||
"Ethernet5",
|
||||
"Ethernet6",
|
||||
"Ethernet7"
|
||||
],
|
||||
"speed": 2500,
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"poe": {
|
||||
"admin-mode": true,
|
||||
"power-limit": 60000
|
||||
}
|
||||
},
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet8",
|
||||
"Ethernet9"
|
||||
],
|
||||
"speed": 10000,
|
||||
"duplex": "full",
|
||||
"media": "sfp-forced-1000sfp"
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "VLAN1",
|
||||
"vlan": {
|
||||
"id": 1
|
||||
},
|
||||
"ipv4": {
|
||||
"addressing": "dynamic"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet0",
|
||||
"Ethernet1",
|
||||
"Ethernet2",
|
||||
"Ethernet3",
|
||||
"Ethernet4",
|
||||
"Ethernet5",
|
||||
"Ethernet6",
|
||||
"Ethernet7",
|
||||
"Ethernet8",
|
||||
"Ethernet9"
|
||||
],
|
||||
"vlan-tag": "un-tagged"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
"dhcp-snooping": {
|
||||
"filters": [
|
||||
"ack",
|
||||
"discover",
|
||||
"offer",
|
||||
"request",
|
||||
"solicit",
|
||||
"reply",
|
||||
"renew"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"interval": 60
|
||||
},
|
||||
"statistics": {
|
||||
"interval": 120,
|
||||
"types": []
|
||||
}
|
||||
},
|
||||
"unit": {
|
||||
"leds-active": true,
|
||||
"usage-threshold": 95
|
||||
},
|
||||
"uuid": 1678263900
|
||||
}
|
||||
@@ -12,7 +12,7 @@ info:
|
||||
url: https://www.ucentral.info/support
|
||||
|
||||
servers:
|
||||
- url: 'https://localhost:16001/api/v1'
|
||||
- url: 'https://localhost:16002/api/v1'
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -42,12 +42,10 @@ components:
|
||||
schemas:
|
||||
DeviceType:
|
||||
type: string
|
||||
default: AP
|
||||
default: ap
|
||||
enum:
|
||||
- AP
|
||||
- SWITCH
|
||||
- IOT
|
||||
- MESH
|
||||
- ap
|
||||
- switch
|
||||
|
||||
DeviceRestrictionsKeyInfo:
|
||||
type: object
|
||||
@@ -157,6 +155,9 @@ components:
|
||||
lastRecordedContact:
|
||||
type: integer
|
||||
format: int64
|
||||
blackListed:
|
||||
type: boolean
|
||||
readOnly: true
|
||||
|
||||
DeviceWithStatus:
|
||||
type: object
|
||||
@@ -281,6 +282,9 @@ components:
|
||||
format: float
|
||||
connectReason:
|
||||
type: string
|
||||
blackListed:
|
||||
type: boolean
|
||||
readOnly: true
|
||||
|
||||
DeviceList:
|
||||
type: object
|
||||
@@ -545,6 +549,12 @@ components:
|
||||
lastModified:
|
||||
type: integer
|
||||
format: int64
|
||||
platform:
|
||||
type: string
|
||||
enum:
|
||||
- ap
|
||||
- switch
|
||||
default: ap
|
||||
|
||||
DefaultConfigurationList:
|
||||
properties:
|
||||
@@ -903,6 +913,114 @@ components:
|
||||
kafkaClients:
|
||||
type: integer
|
||||
|
||||
RRM_Kick:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- kick
|
||||
addr:
|
||||
type: string
|
||||
format: mac
|
||||
reason:
|
||||
type: integer
|
||||
default: 5
|
||||
ban_time:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
RRM_channel_switch:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- channel_switch
|
||||
bssid:
|
||||
type: string
|
||||
format: mac
|
||||
channel:
|
||||
type: integer
|
||||
|
||||
RRM_tx_power:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- tx_power
|
||||
bssid:
|
||||
type: string
|
||||
format: mac
|
||||
level:
|
||||
type: integer
|
||||
|
||||
RRM_beacon_request:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- beacon_request
|
||||
addr:
|
||||
type: string
|
||||
format: mac
|
||||
ssid:
|
||||
type: string
|
||||
channel:
|
||||
type: integer
|
||||
|
||||
RRM_bss_transition:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- bss_transition
|
||||
addr:
|
||||
type: string
|
||||
format: mac
|
||||
neighbors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: mac
|
||||
|
||||
RRM_neighbors:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- neighbors
|
||||
bssid:
|
||||
type: string
|
||||
format: mac
|
||||
neighbors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: mac
|
||||
|
||||
RRM_action:
|
||||
type: object
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/RRM_Kick'
|
||||
- $ref: '#/components/schemas/RRM_channel_switch'
|
||||
- $ref: '#/components/schemas/RRM_tx_power'
|
||||
- $ref: '#/components/schemas/RRM_beacon_request'
|
||||
- $ref: '#/components/schemas/RRM_bss_transition'
|
||||
- $ref: '#/components/schemas/RRM_neighbors'
|
||||
|
||||
RRM_actions:
|
||||
type: object
|
||||
properties:
|
||||
actions:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RRM_action'
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## These are endpoints that all services in the uCentral stack must provide
|
||||
@@ -1345,6 +1463,7 @@ components:
|
||||
- generic
|
||||
- orion
|
||||
- globalreach
|
||||
- radsec
|
||||
default:
|
||||
generic
|
||||
poolProxyIp:
|
||||
@@ -1434,6 +1553,129 @@ components:
|
||||
userName:
|
||||
type: string
|
||||
|
||||
DeviceTransferRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
format: uuid
|
||||
server:
|
||||
type: string
|
||||
format: hostname
|
||||
port:
|
||||
type: integer
|
||||
format: int32
|
||||
|
||||
DeviceCertificateUpdateRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
encodedCertificate:
|
||||
type: string
|
||||
format: base64
|
||||
description: This is a base64 encoded string of the certificate bundle (the current bundle .tar.gz file from the PKI portal)
|
||||
|
||||
ReenrollRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
when:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
PowerCycleRequest:
|
||||
type: object
|
||||
properties:
|
||||
serial:
|
||||
type: string
|
||||
when:
|
||||
type: integer
|
||||
format: int64
|
||||
ports:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example:
|
||||
- Ethernet0
|
||||
cycle:
|
||||
type: integer
|
||||
default: 10000
|
||||
minimum: 1
|
||||
maximum: 60000
|
||||
description: off time in milliseconds
|
||||
|
||||
PackageGetResponse:
|
||||
type: object
|
||||
properties:
|
||||
serial:
|
||||
type: string
|
||||
status:
|
||||
type: object
|
||||
properties:
|
||||
package:
|
||||
type: string
|
||||
text:
|
||||
type: string
|
||||
uuid:
|
||||
type: number
|
||||
|
||||
|
||||
PackageInstallRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
packages:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
|
||||
PackageInstallResponse:
|
||||
type: object
|
||||
properties:
|
||||
serial:
|
||||
type: string
|
||||
status:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: number
|
||||
packages:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
result:
|
||||
type: string
|
||||
text:
|
||||
type: string
|
||||
uuid:
|
||||
type: number
|
||||
|
||||
PackageRemoveRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
packages:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
|
||||
paths:
|
||||
/devices:
|
||||
@@ -1526,6 +1768,22 @@ paths:
|
||||
type: integer
|
||||
default: 70
|
||||
required: false
|
||||
- in: query
|
||||
description: return only devices matching a certain platform of AP or SWITCH
|
||||
name: platform
|
||||
schema:
|
||||
type: string
|
||||
default: ALL
|
||||
enum:
|
||||
- all
|
||||
- ap
|
||||
- switch
|
||||
required: false
|
||||
- in: query
|
||||
description: only devices which are not provisioned
|
||||
name: includeProvisioned
|
||||
schema:
|
||||
type: boolean
|
||||
responses:
|
||||
200:
|
||||
description: List devices
|
||||
@@ -1581,8 +1839,12 @@ paths:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
|
||||
|
||||
- in: query
|
||||
description: Filter the results
|
||||
name: simulatedDevices
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
@@ -2575,7 +2837,7 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/:
|
||||
/device/{serialNumber}/script:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
@@ -2789,6 +3051,234 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/rrm:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Send RRM commands to a device.
|
||||
operationId: sendRRMcommandsForADevice
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Commands to send
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RRM_actions'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/transfer:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Transfer a device to a new redirector.
|
||||
operationId: transferDevice
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Transfer details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/DeviceTransferRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/certupdate:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Update the certificates for a device.
|
||||
operationId: updateCertificates
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Certificate update details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/DeviceCertificateUpdateRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/reenroll:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Reenroll operational certificate for the device.
|
||||
operationId: reenrollCertificate
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Reenroll operational certificate for the device
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReenrollRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/powercycle:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Perform PoE power cycle for some PoE ports.
|
||||
operationId: performPowerCycle
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Certificate update details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/PowerCycleRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/package:
|
||||
get:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Get package installed on the remote device.
|
||||
operationId: getDevicePackages
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: pkgName
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: The name or identifier of the package to retrieve.
|
||||
responses:
|
||||
200:
|
||||
description: Successful command execution
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PackageGetResponse'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Install IPK files to remote device.
|
||||
operationId: postDevicePackages
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Packages to be installed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PackageInstallRequest'
|
||||
responses:
|
||||
200:
|
||||
description: Successful command execution
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PackageInstallResponse'
|
||||
|
||||
400:
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Remove install packages from remote device.
|
||||
operationId: deleteDevicePackages
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Packages to be removed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PackageRemoveRequest'
|
||||
responses:
|
||||
200:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PackageInstallResponse'
|
||||
400:
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/ouis:
|
||||
get:
|
||||
tags:
|
||||
@@ -3295,8 +3785,6 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
|
||||
/deviceDashboard:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -52,7 +52,8 @@ openwifi.fileuploader.host.0.cert = ${FILEUPLOADER_HOST_CERT}
|
||||
openwifi.fileuploader.host.0.key = ${FILEUPLOADER_HOST_KEY}
|
||||
openwifi.fileuploader.host.0.key.password = ${FILEUPLOADER_HOST_KEY_PASSWORD}
|
||||
openwifi.fileuploader.path = ${FILEUPLOADER_PATH}
|
||||
openwifi.fileuploader.maxsize = 10000
|
||||
# maxsize in KB
|
||||
openwifi.fileuploader.maxsize = ${FILEUPLOADER_MAXSIZE}
|
||||
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
|
||||
|
||||
#
|
||||
@@ -145,7 +146,7 @@ storage.type.sqlite.db = devices.db
|
||||
storage.type.sqlite.idletime = 120
|
||||
storage.type.sqlite.maxsessions = 128
|
||||
|
||||
storage.type.postgresql.maxsessions = 64
|
||||
storage.type.postgresql.maxsessions = 250
|
||||
storage.type.postgresql.idletime = 60
|
||||
storage.type.postgresql.host = ${STORAGE_TYPE_POSTGRESQL_HOST}
|
||||
storage.type.postgresql.username = ${STORAGE_TYPE_POSTGRESQL_USERNAME}
|
||||
@@ -182,4 +183,4 @@ archiver.db.3.keep = 7
|
||||
########################################################################
|
||||
logging.type = console
|
||||
logging.path = $OWGW_ROOT/logs
|
||||
logging.level = information
|
||||
logging.level = ${LOGGING_LEVEL}
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int AP_WS_ConfigAutoUpgrader::Start() {
|
||||
int AP_WS_ConfigAutoUpgradeAgent::Start() {
|
||||
poco_notice(Logger(), "Starting...");
|
||||
QueueManager_.start(*this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_ConfigAutoUpgrader::Stop() {
|
||||
void AP_WS_ConfigAutoUpgradeAgent::Stop() {
|
||||
poco_notice(Logger(), "Stopping...");
|
||||
Running_ = false;
|
||||
Queue_.wakeUpAll();
|
||||
@@ -24,7 +24,7 @@ namespace OpenWifi {
|
||||
poco_notice(Logger(), "Stopped...");
|
||||
}
|
||||
|
||||
void AP_WS_ConfigAutoUpgrader::run() {
|
||||
void AP_WS_ConfigAutoUpgradeAgent::run() {
|
||||
Utils::SetThreadName("auto:cfgmgr");
|
||||
Running_ = true;
|
||||
|
||||
|
||||
@@ -28,14 +28,14 @@ namespace OpenWifi {
|
||||
std::uint64_t pending_config_=0;
|
||||
};
|
||||
|
||||
class AP_WS_ConfigAutoUpgrader : public SubSystemServer, Poco::Runnable {
|
||||
class AP_WS_ConfigAutoUpgradeAgent : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
void run() final;
|
||||
|
||||
static auto instance() {
|
||||
static auto instance = new AP_WS_ConfigAutoUpgrader;
|
||||
static auto instance = new AP_WS_ConfigAutoUpgradeAgent;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -126,12 +126,12 @@ namespace OpenWifi {
|
||||
mutable std::mutex CacheMutex_;
|
||||
std::map<std::uint64_t, ConfigurationCacheEntry> Cache_;
|
||||
|
||||
AP_WS_ConfigAutoUpgrader() noexcept
|
||||
AP_WS_ConfigAutoUpgradeAgent() noexcept
|
||||
: SubSystemServer("AutoConfigUpgrade", "AUTO-CFG-MGR", "auto.config.updater") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto AP_WS_ConfigAutoUpgrader() { return AP_WS_ConfigAutoUpgrader::instance(); }
|
||||
inline auto AP_WS_ConfigAutoUpgradeAgent() { return AP_WS_ConfigAutoUpgradeAgent::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
|
||||
@@ -2,56 +2,50 @@
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/HTTPServerRequestImpl.h"
|
||||
#include "Poco/Net/HTTPServerResponseImpl.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/WebSocketImpl.h"
|
||||
#include "Poco/zlib.h"
|
||||
#include <Poco/Base64Decoder.h>
|
||||
#include <Poco/Net/Context.h>
|
||||
#include <Poco/Net/HTTPServerRequestImpl.h>
|
||||
#include <Poco/Net/HTTPServerResponseImpl.h>
|
||||
#include <Poco/JSON/JSONException.h>
|
||||
#include <Poco/Net/NetException.h>
|
||||
#include <Poco/Net/SSLException.h>
|
||||
#include <Poco/Net/SecureStreamSocketImpl.h>
|
||||
#include <Poco/Net/WebSocketImpl.h>
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "CommandManager.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "StorageService.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include <framework/KafkaManager.h>
|
||||
#include <framework/MicroServiceFuncs.h>
|
||||
#include <framework/utils.h>
|
||||
#include <framework/ow_constants.h>
|
||||
|
||||
#include "GWKafkaEvents.h"
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
#include "RADIUSSessionTracker.h"
|
||||
#include "RADIUS_proxy_server.h"
|
||||
#include <AP_WS_Connection.h>
|
||||
#include <AP_WS_Server.h>
|
||||
#include <CentralConfig.h>
|
||||
#include <CommandManager.h>
|
||||
#include <StorageService.h>
|
||||
#include <RADIUSSessionTracker.h>
|
||||
#include <RADIUS_proxy_server.h>
|
||||
#include <GWKafkaEvents.h>
|
||||
#include <UI_GW_WebSocketNotifications.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
#define DBL \
|
||||
{ \
|
||||
std::cout << __LINE__ << " ID: " << ConnectionId_ << " Ser: " << SerialNumber_ \
|
||||
<< std::endl; \
|
||||
}
|
||||
|
||||
void AP_WS_Connection::LogException(const Poco::Exception &E) {
|
||||
poco_information(Logger_, fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
|
||||
}
|
||||
|
||||
AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response,
|
||||
uint64_t connection_id, Poco::Logger &L,
|
||||
Poco::Net::SocketReactor &R)
|
||||
: Logger_(L), Reactor_(R) {
|
||||
State_.sessionId = connection_id;
|
||||
uint64_t session_id, Poco::Logger &L,
|
||||
std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R)
|
||||
: Logger_(L), IncomingFrame_(0) {
|
||||
|
||||
Reactor_ = R.first;
|
||||
DbSession_ = R.second;
|
||||
State_.sessionId = session_id;
|
||||
|
||||
WS_ = std::make_unique<Poco::Net::WebSocket>(request, response);
|
||||
|
||||
auto TS = Poco::Timespan(360, 0);
|
||||
@@ -61,29 +55,87 @@ namespace OpenWifi {
|
||||
WS_->setNoDelay(false);
|
||||
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;
|
||||
IncomingFrame_.resize(0);
|
||||
uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
|
||||
|
||||
AP_WS_Server()->IncrementConnectionCount();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::Start() {
|
||||
Registered_ = true;
|
||||
LastContact_ = Utils::Now();
|
||||
|
||||
Reactor_->addEventHandler(*WS_,
|
||||
Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_->addEventHandler(*WS_,
|
||||
Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_->addEventHandler(*WS_,
|
||||
Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
AP_WS_Server()->DecrementConnectionCount();
|
||||
EndConnection();
|
||||
poco_debug(Logger_, fmt::format("TERMINATION({}): Session={}, Connection removed.", SerialNumber_,
|
||||
State_.sessionId));
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
try {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
Details.set(uCentralProtocol::UUID,uuid);
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection() {
|
||||
bool expectedValue=false;
|
||||
if (Dead_.compare_exchange_strong(expectedValue,true,std::memory_order_release,std::memory_order_relaxed)) {
|
||||
|
||||
if(!SerialNumber_.empty() && State_.LastContact!=0) {
|
||||
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
|
||||
}
|
||||
|
||||
if (Registered_) {
|
||||
Registered_ = false;
|
||||
Reactor_->removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_->removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_->removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
Registered_=false;
|
||||
}
|
||||
WS_->close();
|
||||
|
||||
if(!SerialNumber_.empty()) {
|
||||
DeviceDisconnectionCleanup(SerialNumber_, uuid_);
|
||||
}
|
||||
AP_WS_Server()->AddCleanupSession(State_.sessionId, SerialNumberInt_);
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::ValidatedDevice() {
|
||||
|
||||
if(Dead_)
|
||||
return false;
|
||||
|
||||
if (DeviceValidated_)
|
||||
return true;
|
||||
|
||||
if (!Valid_)
|
||||
return false;
|
||||
|
||||
std::lock_guard Lock(ConnectionMutex_);
|
||||
try {
|
||||
auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
|
||||
auto SS =
|
||||
@@ -98,7 +150,6 @@ namespace OpenWifi {
|
||||
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Connection is "
|
||||
"NOT secure. Device is not allowed.",
|
||||
CId_, State_.sessionId));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -111,7 +162,6 @@ namespace OpenWifi {
|
||||
Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_,
|
||||
State_.sessionId));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -122,11 +172,19 @@ namespace OpenWifi {
|
||||
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()));
|
||||
if(!Utils::ValidSerialNumber(CN_)) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Invalid serial number: CN={}", CId_,
|
||||
State_.sessionId, CN_));
|
||||
return false;
|
||||
}
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
|
||||
State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_,
|
||||
@@ -136,30 +194,28 @@ namespace OpenWifi {
|
||||
poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is "
|
||||
"not allowed. Disconnecting.",
|
||||
CId_, State_.sessionId, CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(AP_WS_Server::IsSim(CN_)) {
|
||||
if(AP_WS_Server::IsSim(SerialNumber_)) {
|
||||
State_.VerifiedCertificate = GWObjects::SIMULATED;
|
||||
Simulated_ = true;
|
||||
}
|
||||
|
||||
std::string reason, author;
|
||||
std::uint64_t created;
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(CN_, reason, author, created)) {
|
||||
if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumberInt_, reason, author, created)) {
|
||||
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
|
||||
CId_, State_.sessionId, CN_));
|
||||
EndConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
|
||||
SerialNumber_ = CN_;
|
||||
SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
|
||||
State_.certificateIssuerName = PeerCert.issuerName();
|
||||
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,
|
||||
@@ -223,149 +279,14 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
try {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
|
||||
Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
Details.set(uCentralProtocol::UUID,uuid);
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
Valid_ = false;
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
void AP_WS_Connection::DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
if (KafkaManager()->Enabled()) {
|
||||
NotifyKafkaDisconnect(SerialNumber, uuid);
|
||||
}
|
||||
RADIUSSessionTracker()->DeviceDisconnect(SerialNumber);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection(bool DeleteSession) {
|
||||
Valid_ = false;
|
||||
if (!Dead_.test_and_set()) {
|
||||
|
||||
if(!SerialNumber_.empty() && State_.LastContact!=0) {
|
||||
StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
|
||||
}
|
||||
|
||||
if (Registered_) {
|
||||
Registered_ = false;
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketReadable));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketShutdown));
|
||||
Reactor_.removeEventHandler(
|
||||
*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
|
||||
*this, &AP_WS_Connection::OnSocketError));
|
||||
}
|
||||
WS_->close();
|
||||
|
||||
if(!SerialNumber_.empty()) {
|
||||
std::thread Cleanup(DeviceDisconnectionCleanup,SerialNumber_, uuid_);
|
||||
Cleanup.detach();
|
||||
}
|
||||
|
||||
bool SessionDeleted = false;
|
||||
if(DeleteSession)
|
||||
SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
|
||||
if (SessionDeleted || !DeleteSession) {
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
N.content.serialNumber = SerialNumber_;
|
||||
GWWebSocketNotifications::DeviceDisconnected(N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::LookForUpgrade(const uint64_t UUID, uint64_t &UpgradedUUID) {
|
||||
|
||||
// A UUID of zero means ignore updates for that connection.
|
||||
if (UUID == 0)
|
||||
return false;
|
||||
|
||||
uint64_t GoodConfig = ConfigurationCache().CurrentConfig(SerialNumberInt_);
|
||||
if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) {
|
||||
UpgradedUUID = UUID;
|
||||
return false;
|
||||
}
|
||||
|
||||
GWObjects::Device D;
|
||||
if (StorageService()->GetDevice(SerialNumber_, D)) {
|
||||
|
||||
if(D.pendingUUID!=0 && UUID==D.pendingUUID) {
|
||||
// so we sent an upgrade to a device, and now it is completing now...
|
||||
UpgradedUUID = D.pendingUUID;
|
||||
StorageService()->CompleteDeviceConfigurationChange(SerialNumber_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is the case where the cache is empty after a restart. So GoodConfig will 0. If
|
||||
// the device already has the right UUID, we just return.
|
||||
if (D.UUID == UUID) {
|
||||
UpgradedUUID = UUID;
|
||||
ConfigurationCache().Add(SerialNumberInt_, UUID);
|
||||
return false;
|
||||
}
|
||||
|
||||
Config::Config Cfg(D.Configuration);
|
||||
if (UUID > D.UUID) {
|
||||
// so we have a problem, the device has a newer config than we have. So we need to
|
||||
// make sure our config is newer.
|
||||
D.UUID = UUID + 2;
|
||||
UpgradedUUID = D.UUID;
|
||||
}
|
||||
|
||||
Cfg.SetUUID(D.UUID);
|
||||
D.Configuration = Cfg.get();
|
||||
State_.PendingUUID = UpgradedUUID = D.UUID;
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroServiceCreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::CONFIGURE;
|
||||
Poco::JSON::Parser P;
|
||||
auto ParsedConfig = P.parse(D.Configuration).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::UUID, D.UUID);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
|
||||
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
poco_information(Logger_,
|
||||
fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
|
||||
CId_, UUID, D.UUID));
|
||||
bool Sent;
|
||||
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd,
|
||||
Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
CommandManager()->PostCommand(
|
||||
CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
|
||||
SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false);
|
||||
|
||||
GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
|
||||
Notification.content.serialNumber = D.SerialNumber;
|
||||
Notification.content.oldUUID = UUID;
|
||||
Notification.content.newUUID = UpgradedUUID;
|
||||
GWWebSocketNotifications::DeviceConfigurationChange(Notification);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
GWWebSocketNotifications::SingleDevice_t N;
|
||||
N.content.serialNumber = SerialNumber;
|
||||
GWWebSocketNotifications::DeviceDisconnected(N);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
|
||||
@@ -446,7 +367,7 @@ namespace OpenWifi {
|
||||
|
||||
std::string reason, author;
|
||||
std::uint64_t created;
|
||||
if (StorageService()->IsBlackListed(Serial, reason, author, created)) {
|
||||
if (StorageService()->IsBlackListed(SerialNumberInt_, reason, author, created)) {
|
||||
DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
|
||||
Poco::Exception E(
|
||||
fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
|
||||
@@ -577,17 +498,17 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::SetWebSocketTelemetryReporting(
|
||||
uint64_t RPCID, uint64_t Interval, uint64_t LifeTime,
|
||||
std::uint64_t RPCID, std::uint64_t Interval, std::uint64_t LifeTime,
|
||||
const std::vector<std::string> &TelemetryTypes) {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryWebSocketRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_
|
||||
? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
|
||||
? (Interval < (std::uint64_t)TelemetryInterval_ ? Interval : (std::uint64_t )TelemetryInterval_)
|
||||
: Interval;
|
||||
auto TelemetryWebSocketTimer = LifeTime + Utils::Now();
|
||||
TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > TelemetryWebSocketTimer_
|
||||
? TelemetryWebSocketTimer
|
||||
: TelemetryWebSocketTimer_;
|
||||
TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > (std::uint64_t)TelemetryWebSocketTimer_
|
||||
? (std::uint64_t)TelemetryWebSocketTimer
|
||||
: (std::uint64_t)TelemetryWebSocketTimer_;
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
@@ -603,11 +524,11 @@ namespace OpenWifi {
|
||||
std::unique_lock Lock(TelemetryMutex_);
|
||||
TelemetryKafkaRefCount_++;
|
||||
TelemetryInterval_ = TelemetryInterval_
|
||||
? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
|
||||
? (Interval < (std::uint64_t)TelemetryInterval_ ? (std::uint64_t)Interval : (std::uint64_t)TelemetryInterval_)
|
||||
: Interval;
|
||||
auto TelemetryKafkaTimer = LifeTime + Utils::Now();
|
||||
TelemetryKafkaTimer_ =
|
||||
TelemetryKafkaTimer > TelemetryKafkaTimer_ ? TelemetryKafkaTimer : TelemetryKafkaTimer_;
|
||||
TelemetryKafkaTimer > (std::uint64_t)TelemetryKafkaTimer_ ? (std::uint64_t)TelemetryKafkaTimer : (std::uint64_t)TelemetryKafkaTimer_;
|
||||
UpdateCounts();
|
||||
if (!TelemetryReporting_) {
|
||||
TelemetryReporting_ = true;
|
||||
@@ -643,223 +564,272 @@ namespace OpenWifi {
|
||||
void AP_WS_Connection::OnSocketShutdown(
|
||||
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
|
||||
// std::lock_guard G(ConnectionMutex_);
|
||||
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_));
|
||||
// std::lock_guard G(ConnectionMutex_);
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::OnSocketReadable(
|
||||
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
|
||||
if (!Valid_)
|
||||
if (Dead_) // we are dead, so we do not process anything.
|
||||
return;
|
||||
|
||||
if (!AP_WS_Server()->Running())
|
||||
return EndConnection();
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
|
||||
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();
|
||||
State_.LastContact = LastContact_ = Utils::Now();
|
||||
if (AP_WS_Server()->Running() && (DeviceValidated_ || ValidatedDevice())) {
|
||||
try {
|
||||
return ProcessIncomingFrame();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (const std::exception &E) {
|
||||
std::string W = E.what();
|
||||
poco_information(
|
||||
Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}",
|
||||
W, CId_));
|
||||
} catch (...) {
|
||||
poco_information(
|
||||
Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_));
|
||||
}
|
||||
}
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessWSFinalPayload() {
|
||||
auto IncomingSize = IncomingFrame_.size();
|
||||
|
||||
if (IncomingSize == 0) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("ProcessWSFrame({}): Final Acc. Frame received but empty",
|
||||
CId_));
|
||||
return;
|
||||
}
|
||||
IncomingFrame_.append(0);
|
||||
|
||||
poco_trace(Logger_,
|
||||
fmt::format("ProcessWSFrame({}): Final Acc. Frame received (len={}, Msg={}",
|
||||
CId_, IncomingSize, 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);
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc': {}",
|
||||
CId_, iS.str()));
|
||||
Errors_++;
|
||||
}
|
||||
IncomingFrame_.clear();
|
||||
IncomingFrame_.resize(0);
|
||||
}
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingFrame() {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
Poco::Buffer<char> CurrentFrame(0);
|
||||
bool KillConnection = false;
|
||||
int flags = 0;
|
||||
int IncomingSize = 0;
|
||||
|
||||
try {
|
||||
int Op, flags;
|
||||
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
|
||||
IncomingSize = WS_->receiveFrame(CurrentFrame, flags);
|
||||
int Op;
|
||||
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
if (IncomingSize < 0 && flags == 0) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("EMPTY({}): Non-blocking try-again empty frame (len={}, flags={})",
|
||||
CId_, IncomingSize, flags));
|
||||
} else if (IncomingSize == 0 && flags == 0) {
|
||||
poco_information(Logger_,
|
||||
fmt::format("DISCONNECT({}): device has disconnected. Session={}",
|
||||
CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
}
|
||||
|
||||
IncomingFrame.append(0);
|
||||
|
||||
State_.RX += IncomingSize;
|
||||
AP_WS_Server()->AddRX(IncomingSize);
|
||||
if (IncomingSize > 0) {
|
||||
State_.RX += IncomingSize;
|
||||
AP_WS_Server()->AddRX(IncomingSize);
|
||||
IncomingFrame_.append(CurrentFrame);
|
||||
}
|
||||
State_.MessageCount++;
|
||||
State_.LastContact = Utils::Now();
|
||||
poco_trace(Logger_,
|
||||
fmt::format("FRAME({}): Frame rx (op={} len={}, flags={}, acc.len={})",
|
||||
CId_, Op, IncomingSize, flags, IncomingFrame_.size()));
|
||||
|
||||
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 |
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
poco_trace(Logger_, fmt::format("PING({}): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Object PingObject;
|
||||
Poco::JSON::Object PingDetails;
|
||||
PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware);
|
||||
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
|
||||
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
PingDetails.set(uCentralProtocol::UUID, uuid_);
|
||||
PingDetails.set("locale", State_.locale);
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
|
||||
}
|
||||
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()));
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Object PingObject;
|
||||
Poco::JSON::Object PingDetails;
|
||||
PingDetails.set(uCentralProtocol::FIRMWARE, State_.Firmware);
|
||||
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
|
||||
PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
|
||||
PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
|
||||
PingDetails.set(uCentralProtocol::UUID, uuid_);
|
||||
PingDetails.set("locale", State_.locale);
|
||||
PingObject.set(uCentralProtocol::PING, PingDetails);
|
||||
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,
|
||||
PingObject);
|
||||
}
|
||||
} 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_));
|
||||
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_CONT: {
|
||||
poco_trace(Logger_, fmt::format("CONTINUATION({}): registered.", CId_));
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_BINARY: {
|
||||
poco_trace(Logger_, fmt::format("BINARY({}): Invalid frame type.", CId_));
|
||||
KillConnection=true;
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("TEXT({}): Frame received (len={}, flags={}). Msg={}",
|
||||
CId_, IncomingSize, flags,
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin()));
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
poco_information(Logger_,
|
||||
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
|
||||
KillConnection=true;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}",
|
||||
CId_, std::to_string(Op)));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
poco_information(Logger_,
|
||||
fmt::format("CLOSE({}): Device is closing its connection.", CId_));
|
||||
return EndConnection();
|
||||
} break;
|
||||
|
||||
default: {
|
||||
poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}",
|
||||
CId_, std::to_string(Op)));
|
||||
} break;
|
||||
}
|
||||
|
||||
// Check for final frame and process accumulated payload
|
||||
if (!KillConnection && (flags & Poco::Net::WebSocket::FRAME_FLAG_FIN) != 0) {
|
||||
ProcessWSFinalPayload();
|
||||
}
|
||||
|
||||
} catch (const Poco::Net::ConnectionResetException &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_, E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
|
||||
poco_warning(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
|
||||
CId_, E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::Net::SSLException &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::IOException &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_,
|
||||
E.displayText(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (const std::exception &E) {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_,
|
||||
E.what(),
|
||||
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
|
||||
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
|
||||
State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
} catch (...) {
|
||||
poco_error(Logger_, fmt::format("UnknownException({}): Device must be disconnected. "
|
||||
"Unknown exception. Session:{}",
|
||||
CId_, State_.sessionId));
|
||||
return EndConnection();
|
||||
KillConnection=true;
|
||||
}
|
||||
|
||||
if (Errors_ < 10)
|
||||
if (!KillConnection && Errors_ < 10)
|
||||
return;
|
||||
|
||||
poco_warning(Logger_, fmt::format("DISCONNECTING({}): Too many errors", CId_));
|
||||
return EndConnection();
|
||||
poco_warning(Logger_,
|
||||
fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}",
|
||||
CId_, KillConnection, Errors_ ));
|
||||
EndConnection();
|
||||
}
|
||||
|
||||
bool AP_WS_Connection::Send(const std::string &Payload) {
|
||||
@@ -952,24 +922,55 @@ namespace OpenWifi {
|
||||
|
||||
void AP_WS_Connection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
|
||||
if (Doc->has(uCentralProtocol::RADIUSDATA)) {
|
||||
std::string secret;
|
||||
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(),secret);
|
||||
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(), secret);
|
||||
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(), secret);
|
||||
DecodedData.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
void AP_WS_Connection::SetLastStats(const std::string &LastStats) {
|
||||
RawLastStats_ = LastStats;
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
|
||||
State_.hasGPS = Stats->isObject("gps");
|
||||
auto Unit = Stats->getObject("unit");
|
||||
auto Memory = Unit->getObject("memory");
|
||||
std::uint64_t TotalMemory = Memory->get("total");
|
||||
std::uint64_t FreeMemory = Memory->get("free");
|
||||
if (TotalMemory > 0) {
|
||||
State_.memoryUsed =
|
||||
(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
|
||||
}
|
||||
if (Unit->isArray("load")) {
|
||||
Poco::JSON::Array::Ptr Load = Unit->getArray("load");
|
||||
if (Load->size() > 1) {
|
||||
State_.load = Load->get(1);
|
||||
}
|
||||
}
|
||||
if (Unit->isArray("temperature")) {
|
||||
Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
|
||||
if (Temperature->size() > 1) {
|
||||
State_.temperature = Temperature->get(0);
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(Logger_, "Failed to parse last stats: " + E.displayText());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
@@ -14,27 +14,31 @@
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
#include <Poco/Data/Session.h>
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
#include <AP_WS_Reactor_Pool.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_Connection {
|
||||
static constexpr int BufSize = 256000;
|
||||
static constexpr int BufSize = 512000;
|
||||
|
||||
public:
|
||||
explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response, uint64_t connection_id,
|
||||
Poco::Logger &L, Poco::Net::SocketReactor &R);
|
||||
Poco::Logger &L, std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R);
|
||||
~AP_WS_Connection();
|
||||
|
||||
void EndConnection(bool DeleteSession=true);
|
||||
void EndConnection();
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
|
||||
void ProcessWSFinalPayload();
|
||||
void ProcessIncomingFrame();
|
||||
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
|
||||
|
||||
[[nodiscard]] bool Send(const std::string &Payload);
|
||||
[[nodiscard]] inline bool MustBeSecureRTTY() const { return RTTYMustBeSecure_; }
|
||||
|
||||
bool SendRadiusAuthenticationData(const unsigned char *buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const unsigned char *buffer, std::size_t size);
|
||||
@@ -43,10 +47,7 @@ namespace OpenWifi {
|
||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
|
||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
||||
bool LookForUpgrade(uint64_t UUID, uint64_t &UpgradedUUID);
|
||||
static bool ExtractBase64CompressedData(const std::string &CompressedData,
|
||||
std::string &UnCompressedData,
|
||||
uint64_t compress_sz);
|
||||
bool LookForUpgrade(Poco::Data::Session &Session, uint64_t UUID, uint64_t &UpgradedUUID);
|
||||
void LogException(const Poco::Exception &E);
|
||||
inline Poco::Logger &Logger() { return Logger_; }
|
||||
bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval,
|
||||
@@ -59,81 +60,33 @@ namespace OpenWifi {
|
||||
bool StopKafkaTelemetry(uint64_t RPCID);
|
||||
|
||||
inline void GetLastStats(std::string &LastStats) {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
LastStats = RawLastStats_;
|
||||
}
|
||||
|
||||
inline void SetLastStats(const std::string &LastStats) {
|
||||
std::unique_lock G(ConnectionMutex_);
|
||||
RawLastStats_ = LastStats;
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
|
||||
hasGPS = Stats->isObject("gps");
|
||||
auto Unit = Stats->getObject("unit");
|
||||
auto Memory = Unit->getObject("memory");
|
||||
std::uint64_t TotalMemory = Memory->get("total");
|
||||
std::uint64_t FreeMemory = Memory->get("free");
|
||||
if(TotalMemory>0) {
|
||||
memory_used_ =
|
||||
(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
|
||||
}
|
||||
if(Unit->isArray("load")) {
|
||||
Poco::JSON::Array::Ptr Load = Unit->getArray("load");
|
||||
if(Load->size()>1) {
|
||||
cpu_load_ = Load->get(1);
|
||||
}
|
||||
}
|
||||
if(Unit->isArray("temperature")) {
|
||||
Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
|
||||
if(Temperature->size()>1) {
|
||||
temperature_ = Temperature->get(0);
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
if(!Dead_) {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
LastStats = RawLastStats_;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
|
||||
std::unique_lock G(ConnectionMutex_);
|
||||
RawLastHealthcheck_ = H;
|
||||
}
|
||||
|
||||
inline void GetLastHealthCheck(GWObjects::HealthCheck &H) {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
H = RawLastHealthcheck_;
|
||||
if(!Dead_) {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
H = RawLastHealthcheck_;
|
||||
}
|
||||
}
|
||||
|
||||
inline void GetState(GWObjects::ConnectionState &State) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
State = State_;
|
||||
inline void GetState(GWObjects::ConnectionState &State) {
|
||||
if(!Dead_) {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
State = State_;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool HasGPS() { return hasGPS; }
|
||||
|
||||
inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
R = Restrictions_;
|
||||
inline GWObjects::DeviceRestrictions GetRestrictions() {
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
return Restrictions_;
|
||||
}
|
||||
|
||||
void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
|
||||
void Process_state(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
|
||||
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
bool ValidatedDevice();
|
||||
[[nodiscard]] inline bool HasGPS() const { return hasGPS_; }
|
||||
[[nodiscard]] bool ValidatedDevice();
|
||||
|
||||
inline bool GetTelemetryParameters(bool &Reporting, uint64_t &Interval,
|
||||
uint64_t &WebSocketTimer, uint64_t &KafkaTimer,
|
||||
@@ -153,18 +106,14 @@ namespace OpenWifi {
|
||||
|
||||
friend class AP_WS_Server;
|
||||
|
||||
inline GWObjects::DeviceRestrictions Restrictions() const {
|
||||
std::shared_lock G(ConnectionMutex_);
|
||||
return Restrictions_;
|
||||
}
|
||||
|
||||
inline bool MustBeSecureRtty() const { return RttyMustBeSecure_; }
|
||||
void Start();
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex ConnectionMutex_;
|
||||
std::shared_mutex TelemetryMutex_;
|
||||
mutable std::recursive_mutex ConnectionMutex_;
|
||||
std::mutex TelemetryMutex_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::shared_ptr<Poco::Net::SocketReactor> Reactor_;
|
||||
std::shared_ptr<LockedDbSession> DbSession_;
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
std::string SerialNumber_;
|
||||
uint64_t SerialNumberInt_ = 0;
|
||||
@@ -175,33 +124,57 @@ namespace OpenWifi {
|
||||
uint64_t Errors_ = 0;
|
||||
Poco::Net::IPAddress PeerAddress_;
|
||||
volatile bool TelemetryReporting_ = false;
|
||||
volatile uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
volatile uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
volatile uint64_t TelemetryKafkaTimer_ = 0;
|
||||
volatile uint64_t TelemetryInterval_ = 0;
|
||||
volatile uint64_t TelemetryWebSocketPackets_ = 0;
|
||||
volatile uint64_t TelemetryKafkaPackets_ = 0;
|
||||
std::atomic_uint64_t TelemetryWebSocketRefCount_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaRefCount_ = 0;
|
||||
std::atomic_uint64_t TelemetryWebSocketTimer_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaTimer_ = 0;
|
||||
std::atomic_uint64_t TelemetryInterval_ = 0;
|
||||
std::atomic_uint64_t TelemetryWebSocketPackets_ = 0;
|
||||
std::atomic_uint64_t TelemetryKafkaPackets_ = 0;
|
||||
GWObjects::ConnectionState State_;
|
||||
std::string RawLastStats_;
|
||||
Utils::CompressedString RawLastStats_;
|
||||
GWObjects::HealthCheck RawLastHealthcheck_;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
|
||||
std::atomic_flag Dead_ = false;
|
||||
std::atomic<bool> Dead_ = false;
|
||||
std::atomic_bool DeviceValidated_ = false;
|
||||
std::atomic_bool Valid_ = false;
|
||||
OpenWifi::GWObjects::DeviceRestrictions Restrictions_;
|
||||
bool RttyMustBeSecure_ = false;
|
||||
bool RTTYMustBeSecure_ = false;
|
||||
bool hasGPS_=false;
|
||||
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
|
||||
std::uint64_t uuid_=0;
|
||||
bool Simulated_=false;
|
||||
std::atomic_uint64_t LastContact_=0;
|
||||
Poco::Buffer<char> IncomingFrame_;
|
||||
|
||||
static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
|
||||
|
||||
bool StartTelemetry(uint64_t RPCID, const std::vector<std::string> &TelemetryTypes);
|
||||
bool StopTelemetry(uint64_t RPCID);
|
||||
void UpdateCounts();
|
||||
bool hasGPS=false;
|
||||
std::double_t memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
|
||||
std::uint64_t uuid_=0;
|
||||
static void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid);
|
||||
void SetLastStats(const std::string &LastStats);
|
||||
void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
|
||||
void Process_state(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_log(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_crashlog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_ping(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_recovery(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
|
||||
void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_event(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
|
||||
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
|
||||
|
||||
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
|
||||
RawLastHealthcheck_ = H;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
111
src/AP_WS_LookForUpgrade.cpp
Normal file
111
src/AP_WS_LookForUpgrade.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
#include <AP_WS_Connection.h>
|
||||
#include "ConfigurationCache.h"
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
#include "CommandManager.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
bool AP_WS_Connection::LookForUpgrade(Poco::Data::Session &Session, const uint64_t UUID, uint64_t &UpgradedUUID) {
|
||||
|
||||
// A UUID of zero means ignore updates for that connection.
|
||||
if (UUID == 0)
|
||||
return false;
|
||||
|
||||
uint64_t GoodConfig = GetCurrentConfigurationID(SerialNumberInt_);
|
||||
if (GoodConfig && (GoodConfig == UUID || GoodConfig == State_.PendingUUID)) {
|
||||
UpgradedUUID = UUID;
|
||||
State_.PendingUUID = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
GWObjects::Device D;
|
||||
if (!StorageService()->GetDevice(Session,SerialNumber_, D)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(State_.PendingUUID!=0 && UUID==State_.PendingUUID) {
|
||||
// so we sent an upgrade to a device, and now it is completing now...
|
||||
UpgradedUUID = UUID;
|
||||
StorageService()->CompleteDeviceConfigurationChange(Session, SerialNumber_);
|
||||
State_.PendingUUID = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// dont upgrade a switch if it does not have a real config. Config will always be more than 20 characters
|
||||
if (D.DeviceType==Platforms::SWITCH && D.Configuration.size()<20) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Config::Config Cfg(D.Configuration);
|
||||
// if this is a broken device (UUID==0) just fix it
|
||||
auto StoredConfigurationUUID = Cfg.UUID();
|
||||
if(D.UUID==0) {
|
||||
D.UUID = StoredConfigurationUUID;
|
||||
}
|
||||
|
||||
|
||||
if (D.UUID == UUID) {
|
||||
D.UUID = UpgradedUUID = UUID;
|
||||
State_.PendingUUID = D.pendingUUID = 0;
|
||||
D.pendingConfiguration.clear();
|
||||
D.pendingConfigurationCmd.clear();
|
||||
StorageService()->UpdateDevice(Session, D);
|
||||
SetCurrentConfigurationID(SerialNumberInt_, UUID);
|
||||
// std::cout << __LINE__ << ": " << SerialNumber_ << " GoodConfig: " << GoodConfig << " UUID:" << UUID << " Pending:" << State_.PendingUUID << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UUID > D.UUID) {
|
||||
// so we have a problem, the device has a newer config than we have. So we need to
|
||||
// make sure our config is newer.
|
||||
D.UUID = UUID + 2;
|
||||
UpgradedUUID = D.UUID;
|
||||
// std::cout << __LINE__ << ": " << SerialNumber_ << " GoodConfig: " << GoodConfig << " UUID:" << UUID << " Pending:" << State_.PendingUUID << std::endl;
|
||||
}
|
||||
|
||||
Cfg.SetUUID(D.UUID);
|
||||
D.Configuration = Cfg.get();
|
||||
D.pendingUUID = State_.PendingUUID = UpgradedUUID = D.UUID;
|
||||
StorageService()->UpdateDevice(Session, D);
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = MicroServiceCreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::CONFIGURE;
|
||||
Poco::JSON::Parser P;
|
||||
auto ParsedConfig = P.parse(D.Configuration).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::UUID, D.UUID);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
|
||||
|
||||
std::ostringstream O;
|
||||
Poco::JSON::Stringifier::stringify(Params, O);
|
||||
Cmd.Details = O.str();
|
||||
poco_information(Logger_,
|
||||
fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
|
||||
CId_, UUID, D.UUID));
|
||||
bool Sent;
|
||||
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd,
|
||||
Storage::CommandExecutionType::COMMAND_EXECUTED);
|
||||
CommandManager()->PostCommand(
|
||||
CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
|
||||
SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false);
|
||||
|
||||
GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
|
||||
Notification.content.serialNumber = D.SerialNumber;
|
||||
Notification.content.oldUUID = UUID;
|
||||
Notification.content.newUUID = UpgradedUUID;
|
||||
GWWebSocketNotifications::DeviceConfigurationChange(Notification);
|
||||
|
||||
// std::cout << __LINE__ << ": " << SerialNumber_ << " GoodConfig: " << GoodConfig << " UUID:" << UUID <<
|
||||
// " Pending:" << State_.PendingUUID << " Upgraded:" << UpgradedUUID << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -71,9 +71,8 @@ namespace OpenWifi {
|
||||
|
||||
CommandManager()->ClearQueue(SerialNumberInt_);
|
||||
|
||||
AP_WS_Server()->SetSessionDetails(State_.sessionId, SerialNumberInt_);
|
||||
AP_WS_Server()->StartSession(State_.sessionId, SerialNumberInt_);
|
||||
|
||||
std::lock_guard Lock(ConnectionMutex_);
|
||||
Config::Capabilities Caps(Capabilities);
|
||||
|
||||
Compatible_ = Caps.Compatible();
|
||||
@@ -84,6 +83,8 @@ namespace OpenWifi {
|
||||
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
|
||||
CId_ = SerialNumber_ + "@" + CId_;
|
||||
|
||||
auto Platform = Poco::toLower(Caps.Platform());
|
||||
|
||||
if(ParamsObj->has("reason")) {
|
||||
State_.connectReason = ParamsObj->get("reason").toString();
|
||||
}
|
||||
@@ -100,36 +101,24 @@ namespace OpenWifi {
|
||||
Restrictions_.from_json(RestrictionObject);
|
||||
}
|
||||
|
||||
if (Capabilities->has("developer")) {
|
||||
if (Capabilities->has("developer") && !Capabilities->isNull("developer")) {
|
||||
Restrictions_.developer = Capabilities->getValue<bool>("developer");
|
||||
}
|
||||
|
||||
if(Capabilities->has("secure-rtty")) {
|
||||
RttyMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty");
|
||||
if (Capabilities->has("secure-rtty")) {
|
||||
RTTYMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty");
|
||||
}
|
||||
|
||||
State_.locale = FindCountryFromIP()->Get(IP);
|
||||
GWObjects::Device DeviceInfo;
|
||||
auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
|
||||
std::lock_guard DbSessionLock(DbSession_->Mutex());
|
||||
|
||||
auto DeviceExists = StorageService()->GetDevice(DbSession_->Session(), SerialNumber_, DeviceInfo);
|
||||
if (Daemon()->AutoProvisioning() && !DeviceExists) {
|
||||
// check the firmware version. if this is too old, we cannot let that device connect yet, we must
|
||||
// force a firmware upgrade
|
||||
GWObjects::DefaultFirmware MinimumFirmware;
|
||||
if(FirmwareRevisionCache()->DeviceMustUpgrade(Compatible_, Firmware, MinimumFirmware)) {
|
||||
/*
|
||||
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "upgrade" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
|
||||
"uri" : <URI to download the firmware>,
|
||||
"FWsignature" : <string representation of the signature for the FW> (optional)
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
|
||||
*/
|
||||
Poco::JSON::Object UpgradeCommand, Params;
|
||||
UpgradeCommand.set(uCentralProtocol::JSONRPC,uCentralProtocol::JSONRPC_VERSION);
|
||||
UpgradeCommand.set(uCentralProtocol::METHOD,uCentralProtocol::UPGRADE);
|
||||
@@ -157,7 +146,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
StorageService()->CreateDefaultDevice(
|
||||
StorageService()->CreateDefaultDevice( DbSession_->Session(),
|
||||
SerialNumber_, Caps, Firmware, PeerAddress_,
|
||||
State_.VerifiedCertificate == GWObjects::SIMULATED);
|
||||
}
|
||||
@@ -166,7 +155,7 @@ namespace OpenWifi {
|
||||
poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_));
|
||||
return EndConnection();
|
||||
} else if (DeviceExists) {
|
||||
StorageService()->UpdateDeviceCapabilities(SerialNumber_, Caps);
|
||||
StorageService()->UpdateDeviceCapabilities(DbSession_->Session(), SerialNumber_, Caps);
|
||||
int Updated{0};
|
||||
if (!Firmware.empty()) {
|
||||
if (Firmware != DeviceInfo.Firmware) {
|
||||
@@ -186,6 +175,12 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
if(ParamsObj->has("reason")) {
|
||||
State_.connectReason = ParamsObj->get("reason").toString();
|
||||
DeviceInfo.connectReason = State_.connectReason;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if(DeviceInfo.DevicePassword!=DevicePassword) {
|
||||
DeviceInfo.DevicePassword = DevicePassword.empty() ? "openwifi" : DevicePassword ;
|
||||
++Updated;
|
||||
@@ -211,8 +206,13 @@ namespace OpenWifi {
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (Compatible_ != DeviceInfo.DeviceType) {
|
||||
DeviceInfo.DeviceType = Compatible_;
|
||||
if (Compatible_ != DeviceInfo.Compatible) {
|
||||
DeviceInfo.Compatible = Compatible_;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (Platform != DeviceInfo.DeviceType) {
|
||||
DeviceInfo.DeviceType = Platform;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
@@ -226,13 +226,21 @@ namespace OpenWifi {
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (Updated) {
|
||||
StorageService()->UpdateDevice(DeviceInfo);
|
||||
if(DeviceInfo.certificateExpiryDate!=State_.certificateExpiryDate) {
|
||||
DeviceInfo.certificateExpiryDate = State_.certificateExpiryDate;
|
||||
++Updated;
|
||||
}
|
||||
|
||||
if (Updated) {
|
||||
StorageService()->UpdateDevice(DbSession_->Session(), DeviceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if(!Simulated_) {
|
||||
uint64_t UpgradedUUID = 0;
|
||||
LookForUpgrade(UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
if (LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID)) {
|
||||
State_.UUID = UpgradedUUID;
|
||||
}
|
||||
}
|
||||
|
||||
State_.Compatible = Compatible_;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenWifi {
|
||||
.Recorded = Utils::Now(),
|
||||
.LogType = 1,
|
||||
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace OpenWifi {
|
||||
if (ParamsObj->has("currentPassword")) {
|
||||
auto Password = ParamsObj->get("currentPassword").toString();
|
||||
|
||||
StorageService()->SetDevicePassword(Serial, Password);
|
||||
StorageService()->SetDevicePassword(*DbSession_,Serial, Password);
|
||||
poco_trace(
|
||||
Logger_,
|
||||
fmt::format("DEVICE-UPDATE({}): Device is updating its login password.", Serial));
|
||||
|
||||
@@ -34,8 +34,13 @@ namespace OpenWifi {
|
||||
FullEvent.set("type", EventType);
|
||||
FullEvent.set("timestamp", EventTimeStamp);
|
||||
FullEvent.set("payload", EventPayload);
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
|
||||
FullEvent);
|
||||
if(strncmp(EventType.c_str(),"rrm.",4) == 0 ) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::RRM, SerialNumber_,
|
||||
FullEvent);
|
||||
} else {
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
|
||||
FullEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
@@ -25,6 +26,7 @@ namespace OpenWifi {
|
||||
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
|
||||
State_.sanity = Sanity;
|
||||
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
|
||||
if (CheckData.empty())
|
||||
CheckData = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
@@ -40,10 +42,6 @@ namespace OpenWifi {
|
||||
CId_, UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
|
||||
GWObjects::HealthCheck Check;
|
||||
|
||||
Check.SerialNumber = SerialNumber_;
|
||||
@@ -52,14 +50,14 @@ namespace OpenWifi {
|
||||
Check.Data = CheckData;
|
||||
Check.Sanity = Sanity;
|
||||
|
||||
StorageService()->AddHealthCheckData(Check);
|
||||
StorageService()->AddHealthCheckData(*DbSession_, Check);
|
||||
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, CheckData);
|
||||
}
|
||||
|
||||
SetLastHealthCheck(Check);
|
||||
if (KafkaManager()->Enabled()) {
|
||||
if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableHealthChecks()) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, *ParamsObj);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenWifi {
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 0,
|
||||
.UUID = State_.UUID};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenWifi {
|
||||
.Recorded = ParamsObj->get(uCentralProtocol::DATE),
|
||||
.LogType = 2,
|
||||
.UUID = ParamsObj->get(uCentralProtocol::UUID)};
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
DeviceLogKafkaEvent E(DeviceLog);
|
||||
} else {
|
||||
poco_warning(Logger_, fmt::format("REBOOT-LOG({}): Missing parameters.", CId_));
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenWifi {
|
||||
.LogType = 1,
|
||||
.UUID = 0};
|
||||
|
||||
StorageService()->AddLog(DeviceLog);
|
||||
StorageService()->AddLog(*DbSession_, DeviceLog);
|
||||
|
||||
if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
|
||||
GWObjects::CommandDetails Cmd;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "StateUtils.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
@@ -39,23 +40,27 @@ namespace OpenWifi {
|
||||
UUID, request_uuid));
|
||||
}
|
||||
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
std::lock_guard Guard(DbSession_->Mutex());
|
||||
if(!Simulated_) {
|
||||
uint64_t UpgradedUUID;
|
||||
LookForUpgrade(DbSession_->Session(), UUID, UpgradedUUID);
|
||||
State_.UUID = UpgradedUUID;
|
||||
}
|
||||
|
||||
SetLastStats(StateStr);
|
||||
|
||||
GWObjects::Statistics Stats{
|
||||
.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
|
||||
Stats.Recorded = Utils::Now();
|
||||
StorageService()->AddStatisticsData(Stats);
|
||||
StorageService()->AddStatisticsData(DbSession_->Session(),Stats);
|
||||
if (!request_uuid.empty()) {
|
||||
StorageService()->SetCommandResult(request_uuid, StateStr);
|
||||
}
|
||||
|
||||
StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
|
||||
State_.Associations_5G, State_.Associations_6G);
|
||||
State_.Associations_5G, State_.Associations_6G, State_.uptime);
|
||||
|
||||
if (KafkaManager()->Enabled()) {
|
||||
if (KafkaManager()->Enabled() && !AP_WS_Server()->KafkaDisableState()) {
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, *ParamsObj);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@ namespace OpenWifi {
|
||||
}
|
||||
if (TelemetryWebSocketRefCount_) {
|
||||
if (now < TelemetryWebSocketTimer_) {
|
||||
// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" <<
|
||||
// std::endl;
|
||||
|
||||
TelemetryWebSocketPackets_++;
|
||||
State_.websocketPackets = TelemetryWebSocketPackets_;
|
||||
TelemetryStream()->NotifyEndPoint(SerialNumberInt_, KafkaPayload);
|
||||
@@ -46,7 +45,6 @@ namespace OpenWifi {
|
||||
}
|
||||
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_,
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit AP_WS_ReactorThreadPool() {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount() * 2;
|
||||
if (NumberOfThreads_ == 0)
|
||||
NumberOfThreads_ = 4;
|
||||
}
|
||||
|
||||
~AP_WS_ReactorThreadPool() { Stop(); }
|
||||
|
||||
void Start() {
|
||||
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
|
||||
auto NewReactor = std::make_unique<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->start(*NewReactor);
|
||||
std::string ThreadName{"ap:react:" + std::to_string(i)};
|
||||
Utils::SetThreadName(*NewThread, ThreadName.c_str());
|
||||
Reactors_.emplace_back(std::move(NewReactor));
|
||||
Threads_.emplace_back(std::move(NewThread));
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for (auto &i : Reactors_)
|
||||
i->stop();
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor &NextReactor() {
|
||||
std::shared_lock Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_mutex Mutex_;
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
|
||||
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
77
src/AP_WS_Reactor_Pool.h
Normal file
77
src/AP_WS_Reactor_Pool.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include <framework/utils.h>
|
||||
|
||||
#include <Poco/Environment.h>
|
||||
#include <Poco/Net/SocketAcceptor.h>
|
||||
#include <Poco/Data/SessionPool.h>
|
||||
|
||||
#include <StorageService.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_ReactorThreadPool {
|
||||
public:
|
||||
explicit AP_WS_ReactorThreadPool(Poco::Logger &Logger) : Logger_(Logger) {
|
||||
NumberOfThreads_ = Poco::Environment::processorCount() * 4;
|
||||
if (NumberOfThreads_ == 0)
|
||||
NumberOfThreads_ = 8;
|
||||
NumberOfThreads_ = std::min(NumberOfThreads_, (std::uint64_t) 128);
|
||||
}
|
||||
|
||||
~AP_WS_ReactorThreadPool() { Stop(); }
|
||||
|
||||
void Start() {
|
||||
Reactors_.reserve(NumberOfThreads_);
|
||||
DbSessions_.reserve(NumberOfThreads_);
|
||||
Threads_.reserve(NumberOfThreads_);
|
||||
Logger_.information(fmt::format("WebSocket Processor: starting {} threads.", NumberOfThreads_));
|
||||
for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
|
||||
auto NewReactor = std::make_shared<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->start(*NewReactor);
|
||||
std::string ThreadName{"ap:react:" + std::to_string(i)};
|
||||
Utils::SetThreadName(*NewThread, ThreadName.c_str());
|
||||
Reactors_.emplace_back(std::move(NewReactor));
|
||||
Threads_.emplace_back(std::move(NewThread));
|
||||
DbSessions_.emplace_back(std::make_shared<LockedDbSession>());
|
||||
}
|
||||
Logger_.information(fmt::format("WebSocket Processor: {} threads started.", NumberOfThreads_));
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for (auto &i : Reactors_)
|
||||
i->stop();
|
||||
for (auto &i : Threads_) {
|
||||
i->join();
|
||||
}
|
||||
Reactors_.clear();
|
||||
Threads_.clear();
|
||||
DbSessions_.clear();
|
||||
}
|
||||
|
||||
auto NextReactor() {
|
||||
std::lock_guard Lock(Mutex_);
|
||||
NextReactor_++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return std::make_pair(Reactors_[NextReactor_], DbSessions_[NextReactor_]);
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
uint64_t NumberOfThreads_;
|
||||
uint64_t NextReactor_ = 0;
|
||||
std::vector<std::shared_ptr<Poco::Net::SocketReactor>> Reactors_;
|
||||
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
|
||||
std::vector<std::shared_ptr<LockedDbSession>> DbSessions_;
|
||||
Poco::Logger &Logger_;
|
||||
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
@@ -6,45 +6,83 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include <Poco/Net/Context.h>
|
||||
#include <Poco/Net/HTTPHeaderStream.h>
|
||||
#include <Poco/Net/HTTPServerRequest.h>
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include <AP_WS_Connection.h>
|
||||
#include <AP_WS_Server.h>
|
||||
#include <ConfigurationCache.h>
|
||||
#include <TelemetryStream.h>
|
||||
|
||||
#include "UI_GW_WebSocketNotifications.h"
|
||||
#include "fmt/format.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <framework/MicroServiceFuncs.h>
|
||||
#include <framework/utils.h>
|
||||
#include <framework/KafkaManager.h>
|
||||
|
||||
#include <UI_GW_WebSocketNotifications.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");
|
||||
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t session_id) : Logger_(L),
|
||||
session_id_(session_id) {
|
||||
};
|
||||
|
||||
void handleRequest( Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override {
|
||||
try {
|
||||
auto NewConnection = std::make_shared<AP_WS_Connection>(request, response, session_id_, Logger_,
|
||||
AP_WS_Server()->NextReactor());
|
||||
AP_WS_Server()->AddConnection(NewConnection);
|
||||
NewConnection->Start();
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Exception during WS creation");
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
std::uint64_t session_id_;
|
||||
};
|
||||
|
||||
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L) : Logger_(L) {}
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *
|
||||
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
|
||||
if (request.find("Upgrade") != request.end() &&
|
||||
Poco::icompare(request["Upgrade"], "websocket") == 0) {
|
||||
Utils::SetThreadName("ws:conn-init");
|
||||
session_id_++;
|
||||
return new AP_WS_RequestHandler(Logger_, session_id_);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static std::atomic_uint64_t session_id_ = 0;
|
||||
};
|
||||
|
||||
bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
|
||||
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;
|
||||
// validate certificate agains trusted chain
|
||||
for (const auto &cert : ClientCasCerts_) {
|
||||
if (Certificate.issuedBy(cert)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
poco_warning(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"CERTIFICATE({}): issuer mismatch. Certificate not issued by any trusted CA",
|
||||
ConnectionId)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -57,7 +95,7 @@ namespace OpenWifi {
|
||||
|
||||
SessionTimeOut_ = MicroServiceConfigGetInt("openwifi.session.timeout", 10*60);
|
||||
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
|
||||
Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>(Logger());
|
||||
Reactor_pool_->Start();
|
||||
|
||||
for (const auto &Svr : ConfigServersList_) {
|
||||
@@ -82,7 +120,6 @@ namespace OpenWifi {
|
||||
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>(
|
||||
@@ -99,6 +136,13 @@ namespace OpenWifi {
|
||||
Context->addChainCertificate(Issuing);
|
||||
Context->addCertificateAuthority(Issuing);
|
||||
|
||||
// add certificates from clientcas to trust chain
|
||||
ClientCasCerts_ = Poco::Net::X509Certificate::readPEM(Svr.ClientCas());
|
||||
for (const auto &cert : ClientCasCerts_) {
|
||||
Context->addChainCertificate(cert);
|
||||
Context->addCertificateAuthority(cert);
|
||||
}
|
||||
|
||||
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
|
||||
Context->usePrivateKey(Key);
|
||||
|
||||
@@ -107,7 +151,6 @@ namespace OpenWifi {
|
||||
Context->flushSessionCache();
|
||||
Context->enableSessionCache(true);
|
||||
Context->enableExtendedCertificateVerification(false);
|
||||
// Context->disableStatelessSessionResumption();
|
||||
Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 |
|
||||
Poco::Net::Context::PROTO_TLSV1_1);
|
||||
|
||||
@@ -136,6 +179,9 @@ namespace OpenWifi {
|
||||
WebServerHttpParams);
|
||||
WebServers_.push_back(std::move(NewWebServer));
|
||||
}
|
||||
|
||||
KafkaDisableState_ = MicroServiceConfigGetBool("openwifi.kafka.disablestate", false);
|
||||
KafkaDisableHealthChecks_ = MicroServiceConfigGetBool("openwifi.kafka.disablehealthchecks", false);
|
||||
}
|
||||
|
||||
for (auto &server : WebServers_) {
|
||||
@@ -157,249 +203,420 @@ namespace OpenWifi {
|
||||
UseDefaultConfig_ = true;
|
||||
}
|
||||
|
||||
SimulatorId_ = MicroServiceConfigGetString("simulatorid", "");
|
||||
SimulatorId_ = Poco::toLower(MicroServiceConfigGetString("simulatorid", ""));
|
||||
SimulatorEnabled_ = !SimulatorId_.empty();
|
||||
Utils::SetThreadName(ReactorThread_, "dev:react:head");
|
||||
|
||||
GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(
|
||||
*this, &AP_WS_Server::onGarbageCollecting);
|
||||
Timer_.setStartInterval(10 * 1000);
|
||||
Timer_.setPeriodicInterval(10 * 1000); // every minute
|
||||
Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
|
||||
|
||||
Running_ = true;
|
||||
GarbageCollector_.setName("ws:garbage");
|
||||
GarbageCollector_.start(*this);
|
||||
|
||||
std::thread CleanupThread([this](){ CleanupSessions(); });
|
||||
CleanupThread.detach();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
|
||||
static uint64_t last_log = Utils::Now();
|
||||
auto now = Utils::Now();
|
||||
bool AP_WS_Server::Disconnect(uint64_t SerialNumber) {
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == SerialNumbers_[hashIndex].end() || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
Connection = DeviceHint->second;
|
||||
SerialNumbers_[hashIndex].erase(DeviceHint);
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
if (!Garbage_.empty()) {
|
||||
Garbage_.clear();
|
||||
auto H = SessionHash::Hash(Connection->State_.sessionId);
|
||||
std::lock_guard SessionLock(SessionMutex_[H]);
|
||||
Sessions_[H].erase(Connection->State_.sessionId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_WS_Server::CleanupSessions() {
|
||||
|
||||
while(Running_) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
|
||||
while(Running_ && !CleanupSessions_.empty()) {
|
||||
std::pair<uint64_t, uint64_t> Session;
|
||||
{
|
||||
std::lock_guard G(CleanupMutex_);
|
||||
Session = CleanupSessions_.front();
|
||||
CleanupSessions_.pop_front();
|
||||
}
|
||||
poco_trace(this->Logger(),fmt::format("Cleaning up session: {} for device: {}", Session.first, Utils::IntToSerialNumber(Session.second)));
|
||||
EndSession(Session.first, Session.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Server::run() {
|
||||
uint64_t last_log = Utils::Now(),
|
||||
last_zombie_run = 0,
|
||||
last_garbage_run = 0;
|
||||
|
||||
Poco::Logger &LocalLogger = Poco::Logger::create(
|
||||
"WS-Session-Janitor", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel());
|
||||
|
||||
while(Running_) {
|
||||
|
||||
if(!Poco::Thread::trySleep(30000)) {
|
||||
break;
|
||||
}
|
||||
|
||||
NumberOfConnectedDevices_ = 0;
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
uint64_t total_connected_time = 0;
|
||||
LocalLogger.information(fmt::format("Garbage collecting starting run." ));
|
||||
|
||||
auto hint = SerialNumbers_.begin();
|
||||
while (hint != end(SerialNumbers_)) {
|
||||
if (hint->second.second == nullptr) {
|
||||
hint = SerialNumbers_.erase(hint);
|
||||
} else if ((now - hint->second.second->State_.LastContact) > SessionTimeOut_) {
|
||||
hint->second.second->EndConnection(false);
|
||||
poco_information(Logger(),fmt::format("{}: Session seems idle. Controller disconnecting device.", hint->second.second->SerialNumber_));
|
||||
Sessions_.erase(hint->second.second->State_.sessionId);
|
||||
Garbage_.push_back(hint->second.second);
|
||||
hint = SerialNumbers_.erase(hint);
|
||||
} else if (hint->second.second->State_.Connected) {
|
||||
NumberOfConnectedDevices_++;
|
||||
total_connected_time += (now - hint->second.second->State_.started);
|
||||
hint++;
|
||||
} else {
|
||||
NumberOfConnectingDevices_++;
|
||||
hint++;
|
||||
uint64_t total_connected_time = 0, now = Utils::Now();
|
||||
|
||||
if(now-last_zombie_run > 60) {
|
||||
try {
|
||||
poco_information(LocalLogger,
|
||||
fmt::format("Garbage collecting zombies... (step 1)"));
|
||||
NumberOfConnectingDevices_ = 0;
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
int waits = 0;
|
||||
for (int hashIndex = 0; hashIndex < MACHash::HashMax(); hashIndex++) {
|
||||
last_zombie_run = now;
|
||||
waits = 0;
|
||||
while (true) {
|
||||
if (SerialNumbersMutex_[hashIndex].try_lock()) {
|
||||
waits = 0;
|
||||
auto hint = SerialNumbers_[hashIndex].begin();
|
||||
while (hint != end(SerialNumbers_[hashIndex])) {
|
||||
if (hint->second == nullptr) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("Dead device found in hash index {}", hashIndex));
|
||||
hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
} else {
|
||||
auto Device = hint->second;
|
||||
auto RightNow = Utils::Now();
|
||||
if (Device->Dead_) {
|
||||
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
|
||||
++hint;
|
||||
// hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
} else if (RightNow > Device->LastContact_ &&
|
||||
(RightNow - Device->LastContact_) > SessionTimeOut_) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format(
|
||||
"{}: Session seems idle. Controller disconnecting device.",
|
||||
Device->SerialNumber_));
|
||||
// hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
|
||||
++hint;
|
||||
} else {
|
||||
if (Device->State_.Connected) {
|
||||
total_connected_time +=
|
||||
(RightNow - Device->State_.started);
|
||||
}
|
||||
++hint;
|
||||
}
|
||||
}
|
||||
}
|
||||
SerialNumbersMutex_[hashIndex].unlock();
|
||||
break;
|
||||
} else if (waits < 5) {
|
||||
waits++;
|
||||
Poco::Thread::trySleep(10);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poco_information(LocalLogger, fmt::format("Garbage collecting zombies... (step 2)"));
|
||||
LeftOverSessions_ = 0;
|
||||
for (int i = 0; i < SessionHash::HashMax(); i++) {
|
||||
waits = 0;
|
||||
while (true) {
|
||||
if (SessionMutex_[i].try_lock()) {
|
||||
waits = 0;
|
||||
auto hint = Sessions_[i].begin();
|
||||
auto RightNow = Utils::Now();
|
||||
while (hint != end(Sessions_[i])) {
|
||||
if (hint->second == nullptr) {
|
||||
hint = Sessions_[i].erase(hint);
|
||||
} else if (hint->second->Dead_) {
|
||||
// hint = Sessions_[i].erase(hint);
|
||||
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
|
||||
++hint;
|
||||
} else if (RightNow > hint->second->LastContact_ &&
|
||||
(RightNow - hint->second->LastContact_) >
|
||||
SessionTimeOut_) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("{}: Session seems idle. Controller disconnecting device.",
|
||||
hint->second->SerialNumber_));
|
||||
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
|
||||
++hint;
|
||||
// hint = Sessions_[i].erase(hint);
|
||||
} else {
|
||||
++LeftOverSessions_;
|
||||
++hint;
|
||||
}
|
||||
}
|
||||
SessionMutex_[i].unlock();
|
||||
break;
|
||||
} else if (waits < 5) {
|
||||
Poco::Thread::trySleep(10);
|
||||
waits++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ = NumberOfConnectedDevices_ > 0
|
||||
? total_connected_time / NumberOfConnectedDevices_
|
||||
: 0;
|
||||
poco_information(LocalLogger, fmt::format("Garbage collecting zombies done..."));
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(LocalLogger, fmt::format("Poco::Exception: Garbage collecting zombies failed: {}", E.displayText()));
|
||||
} catch (const std::exception &E) {
|
||||
poco_error(LocalLogger, fmt::format("std::exception: Garbage collecting zombies failed: {}", E.what()));
|
||||
} catch (...) {
|
||||
poco_error(LocalLogger, fmt::format("exception:Garbage collecting zombies failed: {}", "unknown"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(NumberOfConnectedDevices_) {
|
||||
if (last_garbage_run > 0) {
|
||||
AverageDeviceConnectionTime_ += (now - last_garbage_run);
|
||||
}
|
||||
}
|
||||
|
||||
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_));
|
||||
try {
|
||||
if ((now - last_log) > 60) {
|
||||
last_log = now;
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds. Left Over Sessions: {}",
|
||||
NumberOfConnectedDevices_, NumberOfConnectingDevices_,
|
||||
AverageDeviceConnectionTime_, LeftOverSessions_));
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::NumberOfConnection_t Notification;
|
||||
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
|
||||
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
|
||||
GetTotalDataStatistics(Notification.content.tx, Notification.content.rx);
|
||||
GWWebSocketNotifications::NumberOfConnections(Notification);
|
||||
|
||||
Poco::JSON::Object KafkaNotification;
|
||||
Notification.to_json(KafkaNotification);
|
||||
|
||||
Poco::JSON::Object FullEvent;
|
||||
FullEvent.set("type", "load-update");
|
||||
FullEvent.set("timestamp", now);
|
||||
FullEvent.set("payload", KafkaNotification);
|
||||
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
|
||||
LocalLogger.information(fmt::format("Garbage collection finished run."));
|
||||
last_garbage_run = now;
|
||||
} catch (const Poco::Exception &E) {
|
||||
LocalLogger.error(fmt::format("Poco::Exception: Garbage collecting failed: {}", E.displayText()));
|
||||
} catch (const std::exception &E) {
|
||||
LocalLogger.error(fmt::format("std::exception: Garbage collecting failed: {}", E.what()));
|
||||
} catch (...) {
|
||||
LocalLogger.error(fmt::format("exception:Garbage collecting failed: {}", "unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
GWWebSocketNotifications::NumberOfConnection_t Notification;
|
||||
Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
Notification.content.numberOfDevices = NumberOfConnectedDevices_;
|
||||
Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
|
||||
GetTotalDataStatistics(Notification.content.tx,Notification.content.rx);
|
||||
GWWebSocketNotifications::NumberOfConnections(Notification);
|
||||
|
||||
Poco::JSON::Object KafkaNotification;
|
||||
Notification.to_json(KafkaNotification);
|
||||
|
||||
Poco::JSON::Object FullEvent;
|
||||
FullEvent.set("type", "load-update");
|
||||
FullEvent.set("timestamp", now);
|
||||
FullEvent.set("payload", KafkaNotification);
|
||||
|
||||
KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
|
||||
LocalLogger.information(fmt::format("Garbage collector done for the day." ));
|
||||
}
|
||||
|
||||
void AP_WS_Server::Stop() {
|
||||
poco_information(Logger(), "Stopping...");
|
||||
Running_ = false;
|
||||
|
||||
Timer_.stop();
|
||||
GarbageCollector_.wakeUp();
|
||||
GarbageCollector_.join();
|
||||
|
||||
for (auto &server : WebServers_) {
|
||||
server->stopAll();
|
||||
}
|
||||
|
||||
Reactor_pool_->Stop();
|
||||
Reactor_.stop();
|
||||
ReactorThread_.join();
|
||||
poco_information(Logger(), "Stopped...");
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
|
||||
SerialNumbers.clear();
|
||||
for(int i=0;i<SessionHash::HashMax();i++) {
|
||||
std::lock_guard Lock(SessionMutex_[i]);
|
||||
for (const auto &connection : Sessions_[i]) {
|
||||
if (connection.second->RawLastHealthcheck_.Sanity >= lowLimit &&
|
||||
connection.second->RawLastHealthcheck_.Sanity <= highLimit) {
|
||||
SerialNumbers.push_back(connection.second->SerialNumber_);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == SerialNumbers_[hashIndex].end() || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->GetLastStats(Statistics);
|
||||
Connection->GetLastStats(Statistics);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == SerialNumbers_[hashIndex].end() ||
|
||||
DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->GetState(State);
|
||||
Connection->GetState(State);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber,
|
||||
GWObjects::HealthCheck &CheckData) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (Device == SerialNumbers_[hashIndex].end() || Device->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = Device->second;
|
||||
}
|
||||
Connection->GetLastHealthCheck(CheckData);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void AP_WS_Server::StartSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
auto sessionHash = SessionHash::Hash(session_id);
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
||||
auto SessionHint = Sessions_[sessionHash].find(session_id);
|
||||
if (SessionHint == end(Sessions_[sessionHash])) {
|
||||
return;
|
||||
}
|
||||
Connection = SessionHint->second;
|
||||
Sessions_[sessionHash].erase(SessionHint);
|
||||
}
|
||||
|
||||
auto deviceHash = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[deviceHash]);
|
||||
SerialNumbers_[deviceHash][SerialNumber] = Connection;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
{
|
||||
poco_trace(Logger(), fmt::format("Ending session 1: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
|
||||
auto sessionHash = SessionHash::Hash(session_id);
|
||||
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
||||
Sessions_[sessionHash].erase(session_id);
|
||||
poco_trace(Logger(), fmt::format("Ended session 1: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
|
||||
}
|
||||
|
||||
{
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
poco_trace(Logger(), fmt::format("Ending session 2.0: {} for device: {} hi:{}", session_id, Utils::IntToSerialNumber(SerialNumber), hashIndex));
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
poco_trace(Logger(), fmt::format("Ending session 2.1: {} for device: {} hi:{}", session_id, Utils::IntToSerialNumber(SerialNumber), hashIndex));
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
poco_trace(Logger(), fmt::format("Ending session 2.2: {} for device: {} hi:{}", session_id, Utils::IntToSerialNumber(SerialNumber), hashIndex));
|
||||
if (DeviceHint == SerialNumbers_[hashIndex].end()
|
||||
|| DeviceHint->second == nullptr
|
||||
|| DeviceHint->second->State_.sessionId != session_id) {
|
||||
poco_trace(Logger(), fmt::format("Did not end session 2: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
|
||||
return false;
|
||||
}
|
||||
SerialNumbers_[hashIndex].erase(DeviceHint);
|
||||
poco_trace(Logger(), fmt::format("Ended session 2: {} for device: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
|
||||
}
|
||||
DevicePtr->GetLastHealthCheck(CheckData);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Conn = Sessions_.find(connection_id);
|
||||
if (Conn == end(Sessions_))
|
||||
return;
|
||||
|
||||
auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
|
||||
if ((CurrentSerialNumber == SerialNumbers_.end()) ||
|
||||
(CurrentSerialNumber->second.first < connection_id)) {
|
||||
SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t serial_number) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
|
||||
auto Session = Sessions_.find(session_id);
|
||||
if (Session == end(Sessions_))
|
||||
return false;
|
||||
|
||||
Garbage_.push_back(Session->second);
|
||||
|
||||
auto Device = SerialNumbers_.find(serial_number);
|
||||
if (Device == end(SerialNumbers_)) {
|
||||
Sessions_.erase(Session);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Device->second.first == session_id) {
|
||||
Sessions_.erase(Session);
|
||||
SerialNumbers_.erase(Device);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sessions_.erase(Session);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSessionUnSafe(uint64_t session_id, uint64_t serial_number) {
|
||||
|
||||
auto Session = Sessions_.find(session_id);
|
||||
if (Session == end(Sessions_))
|
||||
return false;
|
||||
|
||||
Garbage_.push_back(Session->second);
|
||||
|
||||
auto Device = SerialNumbers_.find(serial_number);
|
||||
if (Device == end(SerialNumbers_)) {
|
||||
Sessions_.erase(Session);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Device->second.first == session_id) {
|
||||
Sessions_.erase(Session);
|
||||
SerialNumbers_.erase(Device);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sessions_.erase(Session);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::Connected(uint64_t SerialNumber,
|
||||
GWObjects::DeviceRestrictions &Restrictions) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->GetRestrictions(Restrictions);
|
||||
return DevicePtr->State_.Connected;
|
||||
|
||||
if(Connection->Dead_) {
|
||||
return false;
|
||||
}
|
||||
Restrictions = Connection->GetRestrictions();
|
||||
return Connection->State_.Connected;
|
||||
}
|
||||
|
||||
|
||||
bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
return DevicePtr->State_.Connected;
|
||||
|
||||
if(Connection->Dead_) {
|
||||
return false;
|
||||
}
|
||||
return Connection->State_.Connected;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
|
||||
if(Connection->Dead_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->Send(Payload);
|
||||
return Connection->Send(Payload);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'",
|
||||
Utils::IntToSerialNumber(SerialNumber)));
|
||||
@@ -408,61 +625,64 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_[hashIndex]) || Device->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = Device->second;
|
||||
}
|
||||
DevicePtr->StopWebSocketTelemetry(RPCID);
|
||||
Connection->StopWebSocketTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void
|
||||
AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
|
||||
uint64_t Interval, uint64_t Lifetime,
|
||||
const std::vector<std::string> &TelemetryTypes) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
Connection->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
}
|
||||
|
||||
void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
|
||||
uint64_t Interval, uint64_t Lifetime,
|
||||
const std::vector<std::string> &TelemetryTypes) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
Connection->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
|
||||
}
|
||||
|
||||
void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->StopKafkaTelemetry(RPCID);
|
||||
Connection->StopKafkaTelemetry(RPCID);
|
||||
}
|
||||
|
||||
void AP_WS_Server::GetTelemetryParameters(
|
||||
@@ -470,16 +690,19 @@ namespace OpenWifi {
|
||||
uint64_t &TelemetryWebSocketTimer, uint64_t &TelemetryKafkaTimer,
|
||||
uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount,
|
||||
uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(SerialNumber);
|
||||
if (Device == end(SerialNumbers_) || Device->second.second == nullptr) {
|
||||
auto hashIndex = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
DevicePtr->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
|
||||
|
||||
Connection->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
|
||||
TelemetryWebSocketTimer, TelemetryKafkaTimer,
|
||||
TelemetryWebSocketCount, TelemetryKafkaCount,
|
||||
TelemetryWebSocketPackets, TelemetryKafkaPackets);
|
||||
@@ -487,18 +710,25 @@ namespace OpenWifi {
|
||||
|
||||
bool AP_WS_Server::SendRadiusAccountingData(const std::string &SerialNumber,
|
||||
const unsigned char *buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
|
||||
auto hashIndex = MACHash::Hash(IntSerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
|
||||
if(Connection->Dead_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->SendRadiusAccountingData(buffer, size);
|
||||
return Connection->SendRadiusAccountingData(buffer, size);
|
||||
} catch (...) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
@@ -510,18 +740,24 @@ namespace OpenWifi {
|
||||
|
||||
bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber,
|
||||
const unsigned char *buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
|
||||
auto hashIndex = MACHash::Hash(IntSerialNumber);
|
||||
std::lock_guard DevicesLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
|
||||
if(Connection->Dead_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return DevicePtr->SendRadiusAuthenticationData(buffer, size);
|
||||
return Connection->SendRadiusAuthenticationData(buffer, size);
|
||||
} catch (...) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
@@ -533,18 +769,23 @@ namespace OpenWifi {
|
||||
|
||||
bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber,
|
||||
const unsigned char *buffer, std::size_t size) {
|
||||
std::shared_ptr<AP_WS_Connection> DevicePtr;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
auto Device = SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
|
||||
if (Device == SerialNumbers_.end() || Device->second.second == nullptr) {
|
||||
auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
|
||||
auto hashIndex = MACHash::Hash(IntSerialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(IntSerialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr) {
|
||||
return false;
|
||||
}
|
||||
DevicePtr = Device->second.second;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
|
||||
if(Connection->Dead_) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return DevicePtr->SendRadiusCoAData(buffer, size);
|
||||
return Connection->SendRadiusCoAData(buffer, size);
|
||||
} catch (...) {
|
||||
poco_debug(Logger(),
|
||||
fmt::format(": SendRadiusCoAData: Could not send data to device '{}'",
|
||||
@@ -553,4 +794,4 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -24,46 +24,51 @@
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
#include "AP_WS_Connection.h"
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
#include "AP_WS_Reactor_Pool.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
constexpr uint MACHashMax = 256;
|
||||
constexpr uint MACHashMask = MACHashMax-1;
|
||||
class MACHash {
|
||||
public:
|
||||
explicit AP_WS_RequestHandler(Poco::Logger &L, uint64_t id) : Logger_(L), id_(id){};
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
uint64_t id_ = 0;
|
||||
};
|
||||
|
||||
class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L) : Logger_(L) {}
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *
|
||||
createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
|
||||
if (request.find("Upgrade") != request.end() &&
|
||||
Poco::icompare(request["Upgrade"], "websocket") == 0) {
|
||||
Utils::SetThreadName("ws:conn-init");
|
||||
return new AP_WS_RequestHandler(Logger_, id_++);
|
||||
} else {
|
||||
return nullptr;
|
||||
[[nodiscard]] static inline uint16_t Hash(std::uint64_t value) {
|
||||
uint8_t hash = 0, i=6;
|
||||
while(i) {
|
||||
hash ^= (value & MACHashMask) + 1;
|
||||
value >>= 8;
|
||||
--i;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static uint64_t id_ = 1;
|
||||
[[nodiscard]] static inline uint16_t Hash(const std::string & value) {
|
||||
return Hash(Utils::MACToInt(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline uint16_t HashMax() {
|
||||
return MACHashMax;
|
||||
}
|
||||
};
|
||||
|
||||
class AP_WS_Server : public SubSystemServer {
|
||||
constexpr uint SessionHashMax = 256;
|
||||
constexpr uint SessionHashMask = SessionHashMax-1;
|
||||
class SessionHash {
|
||||
public:
|
||||
[[nodiscard]] static inline uint16_t Hash(std::uint64_t value) {
|
||||
return (value & SessionHashMask);
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline uint16_t HashMax() {
|
||||
return SessionHashMax;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class AP_WS_Server : public SubSystemServer, public Poco::Runnable {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new AP_WS_Server;
|
||||
@@ -75,59 +80,52 @@ namespace OpenWifi {
|
||||
bool IsCertOk() { return IssuerCert_ != nullptr; }
|
||||
bool ValidateCertificate(const std::string &ConnectionId,
|
||||
const Poco::Crypto::X509Certificate &Certificate);
|
||||
// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
|
||||
|
||||
inline bool IsSimSerialNumber(const std::string &SerialNumber) const {
|
||||
return IsSim(Poco::toLower(SerialNumber)) &&
|
||||
Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
|
||||
return IsSim(SerialNumber) &&
|
||||
SerialNumber == SimulatorId_;
|
||||
}
|
||||
|
||||
inline static bool IsSim(const std::string &SerialNumber) {
|
||||
return SerialNumber.substr(0, 6) == "53494d";
|
||||
}
|
||||
|
||||
inline bool IsSimEnabled() const { return SimulatorEnabled_; }
|
||||
|
||||
inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; }
|
||||
|
||||
inline uint64_t MismatchDepth() const { return MismatchDepth_; }
|
||||
|
||||
inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
|
||||
[[nodiscard]] inline Poco::Net::SocketReactor &NextReactor() {
|
||||
void run() override; // Garbage collector thread.
|
||||
[[nodiscard]] inline bool IsSimEnabled() const { return SimulatorEnabled_; }
|
||||
[[nodiscard]] inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; }
|
||||
[[nodiscard]] inline uint64_t MismatchDepth() const { return MismatchDepth_; }
|
||||
[[nodiscard]] inline bool UseProvisioning() const { return LookAtProvisioning_; }
|
||||
[[nodiscard]] inline bool UseDefaults() const { return UseDefaultConfig_; }
|
||||
[[nodiscard]] inline bool Running() const { return Running_; }
|
||||
[[nodiscard]] inline std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> NextReactor() {
|
||||
return Reactor_pool_->NextReactor();
|
||||
}
|
||||
[[nodiscard]] inline bool Running() const { return Running_; }
|
||||
|
||||
inline void AddConnection(uint64_t session_id,
|
||||
std::shared_ptr<AP_WS_Connection> Connection) {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
Sessions_[session_id] = std::move(Connection);
|
||||
inline void AddConnection(std::shared_ptr<AP_WS_Connection> Connection) {
|
||||
std::uint64_t sessionHash = SessionHash::Hash(Connection->State_.sessionId);
|
||||
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
||||
if(Sessions_[sessionHash].find(Connection->State_.sessionId)==end(Sessions_[sessionHash])) {
|
||||
Sessions_[sessionHash][Connection->State_.sessionId] = std::move(Connection);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::shared_ptr<AP_WS_Connection> FindConnection(uint64_t session_id) const {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Connection = Sessions_.find(session_id);
|
||||
if (Connection != end(Sessions_))
|
||||
return Connection->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const {
|
||||
std::lock_guard Lock(WSServerMutex_);
|
||||
|
||||
auto Connection = SerialNumbers_.find(serialNumber);
|
||||
if (Connection==end(SerialNumbers_) || Connection->second.second==nullptr)
|
||||
return false;
|
||||
return Connection->second.second->RttyMustBeSecure_;
|
||||
[[nodiscard]] inline bool DeviceRequiresSecureRTTY(uint64_t serialNumber) const {
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
auto hashIndex = MACHash::Hash(serialNumber);
|
||||
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
|
||||
auto DeviceHint = SerialNumbers_[hashIndex].find(serialNumber);
|
||||
if (DeviceHint == end(SerialNumbers_[hashIndex]) || DeviceHint->second == nullptr)
|
||||
return false;
|
||||
Connection = DeviceHint->second;
|
||||
}
|
||||
return Connection->RTTYMustBeSecure_;
|
||||
}
|
||||
|
||||
inline bool GetStatistics(const std::string &SerialNumber, std::string &Statistics) const {
|
||||
return GetStatistics(Utils::SerialNumberToInt(SerialNumber), Statistics);
|
||||
}
|
||||
bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const;
|
||||
[[nodiscard]] bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const;
|
||||
|
||||
inline bool GetState(const std::string &SerialNumber,
|
||||
GWObjects::ConnectionState &State) const {
|
||||
@@ -143,13 +141,8 @@ namespace OpenWifi {
|
||||
|
||||
bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const;
|
||||
bool Connected(uint64_t SerialNumber) const;
|
||||
|
||||
inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const {
|
||||
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
|
||||
}
|
||||
|
||||
bool Disconnect(uint64_t SerialNumber);
|
||||
bool SendFrame(uint64_t SerialNumber, const std::string &Payload) const;
|
||||
|
||||
bool SendRadiusAuthenticationData(const std::string &SerialNumber,
|
||||
const unsigned char *buffer, std::size_t size);
|
||||
bool SendRadiusAccountingData(const std::string &SerialNumber, const unsigned char *buffer,
|
||||
@@ -157,9 +150,8 @@ namespace OpenWifi {
|
||||
bool SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer,
|
||||
std::size_t size);
|
||||
|
||||
void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
|
||||
bool EndSession(uint64_t connection_id, uint64_t serial_number);
|
||||
bool EndSessionUnSafe(uint64_t session_id, uint64_t serial_number);
|
||||
void StartSession(uint64_t session_id, uint64_t SerialNumber);
|
||||
bool EndSession(uint64_t session_id, uint64_t SerialNumber);
|
||||
void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
|
||||
uint64_t Interval, uint64_t Lifetime,
|
||||
const std::vector<std::string> &TelemetryTypes);
|
||||
@@ -176,7 +168,9 @@ namespace OpenWifi {
|
||||
uint64_t &TelemetryWebSocketPackets,
|
||||
uint64_t &TelemetryKafkaPackets);
|
||||
|
||||
void onGarbageCollecting(Poco::Timer &timer);
|
||||
bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers);
|
||||
// bool ExtendedAttributes(const std::string &serialNumber, bool & hasGPS, std::uint64_t &Sanity,
|
||||
// std::double_t &MemoryUsed, std::double_t &Load, std::double_t &Temperature);
|
||||
|
||||
inline void AverageDeviceStatistics(uint64_t &Connections, uint64_t &AverageConnectionTime,
|
||||
uint64_t &NumberOfConnectingDevices) const {
|
||||
@@ -185,84 +179,81 @@ namespace OpenWifi {
|
||||
NumberOfConnectingDevices = NumberOfConnectingDevices_;
|
||||
}
|
||||
|
||||
inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const {
|
||||
return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
|
||||
}
|
||||
|
||||
inline void AddRX(std::uint64_t bytes) {
|
||||
std::lock_guard G(StatsMutex_);
|
||||
RX_ += bytes;
|
||||
}
|
||||
|
||||
inline void AddTX(std::uint64_t bytes) {
|
||||
std::lock_guard G(StatsMutex_);
|
||||
TX_ += bytes;
|
||||
}
|
||||
|
||||
inline void GetTotalDataStatistics(std::uint64_t &TX, std::uint64_t &RX) const {
|
||||
std::lock_guard G(StatsMutex_);
|
||||
TX = TX_;
|
||||
RX = RX_;
|
||||
}
|
||||
|
||||
inline bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t highLimit, std::vector<std::string> & SerialNumbers) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
bool KafkaDisableState() const { return KafkaDisableState_; }
|
||||
bool KafkaDisableHealthChecks() const { return KafkaDisableHealthChecks_; }
|
||||
|
||||
for(const auto &connection:Sessions_) {
|
||||
if( connection.second->RawLastHealthcheck_.Sanity>=lowLimit &&
|
||||
connection.second->RawLastHealthcheck_.Sanity<=highLimit) {
|
||||
SerialNumbers.push_back(connection.second->SerialNumber_);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
inline void IncrementConnectionCount() {
|
||||
++NumberOfConnectedDevices_;
|
||||
}
|
||||
|
||||
inline bool ExtendedAttributes(const std::string &serialNumber,
|
||||
bool & hasGPS,
|
||||
std::uint64_t &Sanity,
|
||||
std::double_t &MemoryUsed,
|
||||
std::double_t &Load,
|
||||
std::double_t &Temperature
|
||||
) {
|
||||
std::lock_guard G(WSServerMutex_);
|
||||
auto session_hint = SerialNumbers_.find(Utils::SerialNumberToInt(serialNumber));
|
||||
if(session_hint==end(SerialNumbers_)) {
|
||||
return false;
|
||||
}
|
||||
hasGPS = session_hint->second.second->hasGPS;
|
||||
Sanity = session_hint->second.second->RawLastHealthcheck_.Sanity;
|
||||
MemoryUsed = session_hint->second.second->memory_used_;
|
||||
Load = session_hint->second.second->cpu_load_;
|
||||
Temperature = session_hint->second.second->temperature_;
|
||||
return true;
|
||||
inline void DecrementConnectionCount() {
|
||||
--NumberOfConnectedDevices_;
|
||||
}
|
||||
|
||||
inline void AddCleanupSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
std::lock_guard G(CleanupMutex_);
|
||||
CleanupSessions_.emplace_back(session_id, SerialNumber);
|
||||
}
|
||||
|
||||
void CleanupSessions();
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex WSServerMutex_;
|
||||
std::array<std::mutex,SessionHashMax> SessionMutex_;
|
||||
std::array<std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>>,SessionHashMax> Sessions_;
|
||||
using SerialNumberMap = std::map<uint64_t /* serial number */,
|
||||
std::shared_ptr<AP_WS_Connection>>;
|
||||
std::array<SerialNumberMap,MACHashMax> SerialNumbers_;
|
||||
mutable std::array<std::mutex,MACHashMax> SerialNumbersMutex_;
|
||||
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
std::vector<Poco::Crypto::X509Certificate> ClientCasCerts_;
|
||||
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
|
||||
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
|
||||
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;
|
||||
bool AllowSerialNumberMismatch_ = true;
|
||||
|
||||
Poco::Thread CleanupThread_;
|
||||
std::mutex CleanupMutex_;
|
||||
std::deque<std::pair<uint64_t, uint64_t>> CleanupSessions_;
|
||||
|
||||
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
|
||||
std::atomic_bool Running_ = false;
|
||||
std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Sessions_;
|
||||
std::map<uint64_t, std::pair<uint64_t, std::shared_ptr<AP_WS_Connection>>> SerialNumbers_;
|
||||
std::atomic_bool AllowSerialNumberMismatch_ = true;
|
||||
std::atomic_uint64_t MismatchDepth_ = 2;
|
||||
|
||||
std::uint64_t NumberOfConnectedDevices_ = 0;
|
||||
std::uint64_t AverageDeviceConnectionTime_ = 0;
|
||||
std::uint64_t MismatchDepth_ = 2;
|
||||
|
||||
std::atomic_uint64_t NumberOfConnectedDevices_ = 0;
|
||||
std::atomic_uint64_t AverageDeviceConnectionTime_ = 0;
|
||||
std::uint64_t NumberOfConnectingDevices_ = 0;
|
||||
std::uint64_t SessionTimeOut_ = 10*60;
|
||||
mutable std::mutex StatsMutex_;
|
||||
std::uint64_t LeftOverSessions_ = 0;
|
||||
std::atomic_uint64_t TX_=0,RX_=0;
|
||||
|
||||
std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;
|
||||
std::atomic_bool KafkaDisableState_=false,
|
||||
KafkaDisableHealthChecks_=false;
|
||||
|
||||
std::unique_ptr<Poco::TimerCallback<AP_WS_Server>> GarbageCollectorCallback_;
|
||||
Poco::Timer Timer_;
|
||||
Poco::Thread GarbageCollector_;
|
||||
Poco::Thread GarbageCollector_;
|
||||
|
||||
AP_WS_Server() noexcept
|
||||
: SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
#include "CentralConfig.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
@@ -34,7 +35,7 @@ namespace OpenWifi {
|
||||
std::lock_guard G(Mutex_);
|
||||
if (!PlatformsLoaded_)
|
||||
LoadPlatforms();
|
||||
auto P = Poco::toUpper(Caps.Platform());
|
||||
auto P = Poco::toLower(Caps.Platform());
|
||||
auto Hint = Platforms_.find(Caps.Compatible());
|
||||
if (Hint == Platforms_.end()) {
|
||||
Platforms_.insert(std::make_pair(Caps.Compatible(), P));
|
||||
@@ -68,7 +69,7 @@ namespace OpenWifi {
|
||||
|
||||
auto Hint = Platforms_.find(DeviceType);
|
||||
if (Hint == Platforms_.end())
|
||||
return "AP";
|
||||
return Platforms::AP;
|
||||
return Hint->second;
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ namespace OpenWifi {
|
||||
i >> cache;
|
||||
|
||||
for (const auto &[Type, Platform] : cache.items()) {
|
||||
Platforms_[Type] = Platform;
|
||||
Platforms_[Type] = Poco::toLower(Platform.get<std::string>());
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
@@ -204,6 +204,17 @@ namespace OpenWifi::Config {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::uint64_t Config::UUID() {
|
||||
try {
|
||||
Poco::JSON::Parser Parser;
|
||||
auto object = Parser.parse(Config_).extract<Poco::JSON::Object::Ptr>();
|
||||
if (object->has("uuid"))
|
||||
return object->get("uuid");
|
||||
} catch (...) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Config::Valid() {
|
||||
try {
|
||||
Poco::JSON::Parser Parser;
|
||||
@@ -254,7 +265,11 @@ namespace OpenWifi::Config {
|
||||
Model_ = Caps->get("model").toString();
|
||||
|
||||
if (Caps->has("platform"))
|
||||
Platform_ = Caps->get("platform").toString();
|
||||
Platform_ = Poco::toLower(Caps->get("platform").toString());
|
||||
|
||||
if(Compatible_.empty()) {
|
||||
Compatible_ = Model_;
|
||||
}
|
||||
|
||||
std::ostringstream OS;
|
||||
Caps->stringify(OS);
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace OpenWifi::Config {
|
||||
[[nodiscard]] std::string get() { return Config_; };
|
||||
[[nodiscard]] std::string Default();
|
||||
[[nodiscard]] Poco::JSON::Object::Ptr to_json();
|
||||
[[nodiscard]] std::uint64_t UUID();
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
@@ -45,11 +45,9 @@ namespace OpenWifi {
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
auto RPC = OutStandingRequests_.find(ID);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
poco_debug(Logger(), fmt::format("({}): RPC {} cannot be found.",
|
||||
SerialNumberStr, ID));
|
||||
} else if (RPC->second.SerialNumber != Resp->SerialNumber_) {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format("({}): RPC {} serial number mismatch {}!={}.",
|
||||
@@ -60,7 +58,6 @@ namespace OpenWifi {
|
||||
std::chrono::duration<double, std::milli> rpc_execution_time =
|
||||
std::chrono::high_resolution_clock::now() -
|
||||
RPC->second.submitted;
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
poco_debug(Logger(),
|
||||
fmt::format("({}): Received RPC answer {}. Command={}",
|
||||
SerialNumberStr, ID,
|
||||
@@ -140,7 +137,6 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
Command.State = 0;
|
||||
|
||||
@@ -163,7 +159,6 @@ namespace OpenWifi {
|
||||
if (Command.rpc_entry) {
|
||||
TmpRpcEntry = Command.rpc_entry;
|
||||
}
|
||||
// std::cout << __LINE__ << " State=" << Command.State << std::endl;
|
||||
if (Command.State == 2) {
|
||||
// look at the payload to see if we should continue or not...
|
||||
if (Payload->has("result")) {
|
||||
@@ -173,12 +168,10 @@ namespace OpenWifi {
|
||||
|
||||
std::uint64_t Error = Status->get("error");
|
||||
if (Error == 0) {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
StorageService()->CommandCompleted(Command.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
Command.State = 1;
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
StorageService()->CommandCompleted(Command.UUID, Payload,
|
||||
rpc_execution_time, true);
|
||||
std::string ErrorTxt = Status->get("result");
|
||||
@@ -186,14 +179,11 @@ namespace OpenWifi {
|
||||
Command.State = 0;
|
||||
}
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
} else {
|
||||
// std::cout << __LINE__ << std::endl;
|
||||
Command.State = 0;
|
||||
}
|
||||
} else if (Command.State == 1) {
|
||||
// std::cout << "Completing script 2 phase commit." << std::endl;
|
||||
StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true);
|
||||
if (Command.Deferred) {
|
||||
Reply = false;
|
||||
@@ -202,7 +192,6 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if (Command.State == 0) {
|
||||
// std::cout << __LINE__ << " State=" << Command.State << std::endl;
|
||||
OutStandingRequests_.erase(Command.Id);
|
||||
}
|
||||
if (Reply && TmpRpcEntry != nullptr)
|
||||
@@ -262,8 +251,6 @@ namespace OpenWifi {
|
||||
for (auto request = OutStandingRequests_.begin(); request != OutStandingRequests_.end();) {
|
||||
std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
|
||||
if (delta > 10min) {
|
||||
// std::cout << __LINE__ << " -->> " << request->second.Id <<
|
||||
// std::endl;
|
||||
MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.", request->second.UUID,
|
||||
APCommands::to_string(request->second.Command),
|
||||
Utils::IntToSerialNumber(request->second.SerialNumber)));
|
||||
@@ -275,8 +262,6 @@ namespace OpenWifi {
|
||||
StorageService()->SetCommandTimedOut(request->second.UUID);
|
||||
request = OutStandingRequests_.erase(request);
|
||||
} else {
|
||||
// std::cout << __LINE__ << " -->> " << request->second.Id <<
|
||||
// std::endl;
|
||||
++request;
|
||||
}
|
||||
}
|
||||
@@ -467,4 +452,16 @@ namespace OpenWifi {
|
||||
poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CommandManager::FireAndForget(const std::string &SerialNumber, const std::string &Method, const Poco::JSON::Object &Params) {
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, 0);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
std::stringstream ToSend;
|
||||
CompleteRPC.stringify(ToSend);
|
||||
poco_debug(Logger(), fmt::format("{}: Fire and forget command {}.", SerialNumber, Method));
|
||||
return AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())>0;
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
@@ -162,8 +162,10 @@ namespace OpenWifi {
|
||||
inline auto CommandTimeout() const { return commandTimeOut_; }
|
||||
inline auto CommandRetry() const { return commandRetry_; }
|
||||
|
||||
bool FireAndForget(const std::string &SerialNumber, const std::string &Method,
|
||||
const Poco::JSON::Object &Params);
|
||||
private:
|
||||
mutable std::recursive_mutex LocalMutex_;
|
||||
mutable std::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..
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
namespace OpenWifi {
|
||||
class ConfigurationCache {
|
||||
public:
|
||||
static ConfigurationCache &instance() {
|
||||
static ConfigurationCache instance;
|
||||
static auto instance() {
|
||||
static auto instance = new ConfigurationCache;
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline uint64_t CurrentConfig(uint64_t SerialNumber) {
|
||||
inline uint64_t GetCurrentConfig(std::uint64_t SerialNumber) {
|
||||
std::lock_guard G(Mutex_);
|
||||
const auto Hint = Cache_.find(SerialNumber);
|
||||
if (Hint == end(Cache_))
|
||||
@@ -24,25 +24,25 @@ namespace OpenWifi {
|
||||
return Hint->second;
|
||||
}
|
||||
|
||||
inline void Add(uint64_t SerialNumber, uint64_t Id) {
|
||||
inline void SetCurrentConfig(std::uint64_t SerialNumber, uint64_t Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Cache_[SerialNumber] = Id;
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
std::mutex Mutex_;
|
||||
std::map<uint64_t, uint64_t> Cache_;
|
||||
};
|
||||
|
||||
inline uint64_t GetCurrentConfigurationID(uint64_t SerialNumber) {
|
||||
return ConfigurationCache::instance().CurrentConfig(SerialNumber);
|
||||
inline auto GetCurrentConfigurationID(std::uint64_t SerialNumber) {
|
||||
return ConfigurationCache::instance()->GetCurrentConfig(SerialNumber);
|
||||
}
|
||||
|
||||
inline void SetCurrentConfigurationID(const std::string &SerialNumber, uint64_t ID) {
|
||||
return ConfigurationCache::instance().Add(Utils::SerialNumberToInt(SerialNumber), ID);
|
||||
inline void SetCurrentConfigurationID(const std::string &SerialNumber, std::uint64_t ID) {
|
||||
return ConfigurationCache::instance()->SetCurrentConfig(Utils::SerialNumberToInt(SerialNumber), ID);
|
||||
}
|
||||
|
||||
inline void SetCurrentConfigurationID(uint64_t SerialNumber, uint64_t ID) {
|
||||
return ConfigurationCache::instance().Add(SerialNumber, ID);
|
||||
inline void SetCurrentConfigurationID(uint64_t SerialNumber, std::uint64_t ID) {
|
||||
return ConfigurationCache::instance()->SetCurrentConfig(SerialNumber, ID);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace OpenWifi {
|
||||
SignatureManager(), AP_WS_Server(),
|
||||
RegulatoryInfo(),
|
||||
RADIUSSessionTracker(),
|
||||
AP_WS_ConfigAutoUpgrader(),
|
||||
AP_WS_ConfigAutoUpgradeAgent(),
|
||||
FirmwareRevisionCache()
|
||||
});
|
||||
return &instance;
|
||||
@@ -78,7 +78,7 @@ namespace OpenWifi {
|
||||
if (Id == DeviceType)
|
||||
return Type;
|
||||
}
|
||||
return "AP";
|
||||
return Platforms::AP;
|
||||
}
|
||||
|
||||
void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace OpenWifi {
|
||||
|
||||
void DeviceDashboard::Generate(GWObjects::Dashboard &D, Poco::Logger &Logger) {
|
||||
if (GeneratingDashboard_.load()) {
|
||||
// std::cout << "Trying to generate dashboard but already being generated" << std::endl;
|
||||
while (GeneratingDashboard_.load()) {
|
||||
Poco::Thread::trySleep(100);
|
||||
}
|
||||
@@ -31,7 +30,6 @@ namespace OpenWifi {
|
||||
GeneratingDashboard_ = true;
|
||||
ValidDashboard_ = false;
|
||||
try {
|
||||
// std::cout << "Generating dashboard." << std::endl;
|
||||
poco_information(Logger, "DASHBOARD: Generating a new dashboard.");
|
||||
GWObjects::Dashboard NewData;
|
||||
StorageService()->AnalyzeCommands(NewData.commands);
|
||||
|
||||
@@ -315,4 +315,4 @@ namespace OpenWifi {
|
||||
poco_notice(Logger(), "Stopped...");
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/Net/HTTPRequestHandler.h"
|
||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include <Poco/Net/HTTPRequestHandler.h>
|
||||
#include <Poco/Net/HTTPRequestHandlerFactory.h>
|
||||
#include <Poco/Net/HTTPServer.h>
|
||||
#include <Poco/Net/HTTPServerRequest.h>
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include <framework/SubSystemServer.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
@@ -50,17 +50,27 @@ namespace OpenWifi {
|
||||
class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
|
||||
public:
|
||||
DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber,
|
||||
std::uint64_t timestamp, const std::string config)
|
||||
std::uint64_t timestamp,
|
||||
const Poco::JSON::Object::Ptr config)
|
||||
: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
|
||||
}
|
||||
|
||||
~DeviceConfigurationChangeKafkaEvent() {
|
||||
payload_->set("configuration", config_);
|
||||
if(config_!= nullptr) {
|
||||
std::ostringstream os;
|
||||
config_->stringify(os);
|
||||
if(os.str().size()> KafkaManager()->KafkaManagerMaximumPayloadSize()) {
|
||||
payload_->set("configuration", "{}");
|
||||
payload_->set("configurationTooBig", true);
|
||||
} else {
|
||||
payload_->set("configuration", *config_);
|
||||
}
|
||||
}
|
||||
Send();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string config_;
|
||||
Poco::JSON::Object::Ptr config_;
|
||||
};
|
||||
|
||||
class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace OpenWifi {
|
||||
bool Recovered = false;
|
||||
Poco::File OuiFile(CurrentOUIFileName_);
|
||||
if (OuiFile.exists()) {
|
||||
std::unique_lock Lock(LocalMutex_);
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
Recovered = ProcessFile(CurrentOUIFileName_, OUIs_);
|
||||
if (Recovered) {
|
||||
poco_notice(Logger(),
|
||||
@@ -150,7 +150,7 @@ namespace OpenWifi {
|
||||
|
||||
OUIMap TmpOUIs;
|
||||
if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
|
||||
std::unique_lock G(LocalMutex_);
|
||||
std::lock_guard G(LocalMutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
LastUpdate_ = Utils::Now();
|
||||
Poco::File F1(CurrentOUIFileName_);
|
||||
@@ -163,7 +163,7 @@ namespace OpenWifi {
|
||||
} else if (OUIs_.empty()) {
|
||||
if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
|
||||
LastUpdate_ = Utils::Now();
|
||||
std::unique_lock G(LocalMutex_);
|
||||
std::lock_guard G(LocalMutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
}
|
||||
}
|
||||
@@ -173,7 +173,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
std::string OUIServer::GetManufacturer(const std::string &MAC) {
|
||||
std::shared_lock Lock(LocalMutex_);
|
||||
std::lock_guard Lock(LocalMutex_);
|
||||
|
||||
auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
|
||||
if (Manufacturer != OUIs_.end())
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace OpenWifi {
|
||||
[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
|
||||
|
||||
private:
|
||||
std::shared_mutex LocalMutex_;
|
||||
std::mutex LocalMutex_;
|
||||
uint64_t LastUpdate_ = 0;
|
||||
bool Initialized_ = false;
|
||||
OUIMap OUIs_;
|
||||
|
||||
@@ -1753,7 +1753,6 @@ namespace OpenWifi {
|
||||
nlohmann::json new_ie;
|
||||
nlohmann::json content;
|
||||
|
||||
// std::cout << BufferToHex(&data[0],data.size()) << std::endl;
|
||||
uint offset = 0;
|
||||
auto sub_ie = data[offset++];
|
||||
switch (sub_ie) {
|
||||
@@ -1788,7 +1787,6 @@ namespace OpenWifi {
|
||||
|
||||
try {
|
||||
nlohmann::json D = nlohmann::json::parse(ofs.str());
|
||||
// std::cout << "Start of parsing wifi" << std::endl;
|
||||
if (D.contains("status")) {
|
||||
auto Status = D["status"];
|
||||
if (Status.contains("scan") && Status["scan"].is_array()) {
|
||||
@@ -1803,8 +1801,6 @@ namespace OpenWifi {
|
||||
if (ie.contains("type") && ie.contains("data")) {
|
||||
uint64_t ie_type = ie["type"];
|
||||
std::string ie_data = ie["data"];
|
||||
// std::cout << "TYPE:" << ie_type << " DATA:" << ie_data
|
||||
// << std::endl;
|
||||
auto data = Base64Decode2Vec(ie_data);
|
||||
if (ie_type == ieee80211_eid::WLAN_EID_COUNTRY) {
|
||||
new_ies.push_back(WFS_WLAN_EID_COUNTRY(data));
|
||||
@@ -1858,18 +1854,12 @@ namespace OpenWifi {
|
||||
} else if (ie_type == ieee80211_eid::WLAN_EID_EXTENSION) {
|
||||
new_ies.push_back(WFS_WLAN_EID_EXTENSION(data));
|
||||
} else {
|
||||
// std::cout
|
||||
// << "Skipping IE: no parsing available: " << ie_type
|
||||
// << std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} else {
|
||||
// std::cout << "Skipping IE: no data and type" <<
|
||||
// std::endl;
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
} catch (...) {
|
||||
// std::cout << "Skipping IE: exception" << std::endl;
|
||||
Logger.information(fmt::format("Error parsing IEs"));
|
||||
new_ies.push_back(ie);
|
||||
}
|
||||
@@ -1877,7 +1867,6 @@ namespace OpenWifi {
|
||||
scan_entry["ies"] = new_ies;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
} else {
|
||||
// std::cout << "Skipping scan" << std::endl;
|
||||
ParsedScan.push_back(scan_entry);
|
||||
}
|
||||
}
|
||||
@@ -1886,7 +1875,6 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
Result << to_string(D);
|
||||
// std::cout << "End of parsing wifi" << std::endl;
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger.log(E);
|
||||
|
||||
@@ -177,15 +177,6 @@ namespace OpenWifi {
|
||||
} else {
|
||||
session_hint->second->lastTransaction = Utils::Now();
|
||||
}
|
||||
|
||||
/*
|
||||
if(ap_hint!=AccountingSessions_.end()) {
|
||||
std::cout << "Auth table:" << std::endl;
|
||||
for(const auto &session:ap_hint->second) {
|
||||
std::cout << Notification.SerialNumber_ << ": Index: " << session.first << ": ID: " << session.second->accountingSessionId << " MID:" << session.second->accountingMultiSessionId << std::endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
std::uint32_t GetUiInt32(const std::uint8_t *buf) {
|
||||
@@ -423,15 +414,15 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUSSessionTracker::DisconnectSession(const std::string &SerialNumber) {
|
||||
poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber));
|
||||
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto hint = AccountingSessions_.find(SerialNumber);
|
||||
if(hint==end(AccountingSessions_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
poco_information(Logger(),fmt::format("{}: Disconnecting.", SerialNumber));
|
||||
|
||||
// we need to go through all sessions and send an accounting stop
|
||||
for(const auto &session:hint->second) {
|
||||
poco_debug(Logger(), fmt::format("Stopping accounting for {}:{}", SerialNumber, session.first ));
|
||||
|
||||
747
src/RADIUS_Destination.h
Normal file
747
src/RADIUS_Destination.h
Normal file
@@ -0,0 +1,747 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-08-15.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "RADIUS_helpers.h"
|
||||
#include <RESTObjects/RESTAPI_GWobjects.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RADIUS_Destination : public Poco::Runnable {
|
||||
public:
|
||||
RADIUS_Destination(Poco::Net::SocketReactor &R, const GWObjects::RadiusProxyPool &P)
|
||||
: Reactor_(R),
|
||||
Logger_(Poco::Logger::get(
|
||||
fmt::format("RADSEC: {}", P.name))),
|
||||
Pool_(P)
|
||||
{
|
||||
Type_ = GWObjects::RadiusEndpointType(P.radsecPoolType);
|
||||
Start();
|
||||
}
|
||||
|
||||
~RADIUS_Destination() override { Stop(); }
|
||||
|
||||
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
|
||||
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
|
||||
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
|
||||
const int DEFAULT_RADIUS_CoA_PORT = 3799;
|
||||
|
||||
inline int Start() {
|
||||
ReconnectThread_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() {
|
||||
TryAgain_ = false;
|
||||
Disconnect();
|
||||
ReconnectThread_.wakeUp();
|
||||
ReconnectThread_.join();
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
Poco::Thread::trySleep(5000);
|
||||
std::uint64_t CurrentDelay = 10, maxDelay=300, LastTry=0, LastKeepAlive=0;
|
||||
while (TryAgain_) {
|
||||
if (!Connected_) {
|
||||
if(!LastTry || (Utils::Now()-LastTry)>CurrentDelay) {
|
||||
LastTry = Utils::Now();
|
||||
if (!Connect()) {
|
||||
CurrentDelay *= 2;
|
||||
if(CurrentDelay>maxDelay) CurrentDelay=10;
|
||||
} else {
|
||||
CurrentDelay = 10;
|
||||
}
|
||||
}
|
||||
} else if ((Utils::Now() - LastKeepAlive) > Pool_.radsecKeepAlive) {
|
||||
RADIUS::RadiusOutputPacket P(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
|
||||
P.MakeStatusMessage(Pool_.authConfig.servers[ServerIndex_].name);
|
||||
if(Type_!=GWObjects::RadiusEndpointType::generic) {
|
||||
poco_trace(Logger_, fmt::format("{}: Keep-Alive message.", Pool_.authConfig.servers[ServerIndex_].name));
|
||||
Socket_->sendBytes(P.Data(), P.Len());
|
||||
}
|
||||
LastKeepAlive = Utils::Now();
|
||||
}
|
||||
Poco::Thread::trySleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
|
||||
int length) {
|
||||
try {
|
||||
if (Connected_) {
|
||||
RADIUS::RadiusPacket P(buffer, length);
|
||||
int sent_bytes;
|
||||
if (P.VerifyMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret)) {
|
||||
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
sent_bytes = Socket_->sendBytes(buffer, length);
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
P.ComputeMessageAuthenticator(Pool_.authConfig.servers[ServerIndex_].radsecSecret);
|
||||
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
|
||||
}
|
||||
return (sent_bytes == length);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Exception occurred: while sending data.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void
|
||||
onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
unsigned char Buffer[4096];
|
||||
|
||||
try {
|
||||
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer, sizeof(Buffer));
|
||||
std::string ReplySource;
|
||||
if (NumberOfReceivedBytes >= 20) {
|
||||
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
|
||||
if (P.IsAuthentication()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(),
|
||||
P.PacketTypeToString(),
|
||||
NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else if(P.IsStatusMessageReply(ReplySource)) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: Keepalive message received.", ReplySource));
|
||||
} else {
|
||||
poco_debug(Logger_, "AUTH packet dropped.");
|
||||
}
|
||||
} else if (P.IsAccounting()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(),
|
||||
P.PacketTypeToString(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_debug(Logger_, "ACCT packet dropped.");
|
||||
}
|
||||
} else if (P.IsAuthority()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_debug(Logger_,
|
||||
fmt::format("{}: {}:{} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(),
|
||||
P.PacketTypeToString(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_debug(Logger_, "CoA/DM packet dropped.");
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
|
||||
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
|
||||
}
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void
|
||||
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker error. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void
|
||||
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void OnAccountingSocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger_, "Accounting: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger_, "Accounting: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Accounting Packet Response received for {}", SerialNumber ));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
inline void OnAuthenticationSocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger_, "Authentication: bad packet received.");
|
||||
return;
|
||||
}
|
||||
P.Evaluate(ReceiveSize);
|
||||
|
||||
if(Logger_.trace()) {
|
||||
P.Log(std::cout);
|
||||
}
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger_, "Authentication: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
inline void OnCoASocketReadable(
|
||||
const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
Poco::Net::SocketAddress Sender;
|
||||
RADIUS::RadiusPacket P;
|
||||
|
||||
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(P.Buffer(), P.BufferLen());
|
||||
if (ReceiveSize < SMALLEST_RADIUS_PACKET) {
|
||||
poco_warning(Logger_, "CoA/DM: bad packet received.");
|
||||
return;
|
||||
}
|
||||
|
||||
P.Evaluate(ReceiveSize);
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger_, "CoA/DM: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
static inline bool IsExpired(const Poco::Crypto::X509Certificate &C) {
|
||||
return C.expiresOn().timestamp().epochTime() < (std::time_t)Utils::Now();
|
||||
}
|
||||
|
||||
static inline void Cat(const std::string &F1, const std::string & F2, const std::string &F) {
|
||||
std::ofstream of(F.c_str(),std::ios_base::trunc|std::ios_base::out|std::ios_base::binary);
|
||||
std::ifstream if1(F1.c_str(),std::ios_base::binary|std::ios_base::in);
|
||||
Poco::StreamCopier::copyStream(if1,of);
|
||||
of << std::endl;
|
||||
std::ifstream if2(F2.c_str(),std::ios_base::binary|std::ios_base::in);
|
||||
Poco::StreamCopier::copyStream(if2,of);
|
||||
of << std::endl;
|
||||
of.close();
|
||||
}
|
||||
|
||||
inline bool Connect_GlobalReach() {
|
||||
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile OpenRoamingRootCertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate0(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate1(MicroServiceDataDirectory());
|
||||
|
||||
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
|
||||
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
|
||||
DecodeFile(Intermediate0.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[0]);
|
||||
DecodeFile(Intermediate1.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCacerts[1]);
|
||||
|
||||
const static std::string OpenRoamingRootCert{
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIClDCCAhugAwIBAgIUF1f+h+uJNHyr+ZqTpwew8LYRAW0wCgYIKoZIzj0EAwMw\n"
|
||||
"gYkxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNVBAcTBkxvbmRv\n"
|
||||
"bjEsMCoGA1UEChMjR2xvYmFsUmVhY2ggVGVjaG5vbG9neSBFTUVBIExpbWl0ZWQx\n"
|
||||
"KjAoBgNVBAMTIUdsb2JhbFJlYWNoIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0y\n"
|
||||
"MzA3MTQwOTMyMDBaFw00MzA3MDkwOTMyMDBaMIGJMQswCQYDVQQGEwJHQjEPMA0G\n"
|
||||
"A1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xLDAqBgNVBAoTI0dsb2JhbFJl\n"
|
||||
"YWNoIFRlY2hub2xvZ3kgRU1FQSBMaW1pdGVkMSowKAYDVQQDEyFHbG9iYWxSZWFj\n"
|
||||
"aCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARy\n"
|
||||
"f02umFNy5W/TtM5nfMaLhRF61vLxhT8iNQHR1mXiRmNdME3ArForBcAm2eolHPcJ\n"
|
||||
"RH9DcXs59d2zzoPEaBjXADTCjUts3F7G6fjqvfki2e/txx/xfUopQO8G54XcFWqj\n"
|
||||
"QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRS\n"
|
||||
"tNe7MgAFwTaMZKUtS1/8pVoBqjAKBggqhkjOPQQDAwNnADBkAjA7VKHTybtSMBcN\n"
|
||||
"717jGYvkWlcj4c9/LzPtkHO053wGsPigaq+1SjY7tDhS/g9oUQACMA6UqH2e8cfn\n"
|
||||
"cZqmBNVNN3DBjIb4anug7F+FnYOQF36ua6MLBeGn3aKxvu1aO+hjPg==\n"
|
||||
"-----END CERTIFICATE-----\n"};
|
||||
|
||||
std::ofstream ofs{OpenRoamingRootCertFile_.path().c_str(),
|
||||
std::ios_base::trunc | std::ios_base::out |
|
||||
std::ios_base::binary};
|
||||
ofs << OpenRoamingRootCert;
|
||||
ofs.close();
|
||||
|
||||
auto SecureContext = Poco::AutoPtr<Poco::Net::Context>(
|
||||
new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, ""));
|
||||
|
||||
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
SecureContext->usePrivateKey(Poco::Crypto::RSAKey("", KeyFile_.path(), ""));
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if (!IsExpired(Cert)) {
|
||||
SecureContext->useCertificate(Poco::Crypto::X509Certificate(CertFile_.path()));
|
||||
} else {
|
||||
poco_error(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Certificate for {} has expired. We cannot connect to this server.",
|
||||
Pool_.acctConfig.servers[ServerIndex_].name));
|
||||
return false;
|
||||
}
|
||||
|
||||
SecureContext->addCertificateAuthority(
|
||||
Poco::Crypto::X509Certificate(OpenRoamingRootCertFile_.path()));
|
||||
SecureContext->addChainCertificate(
|
||||
Poco::Crypto::X509Certificate(Intermediate0.path()));
|
||||
SecureContext->addChainCertificate(
|
||||
Poco::Crypto::X509Certificate(Intermediate1.path()));
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
ServerIndex_ = 0 ;
|
||||
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
|
||||
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
|
||||
try {
|
||||
poco_information(Logger_, fmt::format("Attempting to connect to {}", CommonName()));
|
||||
Socket_->connect(Destination, Poco::Timespan(20, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
|
||||
*this, &RADIUS_Destination::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADIUS_Destination::onShutdown));
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_, "NetException: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_, "Exception: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Could not connect.");
|
||||
}
|
||||
ServerIndex_++;
|
||||
}
|
||||
}
|
||||
ServerIndex_=0;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Connect_Orion() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
|
||||
|
||||
DecodeFile(CertFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecCert);
|
||||
DecodeFile(KeyFile_.path(), Pool_.acctConfig.servers[ServerIndex_].radsecKey);
|
||||
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if(IsExpired(Cert)) {
|
||||
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Pool_.acctConfig.servers[ServerIndex_].name));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &cert : Pool_.acctConfig.servers[ServerIndex_].radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(
|
||||
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
|
||||
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
|
||||
}
|
||||
|
||||
auto SecureContext =
|
||||
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
|
||||
Poco::Net::Context::TLS_CLIENT_USE, KeyFile_.path(), CertFile_.path(), ""));
|
||||
if (Pool_.acctConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
for (const auto &ca : CaCertFiles_) {
|
||||
Poco::Crypto::X509Certificate cert(ca->path());
|
||||
SecureContext->addCertificateAuthority(cert);
|
||||
}
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
ServerIndex_ = 0 ;
|
||||
for (const auto &PoolEntryServer : Pool_.acctConfig.servers) {
|
||||
Poco::Net::SocketAddress Destination(PoolEntryServer.ip, PoolEntryServer.port);
|
||||
try {
|
||||
poco_information(Logger_, "Attempting to connect");
|
||||
Socket_->connect(Destination, Poco::Timespan(100, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if (!Pool_.authConfig.servers[ServerIndex_].allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
|
||||
*this, &RADIUS_Destination::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADIUS_Destination::onShutdown));
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_information(Logger_, "Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_information(Logger_, "Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_information(Logger_, "Could not connect.");
|
||||
}
|
||||
ServerIndex_++;
|
||||
}
|
||||
}
|
||||
ServerIndex_=0;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Connect_Generic() {
|
||||
poco_information(Logger_, fmt::format("Connecting {}", Pool_.name));
|
||||
if (TryAgain_ && !Connected_) {
|
||||
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*CoASocketV4_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
|
||||
/*
|
||||
Poco::Net::SocketAddress AuthSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AccountingSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
Reactor_.addEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*CoASocketV6_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
*/
|
||||
Connected_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Connect_Radsec() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Connect() {
|
||||
switch(Type_) {
|
||||
case GWObjects::RadiusEndpointType::orion: return Connect_Orion();
|
||||
case GWObjects::RadiusEndpointType::globalreach: return Connect_GlobalReach();
|
||||
case GWObjects::RadiusEndpointType::radsec: return Connect_Radsec();
|
||||
default:
|
||||
return Connect_Generic();
|
||||
}
|
||||
}
|
||||
|
||||
inline void Disconnect() {
|
||||
if (Connected_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
if(Type_==GWObjects::RadiusEndpointType::generic) {
|
||||
poco_information(Logger_, fmt::format("Disconnecting {} generic server. Releasing all UDP resources.", Pool_.name));
|
||||
|
||||
if(AuthenticationSocketV4_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
AuthenticationSocketV4_->close();
|
||||
AuthenticationSocketV4_.reset();
|
||||
}
|
||||
|
||||
if(AccountingSocketV4_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
AccountingSocketV4_->close();
|
||||
AccountingSocketV4_.reset();
|
||||
}
|
||||
|
||||
if(CoASocketV4_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
CoASocketV4_->close();
|
||||
CoASocketV4_.reset();
|
||||
}
|
||||
|
||||
/*
|
||||
if(AuthenticationSocketV6_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAuthenticationSocketReadable));
|
||||
AuthenticationSocketV6_->close();
|
||||
AuthenticationSocketV6_.reset();
|
||||
}
|
||||
|
||||
if(AccountingSocketV6_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnAccountingSocketReadable));
|
||||
AccountingSocketV6_->close();
|
||||
AccountingSocketV6_.reset();
|
||||
}
|
||||
|
||||
if(CoASocketV6_) {
|
||||
Reactor_.removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::OnCoASocketReadable));
|
||||
CoASocketV6_->close();
|
||||
CoASocketV6_.reset();
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
if(Socket_!=nullptr) {
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_Destination::onData));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADIUS_Destination, Poco::Net::ErrorNotification>(
|
||||
*this, &RADIUS_Destination::onError));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_,
|
||||
Poco::NObserver<RADIUS_Destination, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADIUS_Destination::onShutdown));
|
||||
Socket_->close();
|
||||
}
|
||||
}
|
||||
Connected_ = false;
|
||||
}
|
||||
poco_information(Logger_, fmt::format("Disconnecting {}", Pool_.name));
|
||||
}
|
||||
|
||||
static void DecodeFile(const std::string &filename, const std::string &s) {
|
||||
std::ofstream sec_file(filename, std::ios_base::out | std::ios_base::trunc |
|
||||
std::ios_base::binary);
|
||||
std::stringstream is(s);
|
||||
Poco::Base64Decoder ds(is);
|
||||
Poco::StreamCopier::copyStream(ds, sec_file);
|
||||
sec_file.close();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string CommonName() {
|
||||
if (Peer_Cert_)
|
||||
return Peer_Cert_->commonName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string IssuerName() {
|
||||
if (Peer_Cert_)
|
||||
return Peer_Cert_->issuerName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string SubjectName() {
|
||||
if (Peer_Cert_)
|
||||
return Peer_Cert_->subjectName();
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto &Pool() const { return Pool_; }
|
||||
auto ServerType() const { return Type_; }
|
||||
|
||||
inline bool SendRadiusDataAuthData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
|
||||
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Auth {} bytes.", serialNumber, size));
|
||||
AuthenticationSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.authConfig.servers[0].ip, Pool_.authConfig.servers[0].port));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SendRadiusDataAcctData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
|
||||
poco_trace(Logger_, fmt::format("{}: Sending RADIUS Acct {} bytes.", serialNumber, size));
|
||||
AccountingSocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.acctConfig.servers[0].ip, Pool_.acctConfig.servers[0].port));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SendRadiusDataCoAData(const std::string &serialNumber, const unsigned char *buffer, std::size_t size) {
|
||||
poco_trace(Logger_, fmt::format("{}: Sending RADIUS CoA {} bytes.", serialNumber, size));
|
||||
CoASocketV4_->sendTo(buffer, size, Poco::Net::SocketAddress(Pool_.coaConfig.servers[0].ip, Pool_.coaConfig.servers[0].port));
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex LocalMutex_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
Poco::Logger &Logger_;
|
||||
|
||||
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
|
||||
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
|
||||
|
||||
/*
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
|
||||
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
|
||||
*/
|
||||
|
||||
Poco::Thread ReconnectThread_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
|
||||
volatile bool Connected_ = false;
|
||||
volatile bool TryAgain_ = true;
|
||||
enum GWObjects::RadiusEndpointType Type_{GWObjects::RadiusEndpointType::unknown};
|
||||
GWObjects::RadiusProxyPool Pool_;
|
||||
uint64_t ServerIndex_=0;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "Poco/Net/SocketAddress.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include <framework/utils.h>
|
||||
|
||||
namespace OpenWifi::RADIUS {
|
||||
|
||||
// Packet types
|
||||
@@ -407,6 +409,15 @@ namespace OpenWifi::RADIUS {
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, RadiusPacket const &P);
|
||||
|
||||
[[nodiscard]] inline std::string PacketTypeToString() const {
|
||||
|
||||
for(auto const &Name:radius_command_values) {
|
||||
if(Name.cmd == P_.code)
|
||||
return Name.name;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline bool IsAuthentication() {
|
||||
return (P_.code == RADIUS::Access_Request || P_.code == RADIUS::Access_Accept ||
|
||||
P_.code == RADIUS::Access_Challenge || P_.code == RADIUS::Access_Reject ||
|
||||
@@ -427,6 +438,25 @@ namespace OpenWifi::RADIUS {
|
||||
P_.code == RADIUS::CoA_ACK || P_.code == RADIUS::CoA_NAK);
|
||||
}
|
||||
|
||||
inline bool IsStatusMessageReply(std::string &ReplySource) {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == RADIUS::Attributes::PROXY_STATE) {
|
||||
std::string Attr33;
|
||||
// format is statis:server name
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len);
|
||||
auto Parts = Poco::StringTokenizer(Attr33, ":");
|
||||
if(Parts.count() == 2 && Parts[0] == "status") {
|
||||
ReplySource = Parts[1];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DBGLINE
|
||||
return false;
|
||||
}
|
||||
void Log(std::ostream &os) {
|
||||
uint16_t p = 0;
|
||||
|
||||
@@ -663,6 +693,29 @@ namespace OpenWifi::RADIUS {
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::uint32_t ExtractProxyStateDestinationIPint() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
if (attribute.type == RADIUS::Attributes::PROXY_STATE && attribute.len > 2) {
|
||||
std::string Attr33;
|
||||
// format is
|
||||
|
||||
Attr33.assign((const char *)(const char *)&P_.attributes[attribute.pos],
|
||||
attribute.len);
|
||||
auto Parts = Poco::StringTokenizer(Attr33, "|");
|
||||
if (Parts.count() == 4) {
|
||||
return Utils::IPtoInt(Parts[1]);
|
||||
}
|
||||
Parts = Poco::StringTokenizer(Attr33, ":");
|
||||
if (Parts.count() == 4) {
|
||||
return Utils::IPtoInt(Parts[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string ExtractCallingStationID() const {
|
||||
std::string Result;
|
||||
for (const auto &attribute : Attrs_) {
|
||||
@@ -962,22 +1015,25 @@ namespace OpenWifi::RADIUS {
|
||||
public:
|
||||
explicit RadiusOutputPacket(const std::string &Secret) : Secret_(Secret) {}
|
||||
|
||||
inline void MakeStatusMessage() {
|
||||
inline void MakeStatusMessage(const std::string &Source) {
|
||||
P_.code = RADIUS::Status_Server;
|
||||
P_.identifier = std::rand() & 0x00ff;
|
||||
MakeRadiusAuthenticator(P_.authenticator);
|
||||
unsigned char MessageAuthenticator[16]{0};
|
||||
std::string FullSource = "status:" + Source;
|
||||
AddAttribute(RADIUS::Attributes::PROXY_STATE, FullSource.size(), (const unsigned char *)FullSource.c_str());
|
||||
AddAttribute(RADIUS::Attributes::MESSAGE_AUTHENTICATOR, sizeof(MessageAuthenticator),
|
||||
MessageAuthenticator);
|
||||
int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16;
|
||||
// int PktLen = 1 + 1 + 2 + 16 + 1 + 1 + 16 ;
|
||||
int PktLen = 1 + 1 + 2 + 16 + AttributesLen_;
|
||||
P_.rawlen = htons(PktLen);
|
||||
|
||||
Poco::HMACEngine<Poco::MD5Engine> H(Secret_);
|
||||
H.update((const unsigned char *)&P_, PktLen);
|
||||
auto digest = H.digest();
|
||||
int p = 0;
|
||||
int p = 0, offset = (int)FullSource.size() + 2 ;
|
||||
for (const auto &i : digest)
|
||||
P_.attributes[1 + 1 + p++] = i;
|
||||
P_.attributes[offset + 1 + 1 + p++] = i;
|
||||
}
|
||||
|
||||
inline void AddAttribute(unsigned char attr, uint8_t len, const unsigned char *data) {
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
|
||||
/*
|
||||
const int SMALLEST_RADIUS_PACKET = 20 + 19 + 4;
|
||||
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
|
||||
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
|
||||
const int DEFAULT_RADIUS_CoA_PORT = 3799;
|
||||
*/
|
||||
|
||||
int RADIUS_proxy_server::Start() {
|
||||
|
||||
@@ -25,7 +27,7 @@ namespace OpenWifi {
|
||||
|
||||
Enabled_ = MicroServiceConfigGetBool("radius.proxy.enable", false);
|
||||
if (!Enabled_ && !Config.exists()) {
|
||||
StopRADSECServers();
|
||||
StopRADIUSDestinations();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,279 +35,81 @@ namespace OpenWifi {
|
||||
|
||||
Enabled_ = true;
|
||||
|
||||
Poco::Net::SocketAddress AuthSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV4, true, true);
|
||||
Poco::Net::SocketAddress AuthSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.authentication.port",
|
||||
DEFAULT_RADIUS_AUTHENTICATION_PORT));
|
||||
AuthenticationSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AuthSockAddrV6, true, true);
|
||||
|
||||
Poco::Net::SocketAddress AcctSockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV4_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4, true, true);
|
||||
Poco::Net::SocketAddress AcctSockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.accounting.port",
|
||||
DEFAULT_RADIUS_ACCOUNTING_PORT));
|
||||
AccountingSocketV6_ =
|
||||
std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6, true, true);
|
||||
|
||||
Poco::Net::SocketAddress CoASockAddrV4(
|
||||
Poco::Net::AddressFamily::IPv4,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV4, true, true);
|
||||
Poco::Net::SocketAddress CoASockAddrV6(
|
||||
Poco::Net::AddressFamily::IPv6,
|
||||
MicroServiceConfigGetInt("radius.proxy.coa.port", DEFAULT_RADIUS_CoA_PORT));
|
||||
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(CoASockAddrV6, true, true);
|
||||
|
||||
RadiusReactor_.reset();
|
||||
RadiusReactor_ = std::make_unique<Poco::Net::SocketReactor>();
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
RadiusReactor_->addEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
RadiusReactor_->addEventHandler(
|
||||
*CoASocketV4_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_->addEventHandler(
|
||||
*CoASocketV6_, Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
ParseConfig();
|
||||
StartRADSECServers();
|
||||
RadiusReactorThread_.start(*RadiusReactor_);
|
||||
StartRADIUSDestinations();
|
||||
RadiusReactorThread_.start(RadiusReactor_);
|
||||
Utils::SetThreadName(RadiusReactorThread_, "rad:reactor");
|
||||
Running_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::Stop() {
|
||||
if (Enabled_ && Running_) {
|
||||
poco_information(Logger(), "Stopping...");
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AuthenticationSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AuthenticationSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
|
||||
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AccountingSocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*AccountingSocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
|
||||
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*CoASocketV4_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
RadiusReactor_->removeEventHandler(
|
||||
*CoASocketV6_,
|
||||
Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADIUS_proxy_server::OnCoASocketReadable));
|
||||
|
||||
AuthenticationSocketV4_->close();
|
||||
AuthenticationSocketV6_->close();
|
||||
AccountingSocketV4_->close();
|
||||
AccountingSocketV6_->close();
|
||||
CoASocketV4_->close();
|
||||
CoASocketV6_->close();
|
||||
|
||||
AuthenticationSocketV4_.reset();
|
||||
AuthenticationSocketV6_.reset();
|
||||
AccountingSocketV4_.reset();
|
||||
AccountingSocketV6_.reset();
|
||||
CoASocketV4_.reset();
|
||||
CoASocketV6_.reset();
|
||||
|
||||
StopRADSECServers();
|
||||
RadiusReactor_->stop();
|
||||
StopRADIUSDestinations();
|
||||
RadiusReactor_.stop();
|
||||
RadiusReactorThread_.join();
|
||||
Running_ = false;
|
||||
poco_information(Logger(), "Stopped...");
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StartRADSECServers() {
|
||||
/* inline static bool isRadsec(const GWObjects::RadiusProxyPool &Cfg) {
|
||||
return Cfg.radsecPoolType=="orion" || Cfg.radsecPoolType=="globalreach" || Cfg.radsecPoolType=="radsec";
|
||||
}
|
||||
*/
|
||||
|
||||
void RADIUS_proxy_server::StartRADIUSDestinations() {
|
||||
std::lock_guard G(Mutex_);
|
||||
for (const auto &pool : PoolList_.pools) {
|
||||
if(pool.enabled) {
|
||||
for (const auto &entry : pool.authConfig.servers) {
|
||||
if (entry.radsec) {
|
||||
RADSECservers_[Poco::Net::SocketAddress(entry.ip, 0)] =
|
||||
std::make_unique<RADSEC_server>(*RadiusReactor_, entry, pool);
|
||||
}
|
||||
}
|
||||
RADIUS_Destinations_[Utils::IPtoInt(pool.poolProxyIp)] =
|
||||
std::make_unique<RADIUS_Destination>(RadiusReactor_, pool);
|
||||
} else {
|
||||
poco_information(Logger(),fmt::format("Pool {} is not enabled.", pool.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::StopRADSECServers() {
|
||||
void RADIUS_proxy_server::StopRADIUSDestinations() {
|
||||
std::lock_guard G(Mutex_);
|
||||
RADSECservers_.clear();
|
||||
RADIUS_Destinations_.clear();
|
||||
}
|
||||
|
||||
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. Dropping request.");
|
||||
return;
|
||||
}
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"Accounting Packet Response received for {}", SerialNumber ));
|
||||
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);
|
||||
|
||||
if(Logger().trace()) {
|
||||
P.Log(std::cout);
|
||||
}
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (SerialNumber.empty()) {
|
||||
poco_warning(Logger(), "Authentication: missing serial number. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"Authentication Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
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. Dropping request.");
|
||||
return;
|
||||
}
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format("CoA Packet received for {}, CalledStationID: {}, CallingStationID:{}",
|
||||
SerialNumber, CalledStationID, CallingStationID));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, P.Buffer(), P.Size());
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string & secret) {
|
||||
void RADIUS_proxy_server::RouteAndSendAccountingPacket(const std::string &Destination,const std::string &serialNumber, RADIUS::RadiusPacket &P, bool RecomputeAuthenticator, std::string &Secret) {
|
||||
try{
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
// are we sending this to a pool?
|
||||
auto DstParts = Utils::Split(Destination, ':');
|
||||
std::uint32_t DtsIp = Utils::IPtoInt(DstParts[0]);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::acct, Dst, P, UseRADSEC, secret);
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if (DestinationServer != end(RADSECservers_)) {
|
||||
|
||||
auto DestinationServer = RADIUS_Destinations_.find(DtsIp);
|
||||
if (DestinationServer != end(RADIUS_Destinations_)) {
|
||||
if(Logger().trace()) {
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
auto SessionID = P.ExtractAccountingSessionID();
|
||||
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
|
||||
Logger().trace(
|
||||
fmt::format("{}: Sending Accounting {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
|
||||
serialNumber, P.Size(),
|
||||
DestinationServer->second->Pool().authConfig.servers[0].ip,
|
||||
CalledStationID, CallingStationID, SessionID, MultiSessionID));
|
||||
}
|
||||
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
|
||||
Secret = DestinationServer->second->Pool().acctConfig.servers[0].secret;
|
||||
if(RecomputeAuthenticator) {
|
||||
P.RecomputeAuthenticator("radsec");
|
||||
P.RecomputeAuthenticator(Secret);
|
||||
}
|
||||
DestinationServer->second->SendData(serialNumber, P.Buffer(), P.Size());
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)P.Buffer(),
|
||||
P.Size());
|
||||
} else {
|
||||
DestinationServer->second->SendRadiusDataAcctData(
|
||||
serialNumber, (const unsigned char *)P.Buffer(), P.Size());
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
|
||||
AccountingSocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
|
||||
AccountingSocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"ACCT: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
if(RecomputeAuthenticator) {
|
||||
P.RecomputeAuthenticator(secret);
|
||||
}
|
||||
|
||||
auto AllSent =
|
||||
SendData(Dst.family() == Poco::Net::SocketAddress::IPv4 ? *AccountingSocketV4_
|
||||
: *AccountingSocketV6_
|
||||
, P.Buffer(), P.Size(), FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),
|
||||
fmt::format("{}: Could not send Accounting packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_debug(Logger(), fmt::format("{}: Sending Accounting Packet to {}, "
|
||||
"CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(),
|
||||
CalledStationID, CallingStationID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -325,8 +129,8 @@ namespace OpenWifi {
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size, std::string & secret) {
|
||||
void RADIUS_proxy_server::SendAccountingData( const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
@@ -334,9 +138,9 @@ namespace OpenWifi {
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, secret);
|
||||
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, secret);
|
||||
|
||||
std::string Secret;
|
||||
RouteAndSendAccountingPacket(Destination, serialNumber, P, false, Secret);
|
||||
RADIUSSessionTracker()->AddAccountingSession(Destination, serialNumber, P, Secret);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
@@ -351,55 +155,38 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendAuthenticationData(const std::string &serialNumber,
|
||||
const char *buffer, std::size_t size, std::string & secret) {
|
||||
const char *buffer, std::size_t size) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
Poco::Net::SocketAddress Dst(Destination);
|
||||
|
||||
std::lock_guard G(Mutex_);
|
||||
bool UseRADSEC = false;
|
||||
auto FinalDestination = Route(radius_type::auth, Dst, P, UseRADSEC, secret);
|
||||
RADIUSSessionTracker()->AddAuthenticationSession(Destination, serialNumber, P, secret);
|
||||
|
||||
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);
|
||||
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
|
||||
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
|
||||
if (DestinationServer != end(RADIUS_Destinations_)) {
|
||||
if(Logger().trace()) {
|
||||
auto CallingStationID = P.ExtractCallingStationID();
|
||||
auto CalledStationID = P.ExtractCalledStationID();
|
||||
auto SessionID = P.ExtractAccountingSessionID();
|
||||
auto MultiSessionID = P.ExtractAccountingMultiSessionID();
|
||||
Logger().trace(
|
||||
fmt::format("{}: Sending Authentication {} bytes to {}. CalledStationID={} CallingStationID={} SessionID={}:{}",
|
||||
serialNumber, P.Size(),
|
||||
DestinationServer->second->Pool().authConfig.servers[0].ip,
|
||||
CalledStationID, CallingStationID, SessionID, MultiSessionID));
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 &&
|
||||
AuthenticationSocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 &&
|
||||
AuthenticationSocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"AUTH: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
|
||||
DestinationServer->second->SendData(serialNumber,
|
||||
(const unsigned char *)buffer, size);
|
||||
}
|
||||
else {
|
||||
DestinationServer->second->SendRadiusDataAuthData(
|
||||
serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
auto AllSent = SendData(Dst.family() == Poco::Net::SocketAddress::IPv4
|
||||
? *AuthenticationSocketV4_
|
||||
: *AuthenticationSocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent)
|
||||
poco_error(Logger(),
|
||||
fmt::format("{}: Could not send Authentication packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
else
|
||||
poco_debug(Logger(), fmt::format("{}: Sending Authentication Packet to {}, "
|
||||
"CalledStationID: {}, CallingStationID:{}",
|
||||
serialNumber, FinalDestination.toString(),
|
||||
CalledStationID, CallingStationID));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
@@ -410,65 +197,35 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const char *buffer,
|
||||
std::size_t size, std::string & secret) {
|
||||
std::size_t size) {
|
||||
|
||||
if (!Continue())
|
||||
return;
|
||||
|
||||
try {
|
||||
RADIUS::RadiusPacket P((unsigned char *)buffer, size);
|
||||
auto Destination = P.ExtractProxyStateDestination();
|
||||
|
||||
if (Destination.empty()) {
|
||||
Destination = "0.0.0.0:0";
|
||||
}
|
||||
|
||||
if(Logger().trace()) {
|
||||
P.Log(std::cout);
|
||||
}
|
||||
|
||||
if(Destination.empty()) {
|
||||
poco_warning(Logger(),fmt::format("{}: CoA packet does not have a valid destination.", serialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
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::coa, Dst, P, UseRADSEC, secret);
|
||||
if (UseRADSEC) {
|
||||
Poco::Net::SocketAddress RSP(FinalDestination.host(), 0);
|
||||
auto DestinationServer = RADSECservers_.find(RSP);
|
||||
if (DestinationServer != end(RADSECservers_)) {
|
||||
std::uint32_t DstIp = P.ExtractProxyStateDestinationIPint();
|
||||
auto DestinationServer = RADIUS_Destinations_.find(DstIp);
|
||||
if (DestinationServer != end(RADIUS_Destinations_)) {
|
||||
poco_trace(Logger(),fmt::format("{}: Sending CoA {} bytes to {}", serialNumber, P.Size(), DestinationServer->second->Pool().coaConfig.servers[0].ip));
|
||||
if(DestinationServer->second->ServerType()!=GWObjects::RadiusEndpointType::generic) {
|
||||
DestinationServer->second->SendData(serialNumber, (const unsigned char *)buffer,
|
||||
size);
|
||||
} else {
|
||||
DestinationServer->second->SendRadiusDataCoAData(
|
||||
serialNumber, (const unsigned char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
if ((Dst.family() == Poco::Net::SocketAddress::IPv4 && CoASocketV4_ == nullptr) ||
|
||||
(Dst.family() == Poco::Net::SocketAddress::IPv6 && CoASocketV6_ == nullptr)) {
|
||||
poco_debug(
|
||||
Logger(),
|
||||
fmt::format(
|
||||
"CoA: Trying to use RADIUS GW PROXY but not configured. Device={}",
|
||||
serialNumber));
|
||||
return;
|
||||
}
|
||||
auto AllSent = SendData(
|
||||
Dst.family() == Poco::Net::SocketAddress::IPv4 ? *CoASocketV4_ : *CoASocketV6_,
|
||||
(const unsigned char *)buffer, size, FinalDestination);
|
||||
if (!AllSent) {
|
||||
poco_error(Logger(), fmt::format("{}: Could not send CoA packet packet to {}.",
|
||||
serialNumber, Destination));
|
||||
}
|
||||
else
|
||||
poco_debug(Logger(), fmt::format("{}: Sending CoA Packet to {}", serialNumber,
|
||||
FinalDestination.toString()));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("Bad RADIUS CoA/DM Packet from {}. Dropped.", serialNumber));
|
||||
fmt::format("Bad RADIUS AUTH Packet from {}. Dropped.", serialNumber));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +329,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static bool RealmMatch(const std::string &user_realm, const std::string &realm) {
|
||||
if (realm.find_first_of('*') == std::string::npos)
|
||||
return user_realm == realm;
|
||||
@@ -766,7 +524,7 @@ namespace OpenWifi {
|
||||
}
|
||||
return OriginalAddress;
|
||||
}
|
||||
|
||||
*/
|
||||
void RADIUS_proxy_server::SetConfig(const GWObjects::RadiusProxyPoolList &C) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "RADSEC_server.h"
|
||||
#include "RADIUS_Destination.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -28,25 +28,19 @@ namespace OpenWifi {
|
||||
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, std::string & secret);
|
||||
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, std::string & secret);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size, std::string & secret);
|
||||
std::size_t size);
|
||||
void SendCoAData(const std::string &serialNumber, const char *buffer, std::size_t size);
|
||||
|
||||
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string & secret);
|
||||
void RouteAndSendAccountingPacket(const std::string &Destination, const std::string &serialNumber, RADIUS::RadiusPacket &P, bool reComputeAuthenticator, std::string &Secret);
|
||||
|
||||
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
|
||||
void DeleteConfig();
|
||||
void GetConfig(GWObjects::RadiusProxyPoolList &C);
|
||||
|
||||
void StartRADSECServers();
|
||||
void StopRADSECServers();
|
||||
void StartRADIUSDestinations();
|
||||
void StopRADIUSDestinations();
|
||||
|
||||
struct Destination {
|
||||
Poco::Net::SocketAddress Addr;
|
||||
@@ -68,19 +62,13 @@ namespace OpenWifi {
|
||||
inline bool Continue() const { return Running_ && Enabled_ && !Pools_.empty(); }
|
||||
|
||||
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_;
|
||||
std::unique_ptr<Poco::Net::SocketReactor> RadiusReactor_;
|
||||
Poco::Thread RadiusReactorThread_;
|
||||
Poco::Net::SocketReactor RadiusReactor_;
|
||||
Poco::Thread RadiusReactorThread_;
|
||||
|
||||
GWObjects::RadiusProxyPoolList PoolList_;
|
||||
std::string ConfigFilename_;
|
||||
|
||||
std::map<Poco::Net::SocketAddress, std::unique_ptr<RADSEC_server>> RADSECservers_;
|
||||
std::map<std::uint32_t, std::unique_ptr<RADIUS_Destination>> RADIUS_Destinations_;
|
||||
|
||||
struct RadiusPool {
|
||||
std::vector<Destination> AuthV4;
|
||||
@@ -105,20 +93,21 @@ namespace OpenWifi {
|
||||
|
||||
void ParseConfig();
|
||||
void ResetConfig();
|
||||
Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
|
||||
// Poco::Net::SocketAddress Route(radius_type rtype, const Poco::Net::SocketAddress &A,
|
||||
// const RADIUS::RadiusPacket &P, bool &UseRADSEC, std::string &secret);
|
||||
|
||||
void ParseServerList(const GWObjects::RadiusProxyServerConfig &Config,
|
||||
std::vector<Destination> &V4,
|
||||
std::vector<Destination> &V6, bool setAsDefault,
|
||||
const std::string &poolProxyIp);
|
||||
static Poco::Net::SocketAddress
|
||||
/* static Poco::Net::SocketAddress
|
||||
ChooseAddress(std::vector<Destination> &Pool,
|
||||
const Poco::Net::SocketAddress &OriginalAddress, std::string &Secret);
|
||||
Poco::Net::SocketAddress DefaultRoute([[maybe_unused]] radius_type rtype,
|
||||
const Poco::Net::SocketAddress &RequestedAddress,
|
||||
const RADIUS::RadiusPacket &P, bool &UseRADSEC,
|
||||
std::string &Secret);
|
||||
};
|
||||
*/ };
|
||||
|
||||
inline auto RADIUS_proxy_server() { return RADIUS_proxy_server::instance(); }
|
||||
|
||||
|
||||
@@ -1,452 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-08-15.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "RESTObjects/RESTAPI_GWobjects.h"
|
||||
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
#include "RADIUS_helpers.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RADSEC_server : public Poco::Runnable {
|
||||
public:
|
||||
RADSEC_server(Poco::Net::SocketReactor &R, GWObjects::RadiusProxyServerEntry E, const GWObjects::RadiusProxyPool &P)
|
||||
: Reactor_(R), Server_(std::move(E)),
|
||||
Logger_(Poco::Logger::get(
|
||||
fmt::format("RADSEC: {}@{}:{}", Server_.name, Server_.ip, Server_.port))) {
|
||||
KeepAlive_ = P.radsecKeepAlive;
|
||||
Type_ = P.radsecPoolType;
|
||||
Start();
|
||||
}
|
||||
|
||||
~RADSEC_server() { Stop(); }
|
||||
|
||||
inline int Start() {
|
||||
ReconnectThread_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() {
|
||||
TryAgain_ = false;
|
||||
Disconnect();
|
||||
ReconnectThread_.wakeUp();
|
||||
ReconnectThread_.join();
|
||||
}
|
||||
|
||||
inline void run() final {
|
||||
Poco::Thread::trySleep(5000);
|
||||
std::uint64_t CurrentDelay = 10, maxDelay=300, LastTry=0, LastKeepAlive=0;
|
||||
while (TryAgain_) {
|
||||
if (!Connected_) {
|
||||
if(!LastTry || (Utils::Now()-LastTry)>CurrentDelay) {
|
||||
LastTry = Utils::Now();
|
||||
if (!Connect()) {
|
||||
CurrentDelay *= 2;
|
||||
if(CurrentDelay>maxDelay) CurrentDelay=10;
|
||||
} else {
|
||||
CurrentDelay = 10;
|
||||
}
|
||||
}
|
||||
} else if ((Utils::Now() - LastKeepAlive) > KeepAlive_) {
|
||||
RADIUS::RadiusOutputPacket P(Server_.radsecSecret);
|
||||
P.MakeStatusMessage();
|
||||
poco_trace(Logger_, fmt::format("{}: Keep-Alive message.", Server_.name));
|
||||
Socket_->sendBytes(P.Data(), P.Len());
|
||||
LastKeepAlive = Utils::Now();
|
||||
}
|
||||
Poco::Thread::trySleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SendData(const std::string &serial_number, const unsigned char *buffer,
|
||||
int length) {
|
||||
try {
|
||||
if (Connected_) {
|
||||
RADIUS::RadiusPacket P(buffer, length);
|
||||
int sent_bytes;
|
||||
if (P.VerifyMessageAuthenticator(Server_.radsecSecret)) {
|
||||
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
sent_bytes = Socket_->sendBytes(buffer, length);
|
||||
} else {
|
||||
poco_trace(Logger_, fmt::format("{}: {} Sending {} bytes", serial_number,
|
||||
P.PacketType(), length));
|
||||
P.ComputeMessageAuthenticator(Server_.radsecSecret);
|
||||
sent_bytes = Socket_->sendBytes(P.Buffer(), length);
|
||||
}
|
||||
return (sent_bytes == length);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Exception occurred: while sending data.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void
|
||||
onData([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
|
||||
unsigned char Buffer[4096];
|
||||
|
||||
try {
|
||||
auto NumberOfReceivedBytes = Socket_->receiveBytes(Buffer, sizeof(Buffer));
|
||||
if (NumberOfReceivedBytes >= 20) {
|
||||
RADIUS::RadiusPacket P(Buffer, NumberOfReceivedBytes);
|
||||
if (P.IsAuthentication()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAuthenticationData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_trace(Logger_, "AUTH packet dropped.");
|
||||
}
|
||||
} else if (P.IsAccounting()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberFromProxyState();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusAccountingData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_trace(Logger_, "ACCT packet dropped.");
|
||||
}
|
||||
} else if (P.IsAuthority()) {
|
||||
auto SerialNumber = P.ExtractSerialNumberTIP();
|
||||
if (!SerialNumber.empty()) {
|
||||
poco_trace(Logger_,
|
||||
fmt::format("{}: {} Received {} bytes.", SerialNumber,
|
||||
P.PacketType(), NumberOfReceivedBytes));
|
||||
AP_WS_Server()->SendRadiusCoAData(SerialNumber, Buffer,
|
||||
NumberOfReceivedBytes);
|
||||
} else {
|
||||
poco_trace(Logger_, "CoA/DM packet dropped.");
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_,
|
||||
fmt::format("Unknown packet: Type: {} (type={}) Length={}",
|
||||
P.PacketType(), P.PacketTypeInt(), P.BufferLen()));
|
||||
}
|
||||
} else {
|
||||
poco_warning(Logger_, "Invalid packet received. Resetting the connection.");
|
||||
Disconnect();
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Disconnect();
|
||||
} catch (...) {
|
||||
Disconnect();
|
||||
poco_warning(Logger_, "Exception occurred. Resetting the connection.");
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
onError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker error. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
inline void
|
||||
onShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
|
||||
poco_warning(Logger_, "Socker socket shutdown. Terminating connection.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
static inline bool IsExpired(const Poco::Crypto::X509Certificate &C) {
|
||||
return C.expiresOn().timestamp().epochTime() < (std::time_t)Utils::Now();
|
||||
}
|
||||
|
||||
inline bool Connect_GlobalReach() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile OpenRoamingRootCertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate0(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Intermediate1(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile Combined(MicroServiceDataDirectory());
|
||||
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
|
||||
|
||||
DecodeFile(KeyFile_.path(), Server_.radsecKey);
|
||||
DecodeFile(CertFile_.path(), Server_.radsecCert);
|
||||
DecodeFile(Intermediate0.path(), Server_.radsecCacerts[0]);
|
||||
DecodeFile(Intermediate1.path(), Server_.radsecCacerts[1]);
|
||||
|
||||
for (auto &cert : Server_.radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(
|
||||
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
|
||||
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
|
||||
}
|
||||
|
||||
std::string OpenRoamingRootCert{"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIClDCCAhugAwIBAgIUF1f+h+uJNHyr+ZqTpwew8LYRAW0wCgYIKoZIzj0EAwMw\n"
|
||||
"gYkxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNVBAcTBkxvbmRv\n"
|
||||
"bjEsMCoGA1UEChMjR2xvYmFsUmVhY2ggVGVjaG5vbG9neSBFTUVBIExpbWl0ZWQx\n"
|
||||
"KjAoBgNVBAMTIUdsb2JhbFJlYWNoIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0y\n"
|
||||
"MzA3MTQwOTMyMDBaFw00MzA3MDkwOTMyMDBaMIGJMQswCQYDVQQGEwJHQjEPMA0G\n"
|
||||
"A1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xLDAqBgNVBAoTI0dsb2JhbFJl\n"
|
||||
"YWNoIFRlY2hub2xvZ3kgRU1FQSBMaW1pdGVkMSowKAYDVQQDEyFHbG9iYWxSZWFj\n"
|
||||
"aCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARy\n"
|
||||
"f02umFNy5W/TtM5nfMaLhRF61vLxhT8iNQHR1mXiRmNdME3ArForBcAm2eolHPcJ\n"
|
||||
"RH9DcXs59d2zzoPEaBjXADTCjUts3F7G6fjqvfki2e/txx/xfUopQO8G54XcFWqj\n"
|
||||
"QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRS\n"
|
||||
"tNe7MgAFwTaMZKUtS1/8pVoBqjAKBggqhkjOPQQDAwNnADBkAjA7VKHTybtSMBcN\n"
|
||||
"717jGYvkWlcj4c9/LzPtkHO053wGsPigaq+1SjY7tDhS/g9oUQACMA6UqH2e8cfn\n"
|
||||
"cZqmBNVNN3DBjIb4anug7F+FnYOQF36ua6MLBeGn3aKxvu1aO+hjPg==\n"
|
||||
"-----END CERTIFICATE-----\n"};
|
||||
|
||||
std::ofstream ofs{OpenRoamingRootCertFile_.path().c_str(),std::ios_base::trunc|std::ios_base::out|std::ios_base::binary};
|
||||
ofs << OpenRoamingRootCert;
|
||||
ofs.close();
|
||||
|
||||
Poco::Net::Context::Ptr SecureContext =
|
||||
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
|
||||
Poco::Net::Context::TLS_CLIENT_USE, ""));
|
||||
|
||||
if (Server_.allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
SecureContext->usePrivateKey(Poco::Crypto::RSAKey("",KeyFile_.path(),""));
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if(!IsExpired(Cert)) {
|
||||
SecureContext->useCertificate(Poco::Crypto::X509Certificate(CertFile_.path()));
|
||||
} else {
|
||||
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Server_.name));
|
||||
return false;
|
||||
}
|
||||
SecureContext->addCertificateAuthority(Poco::Crypto::X509Certificate(OpenRoamingRootCertFile_.path()));
|
||||
SecureContext->addChainCertificate(Poco::Crypto::X509Certificate(Intermediate0.path()));
|
||||
SecureContext->addChainCertificate(Poco::Crypto::X509Certificate(Intermediate1.path()));
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
|
||||
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
|
||||
|
||||
try {
|
||||
poco_information(Logger_, "Attempting to connect");
|
||||
Socket_->connect(Destination, Poco::Timespan(20, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if (!Server_.allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_warning(Logger_, "NetException: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_warning(Logger_, "Exception: Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_warning(Logger_, "Could not connect.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Connect_Orion() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Poco::TemporaryFile CertFile_(MicroServiceDataDirectory());
|
||||
Poco::TemporaryFile KeyFile_(MicroServiceDataDirectory());
|
||||
std::vector<std::unique_ptr<Poco::TemporaryFile>> CaCertFiles_;
|
||||
|
||||
DecodeFile(CertFile_.path(), Server_.radsecCert);
|
||||
DecodeFile(KeyFile_.path(), Server_.radsecKey);
|
||||
|
||||
Poco::Crypto::X509Certificate Cert(CertFile_.path());
|
||||
if(IsExpired(Cert)) {
|
||||
poco_error(Logger_, fmt::format("Certificate for {} has expired. We cannot connect to this server.", Server_.name));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &cert : Server_.radsecCacerts) {
|
||||
CaCertFiles_.emplace_back(
|
||||
std::make_unique<Poco::TemporaryFile>(MicroServiceDataDirectory()));
|
||||
DecodeFile(CaCertFiles_[CaCertFiles_.size() - 1]->path(), cert);
|
||||
}
|
||||
|
||||
Poco::Net::Context::Ptr SecureContext =
|
||||
Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(
|
||||
Poco::Net::Context::TLS_CLIENT_USE, KeyFile_.path(), CertFile_.path(), ""));
|
||||
if (Server_.allowSelfSigned) {
|
||||
SecureContext->setSecurityLevel(Poco::Net::Context::SECURITY_LEVEL_NONE);
|
||||
SecureContext->enableExtendedCertificateVerification(false);
|
||||
}
|
||||
|
||||
for (const auto &ca : CaCertFiles_) {
|
||||
Poco::Crypto::X509Certificate cert(ca->path());
|
||||
SecureContext->addCertificateAuthority(cert);
|
||||
}
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::SecureStreamSocket>(SecureContext);
|
||||
|
||||
Poco::Net::SocketAddress Destination(Server_.ip, Server_.port);
|
||||
|
||||
try {
|
||||
poco_information(Logger_, "Attempting to connect");
|
||||
Socket_->connect(Destination, Poco::Timespan(100, 0));
|
||||
Socket_->completeHandshake();
|
||||
|
||||
if (!Server_.allowSelfSigned) {
|
||||
Socket_->verifyPeerCertificate();
|
||||
}
|
||||
|
||||
if (Socket_->havePeerCertificate()) {
|
||||
Peer_Cert_ = std::make_unique<Poco::Crypto::X509Certificate>(
|
||||
Socket_->peerCertificate());
|
||||
}
|
||||
|
||||
Socket_->setBlocking(false);
|
||||
Socket_->setNoDelay(true);
|
||||
Socket_->setKeepAlive(true);
|
||||
Socket_->setReceiveTimeout(Poco::Timespan(1 * 60 * 60, 0));
|
||||
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.addEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
|
||||
Connected_ = true;
|
||||
poco_information(Logger_, fmt::format("Connected. CN={}", CommonName()));
|
||||
return true;
|
||||
} catch (const Poco::Net::NetException &E) {
|
||||
poco_information(Logger_, "Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_information(Logger_, "Could not connect.");
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_information(Logger_, "Could not connect.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Connect_Generic() {
|
||||
if (TryAgain_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Connect() {
|
||||
if(Type_=="orion") return Connect_Orion();
|
||||
if(Type_=="globalreach") return Connect_GlobalReach();
|
||||
return Connect_Generic();
|
||||
}
|
||||
|
||||
inline void Disconnect() {
|
||||
if (Connected_) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ReadableNotification>(
|
||||
*this, &RADSEC_server::onData));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ErrorNotification>(
|
||||
*this, &RADSEC_server::onError));
|
||||
Reactor_.removeEventHandler(
|
||||
*Socket_, Poco::NObserver<RADSEC_server, Poco::Net::ShutdownNotification>(
|
||||
*this, &RADSEC_server::onShutdown));
|
||||
Socket_->close();
|
||||
Connected_ = false;
|
||||
}
|
||||
poco_information(Logger_, "Disconnecting.");
|
||||
}
|
||||
|
||||
static void DecodeFile(const std::string &filename, const std::string &s) {
|
||||
std::ofstream sec_file(filename, std::ios_base::out | std::ios_base::trunc |
|
||||
std::ios_base::binary);
|
||||
std::stringstream is(s);
|
||||
Poco::Base64Decoder ds(is);
|
||||
Poco::StreamCopier::copyStream(ds, sec_file);
|
||||
sec_file.close();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string CommonName() {
|
||||
if (Peer_Cert_)
|
||||
return Peer_Cert_->commonName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string IssuerName() {
|
||||
if (Peer_Cert_)
|
||||
return Peer_Cert_->issuerName();
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string SubjectName() {
|
||||
if (Peer_Cert_)
|
||||
return Peer_Cert_->subjectName();
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex LocalMutex_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
GWObjects::RadiusProxyServerEntry Server_;
|
||||
Poco::Logger &Logger_;
|
||||
std::unique_ptr<Poco::Net::SecureStreamSocket> Socket_;
|
||||
Poco::Thread ReconnectThread_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> Peer_Cert_;
|
||||
volatile bool Connected_ = false;
|
||||
volatile bool TryAgain_ = true;
|
||||
std::uint64_t KeepAlive_;
|
||||
std::string Type_;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
@@ -25,9 +25,23 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
if (StorageService()->AddCommand(Cmd.SerialNumber, Cmd, Status)) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Cmd.to_json(RetObj);
|
||||
if (Handler != nullptr)
|
||||
return Handler->ReturnObject(RetObj);
|
||||
return;
|
||||
if (Handler == nullptr) {
|
||||
// nothing to process/return
|
||||
return;
|
||||
}
|
||||
Poco::Net::HTTPResponse::HTTPStatus cmd_status = Poco::Net::HTTPResponse::HTTP_OK;
|
||||
if (Cmd.ErrorCode > 0) {
|
||||
// command returned error
|
||||
cmd_status = Poco::Net::HTTPResponse::HTTP_BAD_REQUEST;
|
||||
if (Cmd.Command == uCentralProtocol::CONFIGURE) {
|
||||
// special handling for configure command
|
||||
if (!Handler->GetBoolParameter("strict", false)) {
|
||||
// in non-strict mode return success for failed configure command
|
||||
cmd_status = Poco::Net::HTTPResponse::HTTP_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Handler->ReturnObject(RetObj, cmd_status);
|
||||
}
|
||||
if (Handler != nullptr)
|
||||
return Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
@@ -40,8 +54,8 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
std::chrono::milliseconds WaitTimeInMs, Poco::JSON::Object *ObjectToReturn,
|
||||
RESTAPIHandler *Handler, Poco::Logger &Logger, bool Deferred) {
|
||||
|
||||
Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID,
|
||||
RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
|
||||
Logger.information(fmt::format("{},{}: New {} command. User={} Serial={} Details={}. ", Cmd.UUID,
|
||||
RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber, Cmd.Details));
|
||||
Cmd.Submitted = Utils::Now();
|
||||
Cmd.Executed = 0;
|
||||
|
||||
@@ -167,12 +181,29 @@ namespace OpenWifi::RESTAPI_RPC {
|
||||
Cmd.AttachType = "";
|
||||
}
|
||||
|
||||
// If the command fails on the device we should show it as failed and not return 200 OK
|
||||
// exception is configure command which only reported failed in strict validation mode
|
||||
if (Cmd.ErrorCode &&
|
||||
(Cmd.Command != uCentralProtocol::CONFIGURE ||
|
||||
(Cmd.Command == uCentralProtocol::CONFIGURE && Handler->GetBoolParameter("strict", false))
|
||||
))
|
||||
{
|
||||
Logger.information(fmt::format(
|
||||
"Command failed with error on device: {} Reason: {}.",
|
||||
Cmd.ErrorCode, Cmd.ErrorText));
|
||||
return SetCommandStatus(Cmd, Request, Response, Handler,
|
||||
Storage::CommandExecutionType::COMMAND_FAILED, Logger);
|
||||
}
|
||||
|
||||
if (Cmd.ErrorCode == 0 && Cmd.Command == uCentralProtocol::CONFIGURE) {
|
||||
// we need to post a kafka event for this.
|
||||
if (Params.has(uCentralProtocol::CONFIG)) {
|
||||
if (Params.has(uCentralProtocol::CONFIG) && Params.isObject(uCentralProtocol::CONFIG)) {
|
||||
auto Config = Params.get(uCentralProtocol::CONFIG)
|
||||
.extract<Poco::JSON::Object::Ptr>();
|
||||
DeviceConfigurationChangeKafkaEvent KEvent(
|
||||
Utils::SerialNumberToInt(Cmd.SerialNumber), Utils::Now(),
|
||||
Params.get(uCentralProtocol::CONFIG).toString());
|
||||
Config);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace OpenWifi {
|
||||
poco_debug(Logger(), fmt::format("BLACKLIST-POST: {}", D.serialNumber));
|
||||
|
||||
Poco::toLowerInPlace(D.serialNumber);
|
||||
if (StorageService()->IsBlackListed(D.serialNumber)) {
|
||||
if (StorageService()->IsBlackListed(Utils::MACToInt(D.serialNumber))) {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberExists);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,17 +56,27 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
if (DefConfig.Models.empty()) {
|
||||
if (DefConfig.models.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty);
|
||||
}
|
||||
|
||||
std::vector<std::string> Error;
|
||||
if (!ValidateUCentralConfiguration(DefConfig.Configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
DefConfig.platform = DefConfig.platform.empty() ? Platforms::AP : DefConfig.platform;
|
||||
if(DefConfig.platform != Platforms::AP && DefConfig.platform != Platforms::SWITCH) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
DefConfig.Created = DefConfig.LastModified = Utils::Now();
|
||||
if(DefConfig.configuration.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
std::string Error;
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DefConfig.platform),
|
||||
DefConfig.configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
|
||||
}
|
||||
|
||||
DefConfig.created = DefConfig.lastModified = Utils::Now();
|
||||
if (StorageService()->CreateDefaultConfiguration(Name, DefConfig)) {
|
||||
return OK();
|
||||
}
|
||||
@@ -88,19 +98,31 @@ namespace OpenWifi {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!NewConfig.Configuration.empty()) {
|
||||
std::vector<std::string> Error;
|
||||
if (!ValidateUCentralConfiguration(NewConfig.Configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
}
|
||||
Existing.Configuration = NewConfig.Configuration;
|
||||
if(Existing.platform.empty()) {
|
||||
Existing.platform = Platforms::AP;
|
||||
}
|
||||
|
||||
Existing.LastModified = Utils::Now();
|
||||
AssignIfPresent(Obj, "description", Existing.Description);
|
||||
if(ParsedBody_->has("platform")) {
|
||||
if(NewConfig.platform.empty() || (NewConfig.platform != Platforms::AP && NewConfig.platform != Platforms::SWITCH)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
Existing.platform = NewConfig.platform;
|
||||
}
|
||||
|
||||
if (!NewConfig.configuration.empty()) {
|
||||
std::string Error;
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Existing.platform),
|
||||
NewConfig.configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
|
||||
}
|
||||
Existing.configuration = NewConfig.configuration;
|
||||
}
|
||||
|
||||
Existing.lastModified = Utils::Now();
|
||||
AssignIfPresent(Obj, "description", Existing.description);
|
||||
if (Obj->has("modelIds"))
|
||||
Existing.Models = NewConfig.Models;
|
||||
Existing.models = NewConfig.models;
|
||||
|
||||
if (StorageService()->UpdateDefaultConfiguration(Name, Existing)) {
|
||||
GWObjects::DefaultConfiguration ModifiedConfig;
|
||||
|
||||
@@ -87,10 +87,35 @@ namespace OpenWifi {
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Command rtty TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
|
||||
"Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
|
||||
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
|
||||
return Rtty(UUID, RPC, 60000ms, Restrictions);
|
||||
};
|
||||
case APCommands::Commands::package:{
|
||||
GWObjects::DeviceRestrictions Restrictions;
|
||||
std::string pkg_name = "";
|
||||
if (!AP_WS_Server()->Connected(SerialNumberInt_, Restrictions)) {
|
||||
CallCanceled(Command_.c_str(), RESTAPI::Errors::DeviceNotConnected);
|
||||
return BadRequest(RESTAPI::Errors::DeviceNotConnected);
|
||||
}
|
||||
Poco::URI uri(Request->getURI());
|
||||
for (const auto ¶m : uri.getQueryParameters()) {
|
||||
if (param.first == "pkgName") {
|
||||
pkg_name = param.second;
|
||||
}
|
||||
}
|
||||
if (pkg_name.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
auto UUID = MicroServiceCreateUUID();
|
||||
auto RPC = CommandManager()->Next_RPC_ID();
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Command Package TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
|
||||
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
|
||||
return GetPackages(UUID, RPC, pkg_name, 300000ms, Restrictions);
|
||||
}
|
||||
default:
|
||||
return BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||
}
|
||||
@@ -128,6 +153,21 @@ namespace OpenWifi {
|
||||
return DeleteChecks();
|
||||
case APCommands::Commands::statistics:
|
||||
return DeleteStatistics();
|
||||
case APCommands::Commands::package: {
|
||||
GWObjects::DeviceRestrictions Restrictions;
|
||||
if (!AP_WS_Server()->Connected(SerialNumberInt_, Restrictions)) {
|
||||
CallCanceled(Command_.c_str(), RESTAPI::Errors::DeviceNotConnected);
|
||||
return BadRequest(RESTAPI::Errors::DeviceNotConnected);
|
||||
}
|
||||
auto UUID = MicroServiceCreateUUID();
|
||||
auto RPC = CommandManager()->Next_RPC_ID();
|
||||
poco_debug(
|
||||
Logger_,
|
||||
fmt::format(
|
||||
"Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
|
||||
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
|
||||
return DeletePackages(UUID, RPC, 300000ms, Restrictions);
|
||||
}
|
||||
default:
|
||||
return BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||
}
|
||||
@@ -163,8 +203,16 @@ namespace OpenWifi {
|
||||
{APCommands::Commands::telemetry, false, true, &RESTAPI_device_commandHandler::Telemetry,
|
||||
30000ms},
|
||||
{APCommands::Commands::ping, false, true, &RESTAPI_device_commandHandler::Ping, 60000ms},
|
||||
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script,
|
||||
300000ms}};
|
||||
{APCommands::Commands::rrm, false, true, &RESTAPI_device_commandHandler::RRM, 60000ms},
|
||||
{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms},
|
||||
{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
|
||||
{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 60000ms},
|
||||
{APCommands::Commands::powercycle, false, true, &RESTAPI_device_commandHandler::PowerCycle, 60000ms},
|
||||
{APCommands::Commands::fixedconfig, false, true, &RESTAPI_device_commandHandler::FixedConfig, 120000ms},
|
||||
{APCommands::Commands::cablediagnostics, false, true, &RESTAPI_device_commandHandler::CableDiagnostics, 120000ms},
|
||||
{APCommands::Commands::reenroll, false, true, &RESTAPI_device_commandHandler::ReEnroll, 120000ms},
|
||||
{APCommands::Commands::package, false, true, &RESTAPI_device_commandHandler::PackageInstall, 120000ms},
|
||||
};
|
||||
|
||||
void RESTAPI_device_commandHandler::DoPost() {
|
||||
if (!ValidateParameters()) {
|
||||
@@ -401,6 +449,210 @@ namespace OpenWifi {
|
||||
BadRequest(RESTAPI::Errors::NoRecordsDeleted);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::GetPackages(const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
const std::string pkg_name,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
poco_debug(Logger_, fmt::format("GET-PACKAGES: TID={}, user={} serial={}. thr_id={}",
|
||||
TransactionId_, Requester(), SerialNumber_,
|
||||
Poco::Thread::current()->id()));
|
||||
|
||||
if (IsDeviceSimulated(SerialNumber_)) {
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::OPERATION, "list");
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::PACKAGE, pkg_name);
|
||||
|
||||
std::stringstream ParamStream;
|
||||
Params.stringify(ParamStream);
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.Command = uCentralProtocol::PACKAGE;
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.Details = ParamStream.str();
|
||||
|
||||
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::package, false, Cmd, Params,
|
||||
*Request, *Response, timeout, nullptr, nullptr, Logger_);
|
||||
|
||||
Poco::JSON::Object O, P;
|
||||
Cmd.to_json(O);
|
||||
|
||||
Poco::Dynamic::Var resultsVar = O.get("results");
|
||||
Poco::JSON::Object::Ptr resultsObj = resultsVar.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
return ReturnObject(*resultsObj);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::PackageInstall(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("INSTALLPACKAGE", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
poco_debug(Logger_, fmt::format("INSTALL-PACKAGES({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if (IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("INSTALL-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
if (!Obj->has(RESTAPI::Protocol::SERIALNUMBER)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
|
||||
if (SerialNumber_ != SNum) {
|
||||
CallCanceled("INSTALL-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SerialNumberMismatch);
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
|
||||
poco_information(Logger_, fmt::format("INSTALL_OBJECT: {} for device {}", os.str(), SerialNumber_));
|
||||
|
||||
GWObjects::PackageInstall PI;
|
||||
if (!PI.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
Poco::JSON::Array::Ptr ArrayObj = Poco::SharedPtr<Poco::JSON::Array>(new Poco::JSON::Array);
|
||||
for (const auto &i : PI.pkgs) {
|
||||
Poco::JSON::Object::Ptr Obj =
|
||||
Poco::SharedPtr<Poco::JSON::Object>(new Poco::JSON::Object);
|
||||
i.to_json(*Obj);
|
||||
ArrayObj->add(Obj);
|
||||
}
|
||||
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::OPERATION, "install");
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::PACKAGES, ArrayObj);
|
||||
|
||||
std::ostringstream os2;
|
||||
Params.stringify(os2);
|
||||
|
||||
poco_information(Logger_, fmt::format("INSTALL_OBJECT2: {} for device {}", os2.str(), SerialNumber_));
|
||||
|
||||
|
||||
std::stringstream ParamStream;
|
||||
Params.stringify(ParamStream);
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.Command = uCentralProtocol::PACKAGE;
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.Details = ParamStream.str();
|
||||
|
||||
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::package, false, Cmd, Params,
|
||||
*Request, *Response, timeout, nullptr, nullptr, Logger_);
|
||||
|
||||
Poco::JSON::Object O, P;
|
||||
Cmd.to_json(O);
|
||||
|
||||
Poco::Dynamic::Var resultsVar = O.get("results");
|
||||
Poco::JSON::Object::Ptr resultsObj = resultsVar.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
return ReturnObject(*resultsObj);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::DeletePackages(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("DELETE-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
poco_debug(Logger_, fmt::format("DELETE-PACKAGES({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if (IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("DELETE-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
const auto &Obj = ParsedBody_;
|
||||
if (!Obj->has(RESTAPI::Protocol::SERIALNUMBER)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
|
||||
if (SerialNumber_ != SNum) {
|
||||
CallCanceled("DELETE-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SerialNumberMismatch);
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
|
||||
poco_information(Logger_, fmt::format("DELETE_OBJECT: {} for device {}", os.str(), SerialNumber_));
|
||||
|
||||
GWObjects::PackageRemove PR;
|
||||
if (!PR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
Poco::JSON::Array::Ptr ArrayObj = Poco::SharedPtr<Poco::JSON::Array>(new Poco::JSON::Array);
|
||||
for (const auto &i : PR.pkgs) {
|
||||
Poco::JSON::Object::Ptr Obj =
|
||||
Poco::SharedPtr<Poco::JSON::Object>(new Poco::JSON::Object);
|
||||
i.to_json(*Obj);
|
||||
ArrayObj->add(Obj);
|
||||
}
|
||||
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::OPERATION, "delete");
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::PACKAGES, ArrayObj);
|
||||
|
||||
std::ostringstream os2;
|
||||
Params.stringify(os2);
|
||||
|
||||
poco_information(Logger_, fmt::format("DELETE_OBJECT2: {} for device {}", os2.str(), SerialNumber_));
|
||||
|
||||
|
||||
std::stringstream ParamStream;
|
||||
Params.stringify(ParamStream);
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.Command = uCentralProtocol::PACKAGE;
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.Details = ParamStream.str();
|
||||
|
||||
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::package, false, Cmd, Params,
|
||||
*Request, *Response, timeout, nullptr, nullptr, Logger_);
|
||||
|
||||
Poco::JSON::Object O, P;
|
||||
Cmd.to_json(O);
|
||||
|
||||
Poco::Dynamic::Var resultsVar = O.get("results");
|
||||
Poco::JSON::Object::Ptr resultsObj = resultsVar.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
return ReturnObject(*resultsObj);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::Ping(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
@@ -650,13 +902,18 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
}
|
||||
|
||||
GWObjects::Device DeviceInfo;
|
||||
if (!StorageService()->GetDevice(SerialNumber_, DeviceInfo)) {
|
||||
return NotFound();
|
||||
}
|
||||
auto Configuration =
|
||||
GetS(RESTAPI::Protocol::CONFIGURATION, Obj, uCentralProtocol::EMPTY_JSON_DOC);
|
||||
std::vector<std::string> Error;
|
||||
if (!ValidateUCentralConfiguration(Configuration, Error,
|
||||
std::string Error;
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceInfo.DeviceType),
|
||||
Configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
CallCanceled("CONFIGURE", CMD_UUID, CMD_RPC, RESTAPI::Errors::ConfigBlockInvalid);
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
|
||||
}
|
||||
|
||||
auto When = GetWhen(Obj);
|
||||
@@ -682,9 +939,31 @@ namespace OpenWifi {
|
||||
Params.stringify(ParamStream);
|
||||
Cmd.Details = ParamStream.str();
|
||||
|
||||
// retrieve capabilities and encode/compress parameters, if required
|
||||
Poco::JSON::Object ConfigParams = Params;
|
||||
GWObjects::Capabilities Caps;
|
||||
if (StorageService()->GetDeviceCapabilities(SerialNumber_, Caps)) {
|
||||
Poco::JSON::Object CapsJson;
|
||||
Caps.to_json(CapsJson);
|
||||
auto DeviceCaps = CapsJson.getObject(uCentralProtocol::CAPABILITIES);
|
||||
if (DeviceCaps->has("compress_cmd") && DeviceCaps->get("compress_cmd")) {
|
||||
// compressed command capability present and it is set, compress parameters
|
||||
Poco::JSON::Object CompressedParams;
|
||||
std::string CompressedBase64Data;
|
||||
std::uint64_t UncompressedDataLen = ParamStream.str().length();
|
||||
if (Utils::CompressAndEncodeBase64(ParamStream.str(), CompressedBase64Data)) {
|
||||
// set compressed, base 64 encoded data and length of uncompressed data
|
||||
CompressedParams.set(uCentralProtocol::COMPRESS_64, CompressedBase64Data);
|
||||
CompressedParams.set(uCentralProtocol::COMPRESS_SZ, UncompressedDataLen);
|
||||
ConfigParams = CompressedParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// AP_WS_Server()->SetPendingUUID(SerialNumber_, NewUUID);
|
||||
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::configure, true,
|
||||
Cmd, Params, *Request, *Response, timeout,
|
||||
Cmd, ConfigParams, *Request, *Response, timeout,
|
||||
nullptr, this, Logger_);
|
||||
|
||||
if(!Cmd.Executed) {
|
||||
@@ -1166,7 +1445,7 @@ namespace OpenWifi {
|
||||
|
||||
if (RTTYS_server()->UseInternal()) {
|
||||
std::uint64_t SN = Utils::SerialNumberToInt(SerialNumber_);
|
||||
bool mTLS = AP_WS_Server()->DeviceRequiresSecureRtty(SN);
|
||||
bool mTLS = AP_WS_Server()->DeviceRequiresSecureRTTY(SN);
|
||||
auto Hash = Utils::ComputeHash(UserInfo_.webtoken.refresh_token_, Utils::Now());
|
||||
Rtty.Token = Hash.substr(0, RTTY_DEVICE_TOKEN_LENGTH);
|
||||
if (!RTTYS_server()->CreateEndPoint(Rtty.ConnectionId, Rtty.Token, Requester(),
|
||||
@@ -1339,4 +1618,323 @@ namespace OpenWifi {
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::RRM(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
poco_debug(Logger_, fmt::format("RRM({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(!ParsedBody_->has("actions") || !ParsedBody_->isArray("actions")) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
const auto &Actions = *ParsedBody_->getArray("actions");
|
||||
// perform some validation on the commands.
|
||||
for(const auto &action:Actions) {
|
||||
auto ActionDetails = action.extract<Poco::JSON::Object::Ptr>();
|
||||
if(!ActionDetails->has("action")) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
auto ActionStr = ActionDetails->get("action").toString();
|
||||
if( ActionStr != "kick"
|
||||
&& ActionStr != "channel_switch"
|
||||
&& ActionStr != "tx_power"
|
||||
&& ActionStr != "beacon_request"
|
||||
&& ActionStr != "bss_transition"
|
||||
&& ActionStr != "neighbors" ) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidRRMAction);
|
||||
}
|
||||
}
|
||||
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::ACTIONS, Actions);
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::RRM;
|
||||
std::ostringstream os;
|
||||
Params.stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
Cmd.Status= "completed";
|
||||
if(CommandManager()->FireAndForget(SerialNumber_, uCentralProtocol::RRM, Params)) {
|
||||
Cmd.Status= "completed";
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd,
|
||||
Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
return OK();
|
||||
}
|
||||
Cmd.Status= "failed"; // should never happen
|
||||
StorageService()->AddCommand(SerialNumber_, Cmd,
|
||||
Storage::CommandExecutionType::COMMAND_COMPLETED);
|
||||
return BadRequest(RESTAPI::Errors::CouldNotPerformCommand);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::Transfer(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
poco_debug(Logger_, fmt::format("TRANSFER({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
GWObjects::DeviceTransferRequest TR;
|
||||
if(!TR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::TRANSFER;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::transfer, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::CertUpdate(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
poco_debug(Logger_, fmt::format("CERTUPDATE({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
GWObjects::DeviceCertificateUpdateRequest CR;
|
||||
if(!CR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::DeviceTransferRequest TR;
|
||||
if(!TR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::CERTUPDATE;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::certupdate, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::PowerCycle(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
poco_debug(Logger_, fmt::format("POWERCYCLE({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("RRM", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
GWObjects::PowerCycleRequest PR;
|
||||
if(!PR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::POWERCYCLE;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = PR.when;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::powercycle, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
}
|
||||
|
||||
// `fixedconfig` command is used set country propery on AP
|
||||
// This handler uses `fixedconfig` command definitions
|
||||
void RESTAPI_device_commandHandler::FixedConfig(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
poco_debug(Logger_, fmt::format("FIXEDCONFIG({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
|
||||
TransactionId_, Requester(), SerialNumber_));
|
||||
// do not allow `fixedconfig` command for simulated devices
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("FIXEDCONFIG", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
// setup and validate fixedconfig object
|
||||
GWObjects::FixedConfig fixed_config;
|
||||
if(!fixed_config.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
// setup command message
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::FIXEDCONFIG;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = 0;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
// send fixedconfig command to device and return status
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::fixedconfig, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::CableDiagnostics(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
poco_debug(Logger_, fmt::format("CABLEDIAGNOSTICS({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
GWObjects::CableDiagnostics PR;
|
||||
if(!PR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::CABLEDIAGNOSTICS;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = PR.when;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::cablediagnostics, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
}
|
||||
|
||||
void RESTAPI_device_commandHandler::ReEnroll(
|
||||
const std::string &CMD_UUID, uint64_t CMD_RPC,
|
||||
[[maybe_unused]] std::chrono::milliseconds timeout,
|
||||
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
|
||||
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
CallCanceled("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
poco_debug(Logger_, fmt::format("REENROLL({},{}): TID={} user={} serial={}", CMD_UUID,
|
||||
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
|
||||
|
||||
if(IsDeviceSimulated(SerialNumber_)) {
|
||||
CallCanceled("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
|
||||
}
|
||||
|
||||
GWObjects::ReEnroll PR;
|
||||
if(!PR.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.SubmittedBy = Requester();
|
||||
Cmd.UUID = CMD_UUID;
|
||||
Cmd.Command = uCentralProtocol::REENROLL;
|
||||
std::ostringstream os;
|
||||
ParsedBody_->stringify(os);
|
||||
Cmd.Details = os.str();
|
||||
Cmd.RunAt = PR.when;
|
||||
Cmd.ErrorCode = 0;
|
||||
Cmd.WaitingForFile = 0;
|
||||
|
||||
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::reenroll, false, Cmd,
|
||||
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
|
||||
Logger_);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -33,6 +33,13 @@ namespace OpenWifi {
|
||||
void GetStatus();
|
||||
void GetChecks();
|
||||
void DeleteChecks();
|
||||
void GetPackages(const std::string &UUID, uint64_t RPC,
|
||||
std::string pkg_name,
|
||||
std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void DeletePackages(const std::string &UUID, uint64_t RPC,
|
||||
std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
|
||||
bool IsDeviceSimulated(std::string &Serial);
|
||||
|
||||
@@ -62,6 +69,22 @@ namespace OpenWifi {
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void Script(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void RRM(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void CertUpdate(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void Transfer(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void PowerCycle(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void FixedConfig(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void CableDiagnostics(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void ReEnroll(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
void PackageInstall(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
|
||||
const GWObjects::DeviceRestrictions &R);
|
||||
|
||||
static auto PathName() {
|
||||
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "RESTAPI_device_helper.h"
|
||||
|
||||
#include "AP_WS_Server.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoGet() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
@@ -80,6 +82,9 @@ namespace OpenWifi {
|
||||
return OK();
|
||||
|
||||
} else if (StorageService()->DeleteDevice(SerialNumber)) {
|
||||
if(AP_WS_Server()->Connected(Utils::SerialNumberToInt(SerialNumber))) {
|
||||
AP_WS_Server()->Disconnect(Utils::SerialNumberToInt(SerialNumber));
|
||||
}
|
||||
return OK();
|
||||
}
|
||||
|
||||
@@ -101,9 +106,10 @@ namespace OpenWifi {
|
||||
}
|
||||
auto Config = Obj->get("configuration").toString();
|
||||
Poco::JSON::Object Answer;
|
||||
std::vector<std::string> Error;
|
||||
std::string Error;
|
||||
auto DeviceType = Poco::toLower(GetParameter("deviceType", Platforms::AP));
|
||||
auto Res =
|
||||
ValidateUCentralConfiguration(Config, Error, GetBoolParameter("strict", false));
|
||||
ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceType),Config, Error, GetBoolParameter("strict", false));
|
||||
Answer.set("valid", Res);
|
||||
if (!Error.empty())
|
||||
Answer.set("error", Error);
|
||||
@@ -123,12 +129,13 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
}
|
||||
|
||||
std::vector<std::string> Error;
|
||||
std::string Error;
|
||||
if (Device.Configuration.empty() ||
|
||||
(!Device.Configuration.empty() &&
|
||||
!ValidateUCentralConfiguration(Device.Configuration, Error,
|
||||
!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Device.DeviceType),
|
||||
Device.Configuration, Error,
|
||||
GetBoolParameter("strict", false)))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
|
||||
}
|
||||
|
||||
for (auto &i : Device.Notes) {
|
||||
@@ -169,10 +176,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if (!NewDevice.Configuration.empty()) {
|
||||
std::vector<std::string> Error;
|
||||
if (!ValidateUCentralConfiguration(NewDevice.Configuration, Error,
|
||||
std::string Error;
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Existing.DeviceType),
|
||||
NewDevice.Configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
|
||||
}
|
||||
Config::Config NewConfig(NewDevice.Configuration);
|
||||
uint64_t NewConfigUUID = Utils::Now();
|
||||
|
||||
@@ -82,15 +82,24 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
auto platform = Poco::toLower(GetParameter("platform", ""));
|
||||
auto serialOnly = GetBoolParameter(RESTAPI::Protocol::SERIALONLY, false);
|
||||
auto deviceWithStatus = GetBoolParameter(RESTAPI::Protocol::DEVICEWITHSTATUS, false);
|
||||
auto completeInfo = GetBoolParameter("completeInfo", false);
|
||||
auto includeProvisioned = GetBoolParameter("includeProvisioned", true);
|
||||
|
||||
if(!platform.empty() && (platform!=Platforms::AP && platform!=Platforms::SWITCH && platform!="all")) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
if(platform=="all")
|
||||
platform="";
|
||||
|
||||
Poco::JSON::Object RetObj;
|
||||
if (!QB_.Select.empty()) {
|
||||
Poco::JSON::Array Objects;
|
||||
for (auto &i : SelectedRecords()) {
|
||||
auto SerialNumber = i;
|
||||
auto &SerialNumber = i;
|
||||
if (!Utils::ValidSerialNumber(i))
|
||||
continue;
|
||||
GWObjects::Device D;
|
||||
@@ -116,14 +125,14 @@ namespace OpenWifi {
|
||||
else
|
||||
RetObj.set(RESTAPI::Protocol::DEVICES, Objects);
|
||||
|
||||
} else if (QB_.CountOnly == true) {
|
||||
} else if (QB_.CountOnly) {
|
||||
uint64_t Count = 0;
|
||||
if (StorageService()->GetDeviceCount(Count)) {
|
||||
if (StorageService()->GetDeviceCount(Count, platform)) {
|
||||
return ReturnCountOnly(Count);
|
||||
}
|
||||
} else if (serialOnly) {
|
||||
std::vector<std::string> SerialNumbers;
|
||||
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers, OrderBy);
|
||||
StorageService()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers, OrderBy, platform, includeProvisioned);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : SerialNumbers) {
|
||||
Objects.add(i);
|
||||
@@ -141,7 +150,7 @@ namespace OpenWifi {
|
||||
RetObj.set("serialNumbers", Objects);
|
||||
} else {
|
||||
std::vector<GWObjects::Device> Devices;
|
||||
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices, OrderBy);
|
||||
StorageService()->GetDevices(QB_.Offset, QB_.Limit, Devices, OrderBy, platform, includeProvisioned);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : Devices) {
|
||||
Poco::JSON::Object Obj;
|
||||
@@ -174,6 +183,15 @@ namespace OpenWifi {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(GetBoolParameter("simulatedDevices",false)) {
|
||||
auto F = []() ->void {
|
||||
StorageService()->DeleteSimulatedDevice("");
|
||||
};
|
||||
std::thread T(F);
|
||||
T.detach();
|
||||
return OK();
|
||||
}
|
||||
|
||||
if(!QB_.Select.empty() && !Utils::ValidSerialNumbers(QB_.Select)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,15 @@ namespace OpenWifi {
|
||||
|
||||
std::string FileType;
|
||||
std::string FileContent;
|
||||
if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType) || FileContent.empty()) {
|
||||
int WaitingForFile = 0;
|
||||
if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType, WaitingForFile) && !WaitingForFile) {
|
||||
return NotFound();
|
||||
}
|
||||
else if (WaitingForFile) {
|
||||
// waiting for file to be uploaded, return Accepted
|
||||
return Accepted();
|
||||
}
|
||||
|
||||
if (FileType == "pcap") {
|
||||
SendFileContent(FileContent, "application/vnd.tcpdump.pcap", UUID + ".pcap");
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
#include <framework/RESTAPI_Handler.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_file : public RESTAPIHandler {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
static bool ValidRadiusPoolServerType(const std::string &T) {
|
||||
static std::set<std::string> Types{ "generic", "orion", "globalreach"};
|
||||
static std::set<std::string> Types{ "radsec", "generic", "orion", "globalreach"};
|
||||
return Types.find(T)!=Types.end();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "RESTAPI_ProvObjects.h"
|
||||
#include "framework/utils.h"
|
||||
#include <vector>
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#include "RADIUSSessionTracker.h"
|
||||
#include "StorageService.h"
|
||||
#endif
|
||||
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
@@ -29,8 +30,9 @@ namespace OpenWifi::GWObjects {
|
||||
void Device::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "serialNumber", SerialNumber);
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
field_to_json(Obj, "deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible));
|
||||
field_to_json(Obj, "hasRADIUSSessions", RADIUSSessionTracker()->HasSessions(SerialNumber));
|
||||
field_to_json(Obj, "deviceType", StorageService()->GetPlatform(SerialNumber));
|
||||
field_to_json(Obj, "blackListed",
|
||||
StorageService()->IsBlackListed(Utils::MACToInt(SerialNumber)));
|
||||
#endif
|
||||
field_to_json(Obj, "macAddress", MACAddress);
|
||||
field_to_json(Obj, "manufacturer", Manufacturer);
|
||||
@@ -59,6 +61,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "pendingUUID", pendingUUID);
|
||||
field_to_json(Obj, "simulated", simulated);
|
||||
field_to_json(Obj, "lastRecordedContact", lastRecordedContact);
|
||||
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
|
||||
field_to_json(Obj, "connectReason", connectReason);
|
||||
}
|
||||
|
||||
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
|
||||
@@ -66,9 +70,14 @@ namespace OpenWifi::GWObjects {
|
||||
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
ConnectionState ConState;
|
||||
|
||||
#ifdef USE_MEDUSA_CLIENT
|
||||
auto Res = GS()->GetState(SerialNumber);
|
||||
if (Res.has_value()) {
|
||||
Res.value().to_json(SerialNumber, Obj);
|
||||
#else
|
||||
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
|
||||
ConState.to_json(SerialNumber,Obj);
|
||||
ConState.to_json(SerialNumber, Obj);
|
||||
#endif
|
||||
} else {
|
||||
field_to_json(Obj, "ipAddress", "");
|
||||
field_to_json(Obj, "txBytes", (uint64_t)0);
|
||||
@@ -122,6 +131,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj, "pendingUUID", pendingUUID);
|
||||
field_from_json(Obj, "simulated", simulated);
|
||||
field_from_json(Obj, "lastRecordedContact", lastRecordedContact);
|
||||
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
|
||||
field_from_json(Obj, "connectReason", connectReason);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -162,13 +173,15 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "recorded", Recorded);
|
||||
}
|
||||
|
||||
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("configuration", Obj, Configuration);
|
||||
field_to_json(Obj, "name", Name);
|
||||
field_to_json(Obj, "modelIds", Models);
|
||||
field_to_json(Obj, "description", Description);
|
||||
field_to_json(Obj, "created", Created);
|
||||
field_to_json(Obj, "lastModified", LastModified);
|
||||
bool HealthCheck::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "UUID", UUID);
|
||||
field_from_json(Obj, "sanity", Sanity);
|
||||
field_from_json(Obj, "recorded", Recorded);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DefaultFirmware::to_json(Poco::JSON::Object &Obj) const {
|
||||
@@ -218,12 +231,25 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "deferred", deferred);
|
||||
}
|
||||
|
||||
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("configuration", Obj, configuration);
|
||||
field_to_json(Obj, "name", name);
|
||||
field_to_json(Obj, "modelIds", models);
|
||||
field_to_json(Obj, "description", description);
|
||||
field_to_json(Obj, "created", created);
|
||||
field_to_json(Obj, "lastModified", lastModified);
|
||||
field_to_json(Obj, "platform", platform);
|
||||
}
|
||||
|
||||
bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "name", Name);
|
||||
field_from_json(Obj, "configuration", Configuration);
|
||||
field_from_json(Obj, "modelIds", Models);
|
||||
field_from_json(Obj, "description", Description);
|
||||
field_from_json(Obj, "configuration", configuration);
|
||||
field_from_json(Obj, "name", name);
|
||||
field_from_json(Obj, "modelIds", models);
|
||||
field_from_json(Obj, "description", description);
|
||||
field_from_json(Obj, "created", created);
|
||||
field_from_json(Obj, "lastModified", lastModified);
|
||||
field_from_json(Obj, "platform", platform);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -249,7 +275,8 @@ namespace OpenWifi::GWObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConnectionState::to_json([[maybe_unused]] const std::string &SerialNumber, Poco::JSON::Object &Obj) {
|
||||
void ConnectionState::to_json([[maybe_unused]] const std::string &SerialNumber,
|
||||
Poco::JSON::Object &Obj) {
|
||||
field_to_json(Obj, "ipAddress", Address);
|
||||
field_to_json(Obj, "txBytes", TX);
|
||||
field_to_json(Obj, "rxBytes", RX);
|
||||
@@ -271,16 +298,15 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
|
||||
field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
|
||||
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
|
||||
field_to_json(Obj, "certificateIssuerName", certificateIssuerName);
|
||||
field_to_json(Obj, "connectReason", connectReason);
|
||||
field_to_json(Obj, "uptime", uptime);
|
||||
field_to_json(Obj, "compatible", Compatible);
|
||||
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
hasRADIUSSessions = RADIUSSessionTracker()->HasSessions(SerialNumber);
|
||||
AP_WS_Server()->ExtendedAttributes(SerialNumber, hasGPS, sanity,
|
||||
memoryUsed,
|
||||
load,
|
||||
temperature);
|
||||
#endif
|
||||
field_to_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
|
||||
field_to_json(Obj, "hasRADIUSSessions", hasRADIUSSessions);
|
||||
field_to_json(Obj, "hasGPS", hasGPS);
|
||||
field_to_json(Obj, "sanity", sanity);
|
||||
field_to_json(Obj, "memoryUsed", memoryUsed);
|
||||
@@ -310,6 +336,46 @@ namespace OpenWifi::GWObjects {
|
||||
}
|
||||
}
|
||||
|
||||
bool ConnectionState::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "compatible", Compatible);
|
||||
field_from_json(Obj, "ipAddress", Address);
|
||||
field_from_json(Obj, "txBytes", TX);
|
||||
field_from_json(Obj, "rxBytes", RX);
|
||||
field_from_json(Obj, "messageCount", MessageCount);
|
||||
field_from_json(Obj, "UUID", UUID);
|
||||
field_from_json(Obj, "connected", Connected);
|
||||
field_from_json(Obj, "firmware", Firmware);
|
||||
field_from_json(Obj, "lastContact", LastContact);
|
||||
field_from_json(Obj, "associations_2G", Associations_2G);
|
||||
field_from_json(Obj, "associations_5G", Associations_5G);
|
||||
field_from_json(Obj, "associations_6G", Associations_6G);
|
||||
field_from_json(Obj, "webSocketClients", webSocketClients);
|
||||
field_from_json(Obj, "websocketPackets", websocketPackets);
|
||||
field_from_json(Obj, "kafkaClients", kafkaClients);
|
||||
field_from_json(Obj, "kafkaPackets", kafkaPackets);
|
||||
field_from_json(Obj, "locale", locale);
|
||||
field_from_json(Obj, "started", started);
|
||||
field_from_json(Obj, "sessionId", sessionId);
|
||||
field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
|
||||
field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
|
||||
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
|
||||
field_from_json(Obj, "certificateIssuerName", certificateIssuerName);
|
||||
field_from_json(Obj, "connectReason", connectReason);
|
||||
field_from_json(Obj, "uptime", uptime);
|
||||
field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions);
|
||||
field_from_json(Obj, "hasGPS", hasGPS);
|
||||
field_from_json(Obj, "sanity", sanity);
|
||||
field_from_json(Obj, "memoryUsed", memoryUsed);
|
||||
field_from_json(Obj, "sanity", sanity);
|
||||
field_from_json(Obj, "load", load);
|
||||
field_from_json(Obj, "temperature", temperature);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "averageConnectionTime", averageConnectionTime);
|
||||
field_to_json(Obj, "connectedDevices", connectedDevices);
|
||||
@@ -694,4 +760,165 @@ namespace OpenWifi::GWObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceTransferRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serialNumber", serialNumber);
|
||||
field_from_json(Obj, "server", server);
|
||||
field_from_json(Obj, "port", port);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceCertificateUpdateRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serial", serialNumber);
|
||||
field_from_json(Obj, "encodedCertificate", encodedCertificate);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PowerCyclePort::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "name", name);
|
||||
field_from_json(Obj, "cycle", cycle);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PowerCycleRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serial", serialNumber);
|
||||
field_from_json(Obj, "when", when);
|
||||
field_from_json(Obj, "ports", ports);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FixedConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serial", serialNumber);
|
||||
field_from_json(Obj, "country", country);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CableDiagnostics::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serial", serialNumber);
|
||||
field_from_json(Obj, "when", when);
|
||||
field_from_json(Obj, "ports", ports);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReEnroll::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serial", serialNumber);
|
||||
field_from_json(Obj, "when", when);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PackageInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "name", name);
|
||||
field_from_json(Obj, "version", version);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PackageInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "name", name);
|
||||
field_to_json(Obj, "version", version);
|
||||
}
|
||||
|
||||
void PackageList::to_json(Poco::JSON::Object &Obj) const {
|
||||
Obj.set("serialNumber", serialNumber);
|
||||
|
||||
Poco::JSON::Array packageJsonArray;
|
||||
for (const auto &pkg : packageArray) {
|
||||
Poco::JSON::Object pkgObj;
|
||||
pkg.to_json(pkgObj);
|
||||
packageJsonArray.add(pkgObj);
|
||||
}
|
||||
Obj.set("packageArray", packageJsonArray);
|
||||
|
||||
Obj.set("FirstUpdate", Poco::UInt64(FirstUpdate));
|
||||
Obj.set("LastUpdate", Poco::UInt64(LastUpdate));
|
||||
}
|
||||
|
||||
bool ToBeInstalled::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "name", name);
|
||||
field_from_json(Obj, "url", url);
|
||||
|
||||
Poco::URI uri(url);
|
||||
std::string scheme = uri.getScheme();
|
||||
if (scheme != "http" && scheme != "https") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ToBeInstalled::to_json(Poco::JSON::Object &Obj) const {
|
||||
Obj.set("name", name);
|
||||
Obj.set("url", url);
|
||||
}
|
||||
|
||||
bool PackageInstall::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serialNumber", serialNumber);
|
||||
field_from_json(Obj, "when", when);
|
||||
field_from_json(Obj, "packages", pkgs);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ToBeRemoved::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "name", name);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ToBeRemoved::to_json(Poco::JSON::Object &Obj) const {
|
||||
Obj.set("name", name);
|
||||
}
|
||||
|
||||
bool PackageRemove::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "serialNumber", serialNumber);
|
||||
field_from_json(Obj, "packages", pkgs);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace OpenWifi::GWObjects
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace OpenWifi::GWObjects {
|
||||
uint64_t sessionId = 0;
|
||||
double connectionCompletionTime = 0.0;
|
||||
std::uint64_t certificateExpiryDate = 0;
|
||||
std::string certificateIssuerName;
|
||||
std::uint64_t hasRADIUSSessions = 0;
|
||||
bool hasGPS = false;
|
||||
std::uint64_t sanity=0;
|
||||
@@ -49,8 +50,11 @@ namespace OpenWifi::GWObjects {
|
||||
std::double_t load=0.0;
|
||||
std::double_t temperature=0.0;
|
||||
std::string connectReason;
|
||||
std::uint64_t uptime=0;
|
||||
std::uint64_t totalConnectionTime=0;
|
||||
|
||||
void to_json(const std::string &SerialNumber, Poco::JSON::Object &Obj) ;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceRestrictionsKeyInfo {
|
||||
@@ -109,7 +113,10 @@ namespace OpenWifi::GWObjects {
|
||||
DeviceRestrictions restrictionDetails;
|
||||
std::uint64_t pendingUUID = 0;
|
||||
bool simulated=false;
|
||||
std::uint64_t lastRecordedContact=0;
|
||||
std::uint64_t lastRecordedContact=0;
|
||||
std::uint64_t certificateExpiryDate = 0;
|
||||
std::string connectReason;
|
||||
bool blackListed=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
||||
@@ -135,13 +142,15 @@ namespace OpenWifi::GWObjects {
|
||||
};
|
||||
|
||||
struct HealthCheck {
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID = 0;
|
||||
std::string Data;
|
||||
uint64_t Recorded = 0;
|
||||
uint64_t Sanity = 0;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID = 0;
|
||||
std::string Data;
|
||||
uint64_t Recorded = 0;
|
||||
uint64_t Sanity = 0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Capabilities {
|
||||
std::string Capabilities;
|
||||
@@ -172,12 +181,13 @@ namespace OpenWifi::GWObjects {
|
||||
};
|
||||
|
||||
struct DefaultConfiguration {
|
||||
std::string Name;
|
||||
std::string Configuration;
|
||||
Types::StringVec Models;
|
||||
std::string Description;
|
||||
uint64_t Created;
|
||||
uint64_t LastModified;
|
||||
std::string name;
|
||||
std::string configuration;
|
||||
Types::StringVec models;
|
||||
std::string description;
|
||||
uint64_t created;
|
||||
uint64_t lastModified;
|
||||
std::string platform;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
@@ -452,4 +462,141 @@ namespace OpenWifi::GWObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
enum class RadiusPoolStrategy {
|
||||
round_robin, random, weighted, unknown
|
||||
};
|
||||
|
||||
enum class RadiusEndpointType {
|
||||
generic, radsec, globalreach, orion, unknown
|
||||
};
|
||||
|
||||
static inline RadiusEndpointType RadiusEndpointType(const std::string &T) {
|
||||
if(T=="generic") return RadiusEndpointType::generic;
|
||||
if(T=="radsec") return RadiusEndpointType::radsec;
|
||||
if(T=="globalreach") return RadiusEndpointType::globalreach;
|
||||
if(T=="orion") return RadiusEndpointType::orion;
|
||||
return RadiusEndpointType::unknown;
|
||||
}
|
||||
|
||||
static inline RadiusPoolStrategy RadiusPoolStrategy(const std::string &T) {
|
||||
if(T=="round_robin") return RadiusPoolStrategy::round_robin;
|
||||
if(T=="random") return RadiusPoolStrategy::random;
|
||||
if(T=="weighted") return RadiusPoolStrategy::weighted;
|
||||
return RadiusPoolStrategy::unknown;
|
||||
}
|
||||
|
||||
static inline std::string to_string(enum RadiusEndpointType T) {
|
||||
switch(T) {
|
||||
case RadiusEndpointType::generic: return "generic";
|
||||
case RadiusEndpointType::radsec: return "radsec";
|
||||
case RadiusEndpointType::globalreach: return "globalreach";
|
||||
case RadiusEndpointType::orion: return "orion";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::string to_string(enum RadiusPoolStrategy T) {
|
||||
switch(T) {
|
||||
case RadiusPoolStrategy::round_robin: return "round_robin";
|
||||
case RadiusPoolStrategy::random: return "random";
|
||||
case RadiusPoolStrategy::weighted: return "weighted";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceTransferRequest {
|
||||
std::string serialNumber;
|
||||
std::string server;
|
||||
std::uint64_t port;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceCertificateUpdateRequest {
|
||||
std::string serialNumber;
|
||||
std::string encodedCertificate;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct PowerCyclePort {
|
||||
std::string name;
|
||||
std::uint64_t cycle=10000;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct PowerCycleRequest {
|
||||
std::string serialNumber;
|
||||
std::uint64_t when;
|
||||
std::vector<PowerCyclePort> ports;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct FixedConfig {
|
||||
std::string serialNumber;
|
||||
std::string country;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct CableDiagnostics {
|
||||
std::string serialNumber;
|
||||
std::uint64_t when;
|
||||
std::vector<std::string> ports;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct ReEnroll {
|
||||
std::string serialNumber;
|
||||
std::uint64_t when;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
struct PackageInfo {
|
||||
std::string name;
|
||||
std::string version;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
struct PackageList {
|
||||
std::string serialNumber;
|
||||
std::vector<PackageInfo> packageArray;
|
||||
uint64_t FirstUpdate = 0;
|
||||
uint64_t LastUpdate = 0;
|
||||
std::string packageStringArray;
|
||||
|
||||
bool from_json(const Poco::JSON::Array::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
struct ToBeInstalled {
|
||||
std::string name;
|
||||
std::string url;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
struct PackageInstall {
|
||||
std::string serialNumber;
|
||||
std::uint64_t when;
|
||||
std::vector<ToBeInstalled> pkgs;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
struct ToBeRemoved {
|
||||
std::string name;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
struct PackageRemove {
|
||||
std::string serialNumber;
|
||||
std::uint64_t when;
|
||||
std::vector<ToBeRemoved> pkgs;
|
||||
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
} // namespace OpenWifi::GWObjects
|
||||
|
||||
@@ -78,21 +78,22 @@ namespace OpenWifi::OWLSObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "simulationId", simulationId);
|
||||
field_to_json(Obj, "state", state);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "msgsTx", msgsTx);
|
||||
field_to_json(Obj, "msgsRx", msgsRx);
|
||||
field_to_json(Obj, "liveDevices", liveDevices);
|
||||
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
|
||||
field_to_json(Obj, "startTime", startTime);
|
||||
field_to_json(Obj, "endTime", endTime);
|
||||
field_to_json(Obj, "errorDevices", errorDevices);
|
||||
field_to_json(Obj, "owner", owner);
|
||||
}
|
||||
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "simulationId", simulationId);
|
||||
field_to_json(Obj, "state", state);
|
||||
field_to_json(Obj, "tx", tx);
|
||||
field_to_json(Obj, "rx", rx);
|
||||
field_to_json(Obj, "msgsTx", msgsTx);
|
||||
field_to_json(Obj, "msgsRx", msgsRx);
|
||||
field_to_json(Obj, "liveDevices", liveDevices);
|
||||
field_to_json(Obj, "timeToFullDevices", timeToFullDevices);
|
||||
field_to_json(Obj, "startTime", startTime);
|
||||
field_to_json(Obj, "endTime", endTime);
|
||||
field_to_json(Obj, "errorDevices", errorDevices);
|
||||
field_to_json(Obj, "owner", owner);
|
||||
field_to_json(Obj, "expectedDevices", expectedDevices);
|
||||
}
|
||||
|
||||
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {}
|
||||
|
||||
|
||||
@@ -43,23 +43,24 @@ namespace OpenWifi::OWLSObjects {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct SimulationStatus {
|
||||
std::string id;
|
||||
std::string simulationId;
|
||||
std::string state;
|
||||
uint64_t tx;
|
||||
uint64_t rx;
|
||||
uint64_t msgsTx;
|
||||
uint64_t msgsRx;
|
||||
uint64_t liveDevices;
|
||||
uint64_t timeToFullDevices;
|
||||
uint64_t startTime;
|
||||
uint64_t endTime;
|
||||
uint64_t errorDevices;
|
||||
std::string owner;
|
||||
struct SimulationStatus {
|
||||
std::string id;
|
||||
std::string simulationId;
|
||||
std::string state;
|
||||
uint64_t tx;
|
||||
uint64_t rx;
|
||||
uint64_t msgsTx;
|
||||
uint64_t msgsRx;
|
||||
uint64_t liveDevices;
|
||||
uint64_t timeToFullDevices;
|
||||
uint64_t startTime;
|
||||
uint64_t endTime;
|
||||
uint64_t errorDevices;
|
||||
std::string owner;
|
||||
uint64_t expectedDevices;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct Dashboard {
|
||||
int O;
|
||||
|
||||
@@ -587,6 +587,9 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json(Obj, "locale", locale);
|
||||
field_to_json(Obj, "realMacAddress", realMacAddress);
|
||||
field_to_json(Obj, "doNotAllowOverrides", doNotAllowOverrides);
|
||||
field_to_json(Obj, "imported", imported);
|
||||
field_to_json(Obj, "connected", connected);
|
||||
field_to_json(Obj, "platform", platform);
|
||||
}
|
||||
|
||||
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -609,6 +612,9 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json(Obj, "locale", locale);
|
||||
field_from_json(Obj, "realMacAddress", realMacAddress);
|
||||
field_from_json(Obj, "doNotAllowOverrides", doNotAllowOverrides);
|
||||
field_from_json(Obj, "imported", imported);
|
||||
field_from_json(Obj, "connected", connected);
|
||||
field_from_json(Obj, "platform", platform);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
@@ -1194,4 +1200,243 @@ namespace OpenWifi::ProvObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLBLRAccountInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json(Obj, "privateKey", privateKey);
|
||||
field_to_json(Obj, "country", country);
|
||||
field_to_json(Obj, "province", province);
|
||||
field_to_json(Obj, "city", city);
|
||||
field_to_json(Obj, "organization", organization);
|
||||
field_to_json(Obj, "commonName", commonName);
|
||||
field_to_json(Obj, "CSR", CSR);
|
||||
field_to_json(Obj, "CSRPrivateKey", CSRPrivateKey);
|
||||
field_to_json(Obj, "CSRPublicKey", CSRPublicKey);
|
||||
field_to_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
|
||||
}
|
||||
|
||||
bool GLBLRAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
info.from_json(Obj);
|
||||
field_from_json(Obj, "privateKey", privateKey);
|
||||
field_from_json(Obj, "country", country);
|
||||
field_from_json(Obj, "province", province);
|
||||
field_from_json(Obj, "city", city);
|
||||
field_from_json(Obj, "organization", organization);
|
||||
field_from_json(Obj, "commonName", commonName);
|
||||
field_from_json(Obj, "CSR", CSR);
|
||||
field_from_json(Obj, "CSRPrivateKey", CSRPrivateKey);
|
||||
field_from_json(Obj, "CSRPublicKey", CSRPublicKey);
|
||||
field_from_json(Obj, "GlobalReachAcctId", GlobalReachAcctId);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLBLRCertificateInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "name", name);
|
||||
field_to_json(Obj, "accountId", accountId);
|
||||
field_to_json(Obj, "csr", csr);
|
||||
field_to_json(Obj, "certificate", certificate);
|
||||
field_to_json(Obj, "certificateChain", certificateChain);
|
||||
field_to_json(Obj, "certificateId", certificateId);
|
||||
field_to_json(Obj, "expiresAt", expiresAt);
|
||||
field_to_json(Obj, "created", created);
|
||||
}
|
||||
|
||||
bool GLBLRCertificateInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "name", name);
|
||||
field_from_json(Obj, "accountId", accountId);
|
||||
field_from_json(Obj, "csr", csr);
|
||||
field_from_json(Obj, "certificate", certificate);
|
||||
field_from_json(Obj, "certificateChain", certificateChain);
|
||||
field_from_json(Obj, "certificateId", certificateId);
|
||||
field_from_json(Obj, "expiresAt", expiresAt);
|
||||
field_from_json(Obj, "created", created);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GooglOrionAccountInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json(Obj, "privateKey", privateKey);
|
||||
field_to_json(Obj, "certificate", certificate);
|
||||
field_to_json(Obj, "cacerts", cacerts);
|
||||
}
|
||||
|
||||
bool GooglOrionAccountInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
info.from_json(Obj);
|
||||
field_from_json(Obj, "privateKey", privateKey);
|
||||
field_from_json(Obj, "certificate", certificate);
|
||||
field_from_json(Obj, "cacerts", cacerts);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSServer::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "Hostname", Hostname);
|
||||
field_to_json(Obj, "IP", IP);
|
||||
field_to_json(Obj, "Port", Port);
|
||||
field_to_json(Obj, "Secret", Secret);
|
||||
}
|
||||
|
||||
bool RADIUSServer::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "Hostname", Hostname);
|
||||
field_from_json(Obj, "IP", IP);
|
||||
field_from_json(Obj, "Port", Port);
|
||||
field_from_json(Obj, "Secret", Secret);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndPointRadiusType::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "Authentication", Authentication);
|
||||
field_to_json(Obj, "Accounting", Accounting);
|
||||
field_to_json(Obj, "CoA", CoA);
|
||||
field_to_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
}
|
||||
|
||||
bool RADIUSEndPointRadiusType::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "Authentication", Authentication);
|
||||
field_from_json(Obj, "Accounting", Accounting);
|
||||
field_from_json(Obj, "CoA", CoA);
|
||||
field_from_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndPointRadsecType::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "Hostname", Hostname);
|
||||
field_to_json(Obj, "IP", IP);
|
||||
field_to_json(Obj, "Port", Port);
|
||||
field_to_json(Obj, "Secret", Secret);
|
||||
field_to_json(Obj, "OpenRoamingType", OpenRoamingType);
|
||||
field_to_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
|
||||
field_to_json(Obj, "Weight", Weight);
|
||||
field_to_json(Obj, "Certificate", Certificate);
|
||||
field_to_json(Obj, "PrivateKey", PrivateKey);
|
||||
field_to_json(Obj, "CaCerts", CaCerts);
|
||||
field_to_json(Obj, "AllowSelfSigned", AllowSelfSigned);
|
||||
}
|
||||
|
||||
bool RADIUSEndPointRadsecType::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "Hostname", Hostname);
|
||||
field_from_json(Obj, "IP", IP);
|
||||
field_from_json(Obj, "Port", Port);
|
||||
field_from_json(Obj, "Secret", Secret);
|
||||
field_from_json(Obj, "OpenRoamingType", OpenRoamingType);
|
||||
field_from_json(Obj, "UseOpenRoamingAccount", UseOpenRoamingAccount);
|
||||
field_from_json(Obj, "Weight", Weight);
|
||||
field_from_json(Obj, "Certificate", Certificate);
|
||||
field_from_json(Obj, "PrivateKey", PrivateKey);
|
||||
field_from_json(Obj, "CaCerts", CaCerts);
|
||||
field_from_json(Obj, "AllowSelfSigned", AllowSelfSigned);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndPoint::to_json(Poco::JSON::Object &Obj) const {
|
||||
info.to_json(Obj);
|
||||
field_to_json(Obj, "Type", Type);
|
||||
field_to_json(Obj, "RadsecServers", RadsecServers);
|
||||
field_to_json(Obj, "RadiusServers", RadiusServers);
|
||||
field_to_json(Obj, "PoolStrategy", PoolStrategy);
|
||||
field_to_json(Obj, "Index", Index);
|
||||
field_to_json(Obj, "UsedBy", UsedBy);
|
||||
field_to_json(Obj, "UseGWProxy", UseGWProxy);
|
||||
field_to_json(Obj, "NasIdentifier", NasIdentifier);
|
||||
field_to_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
}
|
||||
|
||||
bool RADIUSEndPoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
info.from_json(Obj);
|
||||
field_from_json(Obj, "Type", Type);
|
||||
field_from_json(Obj, "RadsecServers", RadsecServers);
|
||||
field_from_json(Obj, "RadiusServers", RadiusServers);
|
||||
field_from_json(Obj, "PoolStrategy", PoolStrategy);
|
||||
field_from_json(Obj, "Index", Index);
|
||||
field_from_json(Obj, "UsedBy", UsedBy);
|
||||
field_from_json(Obj, "UseGWProxy", UseGWProxy);
|
||||
field_from_json(Obj, "NasIdentifier", NasIdentifier);
|
||||
field_from_json(Obj, "AccountingInterval", AccountingInterval);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIUSEndpointUpdateStatus::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "lastUpdate", lastUpdate);
|
||||
field_to_json(Obj, "lastConfigurationChange", lastConfigurationChange);
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "lastUpdate", lastUpdate);
|
||||
field_from_json(Obj, "lastConfigurationChange", lastConfigurationChange);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::Read() {
|
||||
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
|
||||
try {
|
||||
if (F.exists()) {
|
||||
Poco::JSON::Parser P;
|
||||
std::ifstream ifs(F.path(), std::ios_base::in | std::ios_base::binary);
|
||||
auto Obj = P.parse(ifs);
|
||||
return from_json(Obj.extract<Poco::JSON::Object::Ptr>());
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::Save() {
|
||||
Poco::File F(OpenWifi::MicroServiceDataDirectory()+"/RADIUSEndpointUpdateStatus.json");
|
||||
try {
|
||||
Poco::JSON::Object Obj;
|
||||
to_json(Obj);
|
||||
std::ofstream O(F.path(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
|
||||
Poco::JSON::Stringifier::stringify(Obj, O);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RADIUSEndpointUpdateStatus::ChangeConfiguration() {
|
||||
Read();
|
||||
lastConfigurationChange = Utils::Now();
|
||||
return Save();
|
||||
}
|
||||
|
||||
} // namespace OpenWifi::ProvObjects
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
@@ -38,7 +38,7 @@ namespace OpenWifi {
|
||||
inline int Start() final {
|
||||
poco_notice(Logger(), "Starting...");
|
||||
|
||||
std::shared_lock L(KeyMutex_);
|
||||
std::lock_guard L(KeyMutex_);
|
||||
|
||||
CacheFilename_ = MicroServiceDataDirectory() + "/signature_cache";
|
||||
Poco::File CacheFile(CacheFilename_);
|
||||
@@ -91,7 +91,7 @@ namespace OpenWifi {
|
||||
|
||||
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
|
||||
const std::string &Data) const {
|
||||
std::shared_lock L(KeyMutex_);
|
||||
std::lock_guard L(KeyMutex_);
|
||||
try {
|
||||
if (Restrictions.key_info.algo == "static") {
|
||||
return "aaaaaaaaaa";
|
||||
@@ -120,7 +120,7 @@ namespace OpenWifi {
|
||||
|
||||
inline std::string Sign(const GWObjects::DeviceRestrictions &Restrictions,
|
||||
const Poco::URI &uri) {
|
||||
std::shared_lock L(KeyMutex_);
|
||||
std::lock_guard L(KeyMutex_);
|
||||
try {
|
||||
if (Restrictions.key_info.algo == "static") {
|
||||
return "aaaaaaaaaa";
|
||||
@@ -172,7 +172,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex KeyMutex_;
|
||||
mutable std::mutex KeyMutex_;
|
||||
std::map<std::string, Poco::SharedPtr<Poco::Crypto::RSAKey>> Keys_;
|
||||
std::map<std::string, std::string> SignatureCache_;
|
||||
std::string CacheFilename_;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenWifi::StateUtils {
|
||||
}
|
||||
|
||||
bool ComputeAssociations(const Poco::JSON::Object::Ptr RawObject, uint64_t &Radios_2G,
|
||||
uint64_t &Radios_5G, uint64_t &Radios_6G) {
|
||||
uint64_t &Radios_5G, uint64_t &Radios_6G, uint64_t &UpTime ) {
|
||||
Radios_2G = 0;
|
||||
Radios_5G = 0;
|
||||
Radios_6G = 0;
|
||||
@@ -90,9 +90,15 @@ namespace OpenWifi::StateUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
// std::cout << Radios_2G << " " << Radios_5G << " " << Radios_6G << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(RawObject->has("unit") && !RawObject->isNull("unit") && RawObject->isObject("unit")) {
|
||||
auto unit = RawObject->getObject("unit");
|
||||
if(unit->has("uptime")) {
|
||||
UpTime = unit->get("uptime");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace OpenWifi::StateUtils
|
||||
@@ -8,5 +8,5 @@
|
||||
|
||||
namespace OpenWifi::StateUtils {
|
||||
bool ComputeAssociations(const Poco::JSON::Object::Ptr RawObject, uint64_t &Radios_2G,
|
||||
uint64_t &Radios_5G, uint64_t &Radio_6G);
|
||||
uint64_t &Radios_5G, uint64_t &Radio_6G, uint64_t &UpTime);
|
||||
}
|
||||
@@ -22,6 +22,8 @@ namespace OpenWifi {
|
||||
ScriptDB_->Create();
|
||||
ScriptDB_->Initialize();
|
||||
|
||||
FixDeviceTypeBug();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,22 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class LockedDbSession {
|
||||
public:
|
||||
explicit LockedDbSession();
|
||||
~LockedDbSession() = default;
|
||||
inline std::mutex &Mutex() { return *Mutex_; };
|
||||
inline Poco::Data::Session &Session() {
|
||||
if(!Session_->isConnected()) {
|
||||
Session_->reconnect();
|
||||
}
|
||||
return *Session_;
|
||||
};
|
||||
private:
|
||||
std::shared_ptr<Poco::Data::Session> Session_;
|
||||
std::shared_ptr<std::mutex> Mutex_;
|
||||
};
|
||||
|
||||
class Storage : public StorageClass {
|
||||
|
||||
public:
|
||||
@@ -90,7 +106,8 @@ namespace OpenWifi {
|
||||
|
||||
// typedef std::map<std::string,std::string> DeviceCapabilitiesCache;
|
||||
|
||||
bool AddLog(const GWObjects::DeviceLog &Log);
|
||||
bool AddLog(LockedDbSession &Session, const GWObjects::DeviceLog &Log);
|
||||
bool AddStatisticsData(Poco::Data::Session &Session, const GWObjects::Statistics &Stats);
|
||||
bool AddStatisticsData(const GWObjects::Statistics &Stats);
|
||||
bool GetStatisticsData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
|
||||
uint64_t Offset, uint64_t HowMany,
|
||||
@@ -102,6 +119,7 @@ namespace OpenWifi {
|
||||
std::vector<GWObjects::Statistics> &Stats);
|
||||
|
||||
bool AddHealthCheckData(const GWObjects::HealthCheck &Check);
|
||||
bool AddHealthCheckData(LockedDbSession &Session, const GWObjects::HealthCheck &Check);
|
||||
bool GetHealthCheckData(std::string &SerialNumber, uint64_t FromDate, uint64_t ToDate,
|
||||
uint64_t Offset, uint64_t HowMany,
|
||||
std::vector<GWObjects::HealthCheck> &Checks);
|
||||
@@ -115,31 +133,43 @@ namespace OpenWifi {
|
||||
uint64_t &NewUUID);
|
||||
|
||||
bool RollbackDeviceConfigurationChange(std::string & SerialNumber);
|
||||
bool CompleteDeviceConfigurationChange(Poco::Data::Session &Session, std::string & SerialNumber);
|
||||
bool CompleteDeviceConfigurationChange(std::string & SerialNumber);
|
||||
|
||||
bool CreateDevice(LockedDbSession &Session, GWObjects::Device &);
|
||||
bool CreateDevice(GWObjects::Device &);
|
||||
bool CreateDefaultDevice(std::string &SerialNumber, const Config::Capabilities &Caps,
|
||||
bool CreateDefaultDevice(Poco::Data::Session &Session,std::string &SerialNumber,
|
||||
const Config::Capabilities &Caps,
|
||||
std::string &Firmware, const Poco::Net::IPAddress &IPAddress,
|
||||
bool simulated);
|
||||
bool CreateDevice(Poco::Data::Session &Sess, GWObjects::Device &DeviceDetails);
|
||||
|
||||
bool GetDevice(std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevice(LockedDbSession &Session, const std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevice(Poco::Data::Session &Session, const std::string &SerialNumber, GWObjects::Device &DeviceDetails);
|
||||
bool GetDevice(const std::string &SerialNumber, GWObjects::Device &);
|
||||
bool GetDevices(uint64_t From, uint64_t HowMany, std::vector<GWObjects::Device> &Devices,
|
||||
const std::string &orderBy = "");
|
||||
const std::string &orderBy = "",
|
||||
const std::string &platform = "",
|
||||
bool includeProvisioned = true);
|
||||
// bool GetDevices(uint64_t From, uint64_t HowMany, const std::string & Select,
|
||||
// std::vector<GWObjects::Device> &Devices, const std::string & orderBy="");
|
||||
bool DeleteDevice(std::string &SerialNumber);
|
||||
bool DeleteDevices(std::string &SerialPattern, bool SimulatedOnly);
|
||||
bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly);
|
||||
std::string GetPlatform(const std::string &SerialNumber);
|
||||
|
||||
bool UpdateDevice(GWObjects::Device &);
|
||||
bool UpdateDevice(LockedDbSession &Session, GWObjects::Device &);
|
||||
bool UpdateDevice(Poco::Data::Session &Sess, GWObjects::Device &NewDeviceDetails);
|
||||
bool DeviceExists(std::string &SerialNumber);
|
||||
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
|
||||
bool GetDeviceCount(uint64_t &Count);
|
||||
bool GetDeviceCount(uint64_t &Count, const std::string &platform = "");
|
||||
bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany,
|
||||
std::vector<std::string> &SerialNumbers,
|
||||
const std::string &orderBy = "");
|
||||
const std::string &orderBy = "",
|
||||
const std::string &platform = "",
|
||||
bool includeProvisioned = true);
|
||||
bool GetDeviceFWUpdatePolicy(std::string &SerialNumber, std::string &Policy);
|
||||
bool SetDevicePassword(std::string &SerialNumber, std::string &Password);
|
||||
bool SetDevicePassword(LockedDbSession &Session, std::string &SerialNumber, std::string &Password);
|
||||
bool UpdateSerialNumberCache();
|
||||
static void GetDeviceDbFieldList(Types::StringVec &Fields);
|
||||
|
||||
@@ -148,9 +178,11 @@ namespace OpenWifi {
|
||||
|
||||
bool UpdateDeviceCapabilities(std::string &SerialNumber,
|
||||
const Config::Capabilities &Capabilities);
|
||||
bool UpdateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber,
|
||||
const Config::Capabilities &Capabilities);
|
||||
bool GetDeviceCapabilities(std::string &SerialNumber, GWObjects::Capabilities &);
|
||||
bool DeleteDeviceCapabilities(std::string &SerialNumber);
|
||||
bool CreateDeviceCapabilities(std::string &SerialNumber,
|
||||
bool CreateDeviceCapabilities(Poco::Data::Session &Session, std::string &SerialNumber,
|
||||
const Config::Capabilities &Capabilities);
|
||||
bool InitCapabilitiesCache();
|
||||
|
||||
@@ -171,6 +203,7 @@ namespace OpenWifi {
|
||||
bool GetDefaultConfigurations(uint64_t From, uint64_t HowMany,
|
||||
std::vector<GWObjects::DefaultConfiguration> &Devices);
|
||||
bool FindDefaultConfigurationForModel(const std::string &Model,
|
||||
const std::string &Platform,
|
||||
GWObjects::DefaultConfiguration &DefConfig);
|
||||
uint64_t GetDefaultConfigurationsCount();
|
||||
bool DefaultConfigurationAlreadyExists(std::string &Name);
|
||||
@@ -210,7 +243,7 @@ namespace OpenWifi {
|
||||
const std::string &Type);
|
||||
bool CancelWaitFile(std::string &UUID, std::string &ErrorText);
|
||||
bool GetAttachedFileContent(std::string &UUID, const std::string &SerialNumber,
|
||||
std::string &FileContent, std::string &Type);
|
||||
std::string &FileContent, std::string &Type, int& WaitingForFile);
|
||||
bool RemoveAttachedFile(std::string &UUID);
|
||||
bool SetCommandResult(std::string &UUID, std::string &Result);
|
||||
bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany,
|
||||
@@ -222,28 +255,32 @@ namespace OpenWifi {
|
||||
void RemovedExpiredCommands();
|
||||
void RemoveTimedOutCommands();
|
||||
|
||||
bool RemoveOldCommands(std::string &SerilNumber, std::string &Command);
|
||||
bool RemoveOldCommands(std::string &SerialNumber, std::string &Command);
|
||||
|
||||
bool AddBlackListDevices(std::vector<GWObjects::BlackListedDevice> &Devices);
|
||||
bool AddBlackListDevice(GWObjects::BlackListedDevice &Device);
|
||||
bool GetBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
|
||||
bool DeleteBlackListDevice(std::string &SerialNumber);
|
||||
bool IsBlackListed(const std::string &SerialNumber, std::string &reason,
|
||||
bool IsBlackListed(std::uint64_t SerialNumber, std::string &reason,
|
||||
std::string &author, std::uint64_t &created);
|
||||
bool IsBlackListed(const std::string &SerialNumber);
|
||||
bool IsBlackListed(std::uint64_t SerialNumber);
|
||||
bool InitializeBlackListCache();
|
||||
bool GetBlackListDevices(uint64_t Offset, uint64_t HowMany,
|
||||
std::vector<GWObjects::BlackListedDevice> &Devices);
|
||||
bool UpdateBlackListDevice(std::string &SerialNumber, GWObjects::BlackListedDevice &Device);
|
||||
uint64_t GetBlackListDeviceCount();
|
||||
|
||||
bool DeleteSimulatedDevice(const std::string &SerialNumber);
|
||||
|
||||
bool RemoveHealthChecksRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveDeviceLogsRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveStatisticsRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveCommandListRecordsOlderThan(uint64_t Date);
|
||||
bool RemoveUploadedFilesRecordsOlderThan(uint64_t Date);
|
||||
|
||||
bool SetDeviceLastRecordedContact(std::string & SeialNumber, std::uint64_t lastRecordedContact);
|
||||
bool SetDeviceLastRecordedContact(LockedDbSession &Session, std::string & SerialNumber, std::uint64_t lastRecordedContact);
|
||||
bool SetDeviceLastRecordedContact(std::string & SerialNumber, std::uint64_t lastRecordedContact);
|
||||
bool SetDeviceLastRecordedContact(Poco::Data::Session & Session, std::string & SerialNumber, std::uint64_t lastRecordedContact);
|
||||
|
||||
int Create_Tables();
|
||||
int Create_Statistics();
|
||||
@@ -260,13 +297,24 @@ namespace OpenWifi {
|
||||
bool AnalyzeCommands(Types::CountedMap &R);
|
||||
bool AnalyzeDevices(GWObjects::Dashboard &D);
|
||||
|
||||
void FixDeviceTypeBug();
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
inline Poco::Data::Session StartSession() {
|
||||
return Pool_->get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<OpenWifi::ScriptDB> ScriptDB_;
|
||||
};
|
||||
|
||||
inline auto StorageService() { return Storage::instance(); }
|
||||
|
||||
inline LockedDbSession::LockedDbSession() {
|
||||
Session_ = std::make_shared<Poco::Data::Session>(Poco::Data::Session(StorageService()->StartSession()));
|
||||
Mutex_ = std::make_shared<std::mutex>();
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -120,14 +120,16 @@ namespace OpenWifi {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
|
||||
try {
|
||||
int Op, flags;
|
||||
int IncomingSize;
|
||||
int Op, flags, IncomingSize;
|
||||
|
||||
IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
poco_information(
|
||||
Logger(),
|
||||
if (IncomingSize == -1) {
|
||||
poco_trace(Logger(),
|
||||
fmt::format("TELEMETRY-EMPTY({}): Empty frame, non-blocking try-again.", CId_));
|
||||
} else if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
poco_information(Logger(),
|
||||
fmt::format("TELEMETRY-DISCONNECT({}): device has disconnected.", CId_));
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
@@ -136,12 +138,14 @@ namespace OpenWifi {
|
||||
fmt::format("TELEMETRY-WS-PING({}): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} else if (Op == Poco::Net::WebSocket::FRAME_OP_CLOSE) {
|
||||
poco_information(
|
||||
Logger(),
|
||||
poco_information(Logger(),
|
||||
fmt::format("TELEMETRY-DISCONNECT({}): device wants to disconnect.", CId_));
|
||||
MustDisconnect = true;
|
||||
} else if (Op == Poco::Net::WebSocket::FRAME_OP_CONT) {
|
||||
poco_information(Logger(),
|
||||
fmt::format("TELEMETRY-CONT({}): rx {} bytes.", CId_, IncomingSize));
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
@@ -154,4 +158,4 @@ namespace OpenWifi {
|
||||
SendTelemetryShutdown();
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -111,7 +111,6 @@ namespace OpenWifi {
|
||||
}
|
||||
} break;
|
||||
case TelemetryNotification::NotificationType::unregister: {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
auto client = Clients_.find(Notification->Data_);
|
||||
if (client != Clients_.end()) {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "AP_WS_ReactorPool.h"
|
||||
#include "AP_WS_Reactor_Pool.h"
|
||||
#include "TelemetryClient.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
// #include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -28,11 +30,11 @@ namespace OpenWifi {
|
||||
if (F.exists()) {
|
||||
std::ostringstream OS;
|
||||
std::ifstream IF(FileName);
|
||||
Poco::StreamCopier::copyStream(IF, OS);
|
||||
Registry_ = nlohmann::json::parse(OS.str());
|
||||
Poco::JSON::Parser P;
|
||||
Registry_ = P.parse(IF).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
} catch (...) {
|
||||
Registry_ = nlohmann::json::parse("{}");
|
||||
Registry_ = Poco::makeShared<Poco::JSON::Object>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,54 +46,47 @@ namespace OpenWifi {
|
||||
inline ~AppServiceRegistry() { Save(); }
|
||||
|
||||
inline void Save() {
|
||||
std::istringstream IS(to_string(Registry_));
|
||||
std::ofstream OF;
|
||||
OF.open(FileName, std::ios::binary | std::ios::trunc);
|
||||
Poco::StreamCopier::copyStream(IS, OF);
|
||||
Registry_->stringify(OF);
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, uint64_t Value) {
|
||||
Registry_[Key] = Value;
|
||||
void Set(const char *key, const std::vector<std::string> &V) {
|
||||
Poco::JSON::Array Arr;
|
||||
for(const auto &s:V) {
|
||||
Arr.add(s);
|
||||
}
|
||||
Registry_->set(key,Arr);
|
||||
Save();
|
||||
}
|
||||
|
||||
template<class T> void Set(const char *key, const T &Value) {
|
||||
Registry_->set(key,Value);
|
||||
Save();
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, const std::string &Value) {
|
||||
Registry_[Key] = Value;
|
||||
Save();
|
||||
}
|
||||
bool Get(const char *key, std::vector<std::string> &Value) {
|
||||
if(Registry_->has(key) && !Registry_->isNull(key) && Registry_->isArray(key)) {
|
||||
auto Arr = Registry_->get(key);
|
||||
for(const auto &v:Arr) {
|
||||
Value.emplace_back(v);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, bool Value) {
|
||||
Registry_[Key] = Value;
|
||||
Save();
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, bool &Value) {
|
||||
if (Registry_[Key].is_boolean()) {
|
||||
Value = Registry_[Key].get<bool>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, uint64_t &Value) {
|
||||
if (Registry_[Key].is_number_unsigned()) {
|
||||
Value = Registry_[Key].get<uint64_t>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, std::string &Value) {
|
||||
if (Registry_[Key].is_string()) {
|
||||
Value = Registry_[Key].get<std::string>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<class T> bool Get(const char *key, T &Value) {
|
||||
if(Registry_->has(key) && !Registry_->isNull(key)) {
|
||||
Value = Registry_->getValue<T>(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string FileName;
|
||||
nlohmann::json Registry_;
|
||||
Poco::JSON::Object::Ptr Registry_;
|
||||
};
|
||||
|
||||
inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
#include <valijson/adapters/poco_json_adapter.hpp>
|
||||
#include <valijson/constraints/constraint.hpp>
|
||||
#include <valijson/constraints/constraint_visitor.hpp>
|
||||
@@ -17,33 +17,42 @@
|
||||
namespace OpenWifi {
|
||||
class ConfigurationValidator : public SubSystemServer {
|
||||
public:
|
||||
|
||||
enum class ConfigurationType { AP = 0 , SWITCH = 1};
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new ConfigurationValidator;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
bool Validate(const std::string &C, std::vector<std::string> &Errors, bool Strict);
|
||||
bool Validate(ConfigurationType Type, const std::string &C, std::string &Errors, bool Strict);
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
|
||||
inline static ConfigurationType GetType(const std::string &type) {
|
||||
std::string Type = Poco::toLower(type);
|
||||
if (Type == Platforms::AP)
|
||||
return ConfigurationType::AP;
|
||||
if (Type == Platforms::SWITCH)
|
||||
return ConfigurationType::SWITCH;
|
||||
return ConfigurationType::AP;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Initialized_ = false;
|
||||
bool Working_ = false;
|
||||
void Init();
|
||||
std::unique_ptr<valijson::Schema> RootSchema_;
|
||||
std::unique_ptr<valijson::SchemaParser> SchemaParser_;
|
||||
std::unique_ptr<valijson::adapters::PocoJsonAdapter> PocoJsonAdapter_;
|
||||
Poco::JSON::Object::Ptr SchemaDocPtr_;
|
||||
bool SetSchema(const std::string &SchemaStr);
|
||||
std::array<valijson::Schema,2> RootSchema_;
|
||||
bool SetSchema(ConfigurationType Type, const std::string &SchemaStr);
|
||||
|
||||
ConfigurationValidator()
|
||||
: SubSystemServer("ConfigValidator", "CFG-VALIDATOR", "config.validator") {}
|
||||
};
|
||||
|
||||
inline auto ConfigurationValidator() { return ConfigurationValidator::instance(); }
|
||||
inline bool ValidateUCentralConfiguration(const std::string &C, std::vector<std::string> &Error,
|
||||
inline bool ValidateUCentralConfiguration(ConfigurationValidator::ConfigurationType Type, const std::string &C, std::string &Errors,
|
||||
bool strict) {
|
||||
return ConfigurationValidator::instance()->Validate(C, Error, strict);
|
||||
return ConfigurationValidator::instance()->Validate(Type, C, Errors, strict);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
EventBusManager::EventBusManager(Poco::Logger &L) : Logger_(L) {}
|
||||
|
||||
void EventBusManager::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("fmwk:EventMgr");
|
||||
@@ -18,9 +16,9 @@ namespace OpenWifi {
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg,
|
||||
false);
|
||||
while (Running_) {
|
||||
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
|
||||
if (!Running_)
|
||||
break;
|
||||
if(!Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer())) {
|
||||
break;
|
||||
}
|
||||
Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE));
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(),
|
||||
Msg, false);
|
||||
@@ -31,7 +29,7 @@ namespace OpenWifi {
|
||||
};
|
||||
|
||||
void EventBusManager::Start() {
|
||||
poco_information(Logger(), "Starting...");
|
||||
poco_information(Logger_, "Starting...");
|
||||
if (KafkaManager()->Enabled()) {
|
||||
Thread_.start(*this);
|
||||
}
|
||||
@@ -39,11 +37,11 @@ namespace OpenWifi {
|
||||
|
||||
void EventBusManager::Stop() {
|
||||
if (KafkaManager()->Enabled()) {
|
||||
poco_information(Logger(), "Stopping...");
|
||||
poco_information(Logger_, "Stopping...");
|
||||
Running_ = false;
|
||||
Thread_.wakeUp();
|
||||
Thread_.join();
|
||||
poco_information(Logger(), "Stopped...");
|
||||
poco_information(Logger_, "Stopped...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,16 @@ namespace OpenWifi {
|
||||
|
||||
class EventBusManager : public Poco::Runnable {
|
||||
public:
|
||||
explicit EventBusManager(Poco::Logger &L);
|
||||
EventBusManager() :
|
||||
Logger_(Poco::Logger::create(
|
||||
"EventBusManager", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel())) {
|
||||
}
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new EventBusManager;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void run() final;
|
||||
void Start();
|
||||
void Stop();
|
||||
@@ -24,4 +33,6 @@ namespace OpenWifi {
|
||||
Poco::Logger &Logger_;
|
||||
};
|
||||
|
||||
inline auto EventBusManager() { return EventBusManager::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -79,8 +79,10 @@ namespace OpenWifi {
|
||||
Utils::SetThreadName("Kafka:Prod");
|
||||
cppkafka::Configuration Config(
|
||||
{{"client.id", MicroServiceConfigGetString("openwifi.kafka.client.id", "")},
|
||||
{"metadata.broker.list",
|
||||
MicroServiceConfigGetString("openwifi.kafka.brokerlist", "")}});
|
||||
{"metadata.broker.list",MicroServiceConfigGetString("openwifi.kafka.brokerlist", "")} // ,
|
||||
// {"send.buffer.bytes", KafkaManager()->KafkaManagerMaximumPayloadSize() }
|
||||
}
|
||||
);
|
||||
|
||||
AddKafkaSecurity(Config);
|
||||
|
||||
@@ -105,6 +107,19 @@ namespace OpenWifi {
|
||||
NewMessage.partition(0);
|
||||
NewMessage.payload(Msg->Payload());
|
||||
Producer.produce(NewMessage);
|
||||
if (Queue_.size() < 100) {
|
||||
// use flush when internal queue is lightly loaded, i.e. flush after each
|
||||
// message
|
||||
Producer.flush();
|
||||
}
|
||||
else {
|
||||
// use poll when internal queue is loaded to allow messages to be sent in
|
||||
// batches
|
||||
Producer.poll((std::chrono::milliseconds) 0);
|
||||
}
|
||||
}
|
||||
if (Queue_.size() == 0) {
|
||||
// message queue is empty, flush all previously sent messages
|
||||
Producer.flush();
|
||||
}
|
||||
} catch (const cppkafka::HandleException &E) {
|
||||
@@ -117,6 +132,7 @@ namespace OpenWifi {
|
||||
}
|
||||
Note = Queue_.waitDequeueNotification();
|
||||
}
|
||||
Producer.flush();
|
||||
poco_information(Logger_, "Stopped...");
|
||||
}
|
||||
|
||||
@@ -275,6 +291,7 @@ namespace OpenWifi {
|
||||
int KafkaManager::Start() {
|
||||
if (!KafkaEnabled_)
|
||||
return 0;
|
||||
MaxPayloadSize_ = MicroServiceConfigGetInt("openwifi.kafka.max.payload", 250000);
|
||||
ConsumerThr_.Start();
|
||||
ProducerThr_.Start();
|
||||
return 0;
|
||||
@@ -307,10 +324,8 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
|
||||
return fmt::format( R"lit({{ "system" : {{ "id" : {},
|
||||
"host" : "{}" }},
|
||||
"payload" : {} }})lit", MicroServiceID(),
|
||||
MicroServicePrivateEndPoint(), PayLoad ) ;
|
||||
return fmt::format( R"lit({{ "system" : {{ "id" : {}, "host" : "{}" }}, "payload" : {} }})lit",
|
||||
MicroServiceID(), MicroServicePrivateEndPoint(), PayLoad ) ;
|
||||
}
|
||||
|
||||
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList &partitions) {
|
||||
@@ -323,4 +338,4 @@ namespace OpenWifi {
|
||||
partitions.front().get_partition()));
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -94,11 +94,14 @@ namespace OpenWifi {
|
||||
return ConsumerThr_.UnregisterTopicWatcher(Topic,Id);
|
||||
}
|
||||
|
||||
std::uint64_t KafkaManagerMaximumPayloadSize() const { return MaxPayloadSize_; }
|
||||
|
||||
private:
|
||||
bool KafkaEnabled_ = false;
|
||||
std::string SystemInfoWrapper_;
|
||||
KafkaProducer ProducerThr_;
|
||||
KafkaConsumer ConsumerThr_;
|
||||
std::uint64_t MaxPayloadSize_ = 250000;
|
||||
|
||||
void PartitionAssignment(const cppkafka::TopicPartitionList &partitions);
|
||||
void PartitionRevocation(const cppkafka::TopicPartitionList &partitions);
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace OpenWifi::KafkaTopics {
|
||||
inline const char * DEVICE_EVENT_QUEUE = "device_event_queue";
|
||||
inline const char * DEVICE_TELEMETRY = "device_telemetry";
|
||||
inline const char * PROVISIONING_CHANGE = "provisioning_change";
|
||||
inline const char * RRM = "rrm";
|
||||
|
||||
namespace ServiceEvents {
|
||||
inline const char * EVENT_JOIN = "join";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-26.
|
||||
//
|
||||
|
||||
@@ -29,13 +30,29 @@
|
||||
#include "framework/WebSocketLogger.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#ifdef USE_MEDUSA_CLIENT
|
||||
#include <medusa/MedusaClient.h>
|
||||
#endif
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void MicroService::Exit(int Reason) { std::exit(Reason); }
|
||||
static std::string MakeServiceListString(const Types::MicroServiceMetaMap &Services) {
|
||||
std::string SvcList;
|
||||
for (const auto &Svc : Services) {
|
||||
if (SvcList.empty())
|
||||
SvcList = Svc.second.Type;
|
||||
else
|
||||
SvcList += ", " + Svc.second.Type;
|
||||
}
|
||||
return SvcList;
|
||||
}
|
||||
|
||||
void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key,
|
||||
const std::string &Payload) {
|
||||
std::lock_guard G(InfraMutex_);
|
||||
|
||||
Poco::Logger &BusLogger = EventBusManager()->Logger();
|
||||
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Object = P.parse(Payload).extract<Poco::JSON::Object::Ptr>();
|
||||
@@ -55,13 +72,10 @@ namespace OpenWifi {
|
||||
Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) {
|
||||
auto PrivateEndPoint =
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString();
|
||||
if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE &&
|
||||
Services_.find(PrivateEndPoint) != Services_.end()) {
|
||||
Services_[PrivateEndPoint].LastUpdate = Utils::Now();
|
||||
} else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
|
||||
if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
|
||||
Services_.erase(PrivateEndPoint);
|
||||
poco_debug(
|
||||
logger(),
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format(
|
||||
"Service {} ID={} leaving system.",
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
@@ -69,14 +83,7 @@ namespace OpenWifi {
|
||||
ID));
|
||||
} else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN ||
|
||||
Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) {
|
||||
poco_debug(
|
||||
logger(),
|
||||
fmt::format(
|
||||
"Service {} ID={} joining system.",
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
.toString(),
|
||||
ID));
|
||||
Services_[PrivateEndPoint] = Types::MicroServiceMeta{
|
||||
auto ServiceInfo = Types::MicroServiceMeta{
|
||||
.Id = ID,
|
||||
.Type = Poco::toLower(
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::TYPE)
|
||||
@@ -94,20 +101,46 @@ namespace OpenWifi {
|
||||
.toString(),
|
||||
.LastUpdate = Utils::Now()};
|
||||
|
||||
std::string SvcList;
|
||||
for (const auto &Svc : Services_) {
|
||||
if (SvcList.empty())
|
||||
SvcList = Svc.second.Type;
|
||||
else
|
||||
SvcList += ", " + Svc.second.Type;
|
||||
auto s1 = MakeServiceListString(Services_);
|
||||
auto PreviousSize = Services_.size();
|
||||
Services_[PrivateEndPoint] = ServiceInfo;
|
||||
auto CurrentSize = Services_.size();
|
||||
if(Event == KafkaTopics::ServiceEvents::EVENT_JOIN) {
|
||||
if(!s1.empty()) {
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format(
|
||||
"Service {} ID={} is joining the system.",
|
||||
Object
|
||||
->get(
|
||||
KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
.toString(),
|
||||
ID));
|
||||
}
|
||||
std::string SvcList;
|
||||
for (const auto &Svc : Services_) {
|
||||
if (SvcList.empty())
|
||||
SvcList = Svc.second.Type;
|
||||
else
|
||||
SvcList += ", " + Svc.second.Type;
|
||||
}
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format("Current list of microservices: {}", SvcList));
|
||||
} else if(CurrentSize!=PreviousSize) {
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format(
|
||||
"Service {} ID={} is being added back in.",
|
||||
Object
|
||||
->get(KafkaTopics::ServiceEvents::Fields::PRIVATE)
|
||||
.toString(),
|
||||
ID));
|
||||
}
|
||||
poco_information(
|
||||
logger(),
|
||||
fmt::format("Current list of microservices: {}", SvcList));
|
||||
}
|
||||
} else {
|
||||
poco_error(
|
||||
logger(),
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format("KAFKA-MSG: invalid event '{}', missing a field.",
|
||||
Event));
|
||||
}
|
||||
@@ -118,32 +151,39 @@ namespace OpenWifi {
|
||||
Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString());
|
||||
#endif
|
||||
} else {
|
||||
poco_error(
|
||||
logger(),
|
||||
poco_information(
|
||||
BusLogger,
|
||||
fmt::format("KAFKA-MSG: invalid event '{}', missing token", Event));
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(),
|
||||
poco_information(BusLogger,
|
||||
fmt::format("Unknown Event: {} Source: {}", Event, ID));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(), "Bad bus message.");
|
||||
std::ostringstream os;
|
||||
Object->stringify(std::cout);
|
||||
std::ostringstream os;
|
||||
Object->stringify(std::cout);
|
||||
poco_error(BusLogger, fmt::format("Bad bus message: {}", os.str()));
|
||||
}
|
||||
|
||||
auto i = Services_.begin();
|
||||
auto ServiceHint = Services_.begin();
|
||||
auto now = Utils::Now();
|
||||
for (; i != Services_.end();) {
|
||||
if ((now - i->second.LastUpdate) > 60) {
|
||||
i = Services_.erase(i);
|
||||
auto si1 = Services_.size();
|
||||
auto ss1 = MakeServiceListString(Services_);
|
||||
while(ServiceHint!=Services_.end()) {
|
||||
if ((now - ServiceHint->second.LastUpdate) > 120) {
|
||||
poco_information(BusLogger, fmt::format("ZombieService: Removing service {}, ", ServiceHint->second.PublicEndPoint));
|
||||
ServiceHint = Services_.erase(ServiceHint);
|
||||
} else
|
||||
++i;
|
||||
++ServiceHint;
|
||||
}
|
||||
if(Services_.size() != si1) {
|
||||
auto ss2 = MakeServiceListString(Services_);
|
||||
poco_information(BusLogger, fmt::format("Current list of microservices: {} -> {}", ss1, ss2));
|
||||
}
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
BusLogger.log(E);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,25 +207,29 @@ namespace OpenWifi {
|
||||
Res.push_back(ServiceRec);
|
||||
}
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
void MicroService::LoadConfigurationFile() {
|
||||
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR, ".");
|
||||
ConfigFileName_ =
|
||||
ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_;
|
||||
Poco::Path ConfigFile(ConfigFileName_);
|
||||
if(ConfigContent_.empty()) {
|
||||
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR, ".");
|
||||
ConfigFileName_ =
|
||||
ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_;
|
||||
Poco::Path ConfigFile(ConfigFileName_);
|
||||
|
||||
if (!ConfigFile.isFile()) {
|
||||
std::cerr << DAEMON_APP_NAME << ": Configuration " << ConfigFile.toString()
|
||||
<< " does not seem to exist. Please set " + DAEMON_CONFIG_ENV_VAR +
|
||||
" env variable the path of the " + DAEMON_PROPERTIES_FILENAME +
|
||||
" file."
|
||||
<< std::endl;
|
||||
std::exit(Poco::Util::Application::EXIT_CONFIG);
|
||||
}
|
||||
|
||||
// loadConfiguration(ConfigFile.toString());
|
||||
PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(ConfigFile.toString());
|
||||
if (!ConfigFile.isFile()) {
|
||||
std::cerr << DAEMON_APP_NAME << ": Configuration " << ConfigFile.toString()
|
||||
<< " does not seem to exist. Please set " + DAEMON_CONFIG_ENV_VAR +
|
||||
" env variable the path of the " + DAEMON_PROPERTIES_FILENAME +
|
||||
" file."
|
||||
<< std::endl;
|
||||
std::exit(Poco::Util::Application::EXIT_CONFIG);
|
||||
}
|
||||
PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(ConfigFile.toString());
|
||||
} else {
|
||||
std::istringstream is(ConfigContent_);
|
||||
PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(is);
|
||||
}
|
||||
configPtr()->addWriteable(PropConfigurationFile_, PRIO_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -388,49 +432,69 @@ namespace OpenWifi {
|
||||
|
||||
void DaemonPostInitialization(Poco::Util::Application &self);
|
||||
|
||||
void MicroService::initialize(Poco::Util::Application &self) {
|
||||
// add the default services
|
||||
LoadConfigurationFile();
|
||||
InitializeLoggingSystem();
|
||||
void MicroService::StartEverything(Poco::Util::Application &self) {
|
||||
LoadConfigurationFile();
|
||||
InitializeLoggingSystem();
|
||||
|
||||
SubSystems_.push_back(KafkaManager());
|
||||
SubSystems_.push_back(ALBHealthCheckServer());
|
||||
SubSystems_.push_back(RESTAPI_ExtServer());
|
||||
SubSystems_.push_back(RESTAPI_IntServer());
|
||||
static bool InitializedBaseService=false;
|
||||
if(!InitializedBaseService) {
|
||||
InitializedBaseService = true;
|
||||
SubSystems_.push_back(KafkaManager());
|
||||
SubSystems_.push_back(ALBHealthCheckServer());
|
||||
SubSystems_.push_back(RESTAPI_ExtServer());
|
||||
SubSystems_.push_back(RESTAPI_IntServer());
|
||||
#ifndef TIP_SECURITY_SERVICE
|
||||
SubSystems_.push_back(AuthClient());
|
||||
SubSystems_.push_back(AuthClient());
|
||||
#endif
|
||||
Poco::Net::initializeSSL();
|
||||
Poco::Net::HTTPStreamFactory::registerFactory();
|
||||
Poco::Net::HTTPSStreamFactory::registerFactory();
|
||||
Poco::Net::FTPStreamFactory::registerFactory();
|
||||
Poco::Net::FTPSStreamFactory::registerFactory();
|
||||
|
||||
Poco::File DataDir(ConfigPath("openwifi.system.data"));
|
||||
DataDir_ = DataDir.path();
|
||||
if (!DataDir.exists()) {
|
||||
try {
|
||||
DataDir.createDirectory();
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
}
|
||||
}
|
||||
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets", "");
|
||||
if (WWWAssetsDir_.empty())
|
||||
WWWAssetsDir_ = DataDir_;
|
||||
Poco::Net::initializeSSL();
|
||||
Poco::Net::HTTPStreamFactory::registerFactory();
|
||||
Poco::Net::HTTPSStreamFactory::registerFactory();
|
||||
Poco::Net::FTPStreamFactory::registerFactory();
|
||||
Poco::Net::FTPSStreamFactory::registerFactory();
|
||||
}
|
||||
|
||||
LoadMyConfig();
|
||||
Poco::File DataDir(ConfigPath("openwifi.system.data"));
|
||||
DataDir_ = DataDir.path();
|
||||
if (!DataDir.exists()) {
|
||||
try {
|
||||
DataDir.createDirectory();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets", "");
|
||||
if (WWWAssetsDir_.empty())
|
||||
WWWAssetsDir_ = DataDir_;
|
||||
|
||||
AllowExternalMicroServices_ = ConfigGetBool("allowexternalmicroservices", true);
|
||||
LoadMyConfig();
|
||||
|
||||
InitializeSubSystemServers();
|
||||
ServerApplication::initialize(self);
|
||||
DaemonPostInitialization(self);
|
||||
AllowExternalMicroServices_ = ConfigGetBool("allowexternalmicroservices", true);
|
||||
|
||||
Types::TopicNotifyFunction F = [this](const std::string &Key, const std::string &Payload) {
|
||||
this->BusMessageReceived(Key, Payload);
|
||||
};
|
||||
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
|
||||
InitializeSubSystemServers();
|
||||
ServerApplication::initialize(self);
|
||||
DaemonPostInitialization(self);
|
||||
|
||||
Types::TopicNotifyFunction F = [this](const std::string &Key, const std::string &Payload) {
|
||||
this->BusMessageReceived(Key, Payload);
|
||||
};
|
||||
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
|
||||
}
|
||||
|
||||
void MicroService::StopEverything([[maybe_unused]] Poco::Util::Application &self) {
|
||||
LoadConfigurationFile();
|
||||
InitializeLoggingSystem();
|
||||
|
||||
Types::TopicNotifyFunction F = [this](const std::string &Key, const std::string &Payload) {
|
||||
this->BusMessageReceived(Key, Payload);
|
||||
};
|
||||
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
|
||||
}
|
||||
|
||||
void MicroService::initialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
#ifndef USE_MEDUSA_CLIENT
|
||||
StartEverything(self);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MicroService::uninitialize() {
|
||||
@@ -530,14 +594,12 @@ namespace OpenWifi {
|
||||
for (auto i : SubSystems_) {
|
||||
i->Start();
|
||||
}
|
||||
EventBusManager_ = std::make_unique<EventBusManager>(Poco::Logger::create(
|
||||
"EventBusManager", Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel()));
|
||||
EventBusManager_->Start();
|
||||
EventBusManager()->Start();
|
||||
}
|
||||
|
||||
void MicroService::StopSubSystemServers() {
|
||||
AddActivity("Stopping");
|
||||
EventBusManager_->Stop();
|
||||
EventBusManager()->Stop();
|
||||
for (auto i = SubSystems_.rbegin(); i != SubSystems_.rend(); ++i) {
|
||||
(*i)->Stop();
|
||||
}
|
||||
@@ -697,7 +759,7 @@ namespace OpenWifi {
|
||||
auto APIKEY = Request.get("X-API-KEY");
|
||||
return APIKEY == MyHash_;
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -718,6 +780,8 @@ namespace OpenWifi {
|
||||
MicroServiceErrorHandler ErrorHandler(*this);
|
||||
Poco::ErrorHandler::set(&ErrorHandler);
|
||||
|
||||
Args_ = args;
|
||||
|
||||
if (!HelpRequested_) {
|
||||
SavePID();
|
||||
|
||||
@@ -733,11 +797,18 @@ namespace OpenWifi {
|
||||
poco_information(logger, "Starting as a daemon.");
|
||||
}
|
||||
|
||||
#ifdef USE_MEDUSA_CLIENT
|
||||
MedusaClient::instance()->SetSubSystems(SubSystems_);
|
||||
MedusaClient::instance()->Start();
|
||||
waitForTerminationRequest();
|
||||
MedusaClient::instance()->Stop();
|
||||
#else
|
||||
poco_information(logger, fmt::format("System ID set to {}", ID_));
|
||||
StartSubSystemServers();
|
||||
waitForTerminationRequest();
|
||||
StopSubSystemServers();
|
||||
logger.notice(fmt::format("Stopped {}...", DAEMON_APP_NAME));
|
||||
#endif
|
||||
}
|
||||
|
||||
return Application::EXIT_OK;
|
||||
@@ -774,4 +845,4 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
// This must be defined for poco_debug and poco_trace macros to function.
|
||||
|
||||
@@ -40,6 +41,7 @@ namespace OpenWifi {
|
||||
#include "Poco/Util/OptionSet.h"
|
||||
#include "Poco/Util/PropertyFileConfiguration.h"
|
||||
#include "Poco/Util/ServerApplication.h"
|
||||
#include "Poco/ThreadPool.h"
|
||||
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
|
||||
@@ -55,9 +57,6 @@ namespace OpenWifi {
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "ow_version.h"
|
||||
|
||||
#define _OWDEBUG_ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
// #define _OWDEBUG_ Logger().debug(Poco::format("%s: %lu",__FILE__,__LINE__));
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class MicroService : public Poco::Util::ServerApplication {
|
||||
@@ -70,7 +69,6 @@ namespace OpenWifi {
|
||||
SubSystems_(std::move(Subsystems)), Logger_(Poco::Logger::get("FRAMEWORK")) {
|
||||
instance_ = this;
|
||||
RandomEngine_.seed(std::chrono::steady_clock::now().time_since_epoch().count());
|
||||
// Logger_ = Poco::Logger::root().get("BASE-SVC");
|
||||
}
|
||||
|
||||
inline static const char *ExtraConfigurationFilename = "/configuration_override.json";
|
||||
@@ -92,7 +90,7 @@ namespace OpenWifi {
|
||||
inline uint64_t DaemonBusTimer() const { return DAEMON_BUS_TIMER; };
|
||||
[[nodiscard]] const std::string &AppName() { return DAEMON_APP_NAME; }
|
||||
static inline uint64_t GetPID() { return Poco::Process::id(); };
|
||||
[[nodiscard]] inline const std::string GetPublicAPIEndPoint() {
|
||||
[[nodiscard]] inline std::string GetPublicAPIEndPoint() const {
|
||||
return MyPublicEndPoint_ + "/api/v1";
|
||||
};
|
||||
[[nodiscard]] inline const std::string &GetUIURI() const { return UIURI_; };
|
||||
@@ -107,7 +105,8 @@ namespace OpenWifi {
|
||||
}
|
||||
static MicroService &instance() { return *instance_; }
|
||||
|
||||
inline void Exit(int Reason);
|
||||
inline void Exit(int Reason) { std::exit(Reason); }
|
||||
|
||||
void BusMessageReceived(const std::string &Key, const std::string &Payload);
|
||||
Types::MicroServiceMetaVec GetServices(const std::string &Type);
|
||||
Types::MicroServiceMetaVec GetServices();
|
||||
@@ -115,7 +114,9 @@ namespace OpenWifi {
|
||||
void Reload();
|
||||
void LoadMyConfig();
|
||||
void initialize(Poco::Util::Application &self) override;
|
||||
void uninitialize() override;
|
||||
void StartEverything(Poco::Util::Application &self);
|
||||
void StopEverything(Poco::Util::Application &self);
|
||||
void uninitialize() override;
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
void defineOptions(Poco::Util::OptionSet &options) override;
|
||||
void handleHelp(const std::string &name, const std::string &value);
|
||||
@@ -132,7 +133,7 @@ namespace OpenWifi {
|
||||
void Reload(const std::string &Sub);
|
||||
Types::StringVec GetSubSystems() const;
|
||||
Types::StringPairVec GetLogLevels();
|
||||
const Types::StringVec &GetLogLevelNames();
|
||||
static const Types::StringVec &GetLogLevelNames();
|
||||
uint64_t ConfigGetInt(const std::string &Key, uint64_t Default);
|
||||
uint64_t ConfigGetInt(const std::string &Key);
|
||||
uint64_t ConfigGetBool(const std::string &Key, bool Default);
|
||||
@@ -166,12 +167,25 @@ namespace OpenWifi {
|
||||
const std::string &FormatterPattern,
|
||||
const std::string &root_env_var);
|
||||
inline bool AllowExternalMicroServices() const { return AllowExternalMicroServices_; }
|
||||
const ArgVec &Args() const { return Args_; }
|
||||
|
||||
inline void SetConfigContent(const std::string &Content) { ConfigContent_ = Content; }
|
||||
|
||||
inline std::optional<OpenWifi::Types::MicroServiceMeta> GetPrivateEndPointServiceKey( const std::string & ServicePrivateEndPoint ) {
|
||||
std::lock_guard G(InfraMutex_);
|
||||
auto K = Services_.find(ServicePrivateEndPoint);
|
||||
if(K==end(Services_)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return K->second;
|
||||
}
|
||||
|
||||
private:
|
||||
static MicroService *instance_;
|
||||
bool HelpRequested_ = false;
|
||||
std::string LogDir_;
|
||||
std::string ConfigFileName_;
|
||||
std::string ConfigContent_;
|
||||
uint64_t ID_ = 1;
|
||||
Poco::SharedPtr<Poco::Crypto::RSAKey> AppKey_;
|
||||
bool DebugMode_ = false;
|
||||
@@ -201,7 +215,7 @@ namespace OpenWifi {
|
||||
Poco::JWT::Signer Signer_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::ThreadPool TimerPool_{"timer:pool", 2, 32};
|
||||
std::unique_ptr<EventBusManager> EventBusManager_;
|
||||
ArgVec Args_;
|
||||
};
|
||||
|
||||
inline MicroService *MicroService::instance_ = nullptr;
|
||||
|
||||
@@ -129,4 +129,12 @@ namespace OpenWifi {
|
||||
return ALBHealthCheckServer()->RegisterExtendedHealthMessage(Callback);
|
||||
}
|
||||
|
||||
std::string MicroServiceAccessKey() {
|
||||
return MicroService::instance().Hash();
|
||||
}
|
||||
|
||||
std::optional<OpenWifi::Types::MicroServiceMeta> MicroServicePrivateAccessKey(const std::string &servicePrivateEndPoint) {
|
||||
return MicroService::instance().GetPrivateEndPointServiceKey(servicePrivateEndPoint);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
|
||||
@@ -22,7 +23,10 @@ namespace OpenWifi {
|
||||
std::string MicroServicePublicEndPoint();
|
||||
std::string MicroServiceConfigGetString(const std::string &Key,
|
||||
const std::string &DefaultValue);
|
||||
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
|
||||
std::string MicroServiceAccessKey();
|
||||
std::optional<OpenWifi::Types::MicroServiceMeta> MicroServicePrivateAccessKey(const std::string &servicePrivateEndPoint);
|
||||
|
||||
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
|
||||
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue);
|
||||
std::string MicroServicePrivateEndPoint();
|
||||
std::uint64_t MicroServiceID();
|
||||
|
||||
@@ -431,6 +431,11 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
inline void Accepted() {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_ACCEPTED);
|
||||
Response->send();
|
||||
}
|
||||
|
||||
inline void SendCompressedTarFile(const std::string &FileName, const std::string &Content) {
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
|
||||
SetCommonHeaders();
|
||||
@@ -552,8 +557,8 @@ namespace OpenWifi {
|
||||
|
||||
inline bool IsAuthorized(bool &Expired, bool &Contacted, bool SubOnly = false);
|
||||
|
||||
inline void ReturnObject(Poco::JSON::Object &Object) {
|
||||
PrepareResponse();
|
||||
inline void ReturnObject(Poco::JSON::Object &Object, Poco::Net::HTTPResponse::HTTPStatus Status = Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
PrepareResponse(Status);
|
||||
if (Request != nullptr) {
|
||||
// can we compress ???
|
||||
auto AcceptedEncoding = Request->find("Accept-Encoding");
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace OpenWifi {
|
||||
|
||||
}
|
||||
|
||||
Poco::Data::SessionPool &Pool() { return *Pool_; }
|
||||
|
||||
private:
|
||||
inline int Setup_SQLite();
|
||||
inline int Setup_MySQL();
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace OpenWifi {
|
||||
P.verificationDepth = 9;
|
||||
P.loadDefaultCAs = root_ca_.empty();
|
||||
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
|
||||
P.dhUse2048Bits = true;
|
||||
P.caLocation = cas_;
|
||||
// P.securityLevel =
|
||||
|
||||
@@ -68,6 +67,16 @@ namespace OpenWifi {
|
||||
Context->addCertificateAuthority(Issuing);
|
||||
}
|
||||
|
||||
if (!client_cas_.empty()) {
|
||||
// add certificates specified in clientcas
|
||||
std::vector<Poco::Crypto::X509Certificate> Certs =
|
||||
Poco::Net::X509Certificate::readPEM(client_cas_);
|
||||
for (const auto &cert : Certs) {
|
||||
Context->addChainCertificate(cert);
|
||||
Context->addCertificateAuthority(cert);
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Crypto::RSAKey Key("", key_file_, key_file_password_);
|
||||
Context->usePrivateKey(Key);
|
||||
|
||||
@@ -334,4 +343,4 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace OpenWifi {
|
||||
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
|
||||
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
|
||||
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
|
||||
[[nodiscard]] inline auto ClientCas() const { return client_cas_; };
|
||||
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
|
||||
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
|
||||
[[nodiscard]] inline auto Name() const { return name_; };
|
||||
|
||||
@@ -58,11 +58,9 @@ namespace OpenWifi {
|
||||
void UI_WebSocketClientServer::run() {
|
||||
Running_ = true;
|
||||
while (Running_) {
|
||||
Poco::Thread::trySleep(2000);
|
||||
|
||||
if (!Running_)
|
||||
break;
|
||||
|
||||
if(!Poco::Thread::trySleep(2000)) {
|
||||
break;
|
||||
}
|
||||
std::lock_guard G(LocalMutex_);
|
||||
for (const auto i : ToBeRemoved_) {
|
||||
// std::cout << "Erasing old WS UI connection..." << std::endl;
|
||||
@@ -212,10 +210,16 @@ namespace OpenWifi {
|
||||
n = Client->second->WS_->receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (n == -1) {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("UI-EMPTY({}): {} Empty Frame flags {}.",
|
||||
Client->second->Id_, Client->second->UserName_, flags));
|
||||
return;
|
||||
}
|
||||
if (n == 0) {
|
||||
poco_debug(Logger(),
|
||||
fmt::format("CLOSE({}): {} UI Client is closing WS connection.",
|
||||
Client->second->Id_, Client->second->UserName_));
|
||||
fmt::format("CLOSE({}): {} UI Client is closing WS connection.",
|
||||
Client->second->Id_, Client->second->UserName_));
|
||||
return EndConnection(Client);
|
||||
}
|
||||
|
||||
@@ -223,7 +227,7 @@ namespace OpenWifi {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
Client->second->WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
} break;
|
||||
@@ -233,6 +237,11 @@ namespace OpenWifi {
|
||||
Client->second->Id_, Client->second->UserName_));
|
||||
return EndConnection(Client);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CONT: {
|
||||
poco_warning(Logger(),
|
||||
fmt::format("CONT({}): {} Unexpected CONT Frame - Ignoring.",
|
||||
Client->second->Id_, Client->second->UserName_));
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
constexpr const char *DropMessagesCommand = "drop-notifications";
|
||||
IncomingFrame.append(0);
|
||||
@@ -321,4 +330,4 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -7,57 +7,59 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "ow_constants.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
inline const std::vector<std::pair<std::string, std::string>> DefaultDeviceTypeList{
|
||||
{"actiontec_web7200", "AP"},
|
||||
{"cig_wf186w", "AP"},
|
||||
{"cig_wf188n", "AP"},
|
||||
{"cig_wf194c4", "AP"},
|
||||
{"cig_wf196", "AP"},
|
||||
{"cig_wf196-ca", "AP"},
|
||||
{"cig_wf196-ca-ath12", "AP"},
|
||||
{"cig_wf196-us", "AP"},
|
||||
{"cig_wf610d", "AP"},
|
||||
{"cig_wf660a", "AP"},
|
||||
{"cig_wf808", "AP"},
|
||||
{"cybertan_eww622-a1", "AP"},
|
||||
{"edgecore_eap101", "AP"},
|
||||
{"edgecore_eap101-ath12", "AP"},
|
||||
{"edgecore_eap102", "AP"},
|
||||
{"edgecore_eap104", "AP"},
|
||||
{"edgecore_eap104-ath12", "AP"},
|
||||
{"edgecore_ecs4100-12ph", "AP"},
|
||||
{"edgecore_ecw5211", "AP"},
|
||||
{"edgecore_ecw5410", "AP"},
|
||||
{"edgecore_oap100", "AP"},
|
||||
{"edgecore_spw2ac1200", "SWITCH"},
|
||||
{"edgecore_spw2ac1200-lan-poe", "SWITCH"},
|
||||
{"edgecore_ssw2ac2600", "SWITCH"},
|
||||
{"hfcl_ion4", "AP"},
|
||||
{"hfcl_ion4x", "AP"},
|
||||
{"hfcl_ion4x_2", "AP"},
|
||||
{"hfcl_ion4xe", "AP"},
|
||||
{"hfcl_ion4xi", "AP"},
|
||||
{"indio_um-305ac", "AP"},
|
||||
{"indio_um-305ax", "AP"},
|
||||
{"indio_um-310ax-v1", "AP"},
|
||||
{"indio_um-325ac", "AP"},
|
||||
{"indio_um-510ac-v3", "AP"},
|
||||
{"indio_um-510axm-v1", "AP"},
|
||||
{"indio_um-510axp-v1", "AP"},
|
||||
{"indio_um-550ac", "AP"},
|
||||
{"linksys_e8450-ubi", "AP"},
|
||||
{"linksys_ea6350-v4", "AP"},
|
||||
{"linksys_ea8300", "AP"},
|
||||
{"liteon_wpx8324", "AP"},
|
||||
{"meshpp_s618_cp01", "AP"},
|
||||
{"meshpp_s618_cp03", "AP"},
|
||||
{"udaya_a5-id2", "AP"},
|
||||
{"wallys_dr40x9", "AP"},
|
||||
{"wallys_dr6018", "AP"},
|
||||
{"wallys_dr6018_v4", "AP"},
|
||||
{"x64_vm", "AP"},
|
||||
{"yuncore_ax840", "AP"},
|
||||
{"yuncore_fap640", "AP"},
|
||||
{"yuncore_fap650", "AP"}};
|
||||
{"actiontec_web7200", Platforms::AP},
|
||||
{"cig_wf186w", Platforms::AP},
|
||||
{"cig_wf188n", Platforms::AP},
|
||||
{"cig_wf194c4", Platforms::AP},
|
||||
{"cig_wf196", Platforms::AP},
|
||||
{"cig_wf196-ca", Platforms::AP},
|
||||
{"cig_wf196-ca-ath12", Platforms::AP},
|
||||
{"cig_wf196-us", Platforms::AP},
|
||||
{"cig_wf610d", Platforms::AP},
|
||||
{"cig_wf660a", Platforms::AP},
|
||||
{"cig_wf808", Platforms::AP},
|
||||
{"cybertan_eww622-a1", Platforms::AP},
|
||||
{"edgecore_eap101", Platforms::AP},
|
||||
{"edgecore_eap101-ath12", Platforms::AP},
|
||||
{"edgecore_eap102", Platforms::AP},
|
||||
{"edgecore_eap104", Platforms::AP},
|
||||
{"edgecore_eap104-ath12", Platforms::AP},
|
||||
{"edgecore_ecs4100-12ph", Platforms::AP},
|
||||
{"edgecore_ecw5211", Platforms::AP},
|
||||
{"edgecore_ecw5410", Platforms::AP},
|
||||
{"edgecore_oap100", Platforms::AP},
|
||||
{"edgecore_spw2ac1200", Platforms::SWITCH},
|
||||
{"edgecore_spw2ac1200-lan-poe", Platforms::SWITCH},
|
||||
{"edgecore_ssw2ac2600", Platforms::SWITCH},
|
||||
{"hfcl_ion4", Platforms::AP},
|
||||
{"hfcl_ion4x", Platforms::AP},
|
||||
{"hfcl_ion4x_2", Platforms::AP},
|
||||
{"hfcl_ion4xe", Platforms::AP},
|
||||
{"hfcl_ion4xi", Platforms::AP},
|
||||
{"indio_um-305ac", Platforms::AP},
|
||||
{"indio_um-305ax", Platforms::AP},
|
||||
{"indio_um-310ax-v1", Platforms::AP},
|
||||
{"indio_um-325ac", Platforms::AP},
|
||||
{"indio_um-510ac-v3", Platforms::AP},
|
||||
{"indio_um-510axm-v1", Platforms::AP},
|
||||
{"indio_um-510axp-v1", Platforms::AP},
|
||||
{"indio_um-550ac", Platforms::AP},
|
||||
{"linksys_e8450-ubi", Platforms::AP},
|
||||
{"linksys_ea6350-v4", Platforms::AP},
|
||||
{"linksys_ea8300", Platforms::AP},
|
||||
{"liteon_wpx8324", Platforms::AP},
|
||||
{"meshpp_s618_cp01", Platforms::AP},
|
||||
{"meshpp_s618_cp03", Platforms::AP},
|
||||
{"udaya_a5-id2", Platforms::AP},
|
||||
{"wallys_dr40x9", Platforms::AP},
|
||||
{"wallys_dr6018", Platforms::AP},
|
||||
{"wallys_dr6018_v4", Platforms::AP},
|
||||
{"x64_vm", Platforms::AP},
|
||||
{"yuncore_ax840", Platforms::AP},
|
||||
{"yuncore_fap640", Platforms::AP},
|
||||
{"yuncore_fap650", Platforms::AP}};
|
||||
}
|
||||
|
||||
@@ -576,8 +576,8 @@ namespace ORM {
|
||||
bool UpdateRecord(field_name_t FieldName, const T &Value, const RecordType &R) {
|
||||
try {
|
||||
assert(ValidFieldName(FieldName));
|
||||
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Session.begin();
|
||||
Poco::Data::Statement Update(Session);
|
||||
|
||||
RecordTuple RT;
|
||||
@@ -593,6 +593,7 @@ namespace ORM {
|
||||
Update.execute();
|
||||
if (Cache_)
|
||||
Cache_->UpdateCache(R);
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
@@ -662,6 +663,7 @@ namespace ORM {
|
||||
assert(ValidFieldName(FieldName));
|
||||
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Session.begin();
|
||||
Poco::Data::Statement Delete(Session);
|
||||
|
||||
std::string St = "delete from " + TableName_ + " where " + FieldName + "=?";
|
||||
@@ -671,6 +673,7 @@ namespace ORM {
|
||||
Delete.execute();
|
||||
if (Cache_)
|
||||
Cache_->Delete(FieldName, Value);
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
@@ -682,11 +685,13 @@ namespace ORM {
|
||||
try {
|
||||
assert(!WhereClause.empty());
|
||||
Poco::Data::Session Session = Pool_.get();
|
||||
Session.begin();
|
||||
Poco::Data::Statement Delete(Session);
|
||||
|
||||
std::string St = "delete from " + TableName_ + " where " + WhereClause;
|
||||
Delete << St;
|
||||
Delete.execute();
|
||||
Session.commit();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
|
||||
@@ -414,10 +414,28 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
};
|
||||
|
||||
static const struct msg DefFirmwareNameExists { 1175, "Firmware name already exists." };
|
||||
|
||||
static const struct msg NotAValidECKey { 1176, "Not a valid Signing Key." };
|
||||
|
||||
static const struct msg NotAValidRadiusPoolType { 1177, "Not a valid RADIUS pool type." };
|
||||
static const struct msg InvalidRadiusTypeEndpoint { 1178, "Invalid RADIUS Server Endpoint type." };
|
||||
static const struct msg InvalidRadiusEndpointPoolStrategy { 1179, "Invalid RADIUS Server Endpoint Pool strategy." };
|
||||
static const struct msg EndpointMustHaveOneTypeOfServers { 1180, "All servers must be either RADIUS or RADSEC." };
|
||||
static const struct msg RadiusEndpointIndexInvalid { 1181, "Index must be an address between 0.0.1.1 and 0.0.2.254" };
|
||||
static const struct msg RadiusEndpointIndexMustBeUnique { 1182, "Index must be unique." };
|
||||
static const struct msg OrionAccountMustExist { 1183, "Orion account must exist." };
|
||||
static const struct msg GlobalReachCertMustExist { 1184, "Global Reach certificate must exist." };
|
||||
static const struct msg InvalidRadsecMainCertificate { 1185, "Invalid Radsec main certificate." };
|
||||
static const struct msg InvalidRadsecCaCertificate { 1186, "Invalid Radsec CA certificates." };
|
||||
static const struct msg InvalidRadsecPrivteKey { 1187, "Invalid Radsec Private key." };
|
||||
static const struct msg InvalidRadsecIPAddress { 1188, "Invalid Radsec IP Address." };
|
||||
static const struct msg InvalidRadsecPort { 1189, "Invalid Radsec Port." };
|
||||
static const struct msg InvalidRadsecSecret { 1190, "Invalid Radsec Secret." };
|
||||
static const struct msg InvalidRadiusServer { 1191, "Invalid Radius Server." };
|
||||
|
||||
static const struct msg InvalidRRMAction { 1192, "Invalid RRM Action." };
|
||||
|
||||
static const struct msg InvalidPackageURL { 1193, "Invalid URL, must start with http:// or https://." };
|
||||
static const struct msg FailedToDownload { 1194, "Failed to download package." };
|
||||
static const struct msg FailedToDecompress { 1195, "Failed to decompress package data."};
|
||||
|
||||
static const struct msg SimulationDoesNotExist {
|
||||
7000, "Simulation Instance ID does not exist."
|
||||
@@ -536,6 +554,10 @@ namespace OpenWifi::RESTAPI::Protocol {
|
||||
static const char *DEBUG = "debug";
|
||||
static const char *SCRIPT = "script";
|
||||
static const char *TIMEOUT = "timeout";
|
||||
static const char *PACKAGE = "package";
|
||||
static const char *PACKAGES = "packages";
|
||||
static const char *PACKAGEINST = "packageInstall";
|
||||
static const char *PACKAGEDEL = "packageDelete";
|
||||
|
||||
static const char *NEWPASSWORD = "newPassword";
|
||||
static const char *USERS = "users";
|
||||
@@ -549,6 +571,11 @@ namespace OpenWifi::RESTAPI::Protocol {
|
||||
static const char *CONTENTDISPOSITION = "Content-Disposition";
|
||||
static const char *CONTENTTYPE = "Content-Type";
|
||||
|
||||
static const char *TRANSFER = "transfer";
|
||||
static const char *CERTUPDATE = "certupdate";
|
||||
static const char *POWERCYCLE = "powercycle";
|
||||
static const char *RRM = "rrm";
|
||||
|
||||
static const char *REQUIREMENTS = "requirements";
|
||||
static const char *PASSWORDPATTERN = "passwordPattern";
|
||||
static const char *ACCESSPOLICY = "accessPolicy";
|
||||
@@ -561,6 +588,10 @@ namespace OpenWifi::RESTAPI::Protocol {
|
||||
static const char *INTERVAL = "interval";
|
||||
static const char *UI = "UI";
|
||||
static const char *BANDWIDTH = "bandwidth";
|
||||
|
||||
static const char *FIXEDCONFIG = "fixedconfig";
|
||||
static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
|
||||
static const char *REENROLL = "reenroll";
|
||||
} // namespace OpenWifi::RESTAPI::Protocol
|
||||
|
||||
namespace OpenWifi::uCentralProtocol {
|
||||
@@ -589,6 +620,7 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *CFGPENDING = "cfgpending";
|
||||
static const char *RECOVERY = "recovery";
|
||||
static const char *COMPRESS_64 = "compress_64";
|
||||
static const char *COMPRESS_SZ = "compress_sz";
|
||||
static const char *CAPABILITIES = "capabilities";
|
||||
static const char *REQUEST_UUID = "request_uuid";
|
||||
static const char *SANITY = "sanity";
|
||||
@@ -645,6 +677,9 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *SIGNATURE = "signature";
|
||||
static const char *INFO = "info";
|
||||
static const char *DATE = "date";
|
||||
static const char *PACKAGE = "package";
|
||||
static const char *PACKAGES = "packages";
|
||||
static const char *CATEGORY = "category";
|
||||
|
||||
static const char *SERIALNUMBER = "serialNumber";
|
||||
static const char *COMPATIBLE = "compatible";
|
||||
@@ -666,6 +701,18 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *RADIUSCOA = "coa";
|
||||
static const char *RADIUSDST = "dst";
|
||||
static const char *IES = "ies";
|
||||
|
||||
static const char *TRANSFER = "transfer";
|
||||
static const char *CERTUPDATE = "certupdate";
|
||||
static const char *POWERCYCLE = "powercycle";
|
||||
static const char *RRM = "rrm";
|
||||
static const char *ACTIONS = "actions";
|
||||
|
||||
static const char *FIXEDCONFIG = "fixedconfig";
|
||||
static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
|
||||
static const char *REENROLL = "reenroll";
|
||||
|
||||
static const char *OPERATION = "op";
|
||||
} // namespace OpenWifi::uCentralProtocol
|
||||
|
||||
namespace OpenWifi::uCentralProtocol::Events {
|
||||
@@ -700,7 +747,7 @@ namespace OpenWifi::uCentralProtocol::Events {
|
||||
ET_EVENT,
|
||||
ET_WIFISCAN,
|
||||
ET_ALARM,
|
||||
ET_REBOOTLOG
|
||||
ET_REBOOTLOG,
|
||||
};
|
||||
|
||||
inline EVENT_MSG EventFromString(const std::string &Method) {
|
||||
@@ -758,6 +805,14 @@ namespace OpenWifi::APCommands {
|
||||
telemetry,
|
||||
ping,
|
||||
script,
|
||||
rrm,
|
||||
certupdate,
|
||||
transfer,
|
||||
powercycle,
|
||||
fixedconfig,
|
||||
cablediagnostics,
|
||||
reenroll,
|
||||
package,
|
||||
unknown
|
||||
};
|
||||
|
||||
@@ -770,7 +825,12 @@ namespace OpenWifi::APCommands {
|
||||
RESTAPI::Protocol::LEDS, RESTAPI::Protocol::TRACE,
|
||||
RESTAPI::Protocol::REQUEST, RESTAPI::Protocol::WIFISCAN,
|
||||
RESTAPI::Protocol::EVENTQUEUE, RESTAPI::Protocol::TELEMETRY,
|
||||
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT};
|
||||
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT,
|
||||
RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE,
|
||||
RESTAPI::Protocol::TRANSFER, RESTAPI::Protocol::POWERCYCLE,
|
||||
RESTAPI::Protocol::FIXEDCONFIG, RESTAPI::Protocol::CABLEDIAGNOSTICS,
|
||||
RESTAPI::Protocol::REENROLL, RESTAPI::Protocol::PACKAGE
|
||||
};
|
||||
|
||||
inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }
|
||||
|
||||
@@ -798,6 +858,11 @@ namespace OpenWifi::Provisioning::DeviceClass {
|
||||
|
||||
} // namespace OpenWifi::Provisioning::DeviceClass
|
||||
|
||||
namespace OpenWifi::Platforms {
|
||||
static const std::string AP = "ap";
|
||||
static const std::string SWITCH = "switch";
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <resolv.h>
|
||||
|
||||
namespace OpenWifi::Utils {
|
||||
|
||||
bool NormalizeMac(std::string &Mac) {
|
||||
@@ -588,6 +590,26 @@ namespace OpenWifi::Utils {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Compress given data using utility function and encode it in base64 format.
|
||||
//
|
||||
bool CompressAndEncodeBase64(const std::string& UnCompressedData, std::string& CompressedBase64Data) {
|
||||
|
||||
unsigned long CompressedDataSize = UnCompressedData.size();
|
||||
std::vector<Bytef> CompressedData(CompressedDataSize);
|
||||
auto status = compress(&CompressedData[0], &CompressedDataSize,
|
||||
(Bytef*) UnCompressedData.c_str(), UnCompressedData.size());
|
||||
if (status == Z_OK) {
|
||||
CompressedBase64Data = OpenWifi::Utils::base64encode(&CompressedData[0], CompressedDataSize);
|
||||
}
|
||||
else {
|
||||
// failed to compress data
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsAlphaNumeric(const std::string &s) {
|
||||
return std::all_of(s.begin(), s.end(), [](char c) -> bool { return isalnum(c); });
|
||||
}
|
||||
@@ -783,6 +805,10 @@ namespace OpenWifi::Utils {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VerifyPrivateKey(const std::string &key) {
|
||||
return VerifyECKey(key) || VerifyRSAKey(key);
|
||||
}
|
||||
|
||||
bool ValidX509Certificate([[
|
||||
maybe_unused]] const std::string &Cert) {
|
||||
try {
|
||||
@@ -862,4 +888,15 @@ namespace OpenWifi::Utils {
|
||||
return password;
|
||||
}
|
||||
|
||||
/*
|
||||
Note that these 2 functions aren't used. They have been removed due to this deprecation warning:
|
||||
// Function to query NAPTR records for a domain and return them in a vector
|
||||
#47 3.825 /owgw/src/framework/utils.cpp: In function 'std::vector<OpenWifi::Utils::NAPTRRecord> OpenWifi::Utils::getNAPTRRecords(const std::string&)':
|
||||
#47 3.825 /owgw/src/framework/utils.cpp:915:28: warning: 'int ns_sprintrr(const ns_msg*, const ns_rr*, const char*, const char*, char*, size_t)' is deprecated [-Wdeprecated-declarations]
|
||||
|
||||
std::vector<SrvRecord> getSRVRecords(const std::string& domain) {
|
||||
#47 3.833 /owgw/src/framework/utils.cpp: In function 'std::vector<OpenWifi::Utils::SrvRecord> OpenWifi::Utils::getSRVRecords(const std::string&)':
|
||||
#47 3.833 /owgw/src/framework/utils.cpp:952:28: warning: 'int ns_sprintrr(const ns_msg*, const ns_rr*, const char*, const char*, char*, size_t)' is deprecated [-Wdeprecated-declarations]
|
||||
*/
|
||||
|
||||
} // namespace OpenWifi::Utils
|
||||
|
||||
@@ -151,6 +151,8 @@ namespace OpenWifi::Utils {
|
||||
bool ExtractBase64CompressedData(const std::string &CompressedData,
|
||||
std::string &UnCompressedData, uint64_t compress_sz);
|
||||
|
||||
bool CompressAndEncodeBase64(const std::string& UnCompressedData, std::string& CompressedData);
|
||||
|
||||
inline bool match(const char* first, const char* second)
|
||||
{
|
||||
// If we reach at the end of both strings, we are done
|
||||
@@ -247,6 +249,24 @@ namespace OpenWifi::Utils {
|
||||
return count;
|
||||
}
|
||||
|
||||
inline std::uint32_t IPtoInt(const std::string &A) {
|
||||
Poco::Net::IPAddress IP;
|
||||
std::uint32_t Result=0;
|
||||
|
||||
if(Poco::Net::IPAddress::tryParse(A,IP)) {
|
||||
for(const auto i:IP.toBytes()) {
|
||||
Result <<= 8;
|
||||
Result += i;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline bool ValidIP(const std::string &IPstr) {
|
||||
Poco::Net::IPAddress IP;
|
||||
return Poco::Net::IPAddress::tryParse(IPstr,IP);
|
||||
}
|
||||
|
||||
struct CSRCreationParameters {
|
||||
std::string Country, Province, City,
|
||||
Organization, CommonName;
|
||||
@@ -261,7 +281,130 @@ namespace OpenWifi::Utils {
|
||||
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase);
|
||||
bool VerifyECKey(const std::string &key);
|
||||
bool VerifyRSAKey(const std::string &key);
|
||||
bool VerifyPrivateKey(const std::string &key);
|
||||
bool ValidX509Certificate(const std::string &Cert);
|
||||
bool ValidX509Certificate(const std::vector<std::string> &Certs);
|
||||
|
||||
struct NAPTRRecord {
|
||||
std::string name;
|
||||
std::string ttl;
|
||||
std::string rclass;
|
||||
std::string rtype;
|
||||
uint32_t order=0;
|
||||
uint32_t preference=0;
|
||||
std::string flags;
|
||||
std::string service;
|
||||
std::string regexp;
|
||||
std::string replacement;
|
||||
};
|
||||
|
||||
// removed due to deprecation: see utils.cpp
|
||||
// Function to query NAPTR records for a domain and return them in a vector
|
||||
//std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
|
||||
|
||||
struct SrvRecord {
|
||||
std::string name;
|
||||
std::string ttl;
|
||||
std::string rclass;
|
||||
std::string rtype;
|
||||
uint32_t pref = 0;
|
||||
uint32_t weight = 0;
|
||||
uint32_t port = 0;
|
||||
std::string srvname;
|
||||
};
|
||||
|
||||
// removed due to deprecation: see utils.cpp
|
||||
// std::vector<SrvRecord> getSRVRecords(const std::string& domain);
|
||||
|
||||
struct HostNameServerResult{
|
||||
std::string Hostname;
|
||||
uint32_t Port;
|
||||
};
|
||||
|
||||
class CompressedString {
|
||||
public:
|
||||
CompressedString() {
|
||||
DecompressedSize_ = 0;
|
||||
};
|
||||
|
||||
explicit CompressedString(const std::string &Data) : DecompressedSize_(Data.size()) {
|
||||
CompressIt(Data);
|
||||
}
|
||||
|
||||
CompressedString(const CompressedString &Data) {
|
||||
this->DecompressedSize_ = Data.DecompressedSize_;
|
||||
this->CompressedData_ = Data.CompressedData_;
|
||||
}
|
||||
|
||||
CompressedString& operator=(const CompressedString& rhs) {
|
||||
if (this != &rhs) {
|
||||
this->DecompressedSize_ = rhs.DecompressedSize_;
|
||||
this->CompressedData_ = rhs.CompressedData_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompressedString& operator=(CompressedString&& rhs) {
|
||||
if (this != &rhs) {
|
||||
this->DecompressedSize_ = rhs.DecompressedSize_;
|
||||
this->CompressedData_ = rhs.CompressedData_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~CompressedString() = default;
|
||||
|
||||
operator std::string() const {
|
||||
return DecompressIt();
|
||||
}
|
||||
|
||||
CompressedString &operator=(const std::string &Data) {
|
||||
DecompressedSize_ = Data.size();
|
||||
CompressIt(Data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto CompressedSize() const { return CompressedData_.size(); }
|
||||
auto DecompressedSize() const { return DecompressedSize_; }
|
||||
|
||||
private:
|
||||
std::string CompressedData_;
|
||||
std::size_t DecompressedSize_;
|
||||
|
||||
inline void CompressIt(const std::string &Data) {
|
||||
z_stream strm; // = {0};
|
||||
CompressedData_.resize(Data.size());
|
||||
strm.next_in = (Bytef *)Data.data();
|
||||
strm.avail_in = Data.size();
|
||||
strm.next_out = (Bytef *)CompressedData_.data();
|
||||
strm.avail_out = Data.size();
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
|
||||
deflate(&strm, Z_FINISH);
|
||||
deflateEnd(&strm);
|
||||
CompressedData_.resize(strm.total_out);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string DecompressIt() const {
|
||||
std::string Result;
|
||||
if(DecompressedSize_!=0) {
|
||||
Result.resize(DecompressedSize_);
|
||||
z_stream strm ; //= {0};
|
||||
strm.next_in = (Bytef *)CompressedData_.data();
|
||||
strm.avail_in = CompressedData_.size();
|
||||
strm.next_out = (Bytef *)Result.data();
|
||||
strm.avail_out = Result.size();
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
inflateInit2(&strm, 15 + 32);
|
||||
inflate(&strm, Z_FINISH);
|
||||
inflateEnd(&strm);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace OpenWifi::Utils
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user