This commit is contained in:
stephb9959
2023-04-13 16:31:45 -07:00
54 changed files with 3335 additions and 1456 deletions

1
.gitignore vendored
View File

@@ -45,3 +45,4 @@ helm/charts/*
# Logs
test_scripts/curl/*.json
/src/ow_version.h

View File

@@ -52,6 +52,8 @@ include_directories(/usr/local/include /usr/local/opt/openssl/include src inclu
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
add_definitions(-DPOCO_LOG_DEBUG="1")
add_compile_options(-Wall -Wextra)
if(ASAN)
add_compile_options(-fsanitize=address)
@@ -117,14 +119,14 @@ add_executable( owls
src/RESTAPI/RESTAPI_routers.cpp
src/Daemon.cpp src/Daemon.h
src/Dashboard.cpp src/Dashboard.h
src/uCentralClient.cpp
src/uCentralClient.h
src/Simulator.cpp src/Simulator.h
src/uCentralEvent.cpp src/uCentralEvent.h
src/uCentralEventTypes.h
src/OWLSclient.cpp
src/OWLSclient.h
src/SimulationRunner.cpp src/SimulationRunner.h
# src/OWLSevent.cpp src/OWLSevent.h
src/OWLSdefinitions.h
src/SimStats.h
src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
src/StorageService.cpp src/StorageService.h src/storage/storage_simulations.cpp src/storage/storage_simulations.h src/storage/storage_results.cpp src/storage/storage_results.h src/RESTAPI/RESTAPI_simulation_handler.cpp src/RESTAPI/RESTAPI_simulation_handler.h src/RESTAPI/RESTAPI_results_handler.cpp src/RESTAPI/RESTAPI_results_handler.h src/RESTAPI/RESTAPI_status_handler.cpp src/RESTAPI/RESTAPI_status_handler.h src/RESTAPI/RESTAPI_operation_handler.cpp src/RESTAPI/RESTAPI_operation_handler.h src/Simulation.cpp src/Simulation.h src/UI_Owls_WebSocketNotifications.cpp src/UI_Owls_WebSocketNotifications.h)
src/StorageService.cpp src/StorageService.h src/storage/storage_simulations.cpp src/storage/storage_simulations.h src/storage/storage_results.cpp src/storage/storage_results.h src/RESTAPI/RESTAPI_simulation_handler.cpp src/RESTAPI/RESTAPI_simulation_handler.h src/RESTAPI/RESTAPI_results_handler.cpp src/RESTAPI/RESTAPI_results_handler.h src/RESTAPI/RESTAPI_status_handler.cpp src/RESTAPI/RESTAPI_status_handler.h src/RESTAPI/RESTAPI_operation_handler.cpp src/RESTAPI/RESTAPI_operation_handler.h src/SimulationCoordinator.cpp src/SimulationCoordinator.h src/UI_Owls_WebSocketNotifications.cpp src/UI_Owls_WebSocketNotifications.h src/OWLS_utils.h src/MockElements.h src/libs/ctpl_stl.h src/libs/Cron.h src/libs/InterruptableSleep.h src/libs/Scheduler.h src/OWLSscheduler.cpp src/OWLSscheduler.h src/OWLS_EstablishConnection.cpp src/OWLS_Reconnect.cpp src/OWLS_Connect.cpp src/OWLSclientEvents.h src/OWLS_State.cpp src/OWLS_HealthCheck.cpp src/OWLS_Log.cpp src/OWLS_Update.cpp src/OWLS_WSPing.cpp src/OWLS_KeepAlive.cpp src/OWLS_Disconnect.cpp src/OWLS_PendingConfig.cpp src/OWLS_CrashLog.cpp src/CensusReport.h)
target_link_libraries(owls PRIVATE
${Poco_LIBRARIES}

2
build
View File

@@ -1 +1 @@
2
22

View File

@@ -177,6 +177,342 @@ src/Dashboard.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/Dashboard.cpp.s
.PHONY : src/Dashboard.cpp.s
src/OWLS_Connect.o: src/OWLS_Connect.cpp.o
.PHONY : src/OWLS_Connect.o
# target to build an object file
src/OWLS_Connect.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Connect.cpp.o
.PHONY : src/OWLS_Connect.cpp.o
src/OWLS_Connect.i: src/OWLS_Connect.cpp.i
.PHONY : src/OWLS_Connect.i
# target to preprocess a source file
src/OWLS_Connect.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Connect.cpp.i
.PHONY : src/OWLS_Connect.cpp.i
src/OWLS_Connect.s: src/OWLS_Connect.cpp.s
.PHONY : src/OWLS_Connect.s
# target to generate assembly for a file
src/OWLS_Connect.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Connect.cpp.s
.PHONY : src/OWLS_Connect.cpp.s
src/OWLS_CrashLog.o: src/OWLS_CrashLog.cpp.o
.PHONY : src/OWLS_CrashLog.o
# target to build an object file
src/OWLS_CrashLog.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_CrashLog.cpp.o
.PHONY : src/OWLS_CrashLog.cpp.o
src/OWLS_CrashLog.i: src/OWLS_CrashLog.cpp.i
.PHONY : src/OWLS_CrashLog.i
# target to preprocess a source file
src/OWLS_CrashLog.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_CrashLog.cpp.i
.PHONY : src/OWLS_CrashLog.cpp.i
src/OWLS_CrashLog.s: src/OWLS_CrashLog.cpp.s
.PHONY : src/OWLS_CrashLog.s
# target to generate assembly for a file
src/OWLS_CrashLog.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_CrashLog.cpp.s
.PHONY : src/OWLS_CrashLog.cpp.s
src/OWLS_Disconnect.o: src/OWLS_Disconnect.cpp.o
.PHONY : src/OWLS_Disconnect.o
# target to build an object file
src/OWLS_Disconnect.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Disconnect.cpp.o
.PHONY : src/OWLS_Disconnect.cpp.o
src/OWLS_Disconnect.i: src/OWLS_Disconnect.cpp.i
.PHONY : src/OWLS_Disconnect.i
# target to preprocess a source file
src/OWLS_Disconnect.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Disconnect.cpp.i
.PHONY : src/OWLS_Disconnect.cpp.i
src/OWLS_Disconnect.s: src/OWLS_Disconnect.cpp.s
.PHONY : src/OWLS_Disconnect.s
# target to generate assembly for a file
src/OWLS_Disconnect.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Disconnect.cpp.s
.PHONY : src/OWLS_Disconnect.cpp.s
src/OWLS_EstablishConnection.o: src/OWLS_EstablishConnection.cpp.o
.PHONY : src/OWLS_EstablishConnection.o
# target to build an object file
src/OWLS_EstablishConnection.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_EstablishConnection.cpp.o
.PHONY : src/OWLS_EstablishConnection.cpp.o
src/OWLS_EstablishConnection.i: src/OWLS_EstablishConnection.cpp.i
.PHONY : src/OWLS_EstablishConnection.i
# target to preprocess a source file
src/OWLS_EstablishConnection.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_EstablishConnection.cpp.i
.PHONY : src/OWLS_EstablishConnection.cpp.i
src/OWLS_EstablishConnection.s: src/OWLS_EstablishConnection.cpp.s
.PHONY : src/OWLS_EstablishConnection.s
# target to generate assembly for a file
src/OWLS_EstablishConnection.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_EstablishConnection.cpp.s
.PHONY : src/OWLS_EstablishConnection.cpp.s
src/OWLS_HealthCheck.o: src/OWLS_HealthCheck.cpp.o
.PHONY : src/OWLS_HealthCheck.o
# target to build an object file
src/OWLS_HealthCheck.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_HealthCheck.cpp.o
.PHONY : src/OWLS_HealthCheck.cpp.o
src/OWLS_HealthCheck.i: src/OWLS_HealthCheck.cpp.i
.PHONY : src/OWLS_HealthCheck.i
# target to preprocess a source file
src/OWLS_HealthCheck.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_HealthCheck.cpp.i
.PHONY : src/OWLS_HealthCheck.cpp.i
src/OWLS_HealthCheck.s: src/OWLS_HealthCheck.cpp.s
.PHONY : src/OWLS_HealthCheck.s
# target to generate assembly for a file
src/OWLS_HealthCheck.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_HealthCheck.cpp.s
.PHONY : src/OWLS_HealthCheck.cpp.s
src/OWLS_KeepAlive.o: src/OWLS_KeepAlive.cpp.o
.PHONY : src/OWLS_KeepAlive.o
# target to build an object file
src/OWLS_KeepAlive.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_KeepAlive.cpp.o
.PHONY : src/OWLS_KeepAlive.cpp.o
src/OWLS_KeepAlive.i: src/OWLS_KeepAlive.cpp.i
.PHONY : src/OWLS_KeepAlive.i
# target to preprocess a source file
src/OWLS_KeepAlive.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_KeepAlive.cpp.i
.PHONY : src/OWLS_KeepAlive.cpp.i
src/OWLS_KeepAlive.s: src/OWLS_KeepAlive.cpp.s
.PHONY : src/OWLS_KeepAlive.s
# target to generate assembly for a file
src/OWLS_KeepAlive.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_KeepAlive.cpp.s
.PHONY : src/OWLS_KeepAlive.cpp.s
src/OWLS_Log.o: src/OWLS_Log.cpp.o
.PHONY : src/OWLS_Log.o
# target to build an object file
src/OWLS_Log.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Log.cpp.o
.PHONY : src/OWLS_Log.cpp.o
src/OWLS_Log.i: src/OWLS_Log.cpp.i
.PHONY : src/OWLS_Log.i
# target to preprocess a source file
src/OWLS_Log.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Log.cpp.i
.PHONY : src/OWLS_Log.cpp.i
src/OWLS_Log.s: src/OWLS_Log.cpp.s
.PHONY : src/OWLS_Log.s
# target to generate assembly for a file
src/OWLS_Log.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Log.cpp.s
.PHONY : src/OWLS_Log.cpp.s
src/OWLS_PendingConfig.o: src/OWLS_PendingConfig.cpp.o
.PHONY : src/OWLS_PendingConfig.o
# target to build an object file
src/OWLS_PendingConfig.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_PendingConfig.cpp.o
.PHONY : src/OWLS_PendingConfig.cpp.o
src/OWLS_PendingConfig.i: src/OWLS_PendingConfig.cpp.i
.PHONY : src/OWLS_PendingConfig.i
# target to preprocess a source file
src/OWLS_PendingConfig.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_PendingConfig.cpp.i
.PHONY : src/OWLS_PendingConfig.cpp.i
src/OWLS_PendingConfig.s: src/OWLS_PendingConfig.cpp.s
.PHONY : src/OWLS_PendingConfig.s
# target to generate assembly for a file
src/OWLS_PendingConfig.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_PendingConfig.cpp.s
.PHONY : src/OWLS_PendingConfig.cpp.s
src/OWLS_Reconnect.o: src/OWLS_Reconnect.cpp.o
.PHONY : src/OWLS_Reconnect.o
# target to build an object file
src/OWLS_Reconnect.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Reconnect.cpp.o
.PHONY : src/OWLS_Reconnect.cpp.o
src/OWLS_Reconnect.i: src/OWLS_Reconnect.cpp.i
.PHONY : src/OWLS_Reconnect.i
# target to preprocess a source file
src/OWLS_Reconnect.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Reconnect.cpp.i
.PHONY : src/OWLS_Reconnect.cpp.i
src/OWLS_Reconnect.s: src/OWLS_Reconnect.cpp.s
.PHONY : src/OWLS_Reconnect.s
# target to generate assembly for a file
src/OWLS_Reconnect.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Reconnect.cpp.s
.PHONY : src/OWLS_Reconnect.cpp.s
src/OWLS_State.o: src/OWLS_State.cpp.o
.PHONY : src/OWLS_State.o
# target to build an object file
src/OWLS_State.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_State.cpp.o
.PHONY : src/OWLS_State.cpp.o
src/OWLS_State.i: src/OWLS_State.cpp.i
.PHONY : src/OWLS_State.i
# target to preprocess a source file
src/OWLS_State.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_State.cpp.i
.PHONY : src/OWLS_State.cpp.i
src/OWLS_State.s: src/OWLS_State.cpp.s
.PHONY : src/OWLS_State.s
# target to generate assembly for a file
src/OWLS_State.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_State.cpp.s
.PHONY : src/OWLS_State.cpp.s
src/OWLS_Update.o: src/OWLS_Update.cpp.o
.PHONY : src/OWLS_Update.o
# target to build an object file
src/OWLS_Update.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Update.cpp.o
.PHONY : src/OWLS_Update.cpp.o
src/OWLS_Update.i: src/OWLS_Update.cpp.i
.PHONY : src/OWLS_Update.i
# target to preprocess a source file
src/OWLS_Update.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Update.cpp.i
.PHONY : src/OWLS_Update.cpp.i
src/OWLS_Update.s: src/OWLS_Update.cpp.s
.PHONY : src/OWLS_Update.s
# target to generate assembly for a file
src/OWLS_Update.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_Update.cpp.s
.PHONY : src/OWLS_Update.cpp.s
src/OWLS_WSPing.o: src/OWLS_WSPing.cpp.o
.PHONY : src/OWLS_WSPing.o
# target to build an object file
src/OWLS_WSPing.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_WSPing.cpp.o
.PHONY : src/OWLS_WSPing.cpp.o
src/OWLS_WSPing.i: src/OWLS_WSPing.cpp.i
.PHONY : src/OWLS_WSPing.i
# target to preprocess a source file
src/OWLS_WSPing.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_WSPing.cpp.i
.PHONY : src/OWLS_WSPing.cpp.i
src/OWLS_WSPing.s: src/OWLS_WSPing.cpp.s
.PHONY : src/OWLS_WSPing.s
# target to generate assembly for a file
src/OWLS_WSPing.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLS_WSPing.cpp.s
.PHONY : src/OWLS_WSPing.cpp.s
src/OWLSclient.o: src/OWLSclient.cpp.o
.PHONY : src/OWLSclient.o
# target to build an object file
src/OWLSclient.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLSclient.cpp.o
.PHONY : src/OWLSclient.cpp.o
src/OWLSclient.i: src/OWLSclient.cpp.i
.PHONY : src/OWLSclient.i
# target to preprocess a source file
src/OWLSclient.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLSclient.cpp.i
.PHONY : src/OWLSclient.cpp.i
src/OWLSclient.s: src/OWLSclient.cpp.s
.PHONY : src/OWLSclient.s
# target to generate assembly for a file
src/OWLSclient.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLSclient.cpp.s
.PHONY : src/OWLSclient.cpp.s
src/OWLSscheduler.o: src/OWLSscheduler.cpp.o
.PHONY : src/OWLSscheduler.o
# target to build an object file
src/OWLSscheduler.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLSscheduler.cpp.o
.PHONY : src/OWLSscheduler.cpp.o
src/OWLSscheduler.i: src/OWLSscheduler.cpp.i
.PHONY : src/OWLSscheduler.i
# target to preprocess a source file
src/OWLSscheduler.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLSscheduler.cpp.i
.PHONY : src/OWLSscheduler.cpp.i
src/OWLSscheduler.s: src/OWLSscheduler.cpp.s
.PHONY : src/OWLSscheduler.s
# target to generate assembly for a file
src/OWLSscheduler.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/OWLSscheduler.cpp.s
.PHONY : src/OWLSscheduler.cpp.s
src/RESTAPI/RESTAPI_deviceDashboardHandler.o: src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp.o
.PHONY : src/RESTAPI/RESTAPI_deviceDashboardHandler.o
@@ -489,53 +825,53 @@ src/RESTObjects/RESTAPI_SecurityObjects.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/RESTObjects/RESTAPI_SecurityObjects.cpp.s
.PHONY : src/RESTObjects/RESTAPI_SecurityObjects.cpp.s
src/Simulation.o: src/Simulation.cpp.o
.PHONY : src/Simulation.o
src/SimulationCoordinator.o: src/SimulationCoordinator.cpp.o
.PHONY : src/SimulationCoordinator.o
# target to build an object file
src/Simulation.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/Simulation.cpp.o
.PHONY : src/Simulation.cpp.o
src/SimulationCoordinator.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/SimulationCoordinator.cpp.o
.PHONY : src/SimulationCoordinator.cpp.o
src/Simulation.i: src/Simulation.cpp.i
.PHONY : src/Simulation.i
src/SimulationCoordinator.i: src/SimulationCoordinator.cpp.i
.PHONY : src/SimulationCoordinator.i
# target to preprocess a source file
src/Simulation.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/Simulation.cpp.i
.PHONY : src/Simulation.cpp.i
src/SimulationCoordinator.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/SimulationCoordinator.cpp.i
.PHONY : src/SimulationCoordinator.cpp.i
src/Simulation.s: src/Simulation.cpp.s
.PHONY : src/Simulation.s
src/SimulationCoordinator.s: src/SimulationCoordinator.cpp.s
.PHONY : src/SimulationCoordinator.s
# target to generate assembly for a file
src/Simulation.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/Simulation.cpp.s
.PHONY : src/Simulation.cpp.s
src/SimulationCoordinator.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/SimulationCoordinator.cpp.s
.PHONY : src/SimulationCoordinator.cpp.s
src/Simulator.o: src/Simulator.cpp.o
.PHONY : src/Simulator.o
src/SimulationRunner.o: src/SimulationRunner.cpp.o
.PHONY : src/SimulationRunner.o
# target to build an object file
src/Simulator.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/Simulator.cpp.o
.PHONY : src/Simulator.cpp.o
src/SimulationRunner.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/SimulationRunner.cpp.o
.PHONY : src/SimulationRunner.cpp.o
src/Simulator.i: src/Simulator.cpp.i
.PHONY : src/Simulator.i
src/SimulationRunner.i: src/SimulationRunner.cpp.i
.PHONY : src/SimulationRunner.i
# target to preprocess a source file
src/Simulator.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/Simulator.cpp.i
.PHONY : src/Simulator.cpp.i
src/SimulationRunner.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/SimulationRunner.cpp.i
.PHONY : src/SimulationRunner.cpp.i
src/Simulator.s: src/Simulator.cpp.s
.PHONY : src/Simulator.s
src/SimulationRunner.s: src/SimulationRunner.cpp.s
.PHONY : src/SimulationRunner.s
# target to generate assembly for a file
src/Simulator.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/Simulator.cpp.s
.PHONY : src/Simulator.cpp.s
src/SimulationRunner.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/SimulationRunner.cpp.s
.PHONY : src/SimulationRunner.cpp.s
src/StorageService.o: src/StorageService.cpp.o
.PHONY : src/StorageService.o
@@ -969,54 +1305,6 @@ src/storage/storage_simulations.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/storage/storage_simulations.cpp.s
.PHONY : src/storage/storage_simulations.cpp.s
src/uCentralClient.o: src/uCentralClient.cpp.o
.PHONY : src/uCentralClient.o
# target to build an object file
src/uCentralClient.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/uCentralClient.cpp.o
.PHONY : src/uCentralClient.cpp.o
src/uCentralClient.i: src/uCentralClient.cpp.i
.PHONY : src/uCentralClient.i
# target to preprocess a source file
src/uCentralClient.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/uCentralClient.cpp.i
.PHONY : src/uCentralClient.cpp.i
src/uCentralClient.s: src/uCentralClient.cpp.s
.PHONY : src/uCentralClient.s
# target to generate assembly for a file
src/uCentralClient.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/uCentralClient.cpp.s
.PHONY : src/uCentralClient.cpp.s
src/uCentralEvent.o: src/uCentralEvent.cpp.o
.PHONY : src/uCentralEvent.o
# target to build an object file
src/uCentralEvent.cpp.o:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/uCentralEvent.cpp.o
.PHONY : src/uCentralEvent.cpp.o
src/uCentralEvent.i: src/uCentralEvent.cpp.i
.PHONY : src/uCentralEvent.i
# target to preprocess a source file
src/uCentralEvent.cpp.i:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/uCentralEvent.cpp.i
.PHONY : src/uCentralEvent.cpp.i
src/uCentralEvent.s: src/uCentralEvent.cpp.s
.PHONY : src/uCentralEvent.s
# target to generate assembly for a file
src/uCentralEvent.cpp.s:
$(MAKE) $(MAKESILENT) -f CMakeFiles/owls.dir/build.make CMakeFiles/owls.dir/src/uCentralEvent.cpp.s
.PHONY : src/uCentralEvent.cpp.s
# Help Target
help:
@echo "The following are some of the valid targets for this Makefile:"
@@ -1032,6 +1320,48 @@ help:
@echo "... src/Dashboard.o"
@echo "... src/Dashboard.i"
@echo "... src/Dashboard.s"
@echo "... src/OWLS_Connect.o"
@echo "... src/OWLS_Connect.i"
@echo "... src/OWLS_Connect.s"
@echo "... src/OWLS_CrashLog.o"
@echo "... src/OWLS_CrashLog.i"
@echo "... src/OWLS_CrashLog.s"
@echo "... src/OWLS_Disconnect.o"
@echo "... src/OWLS_Disconnect.i"
@echo "... src/OWLS_Disconnect.s"
@echo "... src/OWLS_EstablishConnection.o"
@echo "... src/OWLS_EstablishConnection.i"
@echo "... src/OWLS_EstablishConnection.s"
@echo "... src/OWLS_HealthCheck.o"
@echo "... src/OWLS_HealthCheck.i"
@echo "... src/OWLS_HealthCheck.s"
@echo "... src/OWLS_KeepAlive.o"
@echo "... src/OWLS_KeepAlive.i"
@echo "... src/OWLS_KeepAlive.s"
@echo "... src/OWLS_Log.o"
@echo "... src/OWLS_Log.i"
@echo "... src/OWLS_Log.s"
@echo "... src/OWLS_PendingConfig.o"
@echo "... src/OWLS_PendingConfig.i"
@echo "... src/OWLS_PendingConfig.s"
@echo "... src/OWLS_Reconnect.o"
@echo "... src/OWLS_Reconnect.i"
@echo "... src/OWLS_Reconnect.s"
@echo "... src/OWLS_State.o"
@echo "... src/OWLS_State.i"
@echo "... src/OWLS_State.s"
@echo "... src/OWLS_Update.o"
@echo "... src/OWLS_Update.i"
@echo "... src/OWLS_Update.s"
@echo "... src/OWLS_WSPing.o"
@echo "... src/OWLS_WSPing.i"
@echo "... src/OWLS_WSPing.s"
@echo "... src/OWLSclient.o"
@echo "... src/OWLSclient.i"
@echo "... src/OWLSclient.s"
@echo "... src/OWLSscheduler.o"
@echo "... src/OWLSscheduler.i"
@echo "... src/OWLSscheduler.s"
@echo "... src/RESTAPI/RESTAPI_deviceDashboardHandler.o"
@echo "... src/RESTAPI/RESTAPI_deviceDashboardHandler.i"
@echo "... src/RESTAPI/RESTAPI_deviceDashboardHandler.s"
@@ -1071,12 +1401,12 @@ help:
@echo "... src/RESTObjects/RESTAPI_SecurityObjects.o"
@echo "... src/RESTObjects/RESTAPI_SecurityObjects.i"
@echo "... src/RESTObjects/RESTAPI_SecurityObjects.s"
@echo "... src/Simulation.o"
@echo "... src/Simulation.i"
@echo "... src/Simulation.s"
@echo "... src/Simulator.o"
@echo "... src/Simulator.i"
@echo "... src/Simulator.s"
@echo "... src/SimulationCoordinator.o"
@echo "... src/SimulationCoordinator.i"
@echo "... src/SimulationCoordinator.s"
@echo "... src/SimulationRunner.o"
@echo "... src/SimulationRunner.i"
@echo "... src/SimulationRunner.s"
@echo "... src/StorageService.o"
@echo "... src/StorageService.i"
@echo "... src/StorageService.s"
@@ -1131,12 +1461,6 @@ help:
@echo "... src/storage/storage_simulations.o"
@echo "... src/storage/storage_simulations.i"
@echo "... src/storage/storage_simulations.s"
@echo "... src/uCentralClient.o"
@echo "... src/uCentralClient.i"
@echo "... src/uCentralClient.s"
@echo "... src/uCentralEvent.o"
@echo "... src/uCentralEvent.i"
@echo "... src/uCentralEvent.s"
.PHONY : help

View File

@@ -499,31 +499,34 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/status:
/status/{id}:
get:
tags:
- Status
operationId: getStatusOfRunningSimulation
parameters:
- in: path
schema:
type: string
required: true
responses:
200:
$ref: '#/components/schemas/SimulationStatus'
/operation:
/operation/{id}:
post:
tags:
- Operations
operationId: createARunningSimulation
parameters:
- in: query
- in: path
name: id
schema:
type: string
format: uuid
- in: query
name: simulationId
schema:
type: string
format: uuid
required: true
- in: query
name: operation
schema:

66
src/CensusReport.h Normal file
View File

@@ -0,0 +1,66 @@
//
// Created by stephane bourque on 2023-04-13.
//
#pragma once
#include <cstdint>
namespace OpenWifi {
struct CensusReport {
std::uint64_t
ev_none,
ev_reconnect,
ev_connect,
ev_state,
ev_healthcheck,
ev_log,
ev_crashlog,
ev_configpendingchange,
ev_keepalive,
ev_reboot,
ev_disconnect,
ev_wsping,
ev_update,
ev_configure,
ev_firmwareupgrade,
ev_factory,
ev_leds,
ev_trace,
ev_perform,
ev_establish_connection,
protocol_tx,
protocol_rx,
client_tx,
client_rx
;
void Reset() {
ev_none =
ev_reconnect =
ev_connect =
ev_state =
ev_healthcheck =
ev_log =
ev_crashlog =
ev_configpendingchange =
ev_keepalive =
ev_reboot =
ev_disconnect =
ev_wsping =
ev_update =
ev_configure =
ev_firmwareupgrade =
ev_factory =
ev_leds =
ev_trace =
ev_perform =
protocol_tx =
protocol_rx =
client_tx =
client_rx =
ev_establish_connection = 0;
}
};
}

View File

@@ -8,12 +8,13 @@
#include "Daemon.h"
#include "SimStats.h"
#include "Simulation.h"
#include "SimulationCoordinator.h"
#include "StorageService.h"
#include "Poco/Net/SSLManager.h"
#include "UI_Owls_WebSocketNotifications.h"
#include "framework/UI_WebSocketClientServer.h"
#include "OWLSscheduler.h"
namespace OpenWifi {
class Daemon *Daemon::instance_ = nullptr;
@@ -24,7 +25,8 @@ namespace OpenWifi {
new Daemon(vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR,
vDAEMON_CONFIG_ENV_VAR, vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
SubSystemVec{SimStats(), StorageService(), SimulationCoordinator(),
UI_WebSocketClientServer()});
UI_WebSocketClientServer(),
OWLSscheduler()});
}
return instance_;
}

306
src/MockElements.h Normal file
View File

@@ -0,0 +1,306 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include <framework/MicroServiceFuncs.h>
#include <nlohmann/json.hpp>
#include "OWLS_utils.h"
namespace OpenWifi {
struct MockElement {
explicit MockElement(std::uint64_t S) : size(S) {
}
virtual void next() { last_update = Utils::Now(); };
virtual void reset() = 0;
[[nodiscard]] virtual nlohmann::json to_json() const = 0;
virtual ~MockElement() = default;
void SetSize(std::uint64_t S) { size = S; }
std::uint64_t last_update = Utils::Now();
std::uint64_t size = 0;
};
struct MockMemory : public MockElement {
std::uint64_t total=973131776, free=0, cached=0, buffered=0;
explicit MockMemory(std::uint64_t S) : MockElement(S) {
}
void next() final {
MockElement::next();
}
void reset() final {
}
[[nodiscard]] nlohmann::json to_json() const final {
nlohmann::json result;
result["memory"]["buffered"] = buffered;
result["memory"]["cached"] = cached;
result["memory"]["free"] = free;
result["memory"]["total"] = total;
return result;
}
};
struct MockCPULoad : public MockElement {
std::double_t load_1=0.0, load_5=0.0, load_15=0.0;
explicit MockCPULoad(std::uint64_t S) : MockElement(S) {
}
void next() final {
MockElement::next();
}
void reset() final {
}
[[nodiscard]] nlohmann::json to_json() const final {
nlohmann::json result;
result["load"] = std::vector<std::double_t> { load_1, load_5, load_15};
return result;
}
};
struct MockLanClient : public MockElement {
std::vector<std::string> ipv6_addresses, ipv4_addresses, ports;
std::string mac;
explicit MockLanClient() : MockElement(1) {
}
void next() final {
MockElement::next();
}
void reset() final {
}
[[nodiscard]] nlohmann::json to_json() const final {
nlohmann::json res;
res["ipv4_addresses"] = ipv4_addresses;
res["ipv6_addresses"] = ipv6_addresses;
res["ports"] = ports;
res["mac"] = mac;
return res;
}
};
typedef std::vector<MockLanClient> MockLanClients;
struct MockAssociation : public MockElement {
std::string station;
std::string bssid;
std::string ipaddr_v4;
std::string ipaddr_v6;
uint64_t tx_bytes = 0, rx_bytes = 0, rx_duration = 0, rx_packets = 0, connected = 0,
inactive = 0, tx_duration = 0, tx_failed = 0, tx_packets = 0, tx_retries = 0;
int64_t ack_signal = 0, ack_signal_avg = OWLSutils::local_random(-65, -75),
rssi = OWLSutils::local_random(-40, -90);
MockAssociation() : MockElement(1) {
}
[[nodiscard]] nlohmann::json to_json() const final {
nlohmann::json res;
res["ack_signal"] = ack_signal;
res["ack_signal_avg"] = ack_signal_avg;
res["bssid"] = bssid;
res["station"] = station;
res["connected"] = connected;
res["inactive"] = inactive;
res["ipaddr_v4"] = ipaddr_v4;
res["rssi"] = rssi;
res["rx_bytes"] = rx_bytes;
res["rx_duration"] = rx_duration;
res["rx_packets"] = rx_packets;
res["rx_rate"]["bitrate"] = 200000;
res["rx_rate"]["chwidth"] = 40;
res["rx_rate"]["mcs"] = 9;
res["rx_rate"]["nss"] = 9;
res["rx_rate"]["sgi"] = true;
res["rx_rate"]["vht"] = true;
res["tx_bytes"] = tx_bytes;
res["tx_duration"] = tx_duration;
res["tx_failed"] = tx_failed;
res["tx_packets"] = tx_packets;
res["tx_retries"] = tx_retries;
res["tx_rate"]["bitrate"] = 200000;
res["tx_rate"]["chwidth"] = 40;
res["tx_rate"]["mcs"] = 9;
res["tx_rate"]["sgi"] = true;
res["tx_rate"]["ht"] = true;
return res;
}
void next() final {
MockElement::next();
ack_signal = ack_signal_avg + OWLSutils::local_random(-5, 5);
connected += OWLSutils::local_random(100, 500);
inactive += OWLSutils::local_random(100, 500);
rssi += OWLSutils::local_random(-2, 2);
auto new_rx_packets = OWLSutils::local_random(200, 2000);
rx_packets += new_rx_packets;
rx_bytes += new_rx_packets * OWLSutils::local_random(500, 1000);
rx_duration += OWLSutils::local_random(400, 1750);
auto new_tx_packets = OWLSutils::local_random(100, 300);
tx_packets += new_tx_packets;
tx_bytes += new_tx_packets * OWLSutils::local_random(500, 1000);
tx_duration += OWLSutils::local_random(400, 1750);
tx_failed += OWLSutils::local_random(3) * OWLSutils::local_random(800, 1200);
tx_retries += OWLSutils::local_random(3);
}
void reset() final {
ack_signal = ack_signal_avg;
connected = 0;
inactive = 0;
rx_packets = 0;
rx_bytes = 0;
rx_duration = 0;
tx_packets = 0;
tx_bytes = 0;
tx_duration = 0;
tx_failed = 0;
tx_retries = 0;
}
};
typedef std::vector<MockAssociation> MockAssociations;
struct MockRadio : public MockElement {
std::uint64_t active_ms = 0,
busy_ms = 0,
channel = 0,
channel_width = 40,
receive_ms = 0,
transmit_ms = 0,
tx_power = 23;
std::int64_t noise = -100,
temperature = 40;
std::string phy;
uint64_t index = 0;
radio_bands radioBands = radio_bands::band_2g;
std::vector<std::uint64_t> channels;
std::vector<std::uint64_t> frequency;
std::vector<std::string> band;
explicit MockRadio() : MockElement(1) {
}
[[nodiscard]] nlohmann::json to_json() const final {
nlohmann::json res;
res["active_ms"] = active_ms;
res["busy_ms"] = busy_ms;
res["receive_ms"] = receive_ms;
res["transmit_ms"] = transmit_ms;
res["noise"] = noise;
res["temperature"] = temperature;
res["channel"] = channel;
res["channel_width"] = std::to_string(channel_width);
res["tx_power"] = tx_power;
res["phy"] = phy;
res["channels"] = channels;
res["frequency"] = frequency;
res["band"] = band;
return res;
}
void next() final {
MockElement::next();
temperature = 50 + OWLSutils::local_random(-7, 7);
noise = -95 + OWLSutils::local_random(-3, 3);
active_ms += OWLSutils::local_random(100, 2000);
busy_ms += OWLSutils::local_random(200, 3000);
receive_ms += OWLSutils::local_random(500, 1500);
transmit_ms += OWLSutils::local_random(250, 100);
}
void reset() final {
active_ms = 0;
busy_ms = 0;
receive_ms = 0;
transmit_ms = 0;
}
};
struct MockCounters : public MockElement {
std::uint64_t collisions = 0, multicast = 0, rx_bytes = 0, rx_dropped = 0, rx_errors = 0,
rx_packets = 0, tx_bytes = 0, tx_dropped = 0, tx_errors = 0, tx_packets = 0;
MockCounters() : MockElement(1) {
}
[[nodiscard]] nlohmann::json to_json() const final {
nlohmann::json res;
res["collisions"] = collisions;
res["multicast"] = multicast;
res["rx_bytes"] = rx_bytes;
res["rx_dropped"] = rx_dropped;
res["rx_errors"] = rx_errors;
res["rx_packets"] = rx_packets;
res["tx_bytes"] = tx_bytes;
res["tx_dropped"] = tx_dropped;
res["tx_errors"] = tx_errors;
res["tx_packets"] = tx_packets;
return res;
}
void next() final {
MockElement::next();
multicast += OWLSutils::local_random(10, 100);
collisions += OWLSutils::local_random(1);
rx_dropped += OWLSutils::local_random(2);
rx_errors += OWLSutils::local_random(3);
auto new_rx_packets = OWLSutils::local_random(300, 2000);
rx_packets += new_rx_packets;
rx_bytes += new_rx_packets * OWLSutils::local_random(900, 1400);
tx_dropped += OWLSutils::local_random(2);
tx_errors += OWLSutils::local_random(3);
auto new_tx_packets = OWLSutils::local_random(300, 2000);
tx_packets += new_tx_packets;
tx_bytes += new_tx_packets * OWLSutils::local_random(900, 1400);
}
void reset() final {
multicast = 0;
collisions = 0;
rx_dropped = 0;
rx_errors = 0;
rx_packets = 0;
rx_bytes = 0;
tx_dropped = 0;
tx_errors = 0;
tx_packets = 0;
tx_bytes = 0;
}
};
}

59
src/OWLS_Connect.cpp Normal file
View File

@@ -0,0 +1,59 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
#include "OWLSevent.h"
namespace OpenWifi::OWLSclientEvents {
void Connect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_) {
try {
Runner->Report().ev_connect++;
nlohmann::json M;
M["jsonrpc"] = "2.0";
M["method"] = "connect";
M["params"]["serial"] = Client->Serial();
M["params"]["uuid"] = Client->UUID();
M["params"]["firmware"] = Client->Firmware();
auto TmpCapabilities = SimulationCoordinator()->GetSimCapabilities();
auto LabelMac = Utils::SerialNumberToInt(Client->Serial());
auto LabelMacFormatted = Utils::SerialToMAC(Utils::IntToSerialNumber(LabelMac));
auto LabelLanMacFormatted = Utils::SerialToMAC(Utils::IntToSerialNumber(LabelMac + 1));
TmpCapabilities["label_macaddr"] = LabelMac;
TmpCapabilities["macaddr"]["wan"] = LabelMac;
TmpCapabilities["macaddr"]["lan"] = LabelLanMacFormatted;
M["params"]["capabilities"] = TmpCapabilities;
if (Client->Send(to_string(M))) {
Client->Reset();
OWLSscheduler()->Ref().in(std::chrono::seconds(Client->StatisticsInterval_),
OWLSclientEvents::State, Client, Runner);
OWLSscheduler()->Ref().in(std::chrono::seconds(Client->HealthInterval_),
OWLSclientEvents::HealthCheck, Client, Runner);
OWLSscheduler()->Ref().in(std::chrono::seconds(MicroServiceRandom(120, 200)),
OWLSclientEvents::Log, Client, Runner, 1, "Device started");
OWLSscheduler()->Ref().in(std::chrono::seconds(60 * 4),
OWLSclientEvents::WSPing, Client, Runner);
OWLSscheduler()->Ref().in(std::chrono::seconds(30),
OWLSclientEvents::Update, Client, Runner);
return;
}
} catch (const Poco::Exception &E) {
Client->Logger().log(E);
}
OWLSclientEvents::Disconnect(Client, Runner, "Error occurred during connection", true);
}
}
}

25
src/OWLS_CrashLog.cpp Normal file
View File

@@ -0,0 +1,25 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
#include "OWLSevent.h"
namespace OpenWifi::OWLSclientEvents {
void CrashLog(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_) {
Runner->Report().ev_crashlog++;
}
}
}

40
src/OWLS_Disconnect.cpp Normal file
View File

@@ -0,0 +1,40 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
#include "OWLSevent.h"
#include "OWLS_utils.h"
namespace OpenWifi::OWLSclientEvents {
void Disconnect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner, const std::string &Reason, bool Reconnect) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_) {
Runner->Report().ev_disconnect++;
if (Client->Connected_) {
Runner->RemoveClientFd(Client->fd_);
Client->fd_ = -1;
Client->Reactor_.removeEventHandler(
*Client->WS_, Poco::NObserver<SimulationRunner, Poco::Net::ReadableNotification>(
*Client->Runner_, &SimulationRunner::OnSocketReadable));
(*Client->WS_).close();
}
Client->Connected_ = false;
poco_debug(Client->Logger(),fmt::format("{}: disconnecting. Reason: {}", Client->SerialNumber_, Reason));
if(Reconnect) {
OWLSscheduler()->Ref().in(std::chrono::seconds(OWLSutils::local_random(3, 15)),
OWLSclientEvents::EstablishConnection, Client, Runner);
}
}
}
}

View File

@@ -0,0 +1,93 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
namespace OpenWifi::OWLSclientEvents {
void EstablishConnection(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
Poco::URI uri(Runner->Details().gateway);
Poco::Net::Context::Params P;
Runner->Report().ev_establish_connection++;
P.verificationMode = Poco::Net::Context::VERIFY_STRICT;
P.verificationDepth = 9;
P.caLocation = SimulationCoordinator()->GetCasLocation();
P.loadDefaultCAs = false;
P.certificateFile = SimulationCoordinator()->GetCertFileName();
P.privateKeyFile = SimulationCoordinator()->GetKeyFileName();
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
auto Context = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, P);
Poco::Crypto::X509Certificate Cert(SimulationCoordinator()->GetCertFileName());
Poco::Crypto::X509Certificate Root(SimulationCoordinator()->GetRootCAFileName());
Context->useCertificate(Cert);
Context->addChainCertificate(Root);
Context->addCertificateAuthority(Root);
if (SimulationCoordinator()->GetLevel() == Poco::Net::Context::VERIFY_STRICT) {
}
Poco::Crypto::RSAKey Key("", SimulationCoordinator()->GetKeyFileName(), "");
Context->usePrivateKey(Key);
SSL_CTX *SSLCtx = Context->sslContext();
if (!SSL_CTX_check_private_key(SSLCtx)) {
std::cout << "Wrong Certificate: " << SimulationCoordinator()->GetCertFileName()
<< " for " << SimulationCoordinator()->GetKeyFileName() << std::endl;
}
if (SimulationCoordinator()->GetLevel() == Poco::Net::Context::VERIFY_STRICT) {
}
Poco::Net::HTTPSClientSession Session(uri.getHost(), uri.getPort(), Context);
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_GET, "/?encoding=text",
Poco::Net::HTTPMessage::HTTP_1_1);
Request.set("origin", "http://www.websocket.org");
Poco::Net::HTTPResponse Response;
Client->Logger_.information(fmt::format("connecting({}): host={} port={}", Client->SerialNumber_,
uri.getHost(), uri.getPort()));
try {
Client->WS_ = std::make_unique<Poco::Net::WebSocket>(Session, Request, Response);
(*Client->WS_).setKeepAlive(true);
(*Client->WS_).setReceiveTimeout(Poco::Timespan());
(*Client->WS_).setSendTimeout(Poco::Timespan(20, 0));
(*Client->WS_).setNoDelay(true);
Client->Reactor_.addEventHandler(
*Client->WS_, Poco::NObserver<SimulationRunner, Poco::Net::ReadableNotification>(
*Runner, &SimulationRunner::OnSocketReadable));
Client->Connected_ = true;
Runner->AddClientFd(Client->WS_->impl()->sockfd(), Client);
OWLSscheduler()->Ref().in(std::chrono::seconds(1), Connect, Client, Runner);
SimStats()->Connect(Runner->Id());
} catch (const Poco::Exception &E) {
Client->Logger_.warning(
fmt::format("connecting({}): exception. {}", Client->SerialNumber_, E.displayText()));
OWLSscheduler()->Ref().in(std::chrono::seconds(60), Reconnect, Client, Runner);
} catch (const std::exception &E) {
Client->Logger_.warning(
fmt::format("connecting({}): std::exception. {}", Client->SerialNumber_, E.what()));
OWLSscheduler()->Ref().in(std::chrono::seconds(60), Reconnect, Client, Runner);
} catch (...) {
Client->Logger_.warning(fmt::format("connecting({}): unknown exception. {}", Client->SerialNumber_));
OWLSscheduler()->Ref().in(std::chrono::seconds(60), Reconnect, Client, Runner);
}
}
}

43
src/OWLS_HealthCheck.cpp Normal file
View File

@@ -0,0 +1,43 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
namespace OpenWifi::OWLSclientEvents {
void HealthCheck(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_ && Client->Connected_) {
Runner->Report().ev_healthcheck++;
try {
nlohmann::json M, P;
P["memory"] = 23;
M["jsonrpc"] = "2.0";
M["method"] = "healthcheck";
M["params"]["serial"] = Client->Serial();
M["params"]["uuid"] = Client->UUID();
M["params"]["sanity"] = 100;
M["params"]["data"] = P;
if (Client->Send(to_string(M))) {
OWLSscheduler()->Ref().in(std::chrono::seconds(Client->HealthInterval_),
OWLSclientEvents::HealthCheck, Client, Runner);
return;
}
} catch (const Poco::Exception &E) {
Client->Logger().log(E);
}
OWLSclientEvents::Disconnect(Client, Runner, "Error while sending HealthCheck", true);
}
}
}

41
src/OWLS_KeepAlive.cpp Normal file
View File

@@ -0,0 +1,41 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
namespace OpenWifi::OWLSclientEvents {
void KeepAlive(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_ && Client->Connected_) {
Runner->Report().ev_keepalive++;
try {
nlohmann::json M;
M["jsonrpc"] = "2.0";
M["method"] = "ping";
M["params"]["serial"] = Client->Serial();
M["params"]["uuid"] = Client->UUID();
if (Client->Send(to_string(M))) {
OWLSscheduler()->Ref().in(std::chrono::seconds(Runner->Details().keepAlive),
OWLSclientEvents::KeepAlive, Client, Runner);
return;
}
} catch (const Poco::Exception &E) {
Client->Logger().log(E);
}
OWLSclientEvents::Disconnect(Client, Runner, "Error while sending keepalive", true);
}
}
}

41
src/OWLS_Log.cpp Normal file
View File

@@ -0,0 +1,41 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
namespace OpenWifi::OWLSclientEvents {
void Log(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner, std::uint64_t Severity, const std::string & LogLine) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_ && Client->Connected_ ) {
Runner->Report().ev_log++;
try {
nlohmann::json M;
M["jsonrpc"] = "2.0";
M["method"] = "log";
M["params"]["serial"] = Client->Serial();
M["params"]["uuid"] = Client->UUID();
M["params"]["severity"] = Severity;
M["params"]["log"] = LogLine;
if (Client->Send(to_string(M))) {
return;
}
} catch (const Poco::Exception &E) {
Client->Logger().log(E);
}
OWLSclientEvents::Disconnect(Client, Runner, "Error while sending a Log event", true);
}
}
}

View File

@@ -0,0 +1,41 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
#include "OWLSevent.h"
namespace OpenWifi::OWLSclientEvents {
void PendingConfig(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_ && Client->Connected_) {
Runner->Report().ev_configpendingchange++;
try {
nlohmann::json M;
M["jsonrpc"] = "2.0";
M["method"] = "cfgpending";
M["params"]["serial"] = Client->Serial();
M["params"]["uuid"] = Client->UUID();
M["params"]["active"] = Client->Active();
if (Client->Send(to_string(M))) {
return;
}
} catch (const Poco::Exception &E) {
Client->Logger().log(E);
}
OWLSclientEvents::Disconnect(Client, Runner, "Error while sending ConfigPendingEvent", true);
}
}
}

28
src/OWLS_Reconnect.cpp Normal file
View File

@@ -0,0 +1,28 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
#include "OWLS_utils.h"
namespace OpenWifi::OWLSclientEvents {
void Reconnect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_) {
Runner->Report().ev_reconnect++;
Client->Connected_ = false;
OWLSscheduler()->Ref().in(std::chrono::seconds(OWLSutils::local_random(3,15)), OWLSclientEvents::EstablishConnection, Client, Runner);
}
}
}

56
src/OWLS_State.cpp Normal file
View File

@@ -0,0 +1,56 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
namespace OpenWifi::OWLSclientEvents {
void State(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_ && Client->Connected_) {
Runner->Report().ev_state++;
try {
nlohmann::json M;
M["jsonrpc"] = "2.0";
M["method"] = "state";
nlohmann::json ParamsObj;
ParamsObj["serial"] = Client->Serial();
ParamsObj["uuid"] = Client->UUID();
ParamsObj["state"] = Client->CreateState();
auto ParamsStr = to_string(ParamsObj);
unsigned long BufSize = ParamsStr.size() + 4000;
std::vector<Bytef> Buffer(BufSize);
compress(&Buffer[0], &BufSize, (Bytef *)ParamsStr.c_str(), ParamsStr.size());
auto CompressedBase64Encoded = OpenWifi::Utils::base64encode(&Buffer[0], BufSize);
M["params"]["compress_64"] = CompressedBase64Encoded;
M["params"]["compress_sz"] = ParamsStr.size();
if (Client->Send(to_string(M))) {
OWLSscheduler()->Ref().in(std::chrono::seconds(Client->StatisticsInterval_),
OWLSclientEvents::State, Client, Runner);
return;
}
} catch (const Poco::Exception &E) {
Client->Logger().log(E);
}
OWLSclientEvents::Disconnect(Client, Runner, "Error sending stats event", true);
}
}
}

27
src/OWLS_Update.cpp Normal file
View File

@@ -0,0 +1,27 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
namespace OpenWifi::OWLSclientEvents {
void Update(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_ && Client->Connected_) {
Runner->Report().ev_update++;
Client->Update();
OWLSscheduler()->Ref().in(std::chrono::seconds(30),
OWLSclientEvents::Update, Client, Runner);
}
}
}

34
src/OWLS_WSPing.cpp Normal file
View File

@@ -0,0 +1,34 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSclient.h"
#include "SimulationRunner.h"
#include "SimulationCoordinator.h"
#include <fmt/format.h>
#include "OWLSscheduler.h"
#include "SimStats.h"
#include <Poco/NObserver.h>
#include "OWLSclientEvents.h"
namespace OpenWifi::OWLSclientEvents {
void WSPing(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner) {
std::lock_guard G(Client->Mutex_);
if(Client->Valid_ && Client->Connected_) {
Runner->Report().ev_wsping++;
try {
if (Client->SendWSPing()) {
OWLSscheduler()->Ref().in(std::chrono::seconds(60 * 4),
OWLSclientEvents::WSPing, Client, Runner);
return;
}
} catch (const Poco::Exception &E) {
Client->Logger().log(E);
}
OWLSclientEvents::Disconnect(Client, Runner, "Error in WSPing", true);
}
}
}

190
src/OWLS_utils.h Normal file
View File

@@ -0,0 +1,190 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include <random>
#include "framework/MicroServiceFuncs.h"
#include <nlohmann/json.hpp>
namespace OpenWifi {
enum class radio_bands {
band_2g, band_5g, band_6g
};
namespace OWLSutils {
template<typename T>
void AssignIfPresent(const nlohmann::json &doc, const char *name, T &Value, T default_value) {
if (doc.contains(name) && !doc[name].is_null())
Value = doc[name];
else
Value = default_value;
}
inline std::string MakeMac(const char *S, int offset) {
char b[256];
int j = 0, i = 0;
for (int k = 0; k < 6; ++k) {
b[j++] = S[i++];
b[j++] = S[i++];
b[j++] = ':';
}
b[--j] = 0;
b[--j] = '0' + offset;
return b;
}
inline std::string RandomMAC() {
char b[64];
snprintf(b, sizeof(b), "%02x:%02x:%02x:%02x:%02x:%02x", (int) MicroServiceRandom(255),
(int) MicroServiceRandom(255), (int) MicroServiceRandom(255),
(int) MicroServiceRandom(255), (int) MicroServiceRandom(255),
(int) MicroServiceRandom(255));
return b;
}
inline std::string RandomIPv4() {
char b[64];
snprintf(b, sizeof(b), "%d.%d.%d.%d", (int) MicroServiceRandom(255),
(int) MicroServiceRandom(255), (int) MicroServiceRandom(255),
(int) MicroServiceRandom(255));
return b;
}
inline std::string RandomIPv6() {
char b[128];
snprintf(b, sizeof(b), "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
(uint) MicroServiceRandom(0x0ffff), (uint) MicroServiceRandom(0x0ffff),
(uint) MicroServiceRandom(0x0ffff), (uint) MicroServiceRandom(0x0ffff),
(uint) MicroServiceRandom(0x0ffff), (uint) MicroServiceRandom(0x0ffff),
(uint) MicroServiceRandom(0x0ffff), (uint) MicroServiceRandom(0x0ffff));
return b;
}
inline std::int64_t local_random(std::int64_t min, std::int64_t max) {
static std::random_device rd;
static std::mt19937_64 gen{rd()};
if (min > max)
std::swap(min, max);
std::uniform_int_distribution<> dis(min, max);
return dis(gen);
}
inline auto local_random(std::int64_t max) { return local_random(0, max); }
static std::vector<std::uint64_t> Channels_2G{1, 6, 11};
static std::vector<std::uint64_t>
Channels_5G{36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 96, 100, 102, 104, 106,
108,
110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 132, 136, 138, 140, 142, 144, 149, 151,
153, 155, 157, 159, 161};
static std::vector<std::uint64_t> Channels_6G{1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65,
69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117,
121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169,
173, 177, 181, 185, 189, 193, 197, 201, 205, 209,
213, 221, 225, 229, 233};
inline void FillinFrequencies(std::uint64_t channel, radio_bands band, std::uint64_t width,
std::vector<std::uint64_t> &channels, std::vector<std::uint64_t> &frequencies) {
if (band == radio_bands::band_2g) { // 2.4GHz band
if (channel >= 1 && channel <= 11) {
channels.push_back(channel);
std::uint64_t frequency = 2401 + (channel - 1) * 5;
frequencies.push_back(frequency);
if (width == 20) {
frequencies.push_back(frequency + 22);
} else if (width == 40) {
frequencies.push_back(frequency + 32);
} else if (width == 80) {
frequencies.push_back(frequency + 52);
} else {
throw std::invalid_argument("Invalid channel width for 2.4GHz band.");
}
} else {
throw std::invalid_argument("Invalid channel number for 2.4GHz band.");
}
} else if (band == radio_bands::band_5g) { // 5GHz band
if (channel >= 36 && channel <= 165) {
std::uint64_t frequency = 5170 + (channel - 36) * 5;
channels.push_back(channel);
if (width == 20) {
frequencies.push_back(frequency);
frequencies.push_back(frequency + 20);
} else if (width == 40) {
channels.push_back(channel + 2);
frequencies.push_back(frequency - 10);
frequencies.push_back(frequency + 30);
} else if (width == 80) {
channels.push_back(channel + 6);
frequencies.push_back(frequency - 30);
frequencies.push_back(frequency + 50);
} else if (width == 160) {
channels.push_back(channel + 12);
frequencies.push_back(frequency - 70);
frequencies.push_back(frequency + 90);
} else {
throw std::invalid_argument("Invalid channel width for 5GHz band.");
}
} else {
throw std::invalid_argument("Invalid channel number for 5GHz band.");
}
} else if (band == radio_bands::band_6g) { // 6GHz band
if (channel >= 1 && channel <= 233) {
std::uint64_t frequency = 5945 + (channel - 1) * 5;
channels.push_back(channel);
if (width == 20) {
frequencies.push_back(frequency);
frequencies.push_back(frequency + 19);
} else if (width == 40) {
channels.push_back(channel + 2);
frequencies.push_back(frequency - 10);
frequencies.push_back(frequency + 29);
} else if (width == 80) {
channels.push_back(channel + 6);
frequencies.push_back(frequency - 30);
frequencies.push_back(frequency + 49);
} else if (width == 160) {
channels.push_back(channel + 12);
frequencies.push_back(frequency - 70);
frequencies.push_back(frequency + 89);
} else {
throw std::invalid_argument("Invalid channel width for 6GHz band.");
}
} else {
throw std::invalid_argument("Invalid channel number for 6GHz band.");
}
} else {
throw std::invalid_argument("Invalid band number.");
}
}
inline std::uint64_t FindAutoChannel(radio_bands band, [[maybe_unused]] std::uint64_t channel_width) {
std::uint64_t num_chan = 1;
if (channel_width == 20) {
num_chan = 1;
} else if (channel_width == 40) {
num_chan = 2;
} else if (channel_width == 80) {
num_chan = 3;
} else if (channel_width == 160) {
num_chan = 4;
} else if (channel_width == 320) {
num_chan = 5;
}
switch (band) {
case radio_bands::band_2g:
return Channels_2G[std::rand() % Channels_2G.size()];
case radio_bands::band_5g:
return Channels_5G[std::rand() % (Channels_5G.size() - num_chan)];
case radio_bands::band_6g:
return Channels_6G[std::rand() % (Channels_6G.size() - num_chan)];
}
}
}
}

View File

@@ -6,6 +6,9 @@
#include <iostream>
#include <sys/time.h>
#include <thread>
#include <tuple>
#include "OWLS_utils.h"
#include "Poco/NObserver.h"
#include "Poco/Net/Context.h"
@@ -15,96 +18,108 @@
#include "Poco/Net/SSLException.h"
#include "Poco/URI.h"
#include "uCentralClient.h"
#include "OWLSclient.h"
#include "framework/MicroServiceFuncs.h"
#include "SimStats.h"
#include "Simulation.h"
#include "SimulationCoordinator.h"
#include "fmt/format.h"
#include <nlohmann/json.hpp>
#include "OWLSscheduler.h"
using namespace std::chrono_literals;
namespace OpenWifi {
static std::string MakeMac(const char *S, int offset) {
char b[256];
OWLSclient::OWLSclient(Poco::Net::SocketReactor &Reactor, std::string SerialNumber,
Poco::Logger &Logger, SimulationRunner *runner)
: Reactor_(Reactor), Logger_(Logger), SerialNumber_(std::move(SerialNumber)),
Memory_(1),
Load_(1),
Runner_(runner) {
int j = 0, i = 0;
for (int k = 0; k < 6; ++k) {
b[j++] = S[i++];
b[j++] = S[i++];
b[j++] = ':';
}
b[--j] = 0;
b[--j] = '0' + offset;
return b;
}
static std::string RandomMAC() {
char b[64];
snprintf(b, sizeof(b), "%02x:%02x:%02x:%02x:%02x:%02x", (int)MicroServiceRandom(255),
(int)MicroServiceRandom(255), (int)MicroServiceRandom(255),
(int)MicroServiceRandom(255), (int)MicroServiceRandom(255),
(int)MicroServiceRandom(255));
return b;
}
static std::string RandomIPv4() {
char b[64];
snprintf(b, sizeof(b), "%d.%d.%d.%d", (int)MicroServiceRandom(255),
(int)MicroServiceRandom(255), (int)MicroServiceRandom(255),
(int)MicroServiceRandom(255));
return b;
}
static std::string RandomIPv6() {
char b[128];
snprintf(b, sizeof(b), "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
(uint)MicroServiceRandom(0x0ffff), (uint)MicroServiceRandom(0x0ffff),
(uint)MicroServiceRandom(0x0ffff), (uint)MicroServiceRandom(0x0ffff),
(uint)MicroServiceRandom(0x0ffff), (uint)MicroServiceRandom(0x0ffff),
(uint)MicroServiceRandom(0x0ffff), (uint)MicroServiceRandom(0x0ffff));
return b;
}
uCentralClient::uCentralClient(Poco::Net::SocketReactor &Reactor, std::string SerialNumber,
Poco::Logger &Logger)
: Reactor_(Reactor), Logger_(Logger), SerialNumber_(std::move(SerialNumber)) {
AllInterfaceNames_[ap_interface_types::upstream] = "up0v0";
AllInterfaceNames_[ap_interface_types::downstream] = "down0v0";
AllInterfaceRoles_[ap_interface_types::upstream] = "upstream";
AllInterfaceRoles_[ap_interface_types::downstream] = "downstream";
AllPortNames_[ap_interface_types::upstream] = "wan0";
AllPortNames_[ap_interface_types::downstream] = "eth0";
AllPortNames_[ap_interface_types::upstream] = "eth0";
AllPortNames_[ap_interface_types::downstream] = "eth1";
SetFirmware();
Active_ = UUID_ = Utils::Now();
srand(UUID_);
mac_lan = MakeMac(SerialNumber_.c_str(), 0);
mac_lan = OWLSutils::MakeMac(SerialNumber_.c_str(), 0);
CurrentConfig_ = SimulationCoordinator()->GetSimConfiguration(Utils::Now());
UpdateConfiguration();
Valid_ = true;
}
static int Find2GAutoChannel() { return 11; }
void OWLSclient::CreateLanClients(uint64_t min, uint64_t max) {
AllLanClients_.clear();
uint64_t Num = MicroServiceRandom(min, max);
for (uint64_t i = 0; i < Num; i++) {
MockLanClient CI;
CI.mac = OWLSutils::RandomMAC();
CI.ipv4_addresses.push_back(OWLSutils::RandomIPv4());
CI.ipv6_addresses.push_back(OWLSutils::RandomIPv6());
CI.ports.emplace_back("eth1");
AllLanClients_.push_back(CI);
}
Load_.SetSize(AllLanClients_.size()+CountAssociations());
Memory_.SetSize(AllLanClients_.size()+CountAssociations());
}
static int Find5GAutoChannel() { return 36; }
void OWLSclient::CreateAssociations(const interface_location_t &interface, const std::string &bssid, uint64_t min,
uint64_t max) {
auto interface_hint = AllAssociations_.find(interface);
if(interface_hint==end(AllAssociations_)) {
bool inserted;
std::pair<associations_map_t::iterator,bool> insertion_res(interface_hint,inserted);
insertion_res = AllAssociations_.insert(std::make_pair(interface,MockAssociations {}));
}
static int Find6GAutoChannel() { return 147; }
interface_hint->second.clear();
auto NumberOfAssociations = MicroServiceRandom(min, max);
while (NumberOfAssociations) {
MockAssociation FA;
FA.bssid = bssid;
FA.station = OWLSutils::RandomMAC();
FA.ack_signal_avg = OWLSutils::local_random(-40, -60);
FA.ack_signal = FA.ack_signal_avg;
FA.ipaddr_v4 = OWLSutils::RandomIPv4();
FA.ipaddr_v6 = OWLSutils::RandomIPv6();
FA.rssi = OWLSutils::local_random(-40, -90);
interface_hint->second.push_back(FA);
--NumberOfAssociations;
}
Load_.SetSize(AllLanClients_.size()+CountAssociations());
Memory_.SetSize(AllLanClients_.size()+CountAssociations());
}
template <typename T>
void AssignIfPresent(const nlohmann::json &doc, const char *name, T &Value, T default_value) {
if (doc.contains(name) && !doc[name].is_null())
Value = doc[name];
else
Value = default_value;
}
void OWLSclient::Update() {
Memory_.next();
Load_.next();
for(auto &[_,radio]:AllRadios_) {
radio.next();
}
for(auto &[_,counters]:AllCounters_) {
counters.next();
}
for(auto &[_,associations]:AllAssociations_) {
for(auto &association:associations) {
association.next();
}
}
for(auto &lan_client:AllLanClients_) {
lan_client.next();
}
}
bool uCentralClient::FindInterfaceRole(const std::string &role,
OpenWifi::ap_interface_types &interface) {
bool OWLSclient::FindInterfaceRole(const std::string &role,
OpenWifi::ap_interface_types &interface) {
for (const auto &[interface_type, interface_name] : AllInterfaceRoles_) {
if (role == interface_name) {
interface = interface_type;
@@ -114,7 +129,7 @@ namespace OpenWifi {
return false;
}
void uCentralClient::Reset() {
void OWLSclient::Reset() {
for (auto &[_, radio] : AllRadios_) {
radio.reset();
@@ -131,7 +146,7 @@ namespace OpenWifi {
}
}
void uCentralClient::UpdateConfiguration() {
void OWLSclient::UpdateConfiguration() {
// go through the config and harvest the SSID names, also update all the client stuff
auto Interfaces = CurrentConfig_["interfaces"];
AllAssociations_.clear();
@@ -147,129 +162,83 @@ namespace OpenWifi {
for (const auto &band : ssid["wifi-bands"]) {
auto ssidName = ssid["name"];
if (band == "2G") {
AllAssociations_[std::make_tuple(current_interface_role, ssidName,
radio_bands::band_2g)] =
CreateAssociations(Utils::SerialToMAC(Utils::IntToSerialNumber(
CreateAssociations(std::make_tuple(current_interface_role, ssidName,
radio_bands::band_2g), Utils::SerialToMAC(Utils::IntToSerialNumber(
Utils::SerialNumberToInt(SerialNumber_) +
bssid_index++)),
SimulationCoordinator()
->GetSimulationInfo()
.minAssociations,
SimulationCoordinator()
->GetSimulationInfo()
.maxAssociations);
Runner_->Details().minAssociations,
Runner_->Details().maxAssociations);
}
if (band == "5G") {
AllAssociations_[std::make_tuple(current_interface_role, ssidName,
radio_bands::band_5g)] =
CreateAssociations(Utils::SerialToMAC(Utils::IntToSerialNumber(
CreateAssociations(std::make_tuple(current_interface_role, ssidName,
radio_bands::band_5g), Utils::SerialToMAC(Utils::IntToSerialNumber(
Utils::SerialNumberToInt(SerialNumber_) +
bssid_index++)),
SimulationCoordinator()
->GetSimulationInfo()
.minAssociations,
SimulationCoordinator()
->GetSimulationInfo()
.maxAssociations);
Runner_->Details().minAssociations,
Runner_->Details().maxAssociations);
}
if (band == "6G") {
AllAssociations_[std::make_tuple(current_interface_role, ssidName,
radio_bands::band_6g)] =
CreateAssociations(Utils::SerialToMAC(Utils::IntToSerialNumber(
CreateAssociations(std::make_tuple(current_interface_role, ssidName,
radio_bands::band_6g),
Utils::SerialToMAC(Utils::IntToSerialNumber(
Utils::SerialNumberToInt(SerialNumber_) +
bssid_index++)),
SimulationCoordinator()
->GetSimulationInfo()
.minAssociations,
SimulationCoordinator()
->GetSimulationInfo()
.maxAssociations);
Runner_->Details().minAssociations,
Runner_->Details().maxAssociations);
}
}
}
FakeCounters F;
MockCounters F;
AllCounters_[current_interface_role] = F;
}
}
}
AllLanClients_ = CreateLanClients(SimulationCoordinator()->GetSimulationInfo().minClients,
SimulationCoordinator()->GetSimulationInfo().maxClients);
CreateLanClients(Runner_->Details().minClients, Runner_->Details().maxClients);
auto radios = CurrentConfig_["radios"];
uint index = 0;
for (const auto &radio : radios) {
auto band = radio["band"];
FakeRadio R;
radio_bands the_band{radio_bands::band_2g};
std::uint64_t the_channel = Find2GAutoChannel();
if (radio.contains("channel")) {
if (radio["channel"].is_string() && radio["channel"] == "auto") {
if (band == "2G")
the_channel = Find2GAutoChannel();
else if (band == "5G")
the_channel = Find5GAutoChannel();
else if (band == "6G")
the_channel = Find6GAutoChannel();
} else if (radio["channel"].is_number_integer()) {
the_channel = radio["channel"];
}
}
R.channel = the_channel;
MockRadio R;
if (band == "5G") {
the_band = radio_bands::band_5g;
} else if (band == "6G") {
the_band = radio_bands::band_6g;
R.band.push_back(band);
if (band == "2G") {
R.radioBands = radio_bands::band_2g;
} else if (band == "5G") {
R.radioBands = radio_bands::band_5g;
} else if (band == "6G") {
R.radioBands = radio_bands::band_6g;
}
if(radio.contains("channel-width") && radio["channel-width"].is_number_integer())
R.channel_width = radio["channel-width"];
else
R.channel_width = 20;
if ((!radio.contains("channel"))
|| (radio.contains("channel") && radio["channel"].is_string() && radio["channel"] == "auto")
|| (!radio["channel"].is_number_integer())) {
R.channel = OWLSutils::FindAutoChannel(R.radioBands, R.channel_width);
} else if (radio["channel"].is_number_integer()) {
R.channel = radio["channel"];
}
AssignIfPresent(radio, "tx_power", R.tx_power, (uint_fast64_t)23);
OWLSutils::FillinFrequencies(R.channel, R.radioBands, R.channel_width, R.channels, R.frequency);
OWLSutils::AssignIfPresent(radio, "tx_power", R.tx_power, (uint_fast64_t)23);
if (index == 0)
R.phy = "platform/soc/c000000.wifi";
else
R.phy = "platform/soc/c000000.wifi+" + std::to_string(index);
R.index = index;
AllRadios_[the_band] = R;
AllRadios_[R.radioBands] = R;
++index;
}
}
FakeLanClients uCentralClient::CreateLanClients(uint64_t min, uint64_t max) {
FakeLanClients Clients;
uint64_t Num = MicroServiceRandom(min, max);
for (uint64_t i = 0; i < Num; i++) {
FakeLanClient CI;
CI.mac = RandomMAC();
CI.ipv4_addresses.push_back(RandomIPv4());
CI.ipv6_addresses.push_back(RandomIPv6());
CI.ports.push_back("eth0");
Clients.push_back(CI);
}
return Clients;
}
FakeAssociations uCentralClient::CreateAssociations(const std::string &bssid, uint64_t min,
uint64_t max) {
FakeAssociations res;
auto n = MicroServiceRandom(min, max);
while (n) {
FakeAssociation FA;
FA.bssid = bssid;
FA.station = RandomMAC();
FA.ack_signal_avg = local_random(-40, -60);
FA.ack_signal = FA.ack_signal_avg;
FA.ipaddr_v4 = RandomIPv4();
FA.ipaddr_v6 = RandomIPv6();
FA.rssi = local_random(-40, -90);
res.push_back(FA);
--n;
}
return res;
}
nlohmann::json uCentralClient::CreateLinkState() {
nlohmann::json OWLSclient::CreateLinkState() {
nlohmann::json res;
for (const auto &[interface_type, _] : AllCounters_) {
res[AllInterfaceRoles_[interface_type]][AllPortNames_[interface_type]]["carrier"] = 1;
@@ -280,7 +249,7 @@ namespace OpenWifi {
return res;
}
nlohmann::json uCentralClient::CreateState() {
nlohmann::json OWLSclient::CreateState() {
nlohmann::json S;
// set the version
@@ -288,15 +257,11 @@ namespace OpenWifi {
// set the unit stuff
auto now = Utils::Now();
S["unit"]["load"] = std::vector<double>{(double)(MicroServiceRandom(75)) / 100.0,
(double)(MicroServiceRandom(50)) / 100.0,
(double)(MicroServiceRandom(25)) / 100.0};
S["unit"] += Memory_.to_json();
S["unit"] += Load_.to_json();
S["unit"]["localtime"] = now;
S["unit"]["uptime"] = now - StartTime_;
S["unit"]["memory"]["total"] = 973139968;
S["unit"]["memory"]["buffered"] = 10129408;
S["unit"]["memory"]["cached"] = 29233152;
S["unit"]["memory"]["free"] = 760164352;
S["unit"]["temperature"] = std::vector<std::int64_t> { OWLSutils::local_random(48,58), OWLSutils::local_random(48,58)};
// get all the radios out
for (auto &[_, radio] : AllRadios_) {
@@ -315,7 +280,7 @@ namespace OpenWifi {
nlohmann::json up_ssids;
uint64_t ssid_num = 0, interfaces = 0;
auto state_ue_clients = nlohmann::json::array();
auto ue_clients = nlohmann::json::array();
for (auto &[interface, associations] : AllAssociations_) {
auto &[interface_type, ssid, band] = interface;
if (interface_type == ap_interface_type) {
@@ -329,9 +294,12 @@ namespace OpenWifi {
ue["mac"] = association.station;
ue["ipv4_addresses"].push_back(association.ipaddr_v4);
ue["ipv6_addresses"].push_back(association.ipaddr_v6);
ue["ports"].push_back(interface_type == upstream ? "eth0" : "eth1");
// std::cout << "Adding association info" << to_string(ue) << std::endl;
state_ue_clients.push_back(ue);
if(interface_type==upstream)
ue["ports"].push_back("wwan0");
else
ue["ports"].push_back("wlan0");
ue["last_seen"] = 0 ;
ue_clients.push_back(ue);
}
nlohmann::json ssid_info;
ssid_info["associations"] = association_list;
@@ -364,8 +332,8 @@ namespace OpenWifi {
}
// std::cout << "Adding " << state_ue_clients.size() << " UE clients" <<
// std::endl;
for (const auto &ue_assoc : state_ue_clients) {
state_lan_clients.push_back(ue_assoc);
for (const auto &ue_client : ue_clients) {
state_lan_clients.push_back(ue_client);
}
current_interface["clients"] = state_lan_clients;
}
@@ -380,14 +348,15 @@ namespace OpenWifi {
return S;
}
void uCentralClient::Disconnect(const char *Reason, bool Reconnect) {
/*
void OWLSclient::Disconnect(const char *Reason, bool Reconnect) {
std::lock_guard G(Mutex_);
Logger_.debug(fmt::format("DEVICE({}): disconnecting because '{}'", SerialNumber_,
std::string{Reason}));
if (Connected_) {
Reactor_.removeEventHandler(
*WS_, Poco::NObserver<uCentralClient, Poco::Net::ReadableNotification>(
*this, &uCentralClient::OnSocketReadable));
*WS_, Poco::NObserver<OWLSclient, Poco::Net::ReadableNotification>(
*this, &OWLSclient::OnSocketReadable));
(*WS_).close();
}
@@ -395,13 +364,14 @@ namespace OpenWifi {
Commands_.clear();
if (Reconnect)
OWLSscheduler()->Ref().in(std::chrono::seconds(OWLSutils::local_random(3,15)), OWLSclientEvents::Reconnect, Client );
AddEvent(ev_reconnect, SimulationCoordinator()->GetSimulationInfo().reconnectInterval +
MicroServiceRandom(15));
SimStats()->Disconnect();
}
void uCentralClient::DoCensus(CensusReport &Census) {
void OWLSclient::DoCensus(CensusReport &Census) {
std::lock_guard G(Mutex_);
for (const auto i : Commands_)
@@ -442,10 +412,13 @@ namespace OpenWifi {
case ev_wsping:
Census.ev_wsping++;
break;
case ev_update:
Census.ev_update++;
break;
}
}
void uCentralClient::OnSocketReadable(
void OWLSclient::OnSocketReadable(
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
std::lock_guard G(Mutex_);
@@ -501,7 +474,7 @@ namespace OpenWifi {
Disconnect("Exception caught during data reception", true);
}
void uCentralClient::ProcessCommand(nlohmann::json &Vars) {
void OWLSclient::ProcessCommand(nlohmann::json &Vars) {
std::string Method = Vars["method"];
@@ -526,8 +499,8 @@ namespace OpenWifi {
Logger_.warning(fmt::format("COMMAND({}): unknown method '{}'", SerialNumber_, Method));
}
}
void uCentralClient::DoConfigure(uint64_t Id, nlohmann::json &Params) {
*/
void OWLSclient::DoConfigure(uint64_t Id, nlohmann::json &Params) {
std::lock_guard G(Mutex_);
try {
@@ -571,7 +544,7 @@ namespace OpenWifi {
}
}
void uCentralClient::DoReboot(uint64_t Id, nlohmann::json &Params) {
void OWLSclient::DoReboot(uint64_t Id, nlohmann::json &Params) {
std::lock_guard G(Mutex_);
try {
if (Params.contains("serial")) {
@@ -591,7 +564,6 @@ namespace OpenWifi {
SendObject(Answer);
Logger_.information(fmt::format("reboot({}): done.", SerialNumber_));
Disconnect("Rebooting", true);
Reset();
} else {
Logger_.warning(fmt::format("reboot({}): Illegal command.", SerialNumber_));
@@ -619,7 +591,7 @@ namespace OpenWifi {
return p;
}
void uCentralClient::DoUpgrade(uint64_t Id, nlohmann::json &Params) {
void OWLSclient::DoUpgrade(uint64_t Id, nlohmann::json &Params) {
std::lock_guard G(Mutex_);
try {
if (Params.contains("serial") && Params.contains("uri")) {
@@ -643,7 +615,6 @@ namespace OpenWifi {
SendObject(Answer);
Logger_.information(fmt::format("upgrade({}): from URI={}.", SerialNumber_, URI));
Disconnect("Doing an upgrade", true);
} else {
Logger_.warning(fmt::format("upgrade({}): Illegal command.", SerialNumber_));
}
@@ -653,7 +624,7 @@ namespace OpenWifi {
}
}
void uCentralClient::DoFactory(uint64_t Id, nlohmann::json &Params) {
void OWLSclient::DoFactory(uint64_t Id, nlohmann::json &Params) {
std::lock_guard G(Mutex_);
try {
if (Params.contains("serial") && Params.contains("keep_redirector")) {
@@ -680,8 +651,6 @@ namespace OpenWifi {
CurrentConfig_ = SimulationCoordinator()->GetSimConfiguration(Utils::Now());
UpdateConfiguration();
Disconnect("Factory reset", true);
} else {
Logger_.warning(fmt::format("factory({}): Illegal command.", SerialNumber_));
}
@@ -691,7 +660,7 @@ namespace OpenWifi {
}
}
void uCentralClient::DoLEDs(uint64_t Id, nlohmann::json &Params) {
void OWLSclient::DoLEDs(uint64_t Id, nlohmann::json &Params) {
std::lock_guard G(Mutex_);
try {
if (Params.contains("serial") && Params.contains("pattern")) {
@@ -722,7 +691,7 @@ namespace OpenWifi {
}
}
void uCentralClient::DoPerform(uint64_t Id, nlohmann::json &Params) {
void OWLSclient::DoPerform(uint64_t Id, nlohmann::json &Params) {
std::lock_guard G(Mutex_);
try {
if (Params.contains("serial") && Params.contains("command") &&
@@ -756,7 +725,7 @@ namespace OpenWifi {
}
}
void uCentralClient::DoTrace(uint64_t Id, nlohmann::json &Params) {
void OWLSclient::DoTrace(uint64_t Id, nlohmann::json &Params) {
std::lock_guard G(Mutex_);
try {
if (Params.contains("serial") && Params.contains("duration") &&
@@ -796,93 +765,14 @@ namespace OpenWifi {
}
}
void uCentralClient::EstablishConnection() {
Poco::URI uri(SimulationCoordinator()->GetSimulationInfo().gateway);
Poco::Net::Context::Params P;
P.verificationMode = Poco::Net::Context::VERIFY_STRICT;
P.verificationDepth = 9;
P.caLocation = SimulationCoordinator()->GetCasLocation();
P.loadDefaultCAs = false;
P.certificateFile = SimulationCoordinator()->GetCertFileName();
P.privateKeyFile = SimulationCoordinator()->GetKeyFileName();
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
auto Context = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, P);
Poco::Crypto::X509Certificate Cert(SimulationCoordinator()->GetCertFileName());
Poco::Crypto::X509Certificate Root(SimulationCoordinator()->GetRootCAFileName());
Context->useCertificate(Cert);
Context->addChainCertificate(Root);
Context->addCertificateAuthority(Root);
if (SimulationCoordinator()->GetLevel() == Poco::Net::Context::VERIFY_STRICT) {
}
Poco::Crypto::RSAKey Key("", SimulationCoordinator()->GetKeyFileName(), "");
Context->usePrivateKey(Key);
SSL_CTX *SSLCtx = Context->sslContext();
if (!SSL_CTX_check_private_key(SSLCtx)) {
std::cout << "Wrong Certificate: " << SimulationCoordinator()->GetCertFileName()
<< " for " << SimulationCoordinator()->GetKeyFileName() << std::endl;
}
if (SimulationCoordinator()->GetLevel() == Poco::Net::Context::VERIFY_STRICT) {
}
Poco::Net::HTTPSClientSession Session(uri.getHost(), uri.getPort(), Context);
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_GET, "/?encoding=text",
Poco::Net::HTTPMessage::HTTP_1_1);
Request.set("origin", "http://www.websocket.org");
Poco::Net::HTTPResponse Response;
Logger_.information(fmt::format("connecting({}): host={} port={}", SerialNumber_,
uri.getHost(), uri.getPort()));
std::lock_guard guard(Mutex_);
try {
WS_ = std::make_unique<Poco::Net::WebSocket>(Session, Request, Response);
(*WS_).setKeepAlive(true);
(*WS_).setReceiveTimeout(Poco::Timespan());
(*WS_).setSendTimeout(Poco::Timespan(20, 0));
(*WS_).setNoDelay(true);
Reactor_.addEventHandler(
*WS_, Poco::NObserver<uCentralClient, Poco::Net::ReadableNotification>(
*this, &uCentralClient::OnSocketReadable));
Connected_ = true;
AddEvent(ev_connect, 1);
SimStats()->Connect();
} catch (const Poco::Exception &E) {
Logger_.warning(
fmt::format("connecting({}): exception. {}", SerialNumber_, E.displayText()));
AddEvent(ev_reconnect, SimulationCoordinator()->GetSimulationInfo().reconnectInterval +
MicroServiceRandom(15));
} catch (const std::exception &E) {
Logger_.warning(
fmt::format("connecting({}): std::exception. {}", SerialNumber_, E.what()));
AddEvent(ev_reconnect, SimulationCoordinator()->GetSimulationInfo().reconnectInterval +
MicroServiceRandom(15));
} catch (...) {
Logger_.warning(fmt::format("connecting({}): unknown exception. {}", SerialNumber_));
AddEvent(ev_reconnect, SimulationCoordinator()->GetSimulationInfo().reconnectInterval +
MicroServiceRandom(15));
}
}
bool uCentralClient::Send(const std::string &Cmd) {
bool OWLSclient::Send(const std::string &Cmd) {
std::lock_guard guard(Mutex_);
try {
uint32_t BytesSent = WS_->sendFrame(Cmd.c_str(), Cmd.size());
if (BytesSent == Cmd.size()) {
SimStats()->AddTX(Cmd.size());
SimStats()->AddOutMsg();
SimStats()->AddTX(Runner_->Id(),Cmd.size());
SimStats()->AddOutMsg(Runner_->Id());
return true;
} else {
Logger_.warning(
@@ -894,7 +784,7 @@ namespace OpenWifi {
return false;
}
bool uCentralClient::SendWSPing() {
bool OWLSclient::SendWSPing() {
std::lock_guard guard(Mutex_);
try {
@@ -907,15 +797,15 @@ namespace OpenWifi {
return false;
}
bool uCentralClient::SendObject(nlohmann::json &O) {
bool OWLSclient::SendObject(nlohmann::json &O) {
std::lock_guard guard(Mutex_);
try {
auto M = to_string(O);
uint32_t BytesSent = WS_->sendFrame(M.c_str(), M.size());
if (BytesSent == M.size()) {
SimStats()->AddTX(BytesSent);
SimStats()->AddOutMsg();
SimStats()->AddTX(Runner_->Id(),BytesSent);
SimStats()->AddOutMsg(Runner_->Id());
return true;
} else {
Logger_.warning(
@@ -927,9 +817,9 @@ namespace OpenWifi {
return false;
}
static const uint64_t million = 1000000;
/* static const uint64_t million = 1000000;
void uCentralClient::AddEvent(uCentralEventType E, uint64_t InSeconds) {
void OWLSclient::AddEvent(OWLSeventType E, uint64_t InSeconds) {
std::lock_guard guard(Mutex_);
timeval curTime{0, 0};
@@ -943,7 +833,7 @@ namespace OpenWifi {
Commands_[NextCommand] = E;
}
uCentralEventType uCentralClient::NextEvent(bool Remove) {
OWLSeventType OWLSclient::NextEvent(bool Remove) {
std::lock_guard guard(Mutex_);
if (Commands_.empty())
@@ -955,7 +845,7 @@ namespace OpenWifi {
uint64_t Now = (curTime.tv_sec * million) + curTime.tv_usec;
if (EventTime < Now) {
uCentralEventType E = Commands_.begin()->second;
OWLSeventType E = Commands_.begin()->second;
if (Remove)
Commands_.erase(Commands_.begin());
return E;
@@ -963,4 +853,5 @@ namespace OpenWifi {
return ev_none;
}
*/
} // namespace OpenWifi

142
src/OWLSclient.h Normal file
View File

@@ -0,0 +1,142 @@
//
// Created by stephane bourque on 2021-03-12.
//
#pragma once
#include <map>
#include <mutex>
#include <random>
#include <tuple>
#include "Poco/AutoPtr.h"
#include "Poco/JSON/Object.h"
#include "Poco/Logger.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/WebSocket.h"
#include "Poco/Thread.h"
#include "framework/utils.h"
#include "nlohmann/json.hpp"
#include "OWLSdefinitions.h"
#include "MockElements.h"
#include "OWLSclientEvents.h"
namespace OpenWifi {
class SimulationRunner;
class OWLSclient {
public:
OWLSclient(Poco::Net::SocketReactor &Reactor, std::string SerialNumber,
Poco::Logger &Logger, SimulationRunner *runner);
bool Send(const std::string &Cmd);
bool SendWSPing();
bool SendObject(nlohmann::json &O);
void SetFirmware(const std::string &S = "sim-firmware-1") { Firmware_ = S; }
[[nodiscard]] const std::string &Serial() const { return SerialNumber_; }
[[nodiscard]] uint64_t UUID() const { return UUID_; }
[[nodiscard]] uint64_t Active() const { return Active_; }
[[nodiscard]] const std::string &Firmware() const { return Firmware_; }
[[nodiscard]] bool Connected() const { return Connected_; }
[[nodiscard]] inline uint64_t GetStartTime() const { return StartTime_; }
void DoConfigure(uint64_t Id, nlohmann::json &Params);
void DoReboot(uint64_t Id, nlohmann::json &Params);
void DoUpgrade(uint64_t Id, nlohmann::json &Params);
void DoFactory(uint64_t Id, nlohmann::json &Params);
void DoLEDs(uint64_t Id, nlohmann::json &Params);
void DoPerform(uint64_t Id, nlohmann::json &Params);
void DoTrace(uint64_t Id, nlohmann::json &Params);
using interface_location_t = std::tuple<ap_interface_types, std::string, radio_bands>;
using associations_map_t = std::map<interface_location_t, MockAssociations>;
void CreateAssociations(const interface_location_t &interface,const std::string &bssid, uint64_t min,
uint64_t max);
void CreateLanClients(uint64_t min, uint64_t max);
nlohmann::json CreateState();
nlohmann::json CreateLinkState();
Poco::Logger &Logger() { return Logger_; };
[[nodiscard]] uint64_t GetStateInterval() { return StatisticsInterval_; }
[[nodiscard]] uint64_t GetHealthInterval() { return HealthInterval_; }
void UpdateConfiguration();
bool FindInterfaceRole(const std::string &role, ap_interface_types &interface);
void Reset();
inline std::uint64_t CountAssociations() {
std::uint64_t Total=0;
for(const auto &[_,associations]:AllAssociations_) {
Total += associations.size();
}
return Total;
}
inline const auto & Memory() { return Memory_; }
inline const auto & Load() { return Load_; }
void Update();
friend class SimulationRunner;
friend void OWLSclientEvents::EstablishConnection(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::Reconnect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::Connect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::Log(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner, std::uint64_t Severity, const std::string & LogLine);
friend void OWLSclientEvents::State(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::HealthCheck(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::Update(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::WSPing(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::KeepAlive(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::Disconnect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner, const std::string &Reason, bool Reconnect);
friend void OWLSclientEvents::CrashLog(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
friend void OWLSclientEvents::PendingConfig(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
private:
std::recursive_mutex Mutex_;
Poco::Net::SocketReactor &Reactor_;
Poco::Logger &Logger_;
nlohmann::json CurrentConfig_;
std::string SerialNumber_;
std::string Firmware_;
std::unique_ptr<Poco::Net::WebSocket> WS_;
volatile bool Valid_=false;
uint64_t Active_ = 0;
uint64_t UUID_ = 0;
bool Connected_ = false;
bool KeepRedirector_ = false;
uint64_t Version_ = 0;
uint64_t StartTime_ = Utils::Now();
std::string mac_lan;
std::atomic_uint64_t HealthInterval_ = 60;
std::atomic_uint64_t StatisticsInterval_ = 60;
uint64_t bssid_index = 1;
std::int64_t fd_=-1;
MockMemory Memory_;
MockCPULoad Load_;
SimulationRunner *Runner_ = nullptr;
MockLanClients AllLanClients_;
associations_map_t AllAssociations_;
std::map<radio_bands, MockRadio> AllRadios_;
std::map<ap_interface_types, MockCounters> AllCounters_;
std::map<ap_interface_types, std::string> AllInterfaceNames_;
std::map<ap_interface_types, std::string> AllInterfaceRoles_;
std::map<ap_interface_types, std::string> AllPortNames_;
};
} // namespace OpenWifi

27
src/OWLSclientEvents.h Normal file
View File

@@ -0,0 +1,27 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include <memory>
namespace OpenWifi {
class OWLSclient;
class SimulationRunner;
}
namespace OpenWifi::OWLSclientEvents {
void EstablishConnection(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void Reconnect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void Connect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void State(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void HealthCheck(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void Log(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner, std::uint64_t Severity, const std::string & LogLine);
void WSPing(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void Update(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void KeepAlive(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void Disconnect(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner, const std::string &Reason, bool Reconnect);
void CrashLog(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
void PendingConfig(std::shared_ptr<OWLSclient> Client, SimulationRunner *Runner);
};

31
src/OWLSdefinitions.h Normal file
View File

@@ -0,0 +1,31 @@
//
// Created by stephane bourque on 2021-04-03.
//
#pragma once
#include <mutex>
namespace OpenWifi {
enum OWLSeventType {
ev_none,
ev_reconnect,
ev_connect,
ev_state,
ev_healthcheck,
ev_log,
ev_crashlog,
ev_configpendingchange,
ev_keepalive,
ev_reboot,
ev_disconnect,
ev_wsping,
ev_update
};
using my_mutex = std::recursive_mutex;
using my_guard = std::lock_guard<my_mutex>;
enum ap_interface_types { upstream, downstream };
}

View File

@@ -6,14 +6,14 @@
#include "Poco/zlib.h"
#include "nlohmann/json.hpp"
#include "Simulation.h"
#include "uCentralEvent.h"
#include "SimulationCoordinator.h"
#include "OWLSevent.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
bool ConnectEvent::Send() {
bool OWLSConnectEvent::Send() {
try {
nlohmann::json M;
M["jsonrpc"] = "2.0";
@@ -46,7 +46,7 @@ namespace OpenWifi {
return false;
}
bool StateEvent::Send() {
bool OWLSStateEvent::Send() {
try {
nlohmann::json M;
@@ -80,10 +80,11 @@ namespace OpenWifi {
return false;
}
bool HealthCheckEvent::Send() {
bool OWLSHealthCheckEvent::Send() {
try {
nlohmann::json M, P;
P["memory"] = 23;
M["jsonrpc"] = "2.0";
@@ -104,7 +105,7 @@ namespace OpenWifi {
return false;
}
bool LogEvent::Send() {
bool OWLSLogEvent::Send() {
try {
nlohmann::json M;
@@ -126,9 +127,9 @@ namespace OpenWifi {
return false;
};
bool CrashLogEvent::Send() { return false; };
bool OWLSCrashLogEvent::Send() { return false; };
bool ConfigChangePendingEvent::Send() {
bool OWLSConfigChangePendingEvent::Send() {
try {
nlohmann::json M;
@@ -150,7 +151,7 @@ namespace OpenWifi {
return false;
}
bool KeepAliveEvent::Send() {
bool OWLSKeepAliveEvent::Send() {
try {
nlohmann::json M;
@@ -172,12 +173,12 @@ namespace OpenWifi {
};
// This is just a fake event, reboot is handled somewhere else.
bool RebootEvent::Send() { return true; }
bool OWLSRebootEvent::Send() { return true; }
// This is just a fake event, disconnect is handled somewhere else.
bool DisconnectEvent::Send() { return true; }
bool OWLSDisconnectEvent::Send() { return true; }
bool WSPingEvent::Send() {
bool OWLSWSPingEvent::Send() {
try {
if (Client_->SendWSPing()) {
Client_->AddEvent(ev_wsping, 60 * 5);
@@ -189,4 +190,13 @@ namespace OpenWifi {
Client_->Disconnect("Error in WSPing", true);
return false;
}
bool OWLSUpdate::Send() {
try {
Client_->Update();
} catch (const Poco::Exception &E) {
Client_->Logger().log(E);
}
return false;
}
} // namespace OpenWifi

130
src/OWLSevent.h Normal file
View File

@@ -0,0 +1,130 @@
//
// Created by stephane bourque on 2021-04-03.
//
#ifndef UCENTRAL_CLNT_OWLSEVENT_H
#define UCENTRAL_CLNT_OWLSEVENT_H
#include "Poco/JSON/Object.h"
#include "OWLSclient.h"
#include "OWLSclient.h"
#include "OWLSdefinitions.h"
namespace OpenWifi {
class OWLSevent {
public:
explicit OWLSevent(std::shared_ptr<OWLSclient> Client)
: Client_(std::move(Client)) {}
virtual bool Send() = 0;
protected:
bool SendObject(Poco::JSON::Object &Obj);
std::shared_ptr<OWLSclient> Client_;
};
class OWLSConnectEvent : public OWLSevent {
public:
explicit OWLSConnectEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSStateEvent : public OWLSevent {
public:
explicit OWLSStateEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSHealthCheckEvent : public OWLSevent {
public:
explicit OWLSHealthCheckEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSLogEvent : public OWLSevent {
public:
explicit OWLSLogEvent(std::shared_ptr<OWLSclient> Client, std::string LogLine,
uint64_t Severity)
: OWLSevent(std::move(Client)), LogLine_(std::move(LogLine)), Severity_(Severity){};
bool Send() override;
private:
std::string LogLine_;
uint64_t Severity_;
};
class OWLSCrashLogEvent : public OWLSevent {
public:
explicit OWLSCrashLogEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSConfigChangePendingEvent : public OWLSevent {
public:
explicit OWLSConfigChangePendingEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSKeepAliveEvent : public OWLSevent {
public:
explicit OWLSKeepAliveEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSRebootEvent : public OWLSevent {
public:
explicit OWLSRebootEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSDisconnectEvent : public OWLSevent {
public:
explicit OWLSDisconnectEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSWSPingEvent : public OWLSevent {
public:
explicit OWLSWSPingEvent(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
class OWLSUpdate : public OWLSevent {
public:
explicit OWLSUpdate(std::shared_ptr<OWLSclient> Client)
: OWLSevent(std::move(Client)){};
bool Send() override;
private:
};
} // namespace OpenWifi
#endif // UCENTRAL_CLNT_OWLSEVENT_H

17
src/OWLSscheduler.cpp Normal file
View File

@@ -0,0 +1,17 @@
//
// Created by stephane bourque on 2023-04-12.
//
#include "OWLSscheduler.h"
#include <Poco/Environment.h>
namespace OpenWifi {
int OWLSscheduler::Start() {
return 0;
}
void OWLSscheduler::Stop() {
}
} // OpenWifi

36
src/OWLSscheduler.h Normal file
View File

@@ -0,0 +1,36 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include "libs/Scheduler.h"
#include <framework/SubSystemServer.h>
#include <Poco/Environment.h>
namespace OpenWifi {
class OWLSscheduler : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new OWLSscheduler;
return instance_;
}
int Start() final;
void Stop() final;
auto &Ref() { return Scheduler_; }
private:
Bosma::Scheduler Scheduler_;
OWLSscheduler() noexcept
: SubSystemServer("OWLSScheduler", "SIM-SCHEDULER", "scgeduler"),
Scheduler_(Poco::Environment::processorCount()*16){
}
};
inline auto OWLSscheduler() {
return OWLSscheduler::instance();
}
} // OpenWifi

View File

@@ -4,21 +4,22 @@
#include "RESTAPI_operation_handler.h"
#include "SimStats.h"
#include "Simulation.h"
#include "SimulationCoordinator.h"
namespace OpenWifi {
void RESTAPI_operation_handler::DoPost() {
auto Id = GetBinding("id","");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
std::string Op;
if (!HasParameter("operation", Op) || (Op != "start" && Op != "stop" && Op != "cancel")) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
std::string Id;
if (HasParameter("id", Id) && Op == "start") {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
std::string SimId;
if (HasParameter("simulationId", SimId) && Op != "start") {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
@@ -35,7 +36,7 @@ namespace OpenWifi {
if (Error.empty()) {
OWLSObjects::SimulationStatus S;
SimStats()->GetCurrent(S);
SimStats()->GetCurrent(Id,S);
Poco::JSON::Object Answer;
S.to_json(Answer);
return ReturnObject(Answer);

View File

@@ -16,7 +16,7 @@ namespace OpenWifi {
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/operation"}; }
static auto PathName() { return std::list<std::string>{"/api/v1/operation/{id}"}; }
void DoGet() final{};
void DoPost() final;
void DoPut() final{};

View File

@@ -8,8 +8,15 @@
namespace OpenWifi {
void RESTAPI_status_handler::DoGet() {
auto id = GetBinding("id","");
if(id.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
OWLSObjects::SimulationStatus S;
SimStats()->GetCurrent(S);
SimStats()->GetCurrent(id,S);
Poco::JSON::Object Answer;
S.to_json(Answer);
ReturnObject(Answer);

View File

@@ -16,7 +16,7 @@ namespace OpenWifi {
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/status"}; }
static auto PathName() { return std::list<std::string>{"/api/v1/status/{id}"}; }
void DoGet() final;
void DoPost() final{};
void DoPut() final{};

View File

@@ -92,6 +92,7 @@ namespace OpenWifi::OWLSObjects {
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 {}

View File

@@ -57,6 +57,7 @@ namespace OpenWifi::OWLSObjects {
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
uint64_t expectedDevices;
void to_json(Poco::JSON::Object &Obj) const;
};

View File

@@ -14,22 +14,31 @@ namespace OpenWifi {
class SimStats : public SubSystemServer {
public:
inline void Connect() {
inline void Connect(const std::string &id) {
std::lock_guard G(Mutex_);
Status_.liveDevices++;
if ((Status_.timeToFullDevices == 0) && (Status_.liveDevices == ExpectedDevices_)) {
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
stats_hint->second.liveDevices++;
if ((stats_hint->second.timeToFullDevices == 0) && (stats_hint->second.liveDevices == stats_hint->second.expectedDevices)) {
uint64_t Now = Utils::Now();
Status_.timeToFullDevices = Now - Status_.startTime;
stats_hint->second.timeToFullDevices = Now - stats_hint->second.startTime;
}
}
inline void Disconnect() {
if (CollectInfo_) {
std::lock_guard G(Mutex_);
if (Status_.liveDevices)
Status_.liveDevices--;
}
inline void Disconnect(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
if (stats_hint->second.liveDevices)
stats_hint->second.liveDevices--;
}
static auto instance() {
@@ -37,97 +46,143 @@ namespace OpenWifi {
return instance_;
}
inline void AddRX(uint64_t N) {
if (CollectInfo_) {
std::lock_guard G(Mutex_);
Status_.rx += N;
}
inline void AddRX(const std::string &id, uint64_t N) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
stats_hint->second.rx += N;
}
inline void AddOutMsg() {
if (CollectInfo_) {
std::lock_guard G(Mutex_);
Status_.msgsTx++;
}
inline void AddOutMsg(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
stats_hint->second.msgsTx++;
}
inline void AddInMsg() {
if (CollectInfo_) {
std::lock_guard G(Mutex_);
Status_.msgsRx++;
}
inline void AddInMsg(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
stats_hint->second.msgsRx++;
}
inline void AddTX(uint64_t N) {
if (CollectInfo_) {
std::lock_guard G(Mutex_);
Status_.tx += N;
}
inline void AddTX(const std::string &id, uint64_t N) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
stats_hint->second.tx += N;
}
inline void GetCurrent(OWLSObjects::SimulationStatus &S) {
inline void GetCurrent(const std::string &id, OWLSObjects::SimulationStatus &S) {
std::lock_guard G(Mutex_);
S = Status_;
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
S = stats_hint->second;
}
inline int Start() final {
Reset();
return 0;
}
inline void Stop() {}
inline void Stop() {
}
inline void StartSim(const std::string &id, const std::string &simid, uint64_t Devices,
const std::string &owner) {
std::lock_guard G(Mutex_);
CollectInfo_ = true;
ExpectedDevices_ = Devices;
Status_.id = id;
Status_.simulationId = simid;
Status_.state = "running";
Status_.liveDevices = Status_.endTime = Status_.rx = Status_.tx = Status_.msgsTx =
Status_.msgsRx = Status_.timeToFullDevices = Status_.errorDevices = 0;
Status_.startTime = Utils::Now();
Status_.owner = owner;
auto & CurrentStatus = Status_[id];
CurrentStatus.expectedDevices = Devices;
CurrentStatus.id = id;
CurrentStatus.simulationId = simid;
CurrentStatus.state = "running";
CurrentStatus.liveDevices = CurrentStatus.endTime = CurrentStatus.rx = CurrentStatus.tx = CurrentStatus.msgsTx =
CurrentStatus.msgsRx = CurrentStatus.timeToFullDevices = CurrentStatus.errorDevices = 0;
CurrentStatus.startTime = Utils::Now();
CurrentStatus.owner = owner;
}
inline void EndSim() {
std::lock_guard G(Mutex_);
CollectInfo_ = false;
Status_.state = "completed";
Status_.endTime = Utils::Now();
inline void EndSim(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
stats_hint->second.state = "completed";
stats_hint->second.endTime = Utils::Now();
}
inline void SetState(const std::string &S) {
std::lock_guard G(Mutex_);
Status_.state = S;
inline void SetState(const std::string &id, const std::string &S) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
stats_hint->second.state = S;
}
[[nodiscard]] inline const std::string &GetState() {
std::lock_guard G(Mutex_);
return Status_.state;
[[nodiscard]] inline std::string GetState(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return "";
}
return stats_hint->second.state;
}
[[nodiscard]] inline const std::string &Id() const { return Status_.id; }
inline void Reset(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return;
}
inline void Reset() {
ExpectedDevices_ = Status_.liveDevices = Status_.tx = Status_.msgsRx = Status_.msgsTx =
Status_.rx = Status_.endTime = Status_.errorDevices = Status_.startTime =
Status_.timeToFullDevices = 0;
Status_.simulationId = Status_.id = Status_.state = "";
stats_hint->second.liveDevices =
stats_hint->second.rx =
stats_hint->second.tx =
stats_hint->second.msgsRx =
stats_hint->second.msgsTx =
stats_hint->second.errorDevices =
stats_hint->second.startTime =
stats_hint->second.endTime = 0;
stats_hint->second.state = "idle";
}
[[nodiscard]] inline uint64_t GetStartTime() const { return Status_.startTime; }
[[nodiscard]] inline uint64_t GetStartTime(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return 0;
}
return stats_hint->second.startTime;
}
[[nodiscard]] inline uint64_t GetLiveDevices() const { return Status_.liveDevices; }
[[nodiscard]] inline uint64_t GetLiveDevices(const std::string &id) {
std::lock_guard G(Mutex_);
auto stats_hint = Status_.find(id);
if(stats_hint==end(Status_)) {
return 0;
}
return stats_hint->second.liveDevices;
}
private:
OWLSObjects::SimulationStatus Status_;
uint64_t ExpectedDevices_ = 0;
std::atomic_bool CollectInfo_ = false;
std::map<std::string,OWLSObjects::SimulationStatus> Status_;
SimStats() noexcept : SubSystemServer("SimStats", "SIM-STATS", "stats") {}
};
inline SimStats *SimStats() { return SimStats::instance(); }
inline auto SimStats() { return SimStats::instance(); }
} // namespace OpenWifi

View File

@@ -2,7 +2,7 @@
// Created by stephane bourque on 2021-11-03.
//
#include "Simulation.h"
#include "SimulationCoordinator.h"
#include "SimStats.h"
#include "StorageService.h"
@@ -36,136 +36,107 @@ namespace OpenWifi {
Running_ = false;
Worker_.wakeUp();
Worker_.join();
std::lock_guard G(Mutex_);
for(auto &[_,simulation]:Simulations_) {
simulation->Runner.Stop();
}
Simulations_.clear();
}
}
void SimulationCoordinator::run() {
Running_ = true;
while (Running_) {
Poco::Thread::trySleep(2000);
if (!Running_)
break;
if (SimStats()->GetState() != "running") {
continue;
}
uint64_t Now = Utils::Now();
if (CurrentSim_.simulationLength != 0 &&
(Now - SimStats()->GetStartTime()) > CurrentSim_.simulationLength) {
std::string Error;
StopSim(SimStats()->Id(), Error);
}
std::lock_guard G(Mutex_);
for(auto &[_,simulation]:Simulations_) {
if (simulation->Details.simulationLength != 0 &&
(Now - SimStats()->GetStartTime(simulation->Runner.Id())) > simulation->Details.simulationLength) {
std::string Error;
simulation->Runner.Stop();
SimStats()->EndSim(simulation->Runner.Id());
}
}
}
}
void SimulationCoordinator::StartSimulators() {
Logger().notice("Starting simulation threads...");
for (const auto &i : SimThreads_) {
i->Thread.start(i->Sim);
}
}
void SimulationCoordinator::CancelSimulators() {
void SimulationCoordinator::CancelSimulations() {
Logger().notice("Cancel simulation threads...");
SimStats()->EndSim();
for (const auto &i : SimThreads_) {
i->Sim.stop();
i->Thread.join();
for (auto &[_,simulation] : Simulations_) {
simulation->Runner.Stop();
SimStats()->EndSim(simulation->Runner.Id());
}
SimThreads_.clear();
Simulations_.clear();
}
void SimulationCoordinator::StopSimulators() {
void SimulationCoordinator::StopSimulations() {
Logger().notice("Stopping simulation threads...");
SimStats()->EndSim();
for (const auto &i : SimThreads_) {
i->Sim.stop();
i->Thread.join();
}
SimThreads_.clear();
for (auto &[_,simulation] : Simulations_) {
simulation->Runner.Stop();
SimStats()->EndSim(simulation->Runner.Id());
}
Simulations_.clear();
}
static const nlohmann::json DefaultCapabilities = R"(
{"compatible":"edgecore_eap101","label_macaddr":"90:3c:b3:bb:1e:04","macaddr":{"lan":"90:3c:b3:bb:1e:05","wan":"90:3c:b3:bb:1e:04"},"model":"EdgeCore EAP101","network":{"lan":["eth1","eth2"],"wan":["eth0"]},"platform":"ap","switch":{"switch0":{"enable":false,"reset":false}},"wifi":{"platform/soc/c000000.wifi":{"band":["5G"],"channels":[36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165],"dfs_channels":[52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,144],"frequencies":[5180,5200,5220,5240,5260,5280,5300,5320,5500,5520,5540,5560,5580,5600,5620,5640,5660,5680,5700,5720,5745,5765,5785,5805,5825],"he_mac_capa":[13,39432,4160],"he_phy_capa":[28700,34892,49439,1155,11265,0],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80","HE20","HE40","HE80","HE160","HE80+80"],"rx_ant":3,"tx_ant":3,"vht_capa":1939470770},"platform/soc/c000000.wifi+1":{"band":["2G"],"channels":[1,2,3,4,5,6,7,8,9,10,11],"frequencies":[2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462],"he_mac_capa":[13,39432,4160],"he_phy_capa":[28674,34828,49439,1155,11265,0],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80","HE20","HE40"],"rx_ant":3,"tx_ant":3,"vht_capa":1939437970}}}
)"_json;
bool SimulationCoordinator::StartSim(const std::string &SimId, [[maybe_unused]] std::string &Id,
bool SimulationCoordinator::StartSim(const std::string &SimId, std::string &Id,
std::string &Error, const std::string &Owner) {
if (SimRunning_) {
Error = "Another simulation is already running.";
return false;
}
if (!StorageService()->SimulationDB().GetRecord("id", SimId, CurrentSim_)) {
std::lock_guard G(Mutex_);
OWLSObjects::SimulationDetails NewSim;
if (!StorageService()->SimulationDB().GetRecord("id", SimId, NewSim)) {
Error = "Simulation ID specified does not exist.";
return false;
}
DefaultCapabilities_ = DefaultCapabilities;
DefaultCapabilities_["compatible"] = CurrentSim_.deviceType;
DefaultCapabilities_["compatible"] = NewSim.deviceType;
auto ClientCount = CurrentSim_.devices;
auto NumClientsPerThread = CurrentSim_.devices;
// create the actual simulation...
if (CurrentSim_.threads == 0) {
CurrentSim_.threads = Poco::Environment::processorCount() * 4;
}
if (CurrentSim_.devices > 250) {
if (CurrentSim_.devices % CurrentSim_.threads == 0) {
NumClientsPerThread = CurrentSim_.devices / CurrentSim_.threads;
} else {
NumClientsPerThread = CurrentSim_.devices / (CurrentSim_.threads + 1);
}
}
// Poco::Logger & ClientLogger = Poco::Logger::get("WS-CLIENT");
// ClientLogger.setLevel(Poco::Message::PRIO_WARNING);
for (auto i = 0; ClientCount; i++) {
auto Clients = std::min(ClientCount, NumClientsPerThread);
auto NewSimThread =
std::make_unique<SimThread>(i, CurrentSim_.macPrefix, Clients, Logger());
NewSimThread->Sim.Initialize();
SimThreads_.push_back(std::move(NewSimThread));
ClientCount -= Clients;
}
StartSimulators();
SimRunning_ = true;
SimStats()->StartSim(MicroServiceCreateUUID(), SimId, CurrentSim_.devices, Owner);
Id = MicroServiceCreateUUID();
auto NewSimulation = std::make_unique<SimulationRecord>(NewSim, Logger(), Id);
Simulations_[Id] = std::move(NewSimulation);
Simulations_[Id]->Runner.Start();
SimStats()->StartSim(Id, SimId, NewSim.devices, Owner);
return true;
}
bool SimulationCoordinator::StopSim([[maybe_unused]] const std::string &Id,
std::string &Error) {
if (!SimRunning_) {
Error = "No simulation is running.";
return false;
}
bool SimulationCoordinator::StopSim(const std::string &Id, std::string &Error) {
std::lock_guard G(Mutex_);
StopSimulators();
SimRunning_ = false;
auto sim_hint = Simulations_.find(Id);
if(sim_hint==end(Simulations_)) {
Error = "Simulation ID is not valid";
return false;
}
sim_hint->second->Runner.Stop();
OWLSObjects::SimulationStatus S;
SimStats()->GetCurrent(S);
SimStats()->GetCurrent(sim_hint->second->Runner.Id(), S);
StorageService()->SimulationResultsDB().CreateRecord(S);
return true;
}
bool SimulationCoordinator::CancelSim([[maybe_unused]] const std::string &Id,
bool SimulationCoordinator::CancelSim(const std::string &Id,
std::string &Error) {
if (!SimRunning_) {
Error = "No simulation is running.";
return false;
}
std::lock_guard G(Mutex_);
CancelSimulators();
StopSimulators();
SimRunning_ = false;
SimStats()->SetState("none");
auto sim_hint = Simulations_.find(Id);
if(sim_hint==end(Simulations_)) {
Error = "Simulation ID is not valid";
return false;
}
sim_hint->second->Runner.Stop();
SimStats()->SetState(sim_hint->second->Runner.Id(),"none");
return true;
}

View File

@@ -8,23 +8,25 @@
#include <random>
#include "RESTObjects/RESTAPI_OWLSobjects.h"
#include "Simulator.h"
#include "SimulationRunner.h"
#include "framework/SubSystemServer.h"
#include "nlohmann/json-schema.hpp"
namespace OpenWifi {
struct SimThread {
Poco::Thread Thread;
Simulator Sim;
SimThread(uint Index, std::string SerialBase, uint NumClients, Poco::Logger &L)
: Sim(Index, std::move(SerialBase), NumClients, L){};
};
struct SimulationRecord {
SimulationRecord(const OWLSObjects::SimulationDetails & details,Poco::Logger &L, const std::string &id) :
Runner(details, L, id) {
}
std::atomic_bool SimRunning = false;
OWLSObjects::SimulationDetails Details;
SimulationRunner Runner;
};
class SimulationCoordinator : public SubSystemServer, Poco::Runnable {
public:
static SimulationCoordinator *instance() {
static auto *instance_ = new SimulationCoordinator;
static auto instance() {
static auto instance_ = new SimulationCoordinator;
return instance_;
}
@@ -32,13 +34,24 @@ namespace OpenWifi {
void Stop() final;
void run() final;
bool StartSim(const std::string &SimId, std::string &Id, std::string &Error,
const std::string &Owner);
bool StartSim(const std::string &SimId, std::string &Id, std::string &Error, const std::string &Owner);
bool StopSim(const std::string &Id, std::string &Error);
bool CancelSim(const std::string &Id, std::string &Error);
[[nodiscard]] inline const OWLSObjects::SimulationDetails &GetSimulationInfo() {
return CurrentSim_;
[[nodiscard]] inline bool GetSimulationInfo( OWLSObjects::SimulationDetails & Details , const std::string &uuid = "" ) {
std::lock_guard G(Mutex_);
if(Simulations_.empty())
return false;
if(uuid.empty()) {
Details = Simulations_.begin()->second->Details;
return true;
}
auto sim_hint = Simulations_.find(uuid);
if(sim_hint==end(Simulations_))
return false;
Details = sim_hint->second->Details;
return true;
}
[[nodiscard]] inline const std::string &GetCasLocation() { return CASLocation_; }
@@ -49,12 +62,12 @@ namespace OpenWifi {
[[nodiscard]] const nlohmann::json &GetSimCapabilities() { return DefaultCapabilities_; }
[[nodiscard]] nlohmann::json GetSimConfiguration(uint64_t uuid);
private:
Poco::Thread Worker_;
std::atomic_bool Running_ = false;
std::atomic_bool SimRunning_ = false;
std::vector<std::unique_ptr<SimThread>> SimThreads_;
OWLSObjects::SimulationDetails CurrentSim_;
std::map<std::string,std::unique_ptr<SimulationRecord>> Simulations_;
std::string CASLocation_;
std::string CertFileName_;
std::string KeyFileName_;
@@ -65,12 +78,11 @@ namespace OpenWifi {
SimulationCoordinator() noexcept
: SubSystemServer("SimulationCoordinator", "SIM-COORDINATOR", "coordinator") {}
void StartSimulators();
void StopSimulators();
void CancelSimulators();
void StopSimulations();
void CancelSimulations();
};
inline SimulationCoordinator *SimulationCoordinator() {
inline auto SimulationCoordinator() {
return SimulationCoordinator::instance();
}
} // namespace OpenWifi

167
src/SimulationRunner.cpp Normal file
View File

@@ -0,0 +1,167 @@
//
// Created by stephane bourque on 2021-03-13.
//
#include <random>
#include <thread>
#include <chrono>
#include "Poco/Logger.h"
#include "SimStats.h"
#include "SimulationRunner.h"
#include "OWLSevent.h"
#include "fmt/format.h"
#include "UI_Owls_WebSocketNotifications.h"
#include "OWLSscheduler.h"
#include <Poco/Net/NetException.h>
#include <Poco/Net/SSLException.h>
namespace OpenWifi {
void SimulationRunner::Start() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(3, 15);
std::lock_guard Lock(Mutex_);
for (uint64_t i = 0; i < Details_.devices; i++) {
char Buffer[32];
snprintf(Buffer, sizeof(Buffer), "%s%05x0", Details_.macPrefix.c_str(), (unsigned int)i);
auto Client = std::make_shared<OWLSclient>(Reactor_, Buffer, Logger_, this);
Client->SerialNumber_ = Buffer;
OWLSscheduler()->Ref().in(std::chrono::seconds(distrib(gen)), OWLSclientEvents::EstablishConnection, Client, this);
Clients_[Buffer] = Client;
}
OWLSscheduler()->Ref().in(std::chrono::seconds(10), ProgressUpdate, this);
}
void SimulationRunner::ProgressUpdate(SimulationRunner *sim) {
if(sim->Running_) {
OWLSNotifications::SimulationUpdate_t Notification;
SimStats()->GetCurrent(sim->Id_, Notification.content);
OWLSNotifications::SimulationUpdate(Notification);
OWLSscheduler()->Ref().in(std::chrono::seconds(10), ProgressUpdate, sim);
}
}
void SimulationRunner::Stop() {
if (Running_) {
Running_ = false;
Reactor_.stop();
SocketReactorThread_.join();
for(auto &client:Clients_) {
OWLSclientEvents::Disconnect(client.second, this, "Simulation shutting down", false);
client.second->Valid_ = false;
}
Clients_.clear();
}
}
void SimulationRunner::OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
std::lock_guard G(Mutex_);
auto socket = pNf->socket().impl()->sockfd();
auto client_hint = Clients_fd_.find(socket);
if(client_hint==end(Clients_fd_)) {
poco_warning(Logger_,fmt::format("{}: Invalid socket", socket));
return;
}
auto client = client_hint->second;
try {
char Message[16000];
int Flags;
auto MessageSize = client->WS_->receiveFrame(Message, sizeof(Message), Flags);
auto Op = Flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
if (MessageSize == 0 && Flags == 0 && Op == 0) {
Clients_fd_.erase(socket);
OWLSclientEvents::Disconnect(client, this, "Error while waiting for data in WebSocket", true);
return;
}
Message[MessageSize] = 0;
switch (Op) {
case Poco::Net::WebSocket::FRAME_OP_PING: {
client->WS_->sendFrame("", 0,
Poco::Net::WebSocket::FRAME_OP_PONG |
Poco::Net::WebSocket::FRAME_FLAG_FIN);
} break;
case Poco::Net::WebSocket::FRAME_OP_PONG: {
} break;
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
if (MessageSize > 0) {
SimStats()->AddRX(Id_,MessageSize);
SimStats()->AddInMsg(Id_);
auto Vars = nlohmann::json::parse(Message);
if (Vars.contains("jsonrpc") && Vars.contains("id") &&
Vars.contains("method") && Vars.contains("params")) {
ProcessCommand(client, Vars);
} else {
Logger_.warning(
fmt::format("MESSAGE({}): invalid incoming message.", client->SerialNumber_));
}
}
} break;
default: {
} break;
}
return;
} catch (const Poco::Net::SSLException &E) {
Logger_.warning(
fmt::format("Exception({}): SSL exception: {}", client->SerialNumber_, E.displayText()));
} catch (const Poco::Exception &E) {
Logger_.warning(fmt::format("Exception({}): Generic exception: {}", client->SerialNumber_,
E.displayText()));
}
Clients_fd_.erase(socket);
OWLSclientEvents::Disconnect(client, this, "Error while waiting for data in WebSocket", true);
}
void SimulationRunner::ProcessCommand(std::shared_ptr<OWLSclient> Client, nlohmann::json &Vars) {
std::string Method = Vars["method"];
auto Id = Vars["id"];
auto Params = Vars["params"];
if (Method == "configure") {
CensusReport_.ev_configure++;
Client->DoConfigure(Id, Params);
} else if (Method == "reboot") {
Client->DoReboot(Id, Params);
CensusReport_.ev_reboot++;
OWLSclientEvents::Disconnect(Client,this,"Performing reboot", true);
} else if (Method == "upgrade") {
Client->DoUpgrade(Id, Params);
CensusReport_.ev_firmwareupgrade++;
OWLSclientEvents::Disconnect(Client,this,"Performing firmware upgrade", true);
} else if (Method == "factory") {
Client->DoFactory(Id, Params);
CensusReport_.ev_factory++;
OWLSclientEvents::Disconnect(Client,this,"Performing factory reset", true);
} else if (Method == "leds") {
CensusReport_.ev_leds++;
Client->DoLEDs(Id, Params);
} else if (Method == "perform") {
CensusReport_.ev_perform++;
Client->DoPerform(Id, Params);
} else if (Method == "trace") {
CensusReport_.ev_trace++;
Client->DoTrace(Id, Params);
} else {
Logger_.warning(fmt::format("COMMAND({}): unknown method '{}'", Client->SerialNumber_, Method));
}
}
} // namespace OpenWifi

62
src/SimulationRunner.h Normal file
View File

@@ -0,0 +1,62 @@
//
// Created by stephane bourque on 2021-03-13.
//
#pragma once
#include <map>
#include <set>
#include <string>
#include "Poco/Thread.h"
#include "OWLSclient.h"
#include <RESTObjects/RESTAPI_OWLSobjects.h>
#include "CensusReport.h"
namespace OpenWifi {
class SimulationRunner {
public:
explicit SimulationRunner(const OWLSObjects::SimulationDetails &Details, Poco::Logger &L, const std::string &id)
: Details_(Details), Logger_(L), Id_(id) {
}
void Stop();
void Start();
inline const OWLSObjects::SimulationDetails & Details() const { return Details_; }
CensusReport & Report() { return CensusReport_; }
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
const std::string & Id() const { return Id_; }
inline void AddClientFd(std::int64_t fd, std::shared_ptr<OWLSclient> c) {
std::lock_guard G(Mutex_);
Clients_fd_[fd] = c;
}
inline void RemoveClientFd(std::int64_t fd) {
std::lock_guard G(Mutex_);
Clients_fd_.erase(fd);
}
void ProcessCommand(std::shared_ptr<OWLSclient> Client, nlohmann::json &Vars);
private:
my_mutex Mutex_;
OWLSObjects::SimulationDetails Details_;
Poco::Logger &Logger_;
Poco::Net::SocketReactor Reactor_;
std::map<std::string, std::shared_ptr<OWLSclient>> Clients_;
std::map<std::int64_t, std::shared_ptr<OWLSclient>> Clients_fd_;
Poco::Thread SocketReactorThread_;
std::atomic_bool Running_ = false;
CensusReport CensusReport_;
std::string State_{"stopped"};
std::string Id_;
static void ProgressUpdate(SimulationRunner *s);
};
} // namespace OpenWifi

View File

@@ -1,206 +0,0 @@
//
// Created by stephane bourque on 2021-03-13.
//
#include <random>
#include <thread>
#include "Poco/Logger.h"
#include "SimStats.h"
#include "Simulator.h"
#include "uCentralEvent.h"
#include "fmt/format.h"
#include "UI_Owls_WebSocketNotifications.h"
namespace OpenWifi {
void Simulator::Initialize(/*Poco::Logger &ClientLogger*/) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(1, 15);
std::lock_guard Lock(Mutex_);
for (uint64_t i = 0; i < NumClients_; i++) {
char Buffer[32];
snprintf(Buffer, sizeof(Buffer), "%s%02x%03x0", SerialStart_.c_str(),
(unsigned int)Index_, (unsigned int)i);
auto Client = std::make_shared<uCentralClient>(Reactor_, Buffer, Logger_);
Client->AddEvent(ev_reconnect, distrib(gen));
Clients_[Buffer] = std::move(Client);
}
}
void Simulator::stop() {
if (Running_) {
Running_ = false;
Reactor_.stop();
SocketReactorThread_.join();
}
}
void Simulator::run() {
Logger_.notice(fmt::format("Starting reactor {}...", Index_));
Running_ = true;
SocketReactorThread_.start(Reactor_);
while (Running_) {
// wake up every quarter second
Poco::Thread::sleep(1000);
if (State_ == "paused")
continue;
if (State_ == "cancel")
break;
my_guard Lock(Mutex_);
try {
CensusReport_.Reset();
for (const auto &i : Clients_)
i.second->DoCensus(CensusReport_);
for (const auto &i : Clients_) {
auto Client = i.second;
auto Event = Client->NextEvent(false);
switch (Event) {
case ev_none: {
// nothing to do
} break;
case ev_reconnect: {
Logger_.information(fmt::format("reconnect({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
Client->EstablishConnection();
});
T.detach();
} break;
case ev_connect: {
Logger_.information(fmt::format("connect({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
ConnectEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_healthcheck: {
Logger_.information(fmt::format("healthcheck({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
HealthCheckEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_state: {
Logger_.information(fmt::format("state({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
StateEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_log: {
Logger_.information(fmt::format("log({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
LogEvent E(Client, std::string("log"), 2);
E.Send();
});
T.detach();
} break;
case ev_crashlog: {
Logger_.information(fmt::format("crash-log({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
CrashLogEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_configpendingchange: {
Logger_.information(fmt::format("pendingchange({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
ConfigChangePendingEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_keepalive: {
Logger_.information(fmt::format("keepalive({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
KeepAliveEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_reboot: {
Logger_.information(fmt::format("reboot({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
RebootEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_disconnect: {
Logger_.information(fmt::format("disconnect({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
DisconnectEvent E(Client);
E.Send();
});
T.detach();
} break;
case ev_wsping: {
Logger_.information(fmt::format("ws-ping({}): ", Client->Serial()));
std::thread T([Client]() {
Client->NextEvent(true);
WSPingEvent E(Client);
E.Send();
});
T.detach();
} break;
}
}
OWLSNotifications::SimulationUpdate_t Notification;
SimStats()->GetCurrent(Notification.content);
OWLSNotifications::SimulationUpdate(Notification);
} catch (const Poco::Exception &E) {
Logger_.warning(fmt::format("SIMULATOR({}): Crashed. Poco exception:{}", Index_,
E.displayText()));
} catch (const std::exception &E) {
std::string S = E.what();
Logger_.warning(
fmt::format("SIMULATOR({}): Crashed. std::exception:{}", Index_, S));
}
}
for (auto &[Key, Client] : Clients_) {
Client->Disconnect("Simulation termination", false);
}
Clients_.clear();
Logger_.notice(fmt::format("Stopped reactor {}...", Index_));
}
} // namespace OpenWifi

View File

@@ -1,43 +0,0 @@
//
// Created by stephane bourque on 2021-03-13.
//
#pragma once
#include <map>
#include <set>
#include <string>
#include "Poco/Thread.h"
#include "uCentralClient.h"
namespace OpenWifi {
class Simulator : public Poco::Runnable {
public:
Simulator(uint64_t Index, std::string SerialStart, uint64_t NumClients, Poco::Logger &L)
: Logger_(L), Index_(Index), SerialStart_(std::move(SerialStart)),
NumClients_(NumClients) {}
void run() override;
void stop();
void Initialize(/* Poco::Logger & ClientLogger*/);
void Cancel() {
State_ = "cancel";
SocketReactorThread_.wakeUp();
}
private:
Poco::Logger &Logger_;
my_mutex Mutex_;
Poco::Net::SocketReactor Reactor_;
std::map<std::string, std::shared_ptr<uCentralClient>> Clients_;
Poco::Thread SocketReactorThread_;
std::atomic_bool Running_ = false;
uint64_t Index_ = 0;
std::string SerialStart_;
uint64_t NumClients_ = 0;
CensusReport CensusReport_;
std::string State_{"stopped"};
};
} // namespace OpenWifi

View File

@@ -3092,6 +3092,20 @@ static std::string DefaultUCentralSchema = R"foo(
}
}
},
"metrics.wifi-scan": {
"type": "object",
"properties": {
"interval": {
"type": "integer"
},
"verbose": {
"type": "boolean"
},
"information-elements": {
"type": "boolean"
}
}
},
"metrics.telemetry": {
"type": "object",
"properties": {
@@ -3101,7 +3115,27 @@ static std::string DefaultUCentralSchema = R"foo(
"types": {
"type": "array",
"items": {
"type": "string"
"type": "string",
"enum": [
"ssh",
"health",
"health.dns",
"health.dhcp",
"health.radius",
"health.memory",
"client",
"client.join",
"client.leave",
"client.key-mismatch",
"wifi",
"wifi.start",
"wifi.stop",
"wired",
"wired.carrier-up",
"wired.carrier-down",
"unit",
"unit.boot-up"
]
}
}
}
@@ -3112,7 +3146,27 @@ static std::string DefaultUCentralSchema = R"foo(
"types": {
"type": "array",
"items": {
"type": "string"
"type": "string",
"enum": [
"ssh",
"health",
"health.dns",
"health.dhcp",
"health.radius",
"health.memory",
"client",
"client.join",
"client.leave",
"client.key-mismatch",
"wifi",
"wifi.start",
"wifi.stop",
"wired",
"wired.carrier-up",
"wired.carrier-down",
"unit",
"unit.boot-up"
]
}
}
}
@@ -3132,6 +3186,9 @@ static std::string DefaultUCentralSchema = R"foo(
"dhcp-snooping": {
"$ref": "#/$defs/metrics.dhcp-snooping"
},
"wifi-scan": {
"$ref": "#/$defs/metrics.wifi-scan"
},
"telemetry": {
"$ref": "#/$defs/metrics.telemetry"
},

View File

@@ -483,6 +483,7 @@ namespace OpenWifi {
Response->set("Content-Transfer-Encoding", "binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Access-Control-Expose-Headers", "Content-Disposition");
Response->set("Content-Disposition", "attachment; filename=" + Name);
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
@@ -491,7 +492,7 @@ namespace OpenWifi {
Response->sendFile(TempAvatar.path(), MT.ContentType);
}
inline void SendFileContent(const std::string &Content, const std::string &Type,
inline void SendFileContent(const std::string &Content, [[maybe_unused]] const std::string &Type,
const std::string &Name) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
@@ -500,12 +501,13 @@ namespace OpenWifi {
Response->set("Content-Transfer-Encoding", "binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Access-Control-Expose-Headers", "Content-Disposition");
Response->set("Content-Disposition", "attachment; filename=" + Name);
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setContentLength(Content.size());
Response->setContentType(Type);
Response->setContentType(MT.ContentType);
auto &OutputStream = Response->send();
OutputStream << Content;
}

View File

@@ -4,8 +4,8 @@
#pragma once
#include "framework/MicroServiceFuncs.h"
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroServiceFuncs.h"
using namespace std::chrono_literals;
@@ -14,8 +14,8 @@ namespace OpenWifi {
class RESTAPI_system_configuration : public RESTAPIHandler {
public:
RESTAPI_system_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
RESTAPI_GenericServerAccounting &Server,
uint64_t TransactionId, bool Internal)
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_GET,
@@ -27,23 +27,42 @@ namespace OpenWifi {
inline void DoPost() final {}
inline void DoGet() final { return OK(); }
inline void DoGet() final {
auto entries = GetParameter("entries","");
if(entries.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
inline void DoPut() final {
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
auto entriesArray = Poco::StringTokenizer(entries,",",Poco::StringTokenizer::TOK_TRIM);
Poco::JSON::Array Array;
for(const auto &entry:entriesArray) {
SecurityObjects::ExtraSystemConfiguration X;
X.parameterName = entry;
X.parameterValue = MicroServiceConfigGetString(entry,"");
Poco::JSON::Object E;
X.to_json(E);
Array.add(E);
}
std::ostringstream os;
Array.stringify(os);
return ReturnRawJSON(os.str());
}
inline void DoPut() final{
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
return OK();
return BadRequest(RESTAPI::Errors::NotImplemented);
};
inline void DoDelete() final {
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
inline void DoDelete() final{
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
MicroServiceDeleteOverrideConfiguration();
return OK();
return BadRequest(RESTAPI::Errors::NotImplemented);
};
};
} // namespace OpenWifi
}

View File

@@ -437,6 +437,15 @@ namespace OpenWifi::Utils {
return MediaTypeEncoding{.Encoding = PLAIN, .ContentType = "text/css"};
if (E == "js")
return MediaTypeEncoding{.Encoding = PLAIN, .ContentType = "application/javascript"};
if (E == "pcap")
return MediaTypeEncoding{.Encoding = BINARY, .ContentType = "application/vnd.tcpdump.pcap"};
if (E == "txt")
return MediaTypeEncoding{.Encoding = PLAIN, .ContentType = "text/plain"};
if (E == "tgz")
return MediaTypeEncoding{.Encoding = BINARY, .ContentType = "application/tar+gzip"};
if (E == "gz" || E=="gzip")
return MediaTypeEncoding{.Encoding = BINARY, .ContentType = "application/gzip"};
return MediaTypeEncoding{.Encoding = BINARY, .ContentType = "application/octet-stream"};
}

127
src/libs/Cron.h Normal file
View File

@@ -0,0 +1,127 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include <chrono>
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
namespace Bosma {
using Clock = std::chrono::system_clock;
inline void add(std::tm &tm, Clock::duration time) {
auto tp = Clock::from_time_t(std::mktime(&tm));
auto tp_adjusted = tp + time;
auto tm_adjusted = Clock::to_time_t(tp_adjusted);
tm = *std::localtime(&tm_adjusted);
}
class BadCronExpression : public std::exception {
public:
explicit BadCronExpression(std::string msg) : msg_(std::move(msg)) {}
const char *what() const noexcept override { return (msg_.c_str()); }
private:
std::string msg_;
};
inline void
verify_and_set(const std::string &token, const std::string &expression, int &field, const int lower_bound,
const int upper_bound, const bool adjust = false) {
if (token == "*")
field = -1;
else {
try {
field = std::stoi(token);
} catch (const std::invalid_argument &) {
throw BadCronExpression("malformed cron string (`" + token + "` not an integer or *): " + expression);
} catch (const std::out_of_range &) {
throw BadCronExpression("malformed cron string (`" + token + "` not convertable to int): " + expression);
}
if (field < lower_bound || field > upper_bound) {
std::ostringstream oss;
oss << "malformed cron string ('" << token << "' must be <= " << upper_bound << " and >= " << lower_bound
<< "): " << expression;
throw BadCronExpression(oss.str());
}
if (adjust)
field--;
}
}
class Cron {
public:
explicit Cron(const std::string &expression) {
std::istringstream iss(expression);
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
std::istream_iterator<std::string>{}};
if (tokens.size() != 5) throw BadCronExpression("malformed cron string (must be 5 fields): " + expression);
verify_and_set(tokens[0], expression, minute, 0, 59);
verify_and_set(tokens[1], expression, hour, 0, 23);
verify_and_set(tokens[2], expression, day, 1, 31);
verify_and_set(tokens[3], expression, month, 1, 12, true);
verify_and_set(tokens[4], expression, day_of_week, 0, 6);
}
// http://stackoverflow.com/a/322058/1284550
Clock::time_point cron_to_next(const Clock::time_point from = Clock::now()) const {
// get current time as a tm object
auto now = Clock::to_time_t(from);
std::tm next(*std::localtime(&now));
// it will always at least run the next minute
next.tm_sec = 0;
add(next, std::chrono::minutes(1));
while (true) {
if (month != -1 && next.tm_mon != month) {
// add a month
// if this will bring us over a year, increment the year instead and reset the month
if (next.tm_mon + 1 > 11) {
next.tm_mon = 0;
next.tm_year++;
} else
next.tm_mon++;
next.tm_mday = 1;
next.tm_hour = 0;
next.tm_min = 0;
continue;
}
if (day != -1 && next.tm_mday != day) {
add(next, std::chrono::hours(24));
next.tm_hour = 0;
next.tm_min = 0;
continue;
}
if (day_of_week != -1 && next.tm_wday != day_of_week) {
add(next, std::chrono::hours(24));
next.tm_hour = 0;
next.tm_min = 0;
continue;
}
if (hour != -1 && next.tm_hour != hour) {
add(next, std::chrono::hours(1));
next.tm_min = 0;
continue;
}
if (minute != -1 && next.tm_min != minute) {
add(next, std::chrono::minutes(1));
continue;
}
break;
}
// telling mktime to figure out dst
next.tm_isdst = -1;
return Clock::from_time_t(std::mktime(&next));
}
int minute, hour, day, month, day_of_week;
};
}

View File

@@ -0,0 +1,67 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#include <chrono>
#include <thread>
#include <future>
#include <mutex>
#include <sstream>
namespace Bosma {
class InterruptableSleep {
using Clock = std::chrono::system_clock;
// InterruptableSleep offers a sleep that can be interrupted by any thread.
// It can be interrupted multiple times
// and be interrupted before any sleep is called (the sleep will immediately complete)
// Has same interface as condition_variables and futures, except with sleep instead of wait.
// For a given object, sleep can be called on multiple threads safely, but is not recommended as behaviour is undefined.
public:
InterruptableSleep() : interrupted(false) {
}
InterruptableSleep(const InterruptableSleep &) = delete;
InterruptableSleep(InterruptableSleep &&) noexcept = delete;
~InterruptableSleep() noexcept = default;
InterruptableSleep &operator=(const InterruptableSleep &) noexcept = delete;
InterruptableSleep &operator=(InterruptableSleep &&) noexcept = delete;
void sleep_for(Clock::duration duration) {
std::unique_lock<std::mutex> ul(m);
cv.wait_for(ul, duration, [this] { return interrupted; });
interrupted = false;
}
void sleep_until(Clock::time_point time) {
std::unique_lock<std::mutex> ul(m);
cv.wait_until(ul, time, [this] { return interrupted; });
interrupted = false;
}
void sleep() {
std::unique_lock<std::mutex> ul(m);
cv.wait(ul, [this] { return interrupted; });
interrupted = false;
}
void interrupt() {
std::lock_guard<std::mutex> lg(m);
interrupted = true;
cv.notify_one();
}
private:
bool interrupted;
std::mutex m;
std::condition_variable cv;
};
}

228
src/libs/Scheduler.h Normal file
View File

@@ -0,0 +1,228 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
#pragma once
#include <iomanip>
#include <map>
#include "ctpl_stl.h"
#include "InterruptableSleep.h"
#include "Cron.h"
namespace Bosma {
using Clock = std::chrono::system_clock;
class Task {
public:
explicit Task(std::function<void()> &&f, bool recur = false, bool interval = false) :
f(std::move(f)), recur(recur), interval(interval) {}
virtual Clock::time_point get_new_time() const = 0;
virtual ~Task() = default;
std::function<void()> f;
bool recur;
bool interval;
};
class InTask : public Task {
public:
explicit InTask(std::function<void()> &&f) : Task(std::move(f)) {}
// dummy time_point because it's not used
[[nodiscard]] Clock::time_point get_new_time() const override { return Clock::time_point(Clock::duration(0)); }
};
class EveryTask : public Task {
public:
EveryTask(Clock::duration time, std::function<void()> &&f, bool interval = false) :
Task(std::move(f), true, interval), time(time) {}
[[nodiscard]] Clock::time_point get_new_time() const override {
return Clock::now() + time;
};
Clock::duration time;
};
class CronTask : public Task {
public:
CronTask(const std::string &expression, std::function<void()> &&f) : Task(std::move(f), true),
cron(expression) {}
[[nodiscard]] Clock::time_point get_new_time() const override {
return cron.cron_to_next();
};
Cron cron;
};
inline bool try_parse(std::tm &tm, const std::string &expression, const std::string &format) {
std::stringstream ss(expression);
return !(ss >> std::get_time(&tm, format.c_str())).fail();
}
class Scheduler {
public:
explicit Scheduler(unsigned int max_n_tasks = 4) : done(false), threads(max_n_tasks + 1) {
threads.push([this](int) {
while (!done) {
if (tasks.empty()) {
sleeper.sleep();
} else {
auto time_of_first_task = (*tasks.begin()).first;
sleeper.sleep_until(time_of_first_task);
}
manage_tasks();
}
});
}
Scheduler(const Scheduler &) = delete;
Scheduler(Scheduler &&) noexcept = delete;
Scheduler &operator=(const Scheduler &) = delete;
Scheduler &operator=(Scheduler &&) noexcept = delete;
~Scheduler() {
done = true;
sleeper.interrupt();
}
template<typename _Callable, typename... _Args>
void in(const Clock::time_point time, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<InTask>(
std::bind(std::forward<_Callable>(f), std::forward<_Args>(args)...));
add_task(time, std::move(t));
}
template<typename _Callable, typename... _Args>
void in(const Clock::duration time, _Callable &&f, _Args &&... args) {
in(Clock::now() + time, std::forward<_Callable>(f), std::forward<_Args>(args)...);
}
template<typename _Callable, typename... _Args>
void at(const std::string &time, _Callable &&f, _Args &&... args) {
// get current time as a tm object
auto time_now = Clock::to_time_t(Clock::now());
std::tm tm = *std::localtime(&time_now);
// our final time as a time_point
Clock::time_point tp;
if (try_parse(tm, time, "%H:%M:%S")) {
// convert tm back to time_t, then to a time_point and assign to final
tp = Clock::from_time_t(std::mktime(&tm));
// if we've already passed this time, the user will mean next day, so add a day.
if (Clock::now() >= tp)
tp += std::chrono::hours(24);
} else if (try_parse(tm, time, "%Y-%m-%d %H:%M:%S")) {
tp = Clock::from_time_t(std::mktime(&tm));
} else if (try_parse(tm, time, "%Y/%m/%d %H:%M:%S")) {
tp = Clock::from_time_t(std::mktime(&tm));
} else {
// could not parse time
throw std::runtime_error("Cannot parse time string: " + time);
}
in(tp, std::forward<_Callable>(f), std::forward<_Args>(args)...);
}
template<typename _Callable, typename... _Args>
void every(const Clock::duration time, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<EveryTask>(time, std::bind(std::forward<_Callable>(f),
std::forward<_Args>(args)...));
auto next_time = t->get_new_time();
add_task(next_time, std::move(t));
}
// expression format:
// from https://en.wikipedia.org/wiki/Cron#Overview
// ┌───────────── minute (0 - 59)
// │ ┌───────────── hour (0 - 23)
// │ │ ┌───────────── day of month (1 - 31)
// │ │ │ ┌───────────── month (1 - 12)
// │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
// │ │ │ │ │
// │ │ │ │ │
// * * * * *
template<typename _Callable, typename... _Args>
void cron(const std::string &expression, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<CronTask>(expression, std::bind(std::forward<_Callable>(f),
std::forward<_Args>(args)...));
auto next_time = t->get_new_time();
add_task(next_time, std::move(t));
}
template<typename _Callable, typename... _Args>
void interval(const Clock::duration time, _Callable &&f, _Args &&... args) {
std::shared_ptr<Task> t = std::make_shared<EveryTask>(time, std::bind(std::forward<_Callable>(f),
std::forward<_Args>(args)...), true);
add_task(Clock::now(), std::move(t));
}
private:
std::atomic<bool> done;
Bosma::InterruptableSleep sleeper;
std::multimap<Clock::time_point, std::shared_ptr<Task>> tasks;
std::mutex lock;
ctpl::thread_pool threads;
void add_task(const Clock::time_point time, std::shared_ptr<Task> t) {
std::lock_guard<std::mutex> l(lock);
tasks.emplace(time, std::move(t));
sleeper.interrupt();
}
void manage_tasks() {
std::lock_guard<std::mutex> l(lock);
auto end_of_tasks_to_run = tasks.upper_bound(Clock::now());
// if there are any tasks to be run and removed
if (end_of_tasks_to_run != tasks.begin()) {
// keep track of tasks that will be re-added
decltype(tasks) recurred_tasks;
// for all tasks that have been triggered
for (auto i = tasks.begin(); i != end_of_tasks_to_run; ++i) {
auto &task = (*i).second;
if (task->interval) {
// if it's an interval task, only add the task back after f() is completed
threads.push([this, task](int) {
task->f();
// no risk of race-condition,
// add_task() will wait for manage_tasks() to release lock
add_task(task->get_new_time(), task);
});
} else {
threads.push([task](int) {
task->f();
});
// calculate time of next run and add the new task to the tasks to be recurred
if (task->recur)
recurred_tasks.emplace(task->get_new_time(), std::move(task));
}
}
// remove the completed tasks
tasks.erase(tasks.begin(), end_of_tasks_to_run);
// re-add the tasks that are recurring
for (auto &task : recurred_tasks)
tasks.emplace(task.first, std::move(task.second));
}
}
};
}

253
src/libs/ctpl_stl.h Normal file
View File

@@ -0,0 +1,253 @@
//
// Created by stephane bourque on 2023-04-12.
//
#pragma once
/*********************************************************
*
* Copyright (C) 2014 by Vitaliy Vitsentiy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************/
#include <functional>
#include <thread>
#include <atomic>
#include <vector>
#include <memory>
#include <exception>
#include <future>
#include <mutex>
#include <queue>
// thread pool to run user's functors with signature
// ret func(int id, other_params)
// where id is the index of the thread that runs the functor
// ret is some return type
namespace ctpl {
namespace detail {
template <typename T>
class Queue {
public:
bool push(T const & value) {
std::unique_lock<std::mutex> lock(this->mutex);
this->q.push(value);
return true;
}
// deletes the retrieved element, do not use for non integral types
bool pop(T & v) {
std::unique_lock<std::mutex> lock(this->mutex);
if (this->q.empty())
return false;
v = this->q.front();
this->q.pop();
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(this->mutex);
return this->q.empty();
}
private:
std::queue<T> q;
std::mutex mutex;
};
}
class thread_pool {
public:
thread_pool() { this->init(); }
thread_pool(int nThreads) { this->init(); this->resize(nThreads); }
// the destructor waits for all the functions in the queue to be finished
~thread_pool() {
this->stop(true);
}
// get the number of running threads in the pool
int size() { return static_cast<int>(this->threads.size()); }
// number of idle threads
int n_idle() { return this->nWaiting; }
std::thread & get_thread(int i) { return *this->threads[i]; }
// change the number of threads in the pool
// should be called from one thread, otherwise be careful to not interleave, also with this->stop()
// nThreads must be >= 0
void resize(int nThreads) {
if (!this->isStop && !this->isDone) {
int oldNThreads = static_cast<int>(this->threads.size());
if (oldNThreads <= nThreads) { // if the number of threads is increased
this->threads.resize(nThreads);
this->flags.resize(nThreads);
for (int i = oldNThreads; i < nThreads; ++i) {
this->flags[i] = std::make_shared<std::atomic<bool>>(false);
this->set_thread(i);
}
}
else { // the number of threads is decreased
for (int i = oldNThreads - 1; i >= nThreads; --i) {
*this->flags[i] = true; // this thread will finish
this->threads[i]->detach();
}
{
// stop the detached threads that were waiting
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all();
}
this->threads.resize(nThreads); // safe to delete because the threads are detached
this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals
}
}
}
// empty the queue
void clear_queue() {
std::function<void(int id)> * _f;
while (this->q.pop(_f))
delete _f; // empty the queue
}
// pops a functional wrapper to the original function
std::function<void(int)> pop() {
std::function<void(int id)> * _f = nullptr;
this->q.pop(_f);
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
std::function<void(int)> f;
if (_f)
f = *_f;
return f;
}
// wait for all computing threads to finish and stop all threads
// may be called asynchronously to not pause the calling thread while waiting
// if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions
void stop(bool isWait = false) {
if (!isWait) {
if (this->isStop)
return;
this->isStop = true;
for (int i = 0, n = this->size(); i < n; ++i) {
*this->flags[i] = true; // command the threads to stop
}
this->clear_queue(); // empty the queue
}
else {
if (this->isDone || this->isStop)
return;
this->isDone = true; // give the waiting threads a command to finish
}
{
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all(); // stop all waiting threads
}
for (int i = 0; i < static_cast<int>(this->threads.size()); ++i) { // wait for the computing threads to finish
if (this->threads[i]->joinable())
this->threads[i]->join();
}
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
// therefore delete them here
this->clear_queue();
this->threads.clear();
this->flags.clear();
}
template<typename F, typename... Rest>
auto push(F && f, Rest&&... rest) ->std::future<decltype(f(0, rest...))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0, rest...))(int)>>(
std::bind(std::forward<F>(f), std::placeholders::_1, std::forward<Rest>(rest)...)
);
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
// run the user's function that excepts argument int - id of the running thread. returned value is templatized
// operator returns std::future, where the user can get the result and rethrow the catched exceptins
template<typename F>
auto push(F && f) ->std::future<decltype(f(0))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0))(int)>>(std::forward<F>(f));
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
private:
// deleted
thread_pool(const thread_pool &);// = delete;
thread_pool(thread_pool &&);// = delete;
thread_pool & operator=(const thread_pool &);// = delete;
thread_pool & operator=(thread_pool &&);// = delete;
void set_thread(int i) {
std::shared_ptr<std::atomic<bool>> flag(this->flags[i]); // a copy of the shared ptr to the flag
auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() {
std::atomic<bool> & _flag = *flag;
std::function<void(int id)> * _f;
bool isPop = this->q.pop(_f);
while (true) {
while (isPop) { // if there is anything in the queue
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
(*_f)(i);
if (_flag)
return; // the thread is wanted to stop, return even if the queue is not empty yet
else
isPop = this->q.pop(_f);
}
// the queue is empty here, wait for the next command
std::unique_lock<std::mutex> lock(this->mutex);
++this->nWaiting;
this->cv.wait(lock, [this, &_f, &isPop, &_flag](){ isPop = this->q.pop(_f); return isPop || this->isDone || _flag; });
--this->nWaiting;
if (!isPop)
return; // if the queue is empty and this->isDone == true or *flag then return
}
};
this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique()
}
void init() { this->nWaiting = 0; this->isStop = false; this->isDone = false; }
std::vector<std::unique_ptr<std::thread>> threads;
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
detail::Queue<std::function<void(int id)> *> q;
std::atomic<bool> isDone;
std::atomic<bool> isStop;
std::atomic<int> nWaiting; // how many threads are waiting
std::mutex mutex;
std::condition_variable cv;
};
}

View File

@@ -1,339 +0,0 @@
//
// Created by stephane bourque on 2021-03-12.
//
#pragma once
#include <map>
#include <mutex>
#include <random>
#include <tuple>
#include "Poco/AutoPtr.h"
#include "Poco/JSON/Object.h"
#include "Poco/Logger.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/WebSocket.h"
#include "Poco/Thread.h"
#include "framework/utils.h"
#include "nlohmann/json.hpp"
#include "uCentralEventTypes.h"
namespace OpenWifi {
struct CensusReport {
uint32_t ev_none, ev_reconnect, ev_connect, ev_state, ev_healthcheck, ev_log, ev_crashlog,
ev_configpendingchange, ev_keepalive, ev_reboot, ev_disconnect, ev_wsping;
void Reset() {
ev_none = ev_reconnect = ev_connect = ev_state = ev_healthcheck = ev_log = ev_crashlog =
ev_configpendingchange = ev_keepalive = ev_reboot = ev_disconnect = ev_wsping = 0;
}
};
enum class radio_bands { band_2g, band_5g, band_6g };
enum ap_interface_types { upstream, downstream };
inline std::int64_t local_random(std::int64_t min, std::int64_t max) {
static std::random_device rd;
static std::mt19937_64 gen{rd()};
if (min > max)
std::swap(min, max);
std::uniform_int_distribution<> dis(min, max);
return dis(gen);
}
inline auto local_random(std::int64_t max) { return local_random(0, max); }
struct FakeLanClient {
std::vector<std::string> ipv6_addresses, ipv4_addresses, ports;
std::string mac;
[[nodiscard]] nlohmann::json to_json() const {
nlohmann::json res;
res["ipv4_addresses"] = ipv4_addresses;
res["ipv6_addresses"] = ipv6_addresses;
res["ports"] = ports;
res["mac"] = mac;
return res;
}
void next() {}
};
typedef std::vector<FakeLanClient> FakeLanClients;
struct FakeAssociation {
std::string station;
std::string bssid;
std::string ipaddr_v4;
std::string ipaddr_v6;
uint64_t tx_bytes = 0, rx_bytes = 0, rx_duration = 0, rx_packets = 0, connected = 0,
inactive = 0, tx_duration = 0, tx_failed = 0, tx_packets = 0, tx_retries = 0;
int64_t ack_signal = 0, ack_signal_avg = local_random(-65, -75),
rssi = local_random(-40, -90);
[[nodiscard]] nlohmann::json to_json() const {
nlohmann::json res;
res["ack_signal"] = ack_signal;
res["ack_signal_avg"] = ack_signal_avg;
res["bssid"] = bssid;
res["station"] = station;
res["connected"] = connected;
res["inactive"] = inactive;
res["ipaddr_v4"] = ipaddr_v4;
res["rssi"] = rssi;
res["rx_bytes"] = rx_bytes;
res["rx_duration"] = rx_duration;
res["rx_packets"] = rx_packets;
res["rx_rate"]["bitrate"] = 200000;
res["rx_rate"]["chwidth"] = 40;
res["rx_rate"]["mcs"] = 9;
res["rx_rate"]["nss"] = 9;
res["rx_rate"]["sgi"] = true;
res["rx_rate"]["vht"] = true;
res["tx_bytes"] = tx_bytes;
res["tx_duration"] = tx_duration;
res["tx_failed"] = tx_failed;
res["tx_packets"] = tx_packets;
res["tx_retries"] = tx_retries;
res["tx_rate"]["bitrate"] = 200000;
res["tx_rate"]["chwidth"] = 40;
res["tx_rate"]["mcs"] = 9;
res["tx_rate"]["sgi"] = true;
res["tx_rate"]["ht"] = true;
nlohmann::json tid_stats;
nlohmann::json tid_stat;
tid_stat["rx_msdu"] = 0;
tid_stat["tx_msdu"] = 0;
tid_stat["tx_msdu_failed"] = 0;
tid_stat["tx_msdu_retries"] = 0;
tid_stats.push_back(tid_stat);
tid_stats.push_back(tid_stat);
tid_stats.push_back(tid_stat);
tid_stats.push_back(tid_stat);
tid_stats.push_back(tid_stat);
res["tid_stats"] = tid_stats;
return res;
}
void next() {
ack_signal = ack_signal_avg + local_random(-5, 5);
connected += local_random(100, 500);
inactive += local_random(100, 500);
rssi += local_random(-2, 2);
auto new_rx_packets = local_random(200, 2000);
rx_packets += new_rx_packets;
rx_bytes += new_rx_packets * local_random(500, 1000);
rx_duration += local_random(400, 1750);
auto new_tx_packets = local_random(100, 300);
tx_packets += new_tx_packets;
tx_bytes += new_tx_packets * local_random(500, 1000);
tx_duration += local_random(400, 1750);
tx_failed += local_random(3) * local_random(800, 1200);
tx_retries += local_random(3);
}
void reset() {
ack_signal = ack_signal_avg;
connected = 0;
inactive = 0;
rx_packets = 0;
rx_bytes = 0;
rx_duration = 0;
tx_packets = 0;
tx_bytes = 0;
tx_duration = 0;
tx_failed = 0;
tx_retries = 0;
}
};
typedef std::vector<FakeAssociation> FakeAssociations;
struct FakeRadio {
std::uint64_t active_ms = 0, busy_ms = 0, channel = 0, channel_width = 40, receive_ms = 0,
transmit_ms = 0, tx_power = 23;
std::int64_t noise = -100, temperature = 40;
std::string phy;
uint64_t index = 0;
[[nodiscard]] nlohmann::json to_json() const {
nlohmann::json res;
res["active_ms"] = active_ms;
res["busy_ms"] = busy_ms;
res["receive_ms"] = receive_ms;
res["transmit_ms"] = transmit_ms;
res["noise"] = noise;
res["temperature"] = temperature;
res["channel"] = channel;
res["channel_width"] = std::to_string(channel_width);
res["tx_power"] = tx_power;
res["phy"] = phy;
return res;
}
void next() {
temperature = 40 + local_random(-7, 7);
noise = -95 + local_random(-3, 3);
active_ms += local_random(100, 2000);
busy_ms += local_random(200, 3000);
receive_ms += local_random(500, 1500);
transmit_ms += local_random(250, 100);
}
void reset() {
active_ms = 0;
busy_ms = 0;
receive_ms = 0;
transmit_ms = 0;
}
};
struct FakeCounters {
std::uint64_t collisions = 0, multicast = 0, rx_bytes = 0, rx_dropped = 0, rx_errors = 0,
rx_packets = 0, tx_bytes = 0, tx_dropped = 0, tx_errors = 0, tx_packets = 0;
[[nodiscard]] nlohmann::json to_json() const {
nlohmann::json res;
res["collisions"] = collisions;
res["multicast"] = multicast;
res["rx_bytes"] = rx_bytes;
res["rx_dropped"] = rx_dropped;
res["rx_errors"] = rx_errors;
res["rx_packets"] = rx_packets;
res["tx_bytes"] = tx_bytes;
res["tx_dropped"] = tx_dropped;
res["tx_errors"] = tx_errors;
res["tx_packets"] = tx_packets;
return res;
}
void next() {
multicast += local_random(10, 100);
collisions += local_random(1);
rx_dropped += local_random(2);
rx_errors += local_random(3);
auto new_rx_packets = local_random(300, 2000);
rx_packets += new_rx_packets;
rx_bytes += new_rx_packets * local_random(900, 1400);
tx_dropped += local_random(2);
tx_errors += local_random(3);
auto new_tx_packets = local_random(300, 2000);
tx_packets += new_tx_packets;
tx_bytes += new_tx_packets * local_random(900, 1400);
}
void reset() {
multicast = 0;
collisions = 0;
rx_dropped = 0;
rx_errors = 0;
rx_packets = 0;
rx_bytes = 0;
tx_dropped = 0;
tx_errors = 0;
tx_packets = 0;
tx_bytes = 0;
}
};
class uCentralClient {
public:
uCentralClient(Poco::Net::SocketReactor &Reactor, std::string SerialNumber,
Poco::Logger &Logger);
bool Send(const std::string &Cmd);
bool SendWSPing();
bool SendObject(nlohmann::json &O);
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
void EstablishConnection();
void Disconnect(const char *Reason, bool Reconnect);
void ProcessCommand(nlohmann::json &Vars);
void SetFirmware(const std::string &S = "sim-firmware-1") { Firmware_ = S; }
[[nodiscard]] const std::string &Serial() const { return SerialNumber_; }
[[nodiscard]] uint64_t UUID() const { return UUID_; }
[[nodiscard]] uint64_t Active() const { return Active_; }
[[nodiscard]] const std::string &Firmware() const { return Firmware_; }
[[nodiscard]] bool Connected() const { return Connected_; }
[[nodiscard]] inline uint64_t GetStartTime() const { return StartTime_; }
void AddEvent(uCentralEventType E, uint64_t InSeconds);
uCentralEventType NextEvent(bool Remove);
void DoConfigure(uint64_t Id, nlohmann::json &Params);
void DoReboot(uint64_t Id, nlohmann::json &Params);
void DoUpgrade(uint64_t Id, nlohmann::json &Params);
void DoFactory(uint64_t Id, nlohmann::json &Params);
void DoLEDs(uint64_t Id, nlohmann::json &Params);
void DoPerform(uint64_t Id, nlohmann::json &Params);
void DoTrace(uint64_t Id, nlohmann::json &Params);
void DoCensus(CensusReport &Census);
static FakeAssociations CreateAssociations(const std::string &bssid, uint64_t min,
uint64_t max);
static FakeLanClients CreateLanClients(uint64_t min, uint64_t max);
nlohmann::json CreateState();
nlohmann::json CreateLinkState();
Poco::Logger &Logger() { return Logger_; };
[[nodiscard]] uint64_t GetStateInterval() { return StatisticsInterval_; }
[[nodiscard]] uint64_t GetHealthInterval() { return HealthInterval_; }
void UpdateConfiguration();
bool FindInterfaceRole(const std::string &role, ap_interface_types &interface);
void Reset();
private:
std::recursive_mutex Mutex_;
Poco::Net::SocketReactor &Reactor_;
Poco::Logger &Logger_;
nlohmann::json CurrentConfig_;
std::string SerialNumber_;
std::string Firmware_;
std::unique_ptr<Poco::Net::WebSocket> WS_;
uint64_t Active_ = 0;
uint64_t UUID_ = 0;
bool Connected_ = false;
bool KeepRedirector_ = false;
uint64_t Version_ = 0;
uint64_t StartTime_ = Utils::Now();
std::string mac_lan;
std::atomic_uint64_t HealthInterval_ = 60;
std::atomic_uint64_t StatisticsInterval_ = 60;
uint64_t bssid_index = 1;
using interface_location = std::tuple<ap_interface_types, std::string, radio_bands>;
FakeLanClients AllLanClients_;
std::map<interface_location, FakeAssociations> AllAssociations_;
std::map<radio_bands, FakeRadio> AllRadios_;
std::map<ap_interface_types, FakeCounters> AllCounters_;
std::map<ap_interface_types, std::string> AllInterfaceNames_;
std::map<ap_interface_types, std::string> AllInterfaceRoles_;
std::map<ap_interface_types, std::string> AllPortNames_;
// outstanding commands are marked with a time and the event itself
std::map<uint64_t, uCentralEventType> Commands_;
};
} // namespace OpenWifi

View File

@@ -1,121 +0,0 @@
//
// Created by stephane bourque on 2021-04-03.
//
#ifndef UCENTRAL_CLNT_UCENTRALEVENT_H
#define UCENTRAL_CLNT_UCENTRALEVENT_H
#include "Poco/JSON/Object.h"
#include "uCentralClient.h"
#include "uCentralClient.h"
#include "uCentralEventTypes.h"
namespace OpenWifi {
class uCentralEvent {
public:
explicit uCentralEvent(std::shared_ptr<uCentralClient> Client)
: Client_(std::move(Client)) {}
virtual bool Send() = 0;
protected:
bool SendObject(Poco::JSON::Object &Obj);
std::shared_ptr<uCentralClient> Client_;
};
class ConnectEvent : public uCentralEvent {
public:
explicit ConnectEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class StateEvent : public uCentralEvent {
public:
explicit StateEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class HealthCheckEvent : public uCentralEvent {
public:
explicit HealthCheckEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class LogEvent : public uCentralEvent {
public:
explicit LogEvent(std::shared_ptr<uCentralClient> Client, std::string LogLine,
uint64_t Severity)
: uCentralEvent(std::move(Client)), LogLine_(std::move(LogLine)), Severity_(Severity){};
bool Send() override;
private:
std::string LogLine_;
uint64_t Severity_;
};
class CrashLogEvent : public uCentralEvent {
public:
explicit CrashLogEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class ConfigChangePendingEvent : public uCentralEvent {
public:
explicit ConfigChangePendingEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class KeepAliveEvent : public uCentralEvent {
public:
explicit KeepAliveEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class RebootEvent : public uCentralEvent {
public:
explicit RebootEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class DisconnectEvent : public uCentralEvent {
public:
explicit DisconnectEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
class WSPingEvent : public uCentralEvent {
public:
explicit WSPingEvent(std::shared_ptr<uCentralClient> Client)
: uCentralEvent(std::move(Client)){};
bool Send() override;
private:
};
} // namespace OpenWifi
#endif // UCENTRAL_CLNT_UCENTRALEVENT_H

View File

@@ -1,28 +0,0 @@
//
// Created by stephane bourque on 2021-04-03.
//
#ifndef UCENTRAL_CLNT_UCENTRALEVENTTYPES_H
#define UCENTRAL_CLNT_UCENTRALEVENTTYPES_H
#include <mutex>
enum uCentralEventType {
ev_none,
ev_reconnect,
ev_connect,
ev_state,
ev_healthcheck,
ev_log,
ev_crashlog,
ev_configpendingchange,
ev_keepalive,
ev_reboot,
ev_disconnect,
ev_wsping
};
using my_mutex = std::recursive_mutex;
using my_guard = std::lock_guard<my_mutex>;
#endif // UCENTRAL_CLNT_UCENTRALEVENTTYPES_H

View File

@@ -1,129 +0,0 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
//
#ifndef UCENTRALGW_UCENTRALPROTOCOL_H
#define UCENTRALGW_UCENTRALPROTOCOL_H
#include "Poco/String.h"
namespace OpenWifi::uCentralProtocol {
const int SERIAL_NUMBER_LENGTH = 30;
// vocabulary used in the PROTOCOL.md file
static const char *JSONRPC = "jsonrpc";
static const char *ID = "id";
static const char *UUID = "uuid";
static const char *JSONRPC_VERSION = "2.0";
static const char *METHOD = "method";
static const char *PARAMS = "params";
static const char *SERIAL = "serial";
static const char *FIRMWARE = "firmware";
static const char *CONNECT = "connect";
static const char *STATE = "state";
static const char *HEALTHCHECK = "healthcheck";
static const char *LOG = "log";
static const char *CRASHLOG = "crashlog";
static const char *PING = "ping";
static const char *CFGPENDING = "cfgpending";
static const char *RECOVERY = "recovery";
static const char *COMPRESS_64 = "compress_64";
static const char *CAPABILITIES = "capabilities";
static const char *REQUEST_UUID = "request_uuid";
static const char *SANITY = "sanity";
static const char *DATA = "data";
static const char *LOGLINES = "loglines";
static const char *SEVERITY = "severity";
static const char *ACTIVE = "active";
static const char *REBOOT = "reboot";
static const char *WHEN = "when";
static const char *CONFIG = "config";
static const char *EMPTY_JSON_DOC = "{}";
static const char *RESULT = "result";
static const char *REQUEST = "request";
static const char *PERFORM = "perform";
static const char *CONFIGURE = "configure";
static const char *PENDING = "pending";
static const char *SUBMITTED_BY_SYSTEM = "*system";
static const char *URI = "uri";
static const char *COMMAND = "command";
static const char *PAYLOAD = "payload";
static const char *KEEP_REDIRECTOR = "keep_redirector";
static const char *DURATION = "duration";
static const char *PATTERN = "pattern";
static const char *LEDS = "leds";
static const char *ON = "on";
static const char *OFF = "off";
static const char *BLINK = "blink";
static const char *PACKETS = "packets";
static const char *NETWORK = "network";
static const char *INTERFACE = "interface";
static const char *TRACE = "trace";
static const char *WIFISCAN = "wifiscan";
static const char *TYPES = "types";
static const char *EVENT = "event";
static const char *MESSAGE = "message";
static const char *RTTY = "rtty";
static const char *TOKEN = "token";
static const char *SERVER = "server";
static const char *PORT = "port";
static const char *USER = "user";
static const char *TIMEOUT = "timeout";
static const char *UPGRADE = "upgrade";
static const char *FACTORY = "factory";
static const char *VERBOSE = "verbose";
static const char *BANDS = "bands";
static const char *CHANNELS = "channels";
static const char *PASSWORD = "password";
static const char *DEVICEUPDATE = "deviceupdate";
static const char *SERIALNUMBER = "serialNumber";
static const char *COMPATIBLE = "compatible";
static const char *DISCONNECTION = "disconnection";
static const char *TIMESTAMP = "timestamp";
static const char *SYSTEM = "system";
static const char *HOST = "host";
enum EVENT_MSG {
ET_UNKNOWN,
ET_CONNECT,
ET_STATE,
ET_HEALTHCHECK,
ET_LOG,
ET_CRASHLOG,
ET_PING,
ET_CFGPENDING,
ET_RECOVERY,
ET_DEVICEUPDATE
};
static EVENT_MSG EventFromString(const std::string &Method) {
if (!Poco::icompare(Method, CONNECT)) {
return ET_CONNECT;
} else if (!Poco::icompare(Method, STATE)) {
return ET_STATE;
} else if (!Poco::icompare(Method, HEALTHCHECK)) {
return ET_HEALTHCHECK;
} else if (!Poco::icompare(Method, LOG)) {
return ET_LOG;
} else if (!Poco::icompare(Method, CRASHLOG)) {
return ET_CRASHLOG;
} else if (!Poco::icompare(Method, PING)) {
return ET_PING;
} else if (!Poco::icompare(Method, CFGPENDING)) {
return ET_CFGPENDING;
} else if (!Poco::icompare(Method, RECOVERY)) {
return ET_RECOVERY;
} else if (!Poco::icompare(Method, DEVICEUPDATE)) {
return ET_DEVICEUPDATE;
} else
return ET_UNKNOWN;
};
} // namespace OpenWifi::uCentralProtocol
#endif // UCENTRALGW_UCENTRALPROTOCOL_H